Compare commits

...
124 Commits
Author SHA1 Message Date
Nassim Jahnke 1fb3aa8c7a 5.5.1 Release 2025-10-12 18:44:11 +02:00
木葉 Scarlet f175a903a3 Improve some collection usages (#4659) 2025-10-12 18:21:13 +02:00
FlorianMichael 7c80e37e3a Rewrite item ids in 1.12.2->1.13 show_item hover events (#4671) 2025-10-12 18:16:10 +02:00
FlorianMichael ff61e1d897 [ci skip] Update README.md (#4681) 2025-10-12 17:44:30 +02:00
AmirAli Mollaei d49272a41f Fix error when wolf_variant registry data isn't sent in 1.20.5->1.21 (#4655) 2025-10-11 13:01:19 +02:00
Nassim Jahnke bea6df1174 Add april fools snapshot identifiers 2025-10-07 19:44:27 +02:00
Nassim Jahnke 4ca84f6001 Fix <1.13 sounds for VB/VR
Technically unused in VV for now, but may also replace some in-code sound mappings later
2025-10-07 17:42:16 +02:00
Nassim Jahnke 61c079af19 Add 1.21.10 to 1.21.9 version string
No protocol changes
2025-10-07 16:06:55 +02:00
Nassim Jahnke e0b9deb128 Handle repairable item id changes 2025-10-07 15:38:09 +02:00
Nassim Jahnke 1d89bc7f95 Handle deeper lock component changes 2025-10-07 15:23:25 +02:00
dependabot[bot] 28c18c33fa Bump gradle/actions from 4 to 5 (#4678)
Bumps [gradle/actions](https://github.com/gradle/actions) from 4 to 5.
- [Release notes](https://github.com/gradle/actions/releases)
- [Commits](https://github.com/gradle/actions/compare/v4...v5)

---
updated-dependencies:
- dependency-name: gradle/actions
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 23:37:44 +02:00
Nassim Jahnke d08cb1b743 Handle debug sticks with changed blocks/properties 2025-10-06 20:31:14 +02:00
Nassim Jahnke fb18f69a0b Fix world border scale in 1.21.7->1.21.9 2025-10-05 22:05:44 +02:00
Nassim Jahnke 56e1d32aa0 Implement equippable item data hashing 2025-10-05 21:35:35 +02:00
FlorianMichael d4aa5a2fb3 More fixes to team packet filtering in 1.20.3->1.20.5 (#4674) 2025-10-05 21:23:25 +02:00
Nassim Jahnke b54a87f465 Re-shuffle mapping files to reduce size, include sound identifiers 2025-10-05 15:27:32 +02:00
RK_01 5acfa9faf7 Implement 1.21.7 -> 1.21.9 debug sample subscription translation (#4668) 2025-10-05 08:48:42 +02:00
LeonTG 638f4cd19a Fix player team tracking in 1.20.3->1.20.5 packet filtering (#4673) 2025-10-05 03:41:41 +02:00
Nassim Jahnke baf12dd516 Handle particles in biome effects
Fixes #4666
2025-10-04 10:36:17 +02:00
Nassim Jahnke 4b6b26fbba Allow empty block entity mappings in item data 2025-10-03 20:02:06 +02:00
Nassim Jahnke 5c5784795d Bump version to 5.5.1-SNAPSHOT 2025-10-03 20:01:35 +02:00
Nassim Jahnke 1f8e7515b1 5.5.0 Release 2025-10-03 13:46:23 +02:00
Nassim Jahnke 3778698018 Fix resolvable profile type order 2025-10-03 13:46:23 +02:00
Nassim Jahnke 40dd2be139 Prepare for the release later 2025-10-03 13:46:23 +02:00
FlorianMichael edbe2c92ce Add entity identifier when downgrading entity data components 2025-10-03 13:46:23 +02:00
Nassim Jahnke b9ae1ef43e Handle unknown block entity/entity types 2025-10-03 13:46:23 +02:00
Nassim Jahnke 4631fd1977 Remove unhandled compound tag entity data from bad packets 2025-10-03 13:46:22 +02:00
Nassim Jahnke 3d25686745 Handle key changes in item_model 2025-10-03 13:46:22 +02:00
Nassim Jahnke 18b5b2626a Remove snapshot bit 2025-10-03 13:46:22 +02:00
Nassim Jahnke 219ad4737a 1.21.9-rc1 2025-10-03 13:46:22 +02:00
riku6460 b9368ae80a Fix lighting in the end dimension in 1.21.7->1.21.9 2025-10-03 13:46:22 +02:00
Nassim Jahnke 03c80ccff8 1.21.9-pre4 2025-10-03 13:46:22 +02:00
Nassim Jahnke f6aed5578f 1.21.9-pre3 2025-10-03 13:46:21 +02:00
Nassim Jahnke 646de0b1af Handle changed bees data 2025-10-03 13:46:21 +02:00
Nassim Jahnke 4e33a40ede 1.21.9-pre2 2025-10-03 13:46:21 +02:00
Nassim Jahnke 21b0ac7a43 1.21.9-pre1 2025-10-03 13:46:21 +02:00
Nassim Jahnke 15d3944700 Fix mannequin entity data reading 2025-10-03 13:46:21 +02:00
Nassim Jahnke acd9a6f57c 25w37a 2025-10-03 13:46:20 +02:00
Nassim Jahnke d5fe4e22b4 25w36a/b 2025-10-03 13:46:20 +02:00
Nassim Jahnke 9f0c38915a 25w35a 2025-10-03 13:46:20 +02:00
Nassim Jahnke bc7f081b3a I figured out the magic numbers 2025-10-03 13:46:20 +02:00
Nassim Jahnke 46b6627f9f 25w34b
Minus some dynamic player profile stuff
2025-10-03 13:46:20 +02:00
Nassim Jahnke 51cc1843ad 25w33a 2025-10-03 13:46:19 +02:00
Nassim Jahnke 98d1d2cb49 25w32a 2025-10-03 13:46:19 +02:00
Nassim Jahnke 556560a0f3 25w31a 2025-10-03 13:46:19 +02:00
FlorianMichael be2534c6e6 Add missing game test payload sanitize in 1.20->1.20.2 (#4661) 2025-10-02 16:14:50 +02:00
RaynLegends d40d1bd232 Fix system messages sent during config state hidden on <= 1.12.2 servers (#4650)
Fixes ViaVersion/issues#4478
2025-09-21 18:32:14 +02:00
Nassim Jahnke 6143f78ccf Update dependencies 2025-09-20 22:36:43 +02:00
EnZaXD 52cdebc3d3 Execute stored object clear call inside the event loop (#4652)
This fixes NPE exceptions when players disconnect. A packet goes through the pipeline after setActive(false) was called causing NPE exceptions.
2025-09-20 22:35:47 +02:00
EnZaXD cdccae95e0 Remove serialize versions from item hasher (#4651) 2025-09-16 21:24:42 +02:00
EnZaXD b0c45e3ed3 Fix wrong shulker box mapping in 1.12.2->1.13 (#4641)
Closes https://github.com/ViaVersion/ViaVersion/issues/4636
2025-09-14 18:53:16 +02:00
EnZaXD 3ba518650c Filter invalid remove teams packets in 1.20.3->1.20.5 (#4643)
Closes https://github.com/ViaVersion/ViaVersion/issues/4564
2025-09-13 11:23:18 +02:00
Nassim Jahnke 5a303996a1 Cleanup and fixes to storable object task 2025-09-05 19:35:04 +02:00
FlorianMichael 695534e8a8 Don't run movement transmitter provider in netty thread 2025-09-05 19:02:51 +02:00
EnZaXD 16ba011243 Rename ProtocolRunnable, always submit tick logic into event loop (#4644) 2025-09-03 17:05:53 +02:00
Nassim Jahnke 0ea7271157 Update deps 2025-09-03 07:42:12 +02:00
EnZaXD dc2b2f1407 Rename RedirectProtocolVersion (#4642) 2025-09-01 21:01:30 +02:00
Nassim Jahnke 85baefc69b Log channel close outside of event loop when debug is enabled 2025-08-31 22:39:15 +02:00
riku6460andFlorianMichael 41e0fdc20f Add EntityTracker#clear and clear entities on entering configuration state (#4638)
Co-authored-by: FlorianMichael <florian.michael07@gmail.com>
2025-08-29 17:15:39 +02:00
dependabot[bot] 5c328fba33 Bump actions/setup-java from 4 to 5 (#4637)
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4 to 5.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-26 15:35:43 +02:00
EnZaXD 91b11878fb Fix ViaAPI#getConnection javadoc and remove not needed code (#4635) 2025-08-20 17:38:19 +02:00
Nassim Jahnke 0ea5e07d63 Don't replace velocity servers section when merging with default config 2025-08-19 16:14:03 +02:00
Nassim Jahnke 152e4e77a8 Handle custom name in banner etc. in 1.21.4->1.21.5
Newer clients handle errors gracefully and will parse them okay, but this'll make sure they are properly set
2025-08-17 16:41:26 +02:00
Nassim Jahnke cf20c6397d Fix spawn_particles key 2025-08-15 08:35:34 +02:00
Nassim Jahnke 981672e2cf Update particle types in enchantments 2025-08-14 18:22:55 +02:00
dependabot[bot] d10b600e72 [ci skip] Bump actions/checkout from 4 to 5 (#4627)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [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/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 08:23:33 +02:00
Nassim Jahnke de9cec36c7 Don't hash empty items in container 2025-08-10 15:39:45 +02:00
Nassim Jahnke 6eb561607c Fix bad reference 2025-08-10 15:12:22 +02:00
Nassim Jahnke db3e1f605a Fix hashing of maps in lists 2025-08-10 15:04:39 +02:00
Nassim Jahnke 31583fc2d3 Update deps 2025-08-09 18:43:37 +02:00
Nassim Jahnke 6096ce4eea Add option to log blocked joins
Closes #4613
2025-08-09 18:21:15 +02:00
Nassim Jahnke 873da12233 Check if custom_name lock data is actually present in 1.21.2
Fixes #4622
2025-08-09 17:50:04 +02:00
EnZaXD 78191ea366 [ci skip] Gradle & Shadow 9.0.0; Rewrite .gitignore file (#4606) 2025-08-09 14:18:03 +02:00
EnZaXD f8d7c5c193 [ci skip] Fix packet id comments (#4621) 2025-08-09 13:11:52 +02:00
EnZaXD bc9c979e7d Don't make the protocol pipeline depend on simple protocol (#4619) 2025-08-08 18:59:19 +02:00
EnZaXD d686a9ddf0 Move protocol logger creation to AbstractProtocol#createLogger (#4620)
Allows VB to delegate the used logger to the VB platform logger
2025-08-08 15:36:25 +02:00
EnZaXD 9dd610605f Don't put legacy show_text value through json conversion in 1.21.1->.5 (#4611) 2025-08-05 09:19:31 +02:00
EnZaXD 219e163ac2 Add statistic mappings for 1.21.5->1.21.6 (#4609) 2025-08-03 09:33:56 +02:00
EnZaXD 925e7b4664 Add some backwards compatibility functions to PacketTracker (#4607) 2025-08-02 15:09:46 +02:00
criticalcynical 5a9f040af8 Fix wrong connections being removed when switching servers on proxy platforms (#4576) 2025-07-29 20:35:20 +02:00
Nassim Jahnke 992ad7f35a Fix max packet size check 2025-07-29 20:28:37 +02:00
EnZaXD bb93ac011c Null check original root section (#4604) 2025-07-29 19:38:13 +02:00
Nassim Jahnke 4070ea9f02 Revamp max-pps config
Add a config section for setting max packet size, add a toggle for disabling each tracker fully
2025-07-29 12:27:51 +02:00
EnZaXD 499efa1608 Convert HIDE_ADDITIONAL_TOOLTIP in both directions in 1.21.4->1.21.5 (#4600) 2025-07-29 12:19:10 +02:00
Nassim Jahnke 0196d9c83e Bump version to 5.5.0-SNAPSHOT 2025-07-29 12:11:59 +02:00
Nassim Jahnke 4c316de042 5.4.2 Release 2025-07-23 23:03:10 +02:00
EnZaXD 8ee5d7e680 Add missing biome name translations in 1.17.1->1.18 (#4597) 2025-07-22 20:50:33 +02:00
Nassim Jahnke 64c128d414 Fix 1.8/1.9 thrown potion entity data handling
Fixes #4596
2025-07-21 23:55:03 +02:00
Nassim Jahnke 77d11fc593 Update attribute modifier types in show item hovers
Fixes #4593
2025-07-18 20:50:46 +02:00
Nassim Jahnke 2c72a09809 Strip namespace from custom attribute id when getting names 2025-07-18 11:01:52 +02:00
Nassim Jahnke 3dbd81da76 [ci skip] Split up publishing steps
Putting them into the same step meant if one publish action failed, the second one wouldn't run. Before this change, Modrinth would often block Hangar from publishing
2025-07-17 16:10:15 +02:00
Nassim Jahnke a0116c7ea7 Add 1.21.8 version string to 1.21.7 2025-07-17 14:33:58 +02:00
Nassim Jahnke fd5dadbe01 [ci skip] Clean up imports 2025-07-14 12:36:56 +02:00
Kai df87a02c38 Update ViaNBT (#4585) 2025-07-14 12:25:59 +02:00
EnZaXD bb293b3e5d Add cancel-swing-in-inventory option for 1.15.2->1.16 inventory swing fix (#4587) 2025-07-14 12:24:53 +02:00
EnZaXDanddewgs ff03892b25 Fix some directions not being included in chunk-border-fix; Reduce packets sent by checking for needed chunks (#4586)
Co-authored-by: dewgs <23721849+dewgs@users.noreply.github.com>
2025-07-14 12:21:28 +02:00
EnZaXD eb51306d82 Fix ItemFactory#getSpawnEgg NoSuchMethodError on older Paper builds (#4582) 2025-07-13 08:40:09 +02:00
EnZaXD 81eb3362f3 [ci skip] Add Java resolving plugin (#4577) 2025-07-12 10:31:23 +02:00
EnZaXD 7f06b03453 Remove StorableObject#clearOnServerSwitch (#4583) 2025-07-12 10:30:30 +02:00
RK_01 c16432de2a Fix anticheat flags when respawning with 1.21.2+ clients on older servers (#4573)
Fixes #4572
2025-07-07 21:40:01 +02:00
Nassim Jahnke b162dbdff0 Add missing null check to allowed_entities rewrite
Fixes #4568
2025-07-05 13:55:55 +02:00
Nassim Jahnke dfbe57e304 Rewrite Equippable allowed_entities
Fixes #4567
2025-07-04 17:17:05 +02:00
Nassim Jahnke 6f6dc2c641 Rewrite attribute modifiers automatically via interface
An id change in 1.21.5->1.21.6 was missed
2025-06-30 21:27:00 +02:00
Nassim Jahnke 06990ec0c9 Bump version to 5.4.2-SNAPSHOT 2025-06-30 21:26:14 +02:00
Nassim Jahnke 351b42b5e5 5.4.1 Release 2025-06-30 09:56:25 +02:00
Nassim Jahnke 20e3c832fb 1.21.7-rc2 2025-06-30 09:49:48 +02:00
Nassim Jahnke ec9c121da2 1.21.7-rc1 2025-06-30 09:49:47 +02:00
FlorianMichael 12c773edea Add missing translatable mappings (#4542)
Fixes #3331
Fixes #4273
2025-06-30 09:47:33 +02:00
Nassim Jahnke 97b411aa6d Manually handle text component boolean entries
Fixes #4558
2025-06-29 16:36:12 +02:00
Nassim Jahnke 24f6c4f0fd Implement hashing for potion contents 2025-06-29 15:50:56 +02:00
FlorianMichael 9409c7d22a [ci skip] Add SECURITY.md (#4520) 2025-06-29 15:36:49 +02:00
FlorianMichael 17d94a17f0 Always write length in LengthPrefixedTagType 2025-06-29 11:51:38 +02:00
riku6460andFlorianMichael a1cb4d3691 Add Types#CUSTOM_CLICK_ACTION_TAG for VB (#4557)
* Add LengthPrefixedTagType for CUSTOM_CLICK_ACTION

* Move type into own class, add instance into Types

---------

Co-authored-by: FlorianMichael <florian.michael07@gmail.com>
2025-06-29 07:21:48 +02:00
Nassim Jahnke 1d5070a480 Allow mapping sound event holders to empty sounds 2025-06-27 10:24:34 +02:00
FlorianMichaelanddewgs f612adbd0a Rewrite player & display name in player info packet in 1.12.2->1.13 (#4550)
Fixes Tablist plugins on some servers breaking since the game profile name sent is used to determine the scoreboard team which name we rewrite in other packets, also adds missing component rewriter calls to the display names (Not that important given its only translation keys, but we are already here).

Co-authored-by: dewgs <23721849+dewgs@users.noreply.github.com>
2025-06-25 13:31:17 +02:00
FlorianMichael 6716beec5a Remove arbitrary chat-nbt-fix config option in 1.11.1->1.12 (#4551) 2025-06-25 13:28:23 +02:00
Nassim Jahnke d22b00e4a6 Add helper methods for registry entry rewriting 2025-06-22 22:53:08 +02:00
Nassim Jahnke fe9ca49920 Update mcstructs 2025-06-22 10:38:33 +02:00
PacksoliteandNassim Jahnke e1837dc578 Fix legacy block picking on some Paper forks (#4496)
Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
2025-06-21 11:22:22 +02:00
booky 66eead2927 Fix missing clouds in 1.21.5->1.21.6 (#4538) 2025-06-21 11:00:19 +02:00
booky 937a2a2532 Fix server links button not visible in 1.21.5->1.21.6 (#4536)
The Minecraft 1.21.6 client will only show the server links if the the server_links dialog has been sent
2025-06-21 01:47:34 +02:00
Nassim Jahnke bee45ef9ef Use Cache get instead of Map compute
This may or may not fix concurrency issues from... somewhere (bad plugins/old guava impl?)
2025-06-20 21:40:37 +02:00
FlorianMichael 1946a65ab2 Add MathUtil#ceil 2025-06-20 21:36:44 +02:00
Nassim Jahnke f594a946d4 Bump version to 5.4.1-SNAPSHOT 2025-06-20 21:36:33 +02:00
296 changed files with 6493 additions and 1383 deletions

No files matched your search

+3 -3
View File
@@ -11,13 +11,13 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 17
+12 -5
View File
@@ -12,19 +12,26 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
uses: gradle/actions/setup-gradle@v5
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 17
check-latest: true
- name: Publish
- name: Build
run: ./gradlew build
- name: Publish to Hangar
env:
HANGAR_TOKEN: ${{ secrets.HANGAR_TOKEN }}
run: ./gradlew publishAllPublicationsToHangar --stacktrace
continue-on-error: true
- name: Publish to Modrinth
env:
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
run: ./gradlew build modrinth publishAllPublicationsToHangar --stacktrace
run: ./gradlew modrinth --stacktrace
continue-on-error: true
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Update Gradle Wrapper
+19 -98
View File
@@ -1,115 +1,36 @@
### Java files ###
*.class
# Gradle
# Package Files
#*.jar
*.war
*.ear
.gradle/
build/
out/
classes/
.kotlin/
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# Eclipse
*.launch
# Idea
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
# Ignore project files
*.iml
# Ignore IDEA directory
.idea/*
.idea/
!.idea/copyright/*
!.idea/scopes/*
# Include the project's dictionary
!.idea/dictionaries/
!.idea/dictionaries/*
# File-based project format:
*.iml
*.ipr
*.iws
### Plugin-specific files: ###
# IntelliJ
/out/
# VSCode
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# Eclipse Core
.vscode/
bin/
.classpath
.project
# External tool builders
.externalToolBuilders/
# macOS
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml
.nb-gradle/
### MacOS ###
.DS_Store
### Run Folder (ViaProxy) ###
common/run/
# Misc
run/
+2 -4
View File
@@ -8,7 +8,7 @@
it works on any platform you can think of.**
The base ViaVersion jar runs on Paper and Velocity. We also have projects integrating ViaVersion to run
on Fabric, Forge, Bungee, Sponge, or as a standalone proxy to join from basically any client version on
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.**
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
@@ -16,7 +16,7 @@ direct access to client/server state and more extensive API.
Supported Versions:
![Table (https://i.imgur.com/zrQTcf0.png)](https://i.imgur.com/zrQTcf0.png)
![Table (https://ci.viaversion.com/userContent/images/T.png)](https://ci.viaversion.com/userContent/images/T.png)
**User Docs:** https://docs.viaversion.com
@@ -87,12 +87,10 @@ of the `build/libs` directory.
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).
Resources
--------
+10
View File
@@ -0,0 +1,10 @@
# Security Policy
## Reporting a Vulnerability
If you discover a **security vulnerability**, please **do not** open a public issue. Instead, use one of the following **confidential contact methods**:
* **Email:** [security@viaversion.com](mailto:security@viaversion.com)
* **Discord:** Join our [Discord server](https://discord.gg/viaversion) and visit the [#exploit-report](https://discord.com/channels/316206679014244363/1388847764137316485) channel for further instructions.
If your issue is **not security-related** (e.g., bug reports, feature requests, or usage questions), please use the [GitHub Issues page](https://github.com/ViaVersion/ViaVersion/issues) or contact us via the [Discord server](https://discord.gg/viaversion).
@@ -123,7 +123,7 @@ public interface ViaAPI<T> {
boolean isInjected(UUID uuid);
/**
* Returns whether Via injected into this player connection. Note that this method may not work on
* Returns the injected UserConnection if present. Note that this method may not work on
* clientside implementations and is generally not recommended to be used. Use {@link ConnectionManager} instead.
*
* @param uuid uuid of the player
@@ -0,0 +1,27 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.configuration;
public record RateLimitConfig(boolean enabled, int maxRate, String maxRateKickMessage, int warningRate, int maxWarnings,
long trackingPeriodNanos, String warningKickMessage, String ratePlaceholder) {
}
@@ -147,6 +147,7 @@ public interface ViaVersionConfig extends Config {
*
* @return The number of packets a client can send per second.
*/
@Deprecated(forRemoval = true)
int getMaxPPS();
/**
@@ -154,6 +155,7 @@ public interface ViaVersionConfig extends Config {
*
* @return Kick message, with colour codes using '&amp;amp;'
*/
@Deprecated(forRemoval = true)
String getMaxPPSKickMessage();
/**
@@ -161,6 +163,7 @@ public interface ViaVersionConfig extends Config {
*
* @return Time in seconds that should be tracked for warnings
*/
@Deprecated(forRemoval = true)
int getTrackingPeriod();
/**
@@ -168,6 +171,7 @@ public interface ViaVersionConfig extends Config {
*
* @return The number of packets per second to count as a warning.
*/
@Deprecated(forRemoval = true)
int getWarningPPS();
/**
@@ -175,6 +179,7 @@ public interface ViaVersionConfig extends Config {
*
* @return The number of packets a client can send per second.
*/
@Deprecated(forRemoval = true)
int getMaxWarnings();
/**
@@ -182,8 +187,13 @@ public interface ViaVersionConfig extends Config {
*
* @return Kick message, with colour codes using '&amp;amp;'
*/
@Deprecated(forRemoval = true)
String getMaxWarningsKickMessage();
RateLimitConfig getPacketTrackerConfig();
RateLimitConfig getPacketSizeTrackerConfig();
/**
* Send supported versions in the status response packet
*
@@ -233,13 +243,6 @@ public interface ViaVersionConfig extends Config {
*/
boolean isChunkBorderFix();
/**
* Should we fix nbt array's in json chat messages for 1.12 clients
*
* @return true if enabled
*/
boolean is1_12NBTArrayFix();
/**
* Should we make team colours based on the last colour in team prefix
*
@@ -270,6 +273,8 @@ public interface ViaVersionConfig extends Config {
*/
String getBlockedDisconnectMsg();
boolean logBlockedJoins();
/**
* Get the message sent to players being kicked on reload.
* Players are kicked to stop the server crashing
@@ -485,4 +490,12 @@ public interface ViaVersionConfig extends Config {
* @return true if enabled
*/
boolean fix1_21PlacementRotation();
/**
* If enabled, cancel swing packets sent while having an inventory opened on 1.15.2 and below servers.
* This can cause false positives with anti-cheat plugins.
*
* @return true if enabled
*/
boolean cancelSwingInInventory();
}
@@ -30,15 +30,6 @@ package com.viaversion.viaversion.api.connection;
*/
public interface StorableObject {
/**
* Returns whether the object should be uncached on a server switch.
*
* @return whether the object should be uncached on a server switch
*/
default boolean clearOnServerSwitch() {
return true;
}
default void onRemove() {
}
}
@@ -139,17 +139,7 @@ public interface UserConnection {
/**
* Clear stored objects, entity trackers and client worlds.
*/
default void clearStoredObjects() {
clearStoredObjects(false);
}
/**
* Clear stored objects, entity trackers and client worlds.
* If cleared for a proxy server switch, some stored objects and tracker data will be retained.
*
* @param isServerSwitch whether the clear is due to a server switch
*/
void clearStoredObjects(boolean isServerSwitch);
void clearStoredObjects();
/**
* Sends a raw packet to the connection on the current thread.
@@ -204,9 +194,15 @@ public interface UserConnection {
/**
* Monitors serverbound packets and returns whether a packet can/should be processed.
*
* @param bytes the number of bytes in the packet
* @return false if this packet should be cancelled
*/
boolean checkServerboundPacket();
boolean checkServerboundPacket(int bytes);
@Deprecated(forRemoval = true)
default boolean checkServerboundPacket() {
return checkServerboundPacket(0);
}
/**
* Monitors clientbound packets and returns whether a packet can/should be processed.
@@ -219,6 +215,11 @@ public interface UserConnection {
* @see #checkClientboundPacket()
* @see #checkServerboundPacket()
*/
default boolean checkIncomingPacket(final int bytes) {
return isClientSide() ? checkClientboundPacket() : checkServerboundPacket(bytes);
}
@Deprecated(forRemoval = true)
default boolean checkIncomingPacket() {
return isClientSide() ? checkClientboundPacket() : checkServerboundPacket();
}
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.data;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.TagData;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -140,12 +141,14 @@ public interface MappingData {
@Nullable Mappings getBlockMappings();
@Nullable Mappings getBlockEntityMappings();
@Nullable FullMappings getFullBlockMappings();
@Nullable Mappings getBlockStateMappings();
@Nullable Mappings getSoundMappings();
@Nullable FullMappings getFullSoundMappings();
@Nullable Mappings getStatisticsMappings();
@Nullable Mappings getMenuMappings();
@@ -154,6 +157,8 @@ public interface MappingData {
@Nullable Mappings getPaintingMappings();
@Nullable FullMappings getBlockEntityMappings();
@Nullable FullMappings getAttributeMappings();
@Nullable FullMappings getEntityMappings();
@@ -163,4 +168,26 @@ public interface MappingData {
@Nullable FullMappings getRecipeSerializerMappings();
@Nullable FullMappings getDataComponentSerializerMappings();
default @Nullable FullMappings getFullMappings(final MappingType mappingType) {
return switch (mappingType) {
case ITEM -> getFullItemMappings();
case SOUND -> getFullSoundMappings();
case ENTITY -> getEntityMappings();
};
}
/**
* Set of block (not block state) ids that had their base type or properties changed.
*
* @return set of changed block ids, or null if not tracked/none are present
*/
@Nullable IntSet changedBlocks();
/**
* Type of mappings. Currently only relevant for ops writing of generic holder classes and expanded when needed.
*/
enum MappingType {
ITEM, SOUND, ENTITY
}
}
@@ -28,6 +28,8 @@ import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.TagData;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
@@ -44,17 +46,21 @@ public class MappingDataBase implements MappingData {
protected FullMappings recipeSerializerMappings;
protected FullMappings itemDataSerializerMappings;
protected FullMappings attributeMappings;
protected FullMappings blockEntityMappings;
protected ParticleMappings particleMappings;
protected BiMappings itemMappings;
protected BiMappings blockMappings;
protected Mappings blockStateMappings;
protected Mappings blockEntityMappings;
protected Mappings soundMappings;
protected Mappings statisticsMappings;
protected Mappings enchantmentMappings;
protected Mappings paintingMappings;
protected Mappings menuMappings;
protected Map<RegistryType, List<TagData>> tags;
/**
* Set of block ids that have had type or property changes.
*/
protected IntSet changedBlocks;
public MappingDataBase(final String unmappedVersion, final String mappedVersion) {
this.unmappedVersion = unmappedVersion;
@@ -68,10 +74,7 @@ public class MappingDataBase implements MappingData {
}
final CompoundTag data = readMappingsFile("mappings-" + unmappedVersion + "to" + mappedVersion + ".nbt");
blockMappings = loadBiMappings(data, "blocks");
blockStateMappings = loadMappings(data, "blockstates");
blockEntityMappings = loadMappings(data, "blockentities");
soundMappings = loadMappings(data, "sounds");
statisticsMappings = loadMappings(data, "statistics");
menuMappings = loadMappings(data, "menus");
enchantmentMappings = loadMappings(data, "enchantments");
@@ -80,12 +83,16 @@ public class MappingDataBase implements MappingData {
final CompoundTag unmappedIdentifierData = readUnmappedIdentifiersFile("identifiers-" + unmappedVersion + ".nbt");
final CompoundTag mappedIdentifierData = readMappedIdentifiersFile("identifiers-" + mappedVersion + ".nbt");
if (unmappedIdentifierData != null && mappedIdentifierData != null) {
itemMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "items");
itemMappings = loadFullOrBiMappings(data, unmappedIdentifierData, mappedIdentifierData, "items");
blockMappings = loadFullOrBiMappings(data, unmappedIdentifierData, mappedIdentifierData, "blocks");
soundMappings = loadFullOrBiMappings(data, unmappedIdentifierData, mappedIdentifierData, "sounds");
entityMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "entities");
argumentTypeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "argumenttypes");
recipeSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "recipe_serializers");
itemDataSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "data_component_type");
attributeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "attributes");
blockEntityMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "blockentities");
final List<String> unmappedParticles = identifiersFromGlobalIds(unmappedIdentifierData, "particles");
final List<String> mappedParticles = identifiersFromGlobalIds(mappedIdentifierData, "particles");
@@ -99,6 +106,8 @@ public class MappingDataBase implements MappingData {
} else {
// Might not have identifiers in older versions
itemMappings = loadBiMappings(data, "items");
blockMappings = loadBiMappings(data, "blocks");
soundMappings = loadMappings(data, "sounds");
}
final CompoundTag tagsTag = data.getCompoundTag("tags");
@@ -109,6 +118,11 @@ public class MappingDataBase implements MappingData {
loadTags(RegistryType.ENTITY, tagsTag);
}
final IntArrayTag changedBlocks = data.getIntArrayTag("changed_blocks");
if (changedBlocks != null) {
this.changedBlocks = new IntOpenHashSet(changedBlocks.getValue());
}
loadExtras(data);
}
@@ -132,6 +146,11 @@ public class MappingDataBase implements MappingData {
return MappingDataLoader.INSTANCE.loadMappings(data, key);
}
protected @Nullable BiMappings loadFullOrBiMappings(final CompoundTag data, final CompoundTag unmappedIdentifiersTag, final CompoundTag mappedIdentifiersTag, final String key) {
final FullMappings mappings = loadFullMappings(data, unmappedIdentifiersTag, mappedIdentifiersTag, key);
return mappings != null ? mappings : loadBiMappings(data, key);
}
protected @Nullable FullMappings loadFullMappings(final CompoundTag data, final CompoundTag unmappedIdentifiersTag, final CompoundTag mappedIdentifiersTag, final String key) {
if (!unmappedIdentifiersTag.contains(key) || !mappedIdentifiersTag.contains(key)) {
return null;
@@ -208,8 +227,8 @@ public class MappingDataBase implements MappingData {
}
@Override
public int getOldSoundId(final int i) {
return soundMappings.getNewIdOrDefault(i, 0);
public int getOldSoundId(final int id) {
return soundMappings.inverse().getNewIdOrDefault(id, 0);
}
@Override
@@ -224,8 +243,8 @@ public class MappingDataBase implements MappingData {
@Override
public @Nullable FullMappings getFullItemMappings() {
if (itemMappings instanceof FullMappings) {
return (FullMappings) itemMappings;
if (itemMappings instanceof FullMappings fullItemMappings) {
return fullItemMappings;
}
return null;
}
@@ -241,7 +260,15 @@ public class MappingDataBase implements MappingData {
}
@Override
public @Nullable Mappings getBlockEntityMappings() {
public @Nullable FullMappings getFullBlockMappings() {
if (blockMappings instanceof FullMappings fullBlockMappings) {
return fullBlockMappings;
}
return null;
}
@Override
public @Nullable FullMappings getBlockEntityMappings() {
return blockEntityMappings;
}
@@ -255,6 +282,14 @@ public class MappingDataBase implements MappingData {
return soundMappings;
}
@Override
public @Nullable FullMappings getFullSoundMappings() {
if (soundMappings instanceof FullMappings fullSoundMappings) {
return fullSoundMappings;
}
return null;
}
@Override
public @Nullable Mappings getStatisticsMappings() {
return statisticsMappings;
@@ -300,6 +335,11 @@ public class MappingDataBase implements MappingData {
return recipeSerializerMappings;
}
@Override
public @Nullable IntSet changedBlocks() {
return changedBlocks;
}
protected Logger getLogger() {
return Via.getPlatform().getLogger();
}
@@ -210,7 +210,7 @@ public class MappingDataLoader {
return null;
}
final int mappedSize = tag.getIntTag("mappedSize").asInt();
final int mappedSize = tag.getInt("mappedSize", -1);
final byte strategy = tag.getByteTag("id").asByte();
final V mappings;
if (strategy == DIRECT_ID) {
@@ -82,6 +82,11 @@ public interface EntityTracker {
*/
void clearEntities();
/**
* Clears all stored data, including entity types, entity data and client entity id.
*/
void clear();
/**
* Returns the stored entity data if an entity with the id is tracked, else null.
* If no data has been initialized yet, it will be done and returned by this method.
@@ -180,6 +185,20 @@ public interface EntityTracker {
*/
void setCurrentWorld(String currentWorld);
/**
* Returns the id of the current dimension, or -1 if unset (i.e. before 1.20.5).
*
* @return id of the current dimension, or -1 if unset
*/
int currentDimensionId();
/**
* Sets the id of the current dimension.
*
* @param currentDimensionId id of the current dimension
*/
void setCurrentDimensionId(int currentDimensionId);
int biomesSent();
void setBiomesSent(int biomesSent);
@@ -33,7 +33,6 @@ public enum BlockFace {
TOP((byte) 0, (byte) 1, (byte) 0, EnumAxis.Y),
BOTTOM((byte) 0, (byte) -1, (byte) 0, EnumAxis.Y);
public static final BlockFace[] HORIZONTAL = {NORTH, SOUTH, EAST, WEST};
private static final Map<BlockFace, BlockFace> opposites = new EnumMap<>(BlockFace.class);
static {
@@ -29,7 +29,11 @@ import java.util.Map;
import java.util.UUID;
import org.checkerframework.checker.nullness.qual.Nullable;
public record GameProfile(@Nullable String name, @Nullable UUID id, Property[] properties) {
public record GameProfile(@Nullable String name, @Nullable UUID id, Property[] properties, boolean dynamic) {
public GameProfile(@Nullable final String name, @Nullable final UUID id, final Property[] properties) {
this(name, id, properties, true);
}
public GameProfile(@Nullable final String name, @Nullable final UUID id) {
this(name, id, new Property[0]);
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.function.Function;
import java.util.function.Supplier;
public interface Holder<T> {
@@ -89,7 +90,18 @@ public interface Holder<T> {
* @param rewriteFunction the function to rewrite the id
* @return a new holder with the id rewritten, or self
*/
Holder<T> updateId(final Int2IntFunction rewriteFunction);
default Holder<T> updateId(final Int2IntFunction rewriteFunction) {
return this.updateId(rewriteFunction, null);
}
/**
* Returns a new holder with the id rewritten using the given function, or self if this is a direct holder or the id did not change.
*
* @param rewriteFunction the function to rewrite the id
* @param ifMissing a supplier that provides a new holder if the id is missing (i.e. -1)
* @return a new holder with the id rewritten, or self
*/
Holder<T> updateId(Int2IntFunction rewriteFunction, Supplier<Holder<T>> ifMissing);
/**
* Returns a new holder with the value rewritten using the given function, or self if this is an id holder or the value did not change.
@@ -22,7 +22,11 @@
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.function.Function;
/**
* Set of ids that either holds a string tag key or an array of ids.
@@ -32,7 +36,7 @@ public interface HolderSet {
/**
* Creates a new holder set for the given tag.
*
* @param tagKey the tag key
* @param tagKey the tag key, not including '#'
* @return a new holder set
*/
static HolderSet of(final String tagKey) {
@@ -49,10 +53,29 @@ public interface HolderSet {
return new HolderSetImpl.Ids(ids);
}
static HolderSet fromTag(final Tag tag, final Function<String, Integer> mappingFunction) {
if (tag instanceof StringTag stringTag) {
if (stringTag.getValue().startsWith("#")) {
return HolderSet.of(stringTag.getValue().substring(1));
}
final int id = mappingFunction.apply(stringTag.getValue());
return HolderSet.of(new int[]{id});
} else if (tag instanceof ListTag<?> listTag) {
final int[] ids = new int[listTag.size()];
for (int i = 0; i < listTag.size(); i++) {
final String value = ((StringTag) listTag.get(i)).getValue();
ids[i] = mappingFunction.apply(value);
}
return HolderSet.of(ids);
}
throw new IllegalArgumentException();
}
/**
* Gets the tag key.
* Gets the tag key, not including '#'.
*
* @return the tag key
* @return the tag key without a '#'
* @see #hasTagKey()
*/
String tagKey();
@@ -25,6 +25,7 @@ package com.viaversion.viaversion.api.minecraft;
import com.google.common.base.Preconditions;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.function.Function;
import java.util.function.Supplier;
record IdHolder<T>(int id) implements Holder<T> {
@@ -48,12 +49,15 @@ record IdHolder<T>(int id) implements Holder<T> {
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
public Holder<T> updateId(final Int2IntFunction rewriteFunction, final Supplier<Holder<T>> ifMissing) {
final int rewrittenId = rewriteFunction.applyAsInt(id);
if (rewrittenId == id) {
return this;
}
if (rewrittenId == -1) {
if (ifMissing != null) {
return ifMissing.get();
}
throw new IllegalArgumentException("Received invalid id in updateId");
}
return Holder.of(rewrittenId);
@@ -0,0 +1,37 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Profile that can be either dynamically filled by the client or is already static.
* The additional fields are optional overrides.
*/
public record ResolvableProfile(GameProfile profile, @Nullable String bodyTexture, @Nullable String capeTexture,
@Nullable String elytraTexture, @Nullable Integer modelType) {
public ResolvableProfile(final GameProfile profile) {
this(profile, null, null, null, null);
}
}
@@ -22,11 +22,21 @@
*/
package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import org.checkerframework.checker.nullness.qual.Nullable;
public record SoundEvent(String identifier, @Nullable Float fixedRange) {
private static final Holder<SoundEvent> UNKNOWN = Holder.of(new SoundEvent("viaversion:unknown", 0F));
public SoundEvent withIdentifier(final String identifier) {
return new SoundEvent(identifier, this.fixedRange);
}
public static @Nullable Holder<SoundEvent> rewriteHolder(@Nullable final Holder<SoundEvent> holder, final Int2IntFunction soundRewriteFunction) {
if (holder == null) {
return null;
}
return holder.updateId(soundRewriteFunction, () -> UNKNOWN);
}
}
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.function.Function;
import java.util.function.Supplier;
record ValueHolder<T>(T value) implements Holder<T> {
@@ -43,7 +44,7 @@ record ValueHolder<T>(T value) implements Holder<T> {
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
public Holder<T> updateId(final Int2IntFunction rewriteFunction, final Supplier<Holder<T>> ifMissing) {
return this;
}
@@ -0,0 +1,28 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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;
public record Vector3d(double x, double y, double z) {
public static final Vector3d ZERO = new Vector3d(0, 0, 0);
}
@@ -45,6 +45,16 @@ public interface CodecContext {
Key dataComponentType(int id);
Key entity(int id);
Key blockEntity(int id);
Key sound(int id);
Key key(MappingData.MappingType mappingType, int id);
int id(MappingData.MappingType mappingType, String identifier);
static RegistryAccess of(final List<String> enchantments, final MappingData mappingData) {
return new RegistryAccessImpl(enchantments, mappingData);
}
@@ -0,0 +1,110 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.codec;
import com.viaversion.viaversion.api.type.Type;
import java.util.function.Consumer;
public class DelegatingOps implements Ops {
private final Ops delegate;
public DelegatingOps(final Ops delegate) {
this.delegate = delegate;
}
@Override
public CodecContext context() {
return delegate.context();
}
@Override
public void writeByte(final byte b) {
delegate.writeByte(b);
}
@Override
public void writeBytes(final byte[] array) {
delegate.writeBytes(array);
}
@Override
public void writeBoolean(final boolean b) {
delegate.writeBoolean(b);
}
@Override
public void writeShort(final short s) {
delegate.writeShort(s);
}
@Override
public void writeString(final CharSequence sequence) {
delegate.writeString(sequence);
}
@Override
public void writeInt(final int i) {
delegate.writeInt(i);
}
@Override
public void writeLong(final long l) {
delegate.writeLong(l);
}
@Override
public void writeFloat(final float f) {
delegate.writeFloat(f);
}
@Override
public void writeDouble(final double d) {
delegate.writeDouble(d);
}
@Override
public void writeInts(final int[] array) {
delegate.writeInts(array);
}
@Override
public void writeLongs(final long[] array) {
delegate.writeLongs(array);
}
@Override
public void writeList(final Consumer<ListSerializer> consumer) {
delegate.writeList(consumer);
}
@Override
public void writeMap(final Consumer<MapSerializer> consumer) {
delegate.writeMap(consumer);
}
@Override
public <V> void write(final Type<V> type, final V value) {
delegate.write(type, value);
}
}
@@ -129,5 +129,7 @@ public interface Ops {
MapSerializer writeList(String key, Consumer<ListSerializer> consumer);
MapSerializer writeMap(String key, Consumer<MapSerializer> consumer);
<T> MapSerializer writeInlinedMap(Type<T> valueType, T value);
}
}
@@ -66,6 +66,32 @@ final class RegistryAccessImpl implements CodecContext.RegistryAccess {
return key(mappingData.getDataComponentSerializerMappings(), id);
}
@Override
public Key entity(final int id) {
return key(mappingData.getEntityMappings(), id);
}
@Override
public Key blockEntity(final int id) {
return key(mappingData.getBlockEntityMappings(), id);
}
@Override
public Key sound(final int id) {
return key(mappingData.getFullSoundMappings(), id);
}
@Override
public Key key(final MappingData.MappingType mappingType, final int id) {
return key(mappingData.getFullMappings(mappingType), id);
}
@Override
public int id(final MappingData.MappingType mappingType, final String identifier) {
final FullMappings mappings = mappingData.getFullMappings(mappingType);
return mapped ? mappings.mappedId(identifier) : mappings.id(identifier);
}
private Key key(final FullMappings mappings, final int id) {
final String identifier = mapped ? mappings.mappedIdentifier(id) : mappings.identifier(id);
return key(identifier, id);
@@ -0,0 +1,104 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.codec;
import com.viaversion.viaversion.api.type.Type;
import java.util.function.Consumer;
public class ThrowingOps implements Ops {
@Override
public CodecContext context() {
throw new UnsupportedOperationException();
}
@Override
public void writeByte(final byte b) {
throw new UnsupportedOperationException();
}
@Override
public void writeBytes(final byte[] array) {
throw new UnsupportedOperationException();
}
@Override
public void writeBoolean(final boolean b) {
throw new UnsupportedOperationException();
}
@Override
public void writeShort(final short s) {
throw new UnsupportedOperationException();
}
@Override
public void writeString(final CharSequence sequence) {
throw new UnsupportedOperationException();
}
@Override
public void writeInt(final int i) {
throw new UnsupportedOperationException();
}
@Override
public void writeLong(final long l) {
throw new UnsupportedOperationException();
}
@Override
public void writeFloat(final float f) {
throw new UnsupportedOperationException();
}
@Override
public void writeDouble(final double d) {
throw new UnsupportedOperationException();
}
@Override
public void writeInts(final int[] array) {
throw new UnsupportedOperationException();
}
@Override
public void writeLongs(final long[] array) {
throw new UnsupportedOperationException();
}
@Override
public void writeList(final Consumer<ListSerializer> consumer) {
throw new UnsupportedOperationException();
}
@Override
public void writeMap(final Consumer<MapSerializer> consumer) {
throw new UnsupportedOperationException();
}
@Override
public <V> void write(final Type<V> type, final V value) {
throw new UnsupportedOperationException();
}
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.minecraft.data;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.util.ArrayUtil;
import com.viaversion.viaversion.util.Copyable;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
@@ -102,7 +103,7 @@ final class FilledStructuredData<T> implements StructuredData<T> {
public String toString() {
return "FilledStructuredData{" +
"key=" + key +
", value=" + value +
", value=" + ArrayUtil.toString(value) +
", id=" + id +
'}';
}
@@ -241,7 +241,7 @@ public final class StructuredDataContainer implements Copyable {
/**
* Sets the lookup for serializer ids. Required to call most of the other methods.
*
* @param protocol protocol to retreive the id of the serializer from
* @param protocol protocol to retrieve the id of the serializer from
* @param mappedNames if the names are mapped (true if structures from the mapped version are added, false for the unmapped version)
*/
public void setIdLookup(final Protocol<?, ?, ?, ?> protocol, final boolean mappedNames) {
@@ -27,8 +27,8 @@ import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.EitherHolder;
import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_20_5;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_2;
@@ -39,12 +39,14 @@ import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_20_
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer;
import com.viaversion.viaversion.api.minecraft.item.data.Bee;
import com.viaversion.viaversion.api.minecraft.item.data.BlockEntityData;
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.DeathProtection;
import com.viaversion.viaversion.api.minecraft.item.data.DebugStickState;
import com.viaversion.viaversion.api.minecraft.item.data.DyedColor;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantable;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
@@ -56,15 +58,19 @@ import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.ItemModel;
import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable;
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.PotDecorations;
import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
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;
import com.viaversion.viaversion.api.minecraft.item.data.ToolProperties;
import com.viaversion.viaversion.api.minecraft.item.data.TooltipDisplay;
import com.viaversion.viaversion.api.minecraft.item.data.TropicalFishPattern;
import com.viaversion.viaversion.api.minecraft.item.data.EntityData;
import com.viaversion.viaversion.api.minecraft.item.data.Unbreakable;
import com.viaversion.viaversion.api.minecraft.item.data.UseCooldown;
import com.viaversion.viaversion.api.minecraft.item.data.Weapon;
@@ -95,10 +101,10 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Integer> DAMAGE = new StructuredDataKey<>("damage", Types.VAR_INT);
public static final StructuredDataKey<Unbreakable> UNBREAKABLE1_20_5 = new StructuredDataKey<>("unbreakable", Unbreakable.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.TAG);
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Types.TAG);
public static final StructuredDataKey<Key> ITEM_MODEL = new StructuredDataKey<>("item_model", Types.RESOURCE_LOCATION);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", new ArrayType<>(Types.TAG, 256));
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TEXT_COMPONENT_TAG);
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));
public static final StructuredDataKey<Integer> RARITY = new StructuredDataKey<>("rarity", EnumTypes.RARITY);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS1_20_5 = new StructuredDataKey<>("enchantments", Enchantments.TYPE1_20_5);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS1_21_5 = new StructuredDataKey<>("enchantments", Enchantments.TYPE1_21_5);
@@ -132,7 +138,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Equippable> EQUIPPABLE1_21_2 = new StructuredDataKey<>("equippable", Equippable.TYPE1_21_2);
public static final StructuredDataKey<Equippable> EQUIPPABLE1_21_5 = new StructuredDataKey<>("equippable", Equippable.TYPE1_21_5);
public static final StructuredDataKey<Equippable> EQUIPPABLE1_21_6 = new StructuredDataKey<>("equippable", Equippable.TYPE1_21_6);
public static final StructuredDataKey<HolderSet> REPAIRABLE = new StructuredDataKey<>("repairable", Types.HOLDER_SET);
public static final StructuredDataKey<Repairable> REPAIRABLE = new StructuredDataKey<>("repairable", Repairable.TYPE);
public static final StructuredDataKey<Unit> GLIDER = new StructuredDataKey<>("glider", Types.EMPTY);
public static final StructuredDataKey<Key> TOOLTIP_STYLE = new StructuredDataKey<>("tooltip_style", Types.RESOURCE_LOCATION);
public static final StructuredDataKey<DeathProtection> DEATH_PROTECTION = new StructuredDataKey<>("death_protection", DeathProtection.TYPE);
@@ -155,10 +161,12 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<ArmorTrim> TRIM1_21_2 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_21_2);
public static final StructuredDataKey<ArmorTrim> TRIM1_21_4 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_21_4);
public static final StructuredDataKey<ArmorTrim> TRIM1_21_5 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_21_5);
public static final StructuredDataKey<CompoundTag> DEBUG_STICK_STATE = new StructuredDataKey<>("debug_stick_state", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> ENTITY_DATA = new StructuredDataKey<>("entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<DebugStickState> DEBUG_STICK_STATE = new StructuredDataKey<>("debug_stick_state", DebugStickState.TYPE);
public static final StructuredDataKey<CompoundTag> ENTITY_DATA1_20_5 = new StructuredDataKey<>("entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<EntityData> ENTITY_DATA1_21_9 = new StructuredDataKey<>("entity_data", EntityData.TYPE);
public static final StructuredDataKey<CompoundTag> BUCKET_ENTITY_DATA = new StructuredDataKey<>("bucket_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BLOCK_ENTITY_DATA = new StructuredDataKey<>("block_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BLOCK_ENTITY_DATA1_20_5 = new StructuredDataKey<>("block_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<BlockEntityData> BLOCK_ENTITY_DATA1_21_9 = new StructuredDataKey<>("block_entity_data", BlockEntityData.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);
@@ -171,14 +179,17 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
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);
public static final StructuredDataKey<Fireworks> FIREWORKS = new StructuredDataKey<>("fireworks", Fireworks.TYPE);
public static final StructuredDataKey<GameProfile> PROFILE = new StructuredDataKey<>("profile", Types.GAME_PROFILE);
public static final StructuredDataKey<GameProfile> PROFILE1_20_5 = new StructuredDataKey<>("profile", Types.GAME_PROFILE);
public static final StructuredDataKey<ResolvableProfile> PROFILE1_21_9 = new StructuredDataKey<>("profile", Types.RESOLVABLE_PROFILE);
public static final StructuredDataKey<Key> NOTE_BLOCK_SOUND = new StructuredDataKey<>("note_block_sound", Types.RESOURCE_LOCATION);
public static final StructuredDataKey<BannerPatternLayer[]> BANNER_PATTERNS = new StructuredDataKey<>("banner_patterns", BannerPatternLayer.ARRAY_TYPE);
public static final StructuredDataKey<Integer> BASE_COLOR = new StructuredDataKey<>("base_color", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<PotDecorations> POT_DECORATIONS = new StructuredDataKey<>("pot_decorations", PotDecorations.TYPE);
public static final StructuredDataKey<BlockStateProperties> BLOCK_STATE = new StructuredDataKey<>("block_state", BlockStateProperties.TYPE);
public static final StructuredDataKey<Bee[]> BEES = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE);
public static final StructuredDataKey<Tag> LOCK = new StructuredDataKey<>("lock", Types.TAG);
public static final StructuredDataKey<Bee[]> BEES1_20_5 = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE1_20_5);
public static final StructuredDataKey<Bee[]> BEES1_21_9 = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE1_21_9);
public static final StructuredDataKey<Tag> LOCK1_20_5 = new StructuredDataKey<>("lock", Types.TAG);
public static final StructuredDataKey<LockCode> LOCK1_21_2 = new StructuredDataKey<>("lock", LockCode.TYPE);
public static final StructuredDataKey<CompoundTag> CONTAINER_LOOT = new StructuredDataKey<>("container_loot", Types.COMPOUND_TAG);
public static final StructuredDataKey<Holder<SoundEvent>> BREAK_SOUND = new StructuredDataKey<>("break_sound", Types.SOUND_EVENT);
@@ -214,6 +225,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKeys1_21_2 V1_21_4 = VersionedTypes.V1_21_4.structuredDataKeys();
public static final StructuredDataKeys1_21_5 V1_21_5 = VersionedTypes.V1_21_5.structuredDataKeys();
public static final StructuredDataKeys1_21_5 V1_21_6 = VersionedTypes.V1_21_6.structuredDataKeys();
public static final StructuredDataKeys1_21_5 V1_21_9 = VersionedTypes.V1_21_9.structuredDataKeys();
@Override
public String toString() {
@@ -22,8 +22,8 @@
*/
package com.viaversion.viaversion.api.minecraft.entities;
import java.util.HashMap;
import java.util.Map;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class EntityTypes1_10 {
@@ -143,7 +143,7 @@ public class EntityTypes1_10 {
SPIDER(52, ABSTRACT_MONSTER),
CAVE_SPIDER(59, SPIDER);
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
private static final Int2ObjectMap<EntityType> TYPES;
private final int id;
private final EntityType parent;
@@ -184,7 +184,9 @@ public class EntityTypes1_10 {
}
static {
for (EntityType type : EntityType.values()) {
final EntityType[] values = EntityType.values();
TYPES = new Int2ObjectOpenHashMap<>(values.length);
for (EntityType type : values) {
TYPES.put(type.id, type);
}
}
@@ -230,7 +232,7 @@ public class EntityTypes1_10 {
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL);
private static final Map<Integer, Map<Integer, ObjectType>> TYPES = new HashMap<>();
private static final Int2ObjectMap<Int2ObjectMap<ObjectType>> TYPES = new Int2ObjectOpenHashMap<>();
private final int id;
private final int data;
@@ -238,7 +240,7 @@ public class EntityTypes1_10 {
static {
for (ObjectType type : ObjectType.values()) {
TYPES.computeIfAbsent(type.id, k -> new HashMap<>()).put(type.data, type);
TYPES.computeIfAbsent(type.id, k -> new Int2ObjectOpenHashMap<>()).put(type.data, type);
}
}
@@ -268,7 +270,7 @@ public class EntityTypes1_10 {
}
public static ObjectType findById(final int id, final int data) {
final Map<Integer, ObjectType> types = TYPES.get(id);
final Int2ObjectMap<ObjectType> types = TYPES.get(id);
if (types == null) {
return null;
}
@@ -22,8 +22,8 @@
*/
package com.viaversion.viaversion.api.minecraft.entities;
import java.util.HashMap;
import java.util.Map;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class EntityTypes1_11 {
@@ -168,7 +168,7 @@ public class EntityTypes1_11 {
EVOKER(34, ABSTRACT_MONSTER),
VINDICATOR(36, ABSTRACT_MONSTER);
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
private static final Int2ObjectMap<EntityType> TYPES;
private final int id;
private final EntityType parent;
@@ -209,7 +209,9 @@ public class EntityTypes1_11 {
}
static {
for (EntityType type : EntityType.values()) {
final EntityType[] values = EntityType.values();
TYPES = new Int2ObjectOpenHashMap<>(values.length);
for (EntityType type : values) {
TYPES.put(type.id, type);
}
}
@@ -257,7 +259,7 @@ public class EntityTypes1_11 {
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL);
private static final Map<Integer, Map<Integer, ObjectType>> TYPES = new HashMap<>();
private static final Int2ObjectMap<Int2ObjectMap<ObjectType>> TYPES = new Int2ObjectOpenHashMap<>();
private final int id;
private final int data;
@@ -265,7 +267,7 @@ public class EntityTypes1_11 {
static {
for (ObjectType type : ObjectType.values()) {
TYPES.computeIfAbsent(type.id, k -> new HashMap<>()).put(type.data, type);
TYPES.computeIfAbsent(type.id, k -> new Int2ObjectOpenHashMap<>()).put(type.data, type);
}
}
@@ -295,7 +297,7 @@ public class EntityTypes1_11 {
}
public static ObjectType findById(final int id, final int data) {
final Map<Integer, ObjectType> types = TYPES.get(id);
final Int2ObjectMap<ObjectType> types = TYPES.get(id);
if (types == null) {
return null;
}
@@ -22,8 +22,8 @@
*/
package com.viaversion.viaversion.api.minecraft.entities;
import java.util.HashMap;
import java.util.Map;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class EntityTypes1_12 {
@@ -174,7 +174,7 @@ public class EntityTypes1_12 {
EVOKER(34, SPELLCASTER_ILLAGER),
ILLUSIONER(37, SPELLCASTER_ILLAGER);
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
private static final Int2ObjectMap<EntityType> TYPES;
private final int id;
private final EntityType parent;
@@ -215,7 +215,9 @@ public class EntityTypes1_12 {
}
static {
for (EntityType type : EntityType.values()) {
final EntityType[] values = EntityType.values();
TYPES = new Int2ObjectOpenHashMap<>(values.length);
for (EntityType type : values) {
TYPES.put(type.id, type);
}
}
@@ -263,7 +265,7 @@ public class EntityTypes1_12 {
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL);
private static final Map<Integer, Map<Integer, ObjectType>> TYPES = new HashMap<>();
private static final Int2ObjectMap<Int2ObjectMap<ObjectType>> TYPES = new Int2ObjectOpenHashMap<>();
private final int id;
private final int data;
@@ -271,7 +273,7 @@ public class EntityTypes1_12 {
static {
for (ObjectType type : ObjectType.values()) {
TYPES.computeIfAbsent(type.id, k -> new HashMap<>()).put(type.data, type);
TYPES.computeIfAbsent(type.id, k -> new Int2ObjectOpenHashMap<>()).put(type.data, type);
}
}
@@ -301,7 +303,7 @@ public class EntityTypes1_12 {
}
public static ObjectType findById(final int id, final int data) {
final Map<Integer, ObjectType> types = TYPES.get(id);
final Int2ObjectMap<ObjectType> types = TYPES.get(id);
if (types == null) {
return null;
}
@@ -22,8 +22,8 @@
*/
package com.viaversion.viaversion.api.minecraft.entities;
import java.util.HashMap;
import java.util.Map;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class EntityTypes1_13 {
@@ -185,7 +185,7 @@ public class EntityTypes1_13 {
EVOKER(21, SPELLCASTER_ILLAGER),
ILLUSIONER(31, SPELLCASTER_ILLAGER);
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
private static final Int2ObjectMap<EntityType> TYPES;
private final int id;
private final EntityType parent;
@@ -226,7 +226,9 @@ public class EntityTypes1_13 {
}
static {
for (EntityType type : EntityType.values()) {
final EntityType[] values = EntityType.values();
TYPES = new Int2ObjectOpenHashMap<>(values.length);
for (EntityType type : values) {
TYPES.put(type.id, type);
}
}
@@ -275,7 +277,7 @@ public class EntityTypes1_13 {
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL),
TRIDENT(94, EntityType.TRIDENT);
private static final Map<Integer, Map<Integer, ObjectType>> TYPES = new HashMap<>();
private static final Int2ObjectMap<Int2ObjectMap<ObjectType>> TYPES = new Int2ObjectOpenHashMap<>();
private final int id;
private final int data;
@@ -283,7 +285,7 @@ public class EntityTypes1_13 {
static {
for (ObjectType type : ObjectType.values()) {
TYPES.computeIfAbsent(type.id, k -> new HashMap<>()).put(type.data, type);
TYPES.computeIfAbsent(type.id, k -> new Int2ObjectOpenHashMap<>()).put(type.data, type);
}
}
@@ -313,7 +315,7 @@ public class EntityTypes1_13 {
}
public static ObjectType findById(final int id, final int data) {
final Map<Integer, ObjectType> types = TYPES.get(id);
final Int2ObjectMap<ObjectType> types = TYPES.get(id);
if (types == null) {
return null;
}
@@ -213,7 +213,7 @@ public enum EntityTypes1_14 implements EntityType {
EntityTypes1_14(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_14(final EntityType parent, @Nullable final String identifier) {
@@ -214,7 +214,7 @@ public enum EntityTypes1_15 implements EntityType {
EntityTypes1_15(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_15(final EntityType parent, @Nullable final String identifier) {
@@ -218,7 +218,7 @@ public enum EntityTypes1_16 implements EntityType {
EntityTypes1_16(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_16(final EntityType parent, @Nullable final String identifier) {
@@ -221,7 +221,7 @@ public enum EntityTypes1_16_2 implements EntityType {
EntityTypes1_16_2(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_16_2(final EntityType parent, @Nullable final String identifier) {
@@ -227,7 +227,7 @@ public enum EntityTypes1_17 implements EntityType {
EntityTypes1_17(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_17(final EntityType parent, @Nullable final String identifier) {
@@ -232,7 +232,7 @@ public enum EntityTypes1_19 implements EntityType {
EntityTypes1_19(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_19(final EntityType parent, @Nullable final String identifier) {
@@ -233,7 +233,7 @@ public enum EntityTypes1_19_3 implements EntityType {
EntityTypes1_19_3(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_19_3(final EntityType parent, @Nullable final String identifier) {
@@ -240,7 +240,7 @@ public enum EntityTypes1_19_4 implements EntityType {
EntityTypes1_19_4(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_19_4(final EntityType parent, @Nullable final String identifier) {
@@ -242,7 +242,7 @@ public enum EntityTypes1_20_3 implements EntityType {
EntityTypes1_20_3(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_20_3(final EntityType parent, @Nullable final String identifier) {
@@ -248,7 +248,7 @@ public enum EntityTypes1_20_5 implements EntityType {
EntityTypes1_20_5(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_20_5(final EntityType parent, @Nullable final String identifier) {
@@ -272,7 +272,7 @@ public enum EntityTypes1_21_2 implements EntityType {
EntityTypes1_21_2(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_21_2(final EntityType parent, @Nullable final String identifier) {
@@ -271,7 +271,7 @@ public enum EntityTypes1_21_4 implements EntityType {
EntityTypes1_21_4(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_21_4(final EntityType parent, @Nullable final String identifier) {
@@ -0,0 +1,323 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entities;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.util.EntityTypeUtil;
import com.viaversion.viaversion.util.Key;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
public enum EntityTypes1_21_9 implements EntityType {
ENTITY(null, null),
AREA_EFFECT_CLOUD(ENTITY),
END_CRYSTAL(ENTITY),
EVOKER_FANGS(ENTITY),
EXPERIENCE_ORB(ENTITY),
EYE_OF_ENDER(ENTITY),
FALLING_BLOCK(ENTITY),
ITEM(ENTITY),
TNT(ENTITY),
OMINOUS_ITEM_SPAWNER(ENTITY),
MARKER(ENTITY),
LIGHTNING_BOLT(ENTITY),
INTERACTION(ENTITY),
DISPLAY(ENTITY, null),
BLOCK_DISPLAY(DISPLAY),
ITEM_DISPLAY(DISPLAY),
TEXT_DISPLAY(DISPLAY),
// Hanging entities
HANGING_ENTITY(ENTITY, null),
LEASH_KNOT(HANGING_ENTITY),
PAINTING(HANGING_ENTITY),
ITEM_FRAME(HANGING_ENTITY),
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
FISHING_BOBBER(PROJECTILE),
WITHER_SKULL(PROJECTILE),
DRAGON_FIREBALL(PROJECTILE), // Doesn't actually inherit fireball
ABSTRACT_THROWN_POTION(ITEM_PROJECTILE, null),
SPLASH_POTION(ABSTRACT_THROWN_POTION),
LINGERING_POTION(ABSTRACT_THROWN_POTION),
ABSTRACT_ARROW(PROJECTILE, null),
ARROW(ABSTRACT_ARROW),
SPECTRAL_ARROW(ABSTRACT_ARROW),
TRIDENT(ABSTRACT_ARROW),
ABSTRACT_FIREBALL(ENTITY, null),
FIREBALL(ABSTRACT_FIREBALL),
SMALL_FIREBALL(ABSTRACT_FIREBALL),
ABSTRACT_WIND_CHARGE(PROJECTILE, null),
WIND_CHARGE(ABSTRACT_WIND_CHARGE),
BREEZE_WIND_CHARGE(ABSTRACT_WIND_CHARGE),
// Vehicles
VEHICLE(ENTITY, null),
ABSTRACT_MINECART(VEHICLE, null),
MINECART(ABSTRACT_MINECART),
FURNACE_MINECART(ABSTRACT_MINECART),
COMMAND_BLOCK_MINECART(ABSTRACT_MINECART),
TNT_MINECART(ABSTRACT_MINECART),
SPAWNER_MINECART(ABSTRACT_MINECART),
ABSTRACT_MINECART_CONTAINER(ABSTRACT_MINECART, null),
CHEST_MINECART(ABSTRACT_MINECART_CONTAINER),
HOPPER_MINECART(ABSTRACT_MINECART_CONTAINER),
ABSTRACT_BOAT(VEHICLE, null),
ABSTRACT_CHEST_BOAT(ABSTRACT_BOAT, null),
ACACIA_BOAT(ABSTRACT_BOAT),
ACACIA_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
BAMBOO_CHEST_RAFT(ABSTRACT_CHEST_BOAT),
BAMBOO_RAFT(ABSTRACT_BOAT),
BIRCH_BOAT(ABSTRACT_BOAT),
BIRCH_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
CHERRY_BOAT(ABSTRACT_BOAT),
CHERRY_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
DARK_OAK_BOAT(ABSTRACT_BOAT),
DARK_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
JUNGLE_BOAT(ABSTRACT_BOAT),
JUNGLE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
MANGROVE_BOAT(ABSTRACT_BOAT),
MANGROVE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
OAK_BOAT(ABSTRACT_BOAT),
OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
PALE_OAK_BOAT(ABSTRACT_BOAT),
PALE_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
SPRUCE_BOAT(ABSTRACT_BOAT),
SPRUCE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
// Living entities as a larger subclass
LIVING_ENTITY(ENTITY, null),
ARMOR_STAND(LIVING_ENTITY),
// Players
AVATAR(LIVING_ENTITY, null),
MANNEQUIN(AVATAR),
PLAYER(AVATAR),
// Mobs as a larger subclass
MOB(LIVING_ENTITY, null),
ENDER_DRAGON(MOB),
SLIME(MOB),
MAGMA_CUBE(SLIME),
// Ambient mobs
AMBIENT_CREATURE(MOB, null),
BAT(AMBIENT_CREATURE),
// Flying mobs
FLYING_MOB(MOB, null),
GHAST(FLYING_MOB),
PHANTOM(FLYING_MOB),
// Pathfinder mobs and its subclasses
PATHFINDER_MOB(MOB, null),
ALLAY(PATHFINDER_MOB),
ABSTRACT_GOLEM(PATHFINDER_MOB, null),
SNOW_GOLEM(ABSTRACT_GOLEM),
IRON_GOLEM(ABSTRACT_GOLEM),
SHULKER(ABSTRACT_GOLEM),
COPPER_GOLEM(ABSTRACT_GOLEM),
// Ageable mobs and (tamable) animals
ABSTRACT_AGEABLE(PATHFINDER_MOB, null),
ABSTRACT_VILLAGER(ABSTRACT_AGEABLE, null),
VILLAGER(ABSTRACT_VILLAGER),
WANDERING_TRADER(ABSTRACT_VILLAGER),
ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null),
AXOLOTL(ABSTRACT_ANIMAL),
CHICKEN(ABSTRACT_ANIMAL),
PANDA(ABSTRACT_ANIMAL),
PIG(ABSTRACT_ANIMAL),
POLAR_BEAR(ABSTRACT_ANIMAL),
RABBIT(ABSTRACT_ANIMAL),
SHEEP(ABSTRACT_ANIMAL),
BEE(ABSTRACT_ANIMAL),
TURTLE(ABSTRACT_ANIMAL),
FOX(ABSTRACT_ANIMAL),
FROG(ABSTRACT_ANIMAL),
GOAT(ABSTRACT_ANIMAL),
HOGLIN(ABSTRACT_ANIMAL),
STRIDER(ABSTRACT_ANIMAL),
SNIFFER(ABSTRACT_ANIMAL),
ARMADILLO(ABSTRACT_ANIMAL),
HAPPY_GHAST(ABSTRACT_ANIMAL),
ABSTRACT_COW(ABSTRACT_ANIMAL, null),
COW(ABSTRACT_COW),
MOOSHROOM(ABSTRACT_COW),
TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null),
CAT(TAMABLE_ANIMAL),
OCELOT(TAMABLE_ANIMAL),
WOLF(TAMABLE_ANIMAL),
PARROT(TAMABLE_ANIMAL),
ABSTRACT_HORSE(ABSTRACT_ANIMAL, null),
HORSE(ABSTRACT_HORSE),
SKELETON_HORSE(ABSTRACT_HORSE),
ZOMBIE_HORSE(ABSTRACT_HORSE),
CAMEL(ABSTRACT_HORSE),
ABSTRACT_CHESTED_HORSE(ABSTRACT_HORSE, null),
DONKEY(ABSTRACT_CHESTED_HORSE),
MULE(ABSTRACT_CHESTED_HORSE),
LLAMA(ABSTRACT_CHESTED_HORSE),
TRADER_LLAMA(LLAMA),
// Monsters
ABSTRACT_MONSTER(PATHFINDER_MOB, null),
BLAZE(ABSTRACT_MONSTER),
CREEPER(ABSTRACT_MONSTER),
ENDERMITE(ABSTRACT_MONSTER),
ENDERMAN(ABSTRACT_MONSTER),
GIANT(ABSTRACT_MONSTER),
SILVERFISH(ABSTRACT_MONSTER),
VEX(ABSTRACT_MONSTER),
WITHER(ABSTRACT_MONSTER),
BREEZE(ABSTRACT_MONSTER),
ZOGLIN(ABSTRACT_MONSTER),
WARDEN(ABSTRACT_MONSTER),
CREAKING(ABSTRACT_MONSTER),
ABSTRACT_SKELETON(ABSTRACT_MONSTER, null),
SKELETON(ABSTRACT_SKELETON),
STRAY(ABSTRACT_SKELETON),
WITHER_SKELETON(ABSTRACT_SKELETON),
BOGGED(ABSTRACT_SKELETON),
ZOMBIE(ABSTRACT_MONSTER),
DROWNED(ZOMBIE),
HUSK(ZOMBIE),
ZOMBIFIED_PIGLIN(ZOMBIE),
ZOMBIE_VILLAGER(ZOMBIE),
GUARDIAN(ABSTRACT_MONSTER),
ELDER_GUARDIAN(GUARDIAN),
SPIDER(ABSTRACT_MONSTER),
CAVE_SPIDER(SPIDER),
ABSTRACT_PIGLIN(ABSTRACT_MONSTER, null),
PIGLIN(ABSTRACT_PIGLIN),
PIGLIN_BRUTE(ABSTRACT_PIGLIN),
// Water mobs
AGEABLE_WATER_CREATURE(ABSTRACT_AGEABLE, null),
DOLPHIN(AGEABLE_WATER_CREATURE),
SQUID(AGEABLE_WATER_CREATURE),
GLOW_SQUID(SQUID),
WATER_ANIMAL(PATHFINDER_MOB, null),
ABSTRACT_FISH(WATER_ANIMAL, null),
PUFFERFISH(ABSTRACT_FISH),
TADPOLE(ABSTRACT_FISH),
ABSTRACT_SCHOOLING_FISH(ABSTRACT_FISH, null),
COD(ABSTRACT_SCHOOLING_FISH),
SALMON(ABSTRACT_SCHOOLING_FISH),
TROPICAL_FISH(ABSTRACT_SCHOOLING_FISH),
// Raiders
ABSTRACT_RAIDER(ABSTRACT_MONSTER, null),
WITCH(ABSTRACT_RAIDER),
RAVAGER(ABSTRACT_RAIDER),
ABSTRACT_ILLAGER(ABSTRACT_RAIDER, null),
SPELLCASTER_ILLAGER(ABSTRACT_ILLAGER, null),
VINDICATOR(ABSTRACT_ILLAGER),
PILLAGER(ABSTRACT_ILLAGER),
EVOKER(SPELLCASTER_ILLAGER),
ILLUSIONER(SPELLCASTER_ILLAGER);
private static final EntityType[] TYPES = EntityTypeUtil.createSizedArray(values());
private final EntityType parent;
private final String identifier;
private int id = -1;
EntityTypes1_21_9(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_21_9(final EntityType parent, @Nullable final String identifier) {
this.parent = parent;
this.identifier = identifier;
}
@Override
public int getId() {
if (id == -1) {
throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")");
}
return id;
}
@Override
public String identifier() {
Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type");
return identifier;
}
@Override
public @Nullable EntityType getParent() {
return parent;
}
@Override
public boolean isAbstractType() {
return identifier == null;
}
public static EntityType getTypeFromId(final int typeId) {
return EntityTypeUtil.getTypeFromId(TYPES, typeId, PIG);
}
public static void initialize(final Protocol<?, ?, ?, ?> protocol) {
EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id);
}
}
@@ -22,8 +22,8 @@
*/
package com.viaversion.viaversion.api.minecraft.entities;
import java.util.HashMap;
import java.util.Map;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class EntityTypes1_8 {
@@ -135,7 +135,7 @@ public class EntityTypes1_8 {
SPIDER(52, ABSTRACT_MONSTER),
CAVE_SPIDER(59, SPIDER);
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
private static final Int2ObjectMap<EntityType> TYPES;
private final int id;
private final EntityType parent;
@@ -176,7 +176,9 @@ public class EntityTypes1_8 {
}
static {
for (EntityType type : EntityType.values()) {
final EntityType[] values = EntityType.values();
TYPES = new Int2ObjectOpenHashMap<>(values.length);
for (EntityType type : values) {
TYPES.put(type.id, type);
}
}
@@ -218,7 +220,7 @@ public class EntityTypes1_8 {
ARMOR_STAND(78, EntityType.ARMOR_STAND),
FISHIHNG_HOOK(90, EntityType.FISHING_HOOK);
private static final Map<Integer, Map<Integer, ObjectType>> TYPES = new HashMap<>();
private static final Int2ObjectMap<Int2ObjectMap<ObjectType>> TYPES = new Int2ObjectOpenHashMap<>();
private final int id;
private final int data;
@@ -226,7 +228,7 @@ public class EntityTypes1_8 {
static {
for (ObjectType type : ObjectType.values()) {
TYPES.computeIfAbsent(type.id, k -> new HashMap<>()).put(type.data, type);
TYPES.computeIfAbsent(type.id, k -> new Int2ObjectOpenHashMap<>()).put(type.data, type);
}
}
@@ -256,7 +258,7 @@ public class EntityTypes1_8 {
}
public static ObjectType findById(final int id, final int data) {
final Map<Integer, ObjectType> types = TYPES.get(id);
final Int2ObjectMap<ObjectType> types = TYPES.get(id);
if (types == null) {
return null;
}
@@ -22,8 +22,8 @@
*/
package com.viaversion.viaversion.api.minecraft.entities;
import java.util.HashMap;
import java.util.Map;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
public class EntityTypes1_9 {
@@ -142,7 +142,7 @@ public class EntityTypes1_9 {
SPIDER(52, ABSTRACT_MONSTER),
CAVE_SPIDER(59, SPIDER);
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
private static final Int2ObjectMap<EntityType> TYPES;
private final int id;
private final EntityType parent;
@@ -183,7 +183,9 @@ public class EntityTypes1_9 {
}
static {
for (EntityType type : EntityType.values()) {
final EntityType[] values = EntityType.values();
TYPES = new Int2ObjectOpenHashMap<>(values.length);
for (EntityType type : values) {
TYPES.put(type.id, type);
}
}
@@ -229,7 +231,7 @@ public class EntityTypes1_9 {
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL);
private static final Map<Integer, Map<Integer, ObjectType>> TYPES = new HashMap<>();
private static final Int2ObjectMap<Int2ObjectMap<ObjectType>> TYPES = new Int2ObjectOpenHashMap<>();
private final int id;
private final int data;
@@ -237,7 +239,7 @@ public class EntityTypes1_9 {
static {
for (ObjectType type : ObjectType.values()) {
TYPES.computeIfAbsent(type.id, k -> new HashMap<>()).put(type.data, type);
TYPES.computeIfAbsent(type.id, k -> new Int2ObjectOpenHashMap<>()).put(type.data, type);
}
}
@@ -267,7 +269,7 @@ public class EntityTypes1_9 {
}
public static ObjectType findById(final int id, final int data) {
final Map<Integer, ObjectType> types = TYPES.get(id);
final Int2ObjectMap<ObjectType> types = TYPES.get(id);
if (types == null) {
return null;
}
@@ -0,0 +1,76 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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 EntityDataTypes1_21_9 extends AbstractEntityDataTypes {
public final EntityDataType byteType = add(0, Types.BYTE);
public final EntityDataType varIntType = add(1, Types.VAR_INT);
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14);
public final EntityDataType optionalBlockPositionType = add(11, Types.OPTIONAL_POSITION_1_14);
public final EntityDataType directionType = add(12, Types.VAR_INT);
public final EntityDataType optionalUUIDType = add(13, Types.OPTIONAL_UUID);
public final EntityDataType blockStateType = add(14, Types.VAR_INT);
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = 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 cowVariantType = add(22, Types.VAR_INT);
public final EntityDataType wolfVariantType = add(23, Types.VAR_INT);
public final EntityDataType wolfSoundVariantType = add(24, Types.VAR_INT);
public final EntityDataType frogVariantType = add(25, Types.VAR_INT);
public final EntityDataType pigVariantType = add(26, Types.VAR_INT);
public final EntityDataType chickenVariantType = add(27, Types.VAR_INT);
public final EntityDataType optionalGlobalPosition = add(28, Types.OPTIONAL_GLOBAL_POSITION);
public final EntityDataType paintingVariantType = add(29, PaintingVariant.TYPE1_21_2);
public final EntityDataType snifferState = add(30, Types.VAR_INT);
public final EntityDataType armadilloState = add(31, Types.VAR_INT);
public final EntityDataType copperGolemState = add(32, Types.VAR_INT);
public final EntityDataType weatheringCopperState = add(33, Types.VAR_INT);
public final EntityDataType vector3FType = add(34, Types.VECTOR3F);
public final EntityDataType quaternionType = add(35, Types.QUATERNION);
public final EntityDataType mannequinProfileType = add(36, Types.RESOLVABLE_PROFILE);
public EntityDataTypes1_21_9(final VersionedTypesHolder types) {
super(37);
this.itemType = add(7, types.item());
this.particleType = add(16, types.particle());
this.particlesType = add(17, types.particles());
}
}
@@ -24,7 +24,6 @@ package com.viaversion.viaversion.api.minecraft.item;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.util.Copyable;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface Item extends ItemBase {
@@ -22,14 +22,21 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public record AttributeModifiers1_20_5(AttributeModifier[] modifiers, boolean showInTooltip) implements Copyable {
public record AttributeModifiers1_20_5(AttributeModifier[] modifiers,
boolean showInTooltip) implements Copyable, Rewritable {
public static final Type<AttributeModifiers1_20_5> TYPE = new Type<>(AttributeModifiers1_20_5.class) {
@Override
@@ -51,6 +58,23 @@ public record AttributeModifiers1_20_5(AttributeModifier[] modifiers, boolean sh
return new AttributeModifiers1_20_5(Copyable.copy(modifiers), showInTooltip);
}
@Override
public AttributeModifiers1_20_5 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final FullMappings mappings = protocol.getMappingData().getAttributeMappings();
if (mappings == null) {
return this;
}
final List<AttributeModifier> modifiers = new ArrayList<>(this.modifiers.length);
for (final AttributeModifier modifier : this.modifiers) {
final int mappedId = clientbound ? mappings.getNewId(modifier.attribute()) : mappings.inverse().getNewId(modifier.attribute());
if (mappedId != -1) {
modifiers.add(new AttributeModifier(mappedId, modifier.modifier(), modifier.slotType()));
}
}
return new AttributeModifiers1_20_5(modifiers.toArray(AttributeModifier[]::new), this.showInTooltip);
}
public record AttributeModifier(int attribute, ModifierData modifier, int slotType) {
public static final Type<AttributeModifier> TYPE = new Type<>(AttributeModifier.class) {
@@ -23,16 +23,22 @@
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.ArrayList;
import java.util.List;
public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean showInTooltip) implements Copyable {
public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean showInTooltip) implements Copyable, Rewritable {
public AttributeModifiers1_21(final AttributeModifier[] modifiers) {
this(modifiers, true);
@@ -101,6 +107,23 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
return new AttributeModifiers1_21(Copyable.copy(modifiers), showInTooltip);
}
@Override
public AttributeModifiers1_21 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final FullMappings mappings = protocol.getMappingData().getAttributeMappings();
if (mappings == null) {
return this;
}
final List<AttributeModifier> modifiers = new ArrayList<>(this.modifiers.length);
for (final AttributeModifier modifier : this.modifiers) {
final int mappedId = clientbound ? mappings.getNewId(modifier.attribute()) : mappings.inverse().getNewId(modifier.attribute());
if (mappedId != -1) {
modifiers.add(new AttributeModifier(mappedId, modifier.modifier(), modifier.slotType(), modifier.display()));
}
}
return new AttributeModifiers1_21(modifiers.toArray(AttributeModifier[]::new), this.showInTooltip);
}
public record AttributeModifier(int attribute, ModifierData modifier, int slotType, Display display) {
private static final String[] EQUIPMENT_SLOT_GROUPS = {"any", "mainhand", "offhand", "hand", "feet", "legs", "chest", "head", "armor", "body", "saddle"};
private static final String[] OPERATION = {"add_value", "add_multiplied_base", "add_multiplied_total"};
@@ -173,7 +196,7 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
map.writeMap("display", display -> {
display.write("type", Types.STRING, Display.DISPLAY_TYPES[value.display.id()]);
if (value.display instanceof final OverrideText overrideText) {
display.write("value", Types.TAG, overrideText.component);
display.write("value", Types.TEXT_COMPONENT_TAG, overrideText.component);
}
});
});
@@ -30,20 +30,24 @@ import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.util.Copyable;
import io.netty.buffer.ByteBuf;
public record Bee(CompoundTag entityData, int ticksInHive, int minTicksInHive) implements Copyable {
public record Bee(EntityData entityData, int ticksInHive, int minTicksInHive) implements Copyable {
public static final Type<Bee> TYPE = new Type<>(Bee.class) {
public Bee(final CompoundTag entityData, final int ticksInHive, final int minTicksInHive) {
this(new EntityData(-1, entityData), ticksInHive, minTicksInHive);
}
public static final Type<Bee> TYPE1_20_5 = new Type<>(Bee.class) {
@Override
public Bee read(final ByteBuf buffer) {
final CompoundTag entityData = Types.COMPOUND_TAG.read(buffer);
final int ticksInHive = Types.VAR_INT.readPrimitive(buffer);
final int minTicksInHive = Types.VAR_INT.readPrimitive(buffer);
return new Bee(entityData, ticksInHive, minTicksInHive);
return new Bee(new EntityData(-1, entityData), ticksInHive, minTicksInHive);
}
@Override
public void write(final ByteBuf buffer, final Bee value) {
Types.COMPOUND_TAG.write(buffer, value.entityData);
Types.COMPOUND_TAG.write(buffer, value.entityData.tag());
Types.VAR_INT.writePrimitive(buffer, value.ticksInHive);
Types.VAR_INT.writePrimitive(buffer, value.minTicksInHive);
}
@@ -51,12 +55,38 @@ public record Bee(CompoundTag entityData, int ticksInHive, int minTicksInHive) i
@Override
public void write(final Ops ops, final Bee value) {
ops.writeMap(map -> map
.writeOptional("entity_data", Types.COMPOUND_TAG, value.entityData, new CompoundTag())
.writeOptional("entity_data", Types.COMPOUND_TAG, value.entityData.tag(), new CompoundTag())
.write("ticks_in_hive", Types.INT, value.ticksInHive)
.write("min_ticks_in_hive", Types.INT, value.minTicksInHive));
}
};
public static final Type<Bee[]> ARRAY_TYPE = new ArrayType<>(TYPE);
public static final Type<Bee[]> ARRAY_TYPE1_20_5 = new ArrayType<>(TYPE1_20_5);
public static final Type<Bee> TYPE1_21_9 = new Type<>(Bee.class) {
@Override
public Bee read(final ByteBuf buffer) {
final EntityData entityData = EntityData.TYPE.read(buffer);
final int ticksInHive = Types.VAR_INT.readPrimitive(buffer);
final int minTicksInHive = Types.VAR_INT.readPrimitive(buffer);
return new Bee(entityData, ticksInHive, minTicksInHive);
}
@Override
public void write(final ByteBuf buffer, final Bee value) {
EntityData.TYPE.write(buffer, value.entityData);
Types.VAR_INT.writePrimitive(buffer, value.ticksInHive);
Types.VAR_INT.writePrimitive(buffer, value.minTicksInHive);
}
@Override
public void write(final Ops ops, final Bee value) {
ops.writeMap(map -> map
.write("entity_data", EntityData.TYPE, value.entityData)
.write("ticks_in_hive", Types.INT, value.ticksInHive)
.write("min_ticks_in_hive", Types.INT, value.minTicksInHive));
}
};
public static final Type<Bee[]> ARRAY_TYPE1_21_9 = new ArrayType<>(TYPE1_21_9);
@Override
public Bee copy() {
@@ -0,0 +1,65 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record BlockEntityData(int type, CompoundTag tag) implements Rewritable {
public static final Type<BlockEntityData> TYPE = new Type<>(BlockEntityData.class) {
@Override
public BlockEntityData read(final ByteBuf buffer) {
final int type = Types.VAR_INT.readPrimitive(buffer);
final CompoundTag tag = Types.COMPOUND_TAG.read(buffer);
return new BlockEntityData(type, tag);
}
@Override
public void write(final ByteBuf buffer, final BlockEntityData value) {
Types.VAR_INT.writePrimitive(buffer, value.type);
Types.COMPOUND_TAG.write(buffer, value.tag);
}
@Override
public void write(final Ops ops, final BlockEntityData data) {
ops.writeMap(map -> map
.write("id", Types.RESOURCE_LOCATION, ops.context().registryAccess().blockEntity(data.type))
.writeInlinedMap(Types.COMPOUND_TAG, data.tag)
);
}
};
@Override
public BlockEntityData rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final int mappedType = protocol.getMappingData().getBlockEntityMappings().getNewId(type);
// Empty mappings might be possible for removed block entities, set a dummy value in that case. Will be handled fine by server and client without losing data
return new BlockEntityData(mappedType != -1 ? mappedType : 0, tag);
}
}
@@ -22,12 +22,15 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -39,7 +42,7 @@ public record BlocksAttacks(
@Nullable String bypassedByTag,
@Nullable Holder<SoundEvent> blockSound,
@Nullable Holder<SoundEvent> disableSound
) {
) implements Rewritable {
public static final Type<BlocksAttacks> TYPE = new Type<>(BlocksAttacks.class) {
@@ -67,6 +70,13 @@ public record BlocksAttacks(
}
};
@Override
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);
}
public record DamageReduction(float horizontalBlockingAngle, @Nullable HolderSet type, float base, float factor) {
public static final Type<DamageReduction> TYPE = new Type<>(DamageReduction.class) {
@@ -116,7 +116,7 @@ public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<S
@Override
public Consumable1_21_2 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundHolder = this.sound.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> soundHolder = SoundEvent.rewriteHolder(this.sound, Rewritable.soundRewriteFunction(protocol, clientbound));
return soundHolder == this.sound ? this : new Consumable1_21_2(consumeSeconds, animationType, soundHolder, hasConsumeParticles, consumeEffects);
}
@@ -44,6 +44,10 @@ public final class ContainterContents {
ops.writeList(list -> {
for (int i = 0; i < value.length; i++) {
final Item item = value[i];
if (item.isEmpty()) {
continue;
}
final int slot = i;
list.writeMap(map -> map
.write("slot", Types.INT, slot)
@@ -23,24 +23,14 @@
package com.viaversion.viaversion.api.minecraft.item.data;
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;
import com.viaversion.viaversion.util.Key;
import io.netty.buffer.ByteBuf;
public record DamageResistant(Key typesTagKey) {
public static final Type<DamageResistant> TYPE = new Type<>(DamageResistant.class) {
@Override
public DamageResistant read(final ByteBuf buffer) {
final Key typesTagKey = Types.RESOURCE_LOCATION.read(buffer);
return new DamageResistant(typesTagKey);
}
@Override
public void write(final ByteBuf buffer, final DamageResistant value) {
Types.RESOURCE_LOCATION.write(buffer, value.typesTagKey());
}
public static final Type<DamageResistant> TYPE = new TransformingType<>(Types.RESOURCE_LOCATION, DamageResistant.class, DamageResistant::new, DamageResistant::typesTagKey) {
@Override
public void write(final Ops ops, final DamageResistant value) {
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
public record DebugStickState(CompoundTag tag) implements Rewritable, Copyable {
public static final Type<DebugStickState> TYPE = TransformingType.of(Types.COMPOUND_TAG, DebugStickState.class, DebugStickState::new, DebugStickState::tag);
@Override
public DebugStickState rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
CompoundTag updatedTag = tag;
if (clientbound && protocol.getMappingData() != null && protocol.getMappingData().changedBlocks() != null) {
updatedTag = tag.copy();
// Anything beyond this isn't worth the disk space/handling
updatedTag.entrySet().removeIf(entry -> {
final int blockId = protocol.getMappingData().getFullBlockMappings().id(entry.getKey());
return protocol.getMappingData().changedBlocks().contains(blockId);
});
}
return new DebugStickState(updatedTag);
}
@Override
public DebugStickState copy() {
return new DebugStickState(tag.copy());
}
}
@@ -0,0 +1,70 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record EntityData(int type, CompoundTag tag) implements Rewritable, Copyable {
public static final Type<EntityData> TYPE = new Type<>(EntityData.class) {
@Override
public EntityData read(final ByteBuf buffer) {
final int type = Types.VAR_INT.readPrimitive(buffer);
final CompoundTag tag = Types.COMPOUND_TAG.read(buffer);
return new EntityData(type, tag);
}
@Override
public void write(final ByteBuf buffer, final EntityData value) {
Types.VAR_INT.writePrimitive(buffer, value.type);
Types.COMPOUND_TAG.write(buffer, value.tag);
}
@Override
public void write(final Ops ops, final EntityData data) {
ops.writeMap(map -> map
.write("id", Types.RESOURCE_LOCATION, ops.context().registryAccess().entity(data.type))
.writeInlinedMap(Types.COMPOUND_TAG, data.tag)
);
}
};
@Override
public EntityData rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final int mappedType = protocol.getMappingData().getEntityMappings().getNewId(type);
return new EntityData(mappedType, tag);
}
@Override
public EntityData copy() {
return new EntityData(type, tag.copy());
}
}
@@ -44,8 +44,11 @@ public final class EnumTypes {
public static final EnumType HORSE_VARIANT = new EnumType(Fallback.WRAP, "white", "creamy", "chestnut", "brown", "black", "gray", "dark_brown");
public static final EnumType LLAMA_VARIANT = new EnumType(Fallback.CLAMP, "creamy", "white", "brown", "gray");
public static final EnumType AXOLOTL_VARIANT = new EnumType("lucy", "wild", "gold", "cyan", "blue");
public static final EnumType EQUIPMENT_SLOT = new EnumType("mainhand", "feet", "legs", "chest", "head", "offhand", "body", "saddle");
// Enums with non-ordinal ids
public static final FakeEnumType RABBIT_VARIANT = new FakeEnumType(List.of("brown", "white", "black", "white_splotched", "gold", "salt"), of(99, "evil"));
// Pretty much enums, but with a resource location
public static final RegistryValueType VILLAGER_TYPE = new RegistryValueType("desert", "jungle", "plains", "savanna", "snow", "swamp", "taiga");
public static final RegistryValueType POTION = new RegistryValueType("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("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");
}
@@ -23,12 +23,16 @@
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderSetType;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -101,6 +105,21 @@ public record Equippable(int equipmentSlot, Holder<SoundEvent> soundEvent, @Null
buffer.writeBoolean(value.damageOnHurt());
buffer.writeBoolean(value.equipOnInteract());
}
@Override
public void write(final Ops ops, final Equippable value) {
final Holder<SoundEvent> defaultEquipSound = Holder.of(ops.context().registryAccess().id(MappingData.MappingType.SOUND, "item.armor.equip_generic"));
ops.writeMap(map -> map
.write("slot", EnumTypes.EQUIPMENT_SLOT, value.equipmentSlot)
.writeOptional("equip_sound", Types.SOUND_EVENT, value.soundEvent, defaultEquipSound)
.writeOptional("asset_id", Types.RESOURCE_LOCATION, value.model != null ? Key.of(value.model) : null)
.writeOptional("camera_overlay", Types.RESOURCE_LOCATION, value.cameraOverlay != null ? Key.of(value.cameraOverlay) : null)
.writeOptional("allowed_entities", new HolderSetType(MappingData.MappingType.ENTITY), value.allowedEntities)
.writeOptional("dispensable", Types.BOOLEAN, value.dispensable, true)
.writeOptional("swappable", Types.BOOLEAN, value.swappable, true)
.writeOptional("damage_on_hurt", Types.BOOLEAN, value.damageOnHurt, true)
.writeOptional("equip_on_interact", Types.BOOLEAN, value.equipOnInteract, false));
}
};
public static final Type<Equippable> TYPE1_21_6 = new Type<>(Equippable.class) {
@Override
@@ -133,12 +152,32 @@ public record Equippable(int equipmentSlot, Holder<SoundEvent> soundEvent, @Null
buffer.writeBoolean(value.canBeSheared());
Types.SOUND_EVENT.write(buffer, value.shearingSound());
}
@Override
public void write(final Ops ops, final Equippable value) {
final Holder<SoundEvent> defaultSound = Holder.of(ops.context().registryAccess().id(MappingData.MappingType.SOUND, "item.armor.equip_generic"));
final Holder<SoundEvent> defaultShearingSound = Holder.of(ops.context().registryAccess().id(MappingData.MappingType.SOUND, "item.shears.snip"));
ops.writeMap(map -> map
.write("slot", EnumTypes.EQUIPMENT_SLOT, value.equipmentSlot)
.writeOptional("equip_sound", Types.SOUND_EVENT, value.soundEvent, defaultSound)
.writeOptional("asset_id", Types.RESOURCE_LOCATION, value.model != null ? Key.of(value.model) : null)
.writeOptional("camera_overlay", Types.RESOURCE_LOCATION, value.cameraOverlay != null ? Key.of(value.cameraOverlay) : null)
.writeOptional("allowed_entities", new HolderSetType(MappingData.MappingType.ENTITY), value.allowedEntities)
.writeOptional("dispensable", Types.BOOLEAN, value.dispensable, true)
.writeOptional("swappable", Types.BOOLEAN, value.swappable, true)
.writeOptional("damage_on_hurt", Types.BOOLEAN, value.damageOnHurt, true)
.writeOptional("equip_on_interact", Types.BOOLEAN, value.equipOnInteract, false)
.writeOptional("can_be_sheared", Types.BOOLEAN, value.canBeSheared, false)
.writeOptional("shearing_sound", Types.SOUND_EVENT, value.shearingSound, defaultShearingSound));
}
};
@Override
public Equippable rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> shearingSound = this.shearingSound.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
return soundEvent == this.soundEvent && shearingSound == this.shearingSound ? this : new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt, equipOnInteract, canBeSheared, shearingSound);
final Holder<SoundEvent> soundEvent = SoundEvent.rewriteHolder(this.soundEvent, Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> shearingSound = SoundEvent.rewriteHolder(this.shearingSound, Rewritable.soundRewriteFunction(protocol, clientbound));
final HolderSet allowedEntities = this.allowedEntities != null ? this.allowedEntities.rewrite(Rewritable.entityRewriteFunction(protocol, clientbound)) : null;
return soundEvent == this.soundEvent && shearingSound == this.shearingSound && allowedEntities == this.allowedEntities ? this
: new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt, equipOnInteract, canBeSheared, shearingSound);
}
}
@@ -52,7 +52,7 @@ public record Instrument1_20_5(Holder<SoundEvent> soundEvent, int useDuration, f
@Override
public Instrument1_20_5 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> soundEvent = SoundEvent.rewriteHolder(this.soundEvent, Rewritable.soundRewriteFunction(protocol, clientbound));
return soundEvent == this.soundEvent ? this : new Instrument1_20_5(soundEvent, useDuration, range);
}
}
@@ -59,7 +59,7 @@ public record Instrument1_21_2(Holder<SoundEvent> soundEvent, float useDuration,
@Override
public Instrument1_21_2 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> soundEvent = SoundEvent.rewriteHolder(this.soundEvent, Rewritable.soundRewriteFunction(protocol, clientbound));
return soundEvent == this.soundEvent ? this : new Instrument1_21_2(soundEvent, useDuration, range, description);
}
@@ -0,0 +1,44 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Rewritable;
public record ItemModel(Key key) implements Rewritable {
public static final Type<ItemModel> TYPE = TransformingType.of(Types.RESOURCE_LOCATION, ItemModel.class, ItemModel::new, ItemModel::key);
@Override
public ItemModel rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
// This data specifically will often be used with Vanilla items, so the key should be rewritten
final String type = key().toString();
final String mappedType = Rewritable.rewriteItem(protocol, clientbound, type);
return mappedType == null || type.equals(mappedType) ? this : new ItemModel(Key.of(mappedType));
}
}
@@ -111,7 +111,7 @@ public record JukeboxPlayable(EitherHolder<JukeboxSong> song, boolean showInTool
@Override
public JukeboxSong rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> soundEvent = SoundEvent.rewriteHolder(this.soundEvent, Rewritable.soundRewriteFunction(protocol, clientbound));
return soundEvent == this.soundEvent ? this : new JukeboxSong(soundEvent, description, lengthInSeconds, comparatorOutput);
}
}
@@ -0,0 +1,85 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
public record LockCode(CompoundTag tag) implements Rewritable, Copyable {
public static final Type<LockCode> TYPE = TransformingType.of(Types.COMPOUND_TAG, LockCode.class, LockCode::new, LockCode::tag);
@Override
public LockCode rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
CompoundTag updatedTag = tag;
if (clientbound && protocol.getComponentRewriter() != null) {
// Just abuse the component rewriter and keep this one-way
updatedTag = tag.copy();
updatedTag.putString("id", "air");
protocol.getComponentRewriter().handleShowItem(connection, updatedTag);
updatedTag.remove("id");
final FullMappings mappings = protocol.getMappingData().getFullItemMappings();
final Tag itemsTag = updatedTag.get("items");
if (itemsTag != null) {
final HolderSet items = HolderSet.fromTag(itemsTag, key -> mappings.id(key));
items.rewrite(mappings::getNewId);
updatedTag.put("items", toTag(items, mappings));
}
}
return new LockCode(updatedTag);
}
private Tag toTag(final HolderSet holderSet, final FullMappings mappings) {
if (holderSet.hasTagKey()) {
return new StringTag("#" + holderSet.tagKey());
}
final int[] ids = holderSet.ids();
if (ids.length == 1) {
return new StringTag(mappings.mappedIdentifier(ids[0]));
}
final ListTag<StringTag> listTag = new ListTag<>(StringTag.class);
for (final int id : ids) {
listTag.add(new StringTag(mappings.mappedIdentifier(id)));
}
return listTag;
}
@Override
public LockCode copy() {
return new LockCode(tag.copy());
}
}
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Copyable;
@@ -85,6 +86,15 @@ public record PotionContents(@Nullable Integer potion, @Nullable Integer customC
PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects);
Types.OPTIONAL_STRING.write(buffer, value.customName);
}
@Override
public void write(final Ops ops, final PotionContents value) {
ops.writeMap(map -> map
.writeOptional("potion", EnumTypes.POTION, value.potion)
.writeOptional("custom_color", Types.INT, value.customColor)
.writeOptional("custom_effects", PotionEffect.ARRAY_TYPE, value.customEffects, new PotionEffect[0])
.writeOptional("custom_name", Types.STRING, value.customName));
}
};
@Override
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
@@ -42,6 +43,13 @@ public record PotionEffect(int effect, PotionEffectData effectData) {
Types.VAR_INT.writePrimitive(buffer, value.effect);
PotionEffectData.TYPE.write(buffer, value.effectData);
}
@Override
public void write(final Ops ops, final PotionEffect value) {
ops.writeMap(map -> map
.write("id", EnumTypes.MOB_EFFECT, value.effect)
.writeInlinedMap(PotionEffectData.TYPE, value.effectData));
}
};
public static final Type<PotionEffect[]> ARRAY_TYPE = new ArrayType<>(TYPE);
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
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;
@@ -52,6 +53,17 @@ public record PotionEffectData(int amplifier, int duration, boolean ambient, boo
buffer.writeBoolean(value.showIcon);
OPTIONAL_TYPE.write(buffer, value.hiddenEffect);
}
@Override
public void write(final Ops ops, final PotionEffectData value) {
ops.writeMap(map -> map
.writeOptional("amplifier", Types.UNSIGNED_BYTE, (short) value.amplifier, (short) 0)
.writeOptional("duration", Types.INT, value.duration, 0)
.writeOptional("ambient", Types.BOOLEAN, value.ambient, false)
.writeOptional("show_particles", Types.BOOLEAN, value.showParticles, true)
.writeOptional("show_icon", Types.BOOLEAN, value.showIcon)
.writeOptional("hidden_effect", TYPE, value.hiddenEffect));
}
};
public static final Type<PotionEffectData> OPTIONAL_TYPE = new OptionalType<>(TYPE) {
};
@@ -0,0 +1,50 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData.MappingType;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderSetType;
import com.viaversion.viaversion.util.Rewritable;
public record Repairable(HolderSet items) implements Rewritable {
public static final Type<Repairable> TYPE = new TransformingType<>(Types.HOLDER_SET, Repairable.class, Repairable::new, Repairable::items) {
@Override
public void write(final Ops ops, final Repairable value) {
ops.writeMap(map -> map.write("items", new HolderSetType(MappingType.ITEM), value.items));
}
};
@Override
public Repairable rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final HolderSet items = this.items.rewrite(Rewritable.itemRewriteFunction(protocol, clientbound));
return this.items == items ? this : new Repairable(items);
}
}
@@ -100,9 +100,9 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
Preconditions.checkArgument(!initialized, "Protocol has already been initialized");
initialized = true;
// Create logger if protocol does not have one
if (getLogger() == null) {
logger = new ProtocolLogger(getClass());
// Create logger if the protocol doesn't have one
if (logger == null) {
logger = createLogger();
}
registerPackets();
registerConfigurationChangeHandlers();
@@ -128,6 +128,10 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
}
}
protected ProtocolLogger createLogger() {
return new ProtocolLogger(getClass());
}
protected void registerConfigurationChangeHandlers() {
// Register handlers for protocol state switching
// Assuming ids will change too often, it is cleaner to register them here instead of the base protocols,
@@ -139,7 +143,7 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
final CU startConfigurationPacket = startConfigurationPacket();
if (startConfigurationPacket != null) {
appendClientbound(startConfigurationPacket, setServerStateHandler(State.CONFIGURATION));
appendClientbound(startConfigurationPacket, startConfigurationHandler());
}
final SU finishConfigurationPacket = serverboundFinishConfigurationPacket();
@@ -476,6 +480,16 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
return wrapper -> wrapper.user().getProtocolInfo().setServerState(state);
}
private PacketHandler startConfigurationHandler() {
return setServerStateHandler(State.CONFIGURATION).then(wrapper -> {
// Mimic client behaviour
final EntityTracker tracker = wrapper.user().getEntityTracker(getClass());
if (tracker != null) {
tracker.clear();
}
});
}
@Override
public final PacketTypesProvider<CU, CM, SM, SU> getPacketTypesProvider() {
return packetTypesProvider;
@@ -24,11 +24,15 @@ package com.viaversion.viaversion.api.protocol;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.exception.InformativeException;
import java.util.Collection;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface ProtocolPipeline extends SimpleProtocol {
public interface ProtocolPipeline {
/**
* Adds a protocol to the current pipeline.
@@ -67,6 +71,15 @@ public interface ProtocolPipeline extends SimpleProtocol {
@Deprecated
@Nullable <P extends Protocol> P getProtocol(Class<P> pipeClass);
/**
* Transform a packet using the protocols in this pipeline.
*
* @param direction The direction the packet is going in
* @param state The current protocol state
* @param packetWrapper The packet wrapper to transform
*/
void transform(Direction direction, State state, PacketWrapper packetWrapper) throws InformativeException, CancelException;
List<Protocol> pipes(@Nullable Class<? extends Protocol> protocolClass, boolean skipCurrentPipeline, Direction direction);
/**
@@ -23,152 +23,219 @@
package com.viaversion.viaversion.api.protocol.packet;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.configuration.RateLimitConfig;
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
import com.viaversion.viaversion.api.connection.UserConnection;
import java.util.Arrays;
public class PacketTracker {
private final UserConnection connection;
private static final long SECOND_NANOS = 1_000_000_000L;
private final RateTracker packetTracker = new RateTracker(5);
private final RateTracker packetSizeTracker = new RateTracker(3);
private long startTime = System.nanoTime();
private boolean packetLimiterEnabled = true;
private long sentPackets;
private long receivedPackets;
// Used for tracking pps
private long startTime;
private long intervalPackets;
private long packetsPerSecond = -1L;
// Used for handling warnings (over time)
private int secondsObserved;
private int warnings;
private final UserConnection connection;
private long sentPacketsTotal;
private long receivedPacketsTotal;
public PacketTracker(UserConnection connection) {
this.connection = connection;
}
/**
* Used for incrementing the number of packets sent to the client.
* Increments the number of packets sent to the client.
*/
public void incrementSent() {
this.sentPackets++;
this.sentPacketsTotal++;
}
/**
* Used for incrementing the number of packets received from the client.
*
* @return true if the interval has reset and can now be checked for the packets sent
*/
@Deprecated(forRemoval = true)
public boolean incrementReceived() {
// handle stats
long diff = System.currentTimeMillis() - startTime;
if (diff >= 1000) {
packetsPerSecond = intervalPackets;
startTime = System.currentTimeMillis();
intervalPackets = 1;
return true;
} else {
intervalPackets++;
}
// increase total
this.receivedPackets++;
return false;
return incrementReceived(0);
}
/**
* Checks for packet flood with the packets sent in the last second.
* ALWAYS check for {@link #incrementReceived()} before using this method.
* Increments the number of packets received from the client.
*
* @return true if the packet should be cancelled
* @see #incrementReceived()
* @return true if the interval has reset
*/
public boolean exceedsMaxPPS() {
if (connection.isClientSide()) return false; // Don't apply PPS limiting for client-side
ViaVersionConfig conf = Via.getConfig();
// Max PPS Checker
if (conf.getMaxPPS() > 0 && packetsPerSecond >= conf.getMaxPPS()) {
connection.disconnect(conf.getMaxPPSKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
return true; // don't send current packet
}
public boolean incrementReceived(int packetSize) {
receivedPacketsTotal++;
// Tracking PPS Checker
if (conf.getMaxWarnings() > 0 && conf.getTrackingPeriod() > 0) {
if (secondsObserved > conf.getTrackingPeriod()) {
// Reset
warnings = 0;
secondsObserved = 1;
} else {
secondsObserved++;
if (packetsPerSecond >= conf.getWarningPPS()) {
warnings++;
}
if (warnings >= conf.getMaxWarnings()) {
connection.disconnect(conf.getMaxWarningsKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
return true; // don't send current packet
}
ViaVersionConfig config = Via.getConfig();
long currentTime = System.nanoTime();
long elapsed = currentTime - startTime;
if (elapsed < SECOND_NANOS) {
// Add to current interval
if (config.getPacketTrackerConfig().enabled()) {
packetTracker.addIntervalValue(1);
}
if (config.getPacketSizeTrackerConfig().enabled()) {
packetSizeTracker.addIntervalValue(packetSize);
}
return false;
}
return false;
// Reset interval tracking
if (config.getPacketTrackerConfig().enabled()) {
packetTracker.updateRate(elapsed);
packetTracker.addIntervalValue(1);
}
if (config.getPacketSizeTrackerConfig().enabled()) {
packetSizeTracker.updateRate(elapsed);
packetSizeTracker.addIntervalValue(packetSize);
}
startTime = currentTime;
return true;
}
public boolean exceedsLimits() {
if (connection.isClientSide()) {
return false;
}
ViaVersionConfig config = Via.getConfig();
return packetTracker.exceedsLimit(connection, config.getPacketTrackerConfig())
|| packetSizeTracker.exceedsLimit(connection, config.getPacketSizeTrackerConfig());
}
public long getSentPackets() {
return sentPackets;
return sentPacketsTotal;
}
@Deprecated(forRemoval = true)
public void setSentPackets(long sentPackets) {
this.sentPackets = sentPackets;
this.sentPacketsTotal = sentPackets;
}
public long getReceivedPackets() {
return receivedPackets;
return receivedPacketsTotal;
}
@Deprecated(forRemoval = true)
public void setReceivedPackets(long receivedPackets) {
this.receivedPackets = receivedPackets;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
this.receivedPacketsTotal = receivedPackets;
}
@Deprecated(forRemoval = true)
public long getIntervalPackets() {
return intervalPackets;
return this.packetTracker.intervalValue;
}
@Deprecated(forRemoval = true)
public void setIntervalPackets(long intervalPackets) {
this.intervalPackets = intervalPackets;
this.packetTracker.intervalValue = Math.toIntExact(intervalPackets);
}
public long getPacketsPerSecond() {
return packetsPerSecond;
}
public void setPacketsPerSecond(long packetsPerSecond) {
this.packetsPerSecond = packetsPerSecond;
}
public int getSecondsObserved() {
return secondsObserved;
}
public void setSecondsObserved(int secondsObserved) {
this.secondsObserved = secondsObserved;
}
public int getWarnings() {
return warnings;
}
public void setWarnings(int warnings) {
this.warnings = warnings;
public int getPacketsPerSecond() {
return packetTracker.currentRate;
}
public boolean isPacketLimiterEnabled() {
return packetLimiterEnabled;
ViaVersionConfig config = Via.getConfig();
return packetLimiterEnabled && config.getPacketTrackerConfig().enabled() && config.getPacketSizeTrackerConfig().enabled();
}
public void setPacketLimiterEnabled(boolean packetLimiterEnabled) {
this.packetLimiterEnabled = packetLimiterEnabled;
}
@Deprecated(forRemoval = true)
public void setWarnings(int warnings) {
this.packetTracker.warnings = warnings;
}
private static final class RateTracker {
private final int[] history;
private int historyIndex;
private int historyCount;
private int currentRate = -1;
// Interval tracking
int intervalValue;
// Warning system
private long warningPeriodStart = System.nanoTime();
private int warnings;
public RateTracker(int windowSize) {
this.history = new int[windowSize];
}
public void addIntervalValue(int value) {
intervalValue += value;
}
public void updateRate(long elapsedNanos) {
// Update sliding window
history[historyIndex] = (int) ((intervalValue * SECOND_NANOS) / elapsedNanos);
historyIndex = (historyIndex + 1) % history.length;
if (historyCount < history.length) {
historyCount++;
}
// Calculate smoothed average
int sum = 0;
for (int i = 0; i < historyCount; i++) {
sum += history[i];
}
currentRate = sum / historyCount;
intervalValue = 0; // Reset
}
public boolean exceedsLimit(UserConnection connection, RateLimitConfig limitConfig) {
if (!limitConfig.enabled() || currentRate < 0) {
return false;
}
// Immediate limit check
if (limitConfig.maxRate() > 0 && currentRate >= limitConfig.maxRate()) {
connection.disconnect(limitConfig.maxRateKickMessage().replace(limitConfig.ratePlaceholder(), Integer.toString(currentRate)));
return true;
}
// Interval warnings
if (limitConfig.maxWarnings() > 0 && limitConfig.trackingPeriodNanos() > 0 && limitConfig.warningRate() > 0) {
return checkTrackedInterval(connection, limitConfig);
}
return false;
}
private boolean checkTrackedInterval(UserConnection connection, RateLimitConfig config) {
long currentTime = System.nanoTime();
if (currentTime - warningPeriodStart >= config.trackingPeriodNanos()) {
// Reset
warnings = 0;
warningPeriodStart = currentTime;
return false;
}
if (currentRate >= config.warningRate() && ++warnings >= config.maxWarnings()) {
connection.disconnect(config.warningKickMessage().replace(config.ratePlaceholder(), Integer.toString(currentRate)));
return true;
}
return false;
}
public void reset() {
intervalValue = 0;
currentRate = -1;
warnings = 0;
warningPeriodStart = System.nanoTime();
historyIndex = 0;
historyCount = 0;
Arrays.fill(history, 0);
}
}
public void reset() {
sentPacketsTotal = 0;
receivedPacketsTotal = 0;
startTime = System.nanoTime();
packetTracker.reset();
packetSizeTracker.reset();
}
}
@@ -90,6 +90,8 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_21_4 = register(769, "1.21.4");
public static final ProtocolVersion v1_21_5 = register(770, "1.21.5");
public static final ProtocolVersion v1_21_6 = register(771, "1.21.6");
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 unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
static {
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.rewriter;
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 org.checkerframework.checker.nullness.qual.Nullable;
@@ -34,4 +35,6 @@ public interface ComponentRewriter {
void processText(UserConnection connection, @Nullable JsonElement element);
JsonElement processText(UserConnection connection, @Nullable String json);
void handleShowItem(UserConnection connection, CompoundTag itemTag);
}
@@ -0,0 +1,77 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import io.netty.buffer.ByteBuf;
import java.util.function.Function;
public class TransformingType<F, T> extends Type<T> {
private final Type<F> from;
private final Function<F, T> mapFunction;
private final Function<T, F> reverseFunction;
protected TransformingType(
final Type<F> from, final Class<T> outputClass,
final Function<F, T> mapFunction, final Function<T, F> reverseFunction
) {
super(from.getTypeName(), outputClass);
this.from = from;
this.mapFunction = mapFunction;
this.reverseFunction = reverseFunction;
}
/**
* Returns a type that transforms the input to a separate output type.
* Useful if you have wrapper classes of a single object.
*
* @param from type to map from
* @param outputClass output class
* @param mapFunction function to map from F to T
* @param reverseFunction function to map from T to F
* @param <F> from type
* @param <T> to type
* @return transforming type
*/
public static <F, T> Type<T> of(
final Type<F> from, final Class<T> outputClass,
final Function<F, T> mapFunction, final Function<T, F> reverseFunction
) {
return new TransformingType<>(from, outputClass, mapFunction, reverseFunction);
}
@Override
public T read(final ByteBuf buffer) {
return mapFunction.apply(from.read(buffer));
}
@Override
public void write(final ByteBuf buffer, final T value) {
from.write(buffer, reverseFunction.apply(value));
}
@Override
public void write(final Ops ops, final T value) {
from.write(ops, reverseFunction.apply(value));
}
}
@@ -36,8 +36,10 @@ import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature;
import com.viaversion.viaversion.api.minecraft.ProfileKey;
import com.viaversion.viaversion.api.minecraft.Quaternion;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.Vector;
import com.viaversion.viaversion.api.minecraft.Vector3d;
import com.viaversion.viaversion.api.minecraft.Vector3f;
import com.viaversion.viaversion.api.minecraft.VillagerData;
import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity;
@@ -70,6 +72,7 @@ import com.viaversion.viaversion.api.type.types.ShortType;
import com.viaversion.viaversion.api.type.types.StringType;
import com.viaversion.viaversion.api.type.types.UUIDType;
import com.viaversion.viaversion.api.type.types.UnsignedByteType;
import com.viaversion.viaversion.api.type.types.UnsignedIntType;
import com.viaversion.viaversion.api.type.types.UnsignedShortType;
import com.viaversion.viaversion.api.type.types.VarIntArrayType;
import com.viaversion.viaversion.api.type.types.VarIntType;
@@ -100,6 +103,7 @@ 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.QuaternionType;
import com.viaversion.viaversion.api.type.types.math.Vector3fType;
import com.viaversion.viaversion.api.type.types.math.VectorType;
@@ -108,13 +112,16 @@ import com.viaversion.viaversion.api.type.types.misc.GameProfileType;
import com.viaversion.viaversion.api.type.types.misc.HolderSetType;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.api.type.types.misc.KeyType;
import com.viaversion.viaversion.api.type.types.misc.LengthPrefixedTagType;
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.TagKeyType;
import com.viaversion.viaversion.api.type.types.misc.TagType;
import com.viaversion.viaversion.api.type.types.misc.TextComponentTagType;
import com.viaversion.viaversion.api.type.types.misc.VillagerDataType;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.util.Key;
@@ -142,6 +149,7 @@ public final class Types {
public static final IntType INT = new IntType();
public static final Type<int[]> INT_ARRAY_PRIMITIVE = new IntArrayType();
public static final UnsignedIntType UNSIGNED_INT = new UnsignedIntType();
public static final FloatType FLOAT = new FloatType();
public static final FloatType.OptionalFloatType OPTIONAL_FLOAT = new FloatType.OptionalFloatType();
@@ -190,6 +198,7 @@ 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<CompoundTag> NAMED_COMPOUND_TAG = new NamedCompoundTagType();
public static final Type<CompoundTag> OPTIONAL_NAMED_COMPOUND_TAG = new NamedCompoundTagType.OptionalNamedCompoundTagType();
@@ -199,6 +208,8 @@ public final class Types {
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> 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<GlobalBlockPosition> GLOBAL_POSITION = new GlobalBlockPositionType();
public static final Type<GlobalBlockPosition> OPTIONAL_GLOBAL_POSITION = new GlobalBlockPositionType.OptionalGlobalPositionType();
@@ -220,6 +231,7 @@ public final class Types {
public static final Type<VillagerData> VILLAGER_DATA = new VillagerDataType();
public static final Type<GameProfile> GAME_PROFILE = new GameProfileType();
public static final Type<ResolvableProfile> RESOLVABLE_PROFILE = new ResolvableProfileType();
public static final Type<GameProfile.Property> PROFILE_PROPERTY = new ProfilePropertyType();
public static final Type<GameProfile.Property[]> PROFILE_PROPERTY_ARRAY = new ArrayType<>(PROFILE_PROPERTY);
public static final Type<ProfileKey> PROFILE_KEY = new ProfileKeyType();
@@ -41,4 +41,8 @@ public final class RegistryValueType extends VarIntType {
public void write(final Ops ops, final Integer value) {
Types.STRING.write(ops, names[value]);
}
public String[] names() {
return names;
}
}
@@ -0,0 +1,63 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.TypeConverter;
import io.netty.buffer.ByteBuf;
public class UnsignedIntType extends Type<Long> implements TypeConverter<Long> {
public static final long MAX_UNSIGNED_INT = 0xFFFFFFFFL;
public UnsignedIntType() {
super(Long.class);
}
@Override
public Long read(ByteBuf buffer) {
return buffer.readUnsignedInt();
}
public long readPrimitive(ByteBuf buffer) {
return buffer.readUnsignedInt();
}
@Override
public void write(ByteBuf buffer, Long l) {
buffer.writeInt(l.intValue());
}
public void writePrimitive(ByteBuf buffer, long l) {
buffer.writeInt((int) l);
}
@Override
public Long from(Object o) {
if (o instanceof Number number) {
return number.longValue();
} else if (o instanceof Boolean boo) {
return boo ? 1L : 0L;
}
throw new UnsupportedOperationException();
}
}
@@ -25,7 +25,6 @@ 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.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
@@ -24,7 +24,6 @@ package com.viaversion.viaversion.api.type.types.item;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.data.item.ItemHasher;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
@@ -0,0 +1,116 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.math;
import com.viaversion.viaversion.api.minecraft.Vector3d;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
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> {
// 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
private static final int SCALE_BITS_MASK = 3;
private static final int CONTINUATION_FLAG = 1 << 2; // 3rd bit to indicate more scale data
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() {
super(Vector3d.class);
}
@Override
public Vector3d read(final ByteBuf buffer) {
// Pack values back into a single long
final int first = Types.UNSIGNED_BYTE.read(buffer);
if (first == 0) {
return Vector3d.ZERO;
}
final int second = Types.UNSIGNED_BYTE.read(buffer);
final long remaining = Types.UNSIGNED_INT.read(buffer);
final long packed = remaining << 16 | second << 8 | first;
long scale = first & SCALE_BITS_MASK;
if ((first & CONTINUATION_FLAG) != 0) {
// Read the remaining bits and add them to the first two
scale |= (Types.VAR_INT.readPrimitive(buffer) & UnsignedIntType.MAX_UNSIGNED_INT) << SCALE_BITS;
}
// 15 bits for each part after removing the scale bits
return new Vector3d(
unpack(packed >> (0 + SCALE_BITS_MASK)) * scale,
unpack(packed >> (15 + SCALE_BITS_MASK)) * scale,
unpack(packed >> (30 + SCALE_BITS_MASK)) * scale
);
}
@Override
public void write(final ByteBuf buffer, final Vector3d vec) {
final double x = sanitize(vec.x());
final double y = sanitize(vec.y());
final double z = sanitize(vec.z());
final double maxPart = Math.max(Math.abs(x), Math.max(Math.abs(y), Math.abs(z)));
if (maxPart < ABS_MIN_VALUE) {
buffer.writeByte(0);
return;
}
final long scale = MathUtil.ceilLong(maxPart);
final boolean scaleTooLargeForBits = (scale & SCALE_BITS_MASK) != scale;
final long scaleBits = scaleTooLargeForBits ? (scale & SCALE_BITS_MASK) | CONTINUATION_FLAG : scale;
final long packed = scaleBits
| (pack(x / scale) << (0 + SCALE_BITS_MASK))
| (pack(y / scale) << (15 + SCALE_BITS_MASK))
| (pack(z / scale) << (30 + SCALE_BITS_MASK));
buffer.writeByte((byte) packed);
buffer.writeByte((byte) (packed >> 8));
buffer.writeInt((int) (packed >> 16));
if (scaleTooLargeForBits) {
// First two bits have already been written
Types.VAR_INT.writePrimitive(buffer, (int) (scale >> SCALE_BITS));
}
}
private double sanitize(final double value) {
return Double.isNaN(value) ? 0 : MathUtil.clamp(value, -ABS_MAX_VALUE, ABS_MAX_VALUE);
}
private long pack(final double value) {
// Shift to [0, 1] and quantize to 15 bits
final double shifted = (value * 0.5) + 0.5;
return Math.round(shifted * MAX_QUANTIZED_VALUE);
}
private double unpack(final long value) {
// Normalize to [-1, 1]
final double clamped = Math.min(value & Short.MAX_VALUE, MAX_QUANTIZED_VALUE);
return (clamped * 2) / MAX_QUANTIZED_VALUE - 1;
}
}
@@ -22,16 +22,27 @@
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.minecraft.HolderSet;
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.util.Key;
import io.netty.buffer.ByteBuf;
public class HolderSetType extends Type<HolderSet> {
private final MappingDataBase.MappingType mappingType;
public HolderSetType() {
this(null);
}
public HolderSetType(final MappingDataBase.MappingType mappingType) {
super(HolderSet.class);
this.mappingType = mappingType;
}
@Override
@@ -63,6 +74,28 @@ public class HolderSetType extends Type<HolderSet> {
}
}
@Override
public void write(final Ops ops, final HolderSet value) {
if (value.hasTagKey()) {
ops.write(Types.TAG_KEY, Key.of(value.tagKey()));
} else {
Preconditions.checkArgument(mappingType != null, "Cannot write HolderSet with direct ids without a mapping type");
if (value.ids().length == 1) {
// Single entries are inlined
final Key key = ops.context().registryAccess().key(mappingType, value.ids()[0]);
ops.write(Types.RESOURCE_LOCATION, key);
return;
}
ops.writeList(list -> {
for (final int id : value.ids()) {
final Key key = ops.context().registryAccess().key(mappingType, id);
list.write(Types.RESOURCE_LOCATION, key);
}
});
}
}
public static final class OptionalHolderSetType extends OptionalType<HolderSet> {
public OptionalHolderSetType() {
@@ -22,16 +22,27 @@
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Key;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class HolderType<T> extends Type<Holder<T>> {
private final MappingData.MappingType mappingType;
protected HolderType() {
this(null);
}
protected HolderType(final MappingData.MappingType mappingType) {
super(Holder.class);
this.mappingType = mappingType;
}
@Override
@@ -57,6 +68,24 @@ public abstract class HolderType<T> extends Type<Holder<T>> {
public abstract void writeDirect(final ByteBuf buffer, final T object);
@Override
public void write(final Ops ops, final Holder<T> value) {
if (value.hasId()) {
ops.write(Types.RESOURCE_LOCATION, identifier(ops, value.id()));
} else {
writeDirect(ops, value.value());
}
}
protected Key identifier(final Ops ops, final int id) {
Preconditions.checkArgument(mappingType != null, "Mapping type is not defined for this HolderType");
return ops.context().registryAccess().key(mappingType, id);
}
public void writeDirect(final Ops ops, final T object) {
throw new UnsupportedOperationException("Write operation not supported for type: " + getTypeName());
}
public abstract static class OptionalHolderType<T> extends HolderType<T> {
private final HolderType<T> type;
@@ -0,0 +1,65 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.google.common.base.Preconditions;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public final class LengthPrefixedTagType extends Type<Tag> {
private final int maxLength;
public LengthPrefixedTagType(int maxLength) {
super(Tag.class);
this.maxLength = maxLength;
}
@Override
public Tag read(final ByteBuf buffer) {
final int length = Types.VAR_INT.readPrimitive(buffer);
Preconditions.checkArgument(length <= maxLength,
"Cannot receive tag longer than %s bytes (got %s bytes)", maxLength, length);
return Types.TAG.read(buffer.readSlice(length));
}
@Override
public void write(final ByteBuf buffer, final Tag tag) {
final ByteBuf tempBuf = buffer.alloc().buffer();
try {
Types.TAG.write(tempBuf, tag);
Preconditions.checkArgument(tempBuf.readableBytes() <= maxLength,
"Cannot send tag longer than %s bytes (got %s bytes)", maxLength, tempBuf.readableBytes());
Types.VAR_INT.writePrimitive(buffer, tempBuf.readableBytes());
buffer.writeBytes(tempBuf);
} finally {
tempBuf.release();
}
}
}
@@ -160,6 +160,13 @@ public class ParticleType extends DynamicType<Particle> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Duration
};
public static final DataReader<Particle> POWER = (buf, particle) -> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf));
};
public static final DataReader<Particle> SPELL = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Power
};
public static DataReader<Particle> item(Type<Item> item) {
return (buf, particle) -> particle.add(item, item.read(buf));
@@ -0,0 +1,90 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Key;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
public final class ResolvableProfileType extends Type<ResolvableProfile> {
public ResolvableProfileType() {
super(ResolvableProfile.class);
}
@Override
public ResolvableProfile read(final ByteBuf buffer) {
final GameProfile profile;
if (buffer.readBoolean()) {
final UUID id = Types.UUID.read(buffer);
final String name = Types.STRING.read(buffer);
final GameProfile.Property[] properties = Types.PROFILE_PROPERTY_ARRAY.read(buffer);
profile = new GameProfile(name, id, properties, false);
} else {
profile = Types.GAME_PROFILE.read(buffer);
}
final String texture = Types.OPTIONAL_STRING.read(buffer);
final String capeTexture = Types.OPTIONAL_STRING.read(buffer);
final String elytraTexture = Types.OPTIONAL_STRING.read(buffer);
final Boolean encodedModelType = Types.OPTIONAL_BOOLEAN.read(buffer); // ...
final Integer modelType = encodedModelType != null ? (encodedModelType ? 0 : 1) : null;
return new ResolvableProfile(profile, texture, capeTexture, elytraTexture, modelType);
}
@Override
public void write(final ByteBuf buffer, final ResolvableProfile value) {
final GameProfile profile = value.profile();
if (!profile.dynamic()) {
buffer.writeBoolean(true);
Types.UUID.write(buffer, profile.id());
Types.STRING.write(buffer, profile.name());
Types.PROFILE_PROPERTY_ARRAY.write(buffer, profile.properties());
} else {
buffer.writeBoolean(false);
Types.GAME_PROFILE.write(buffer, profile);
}
Types.OPTIONAL_STRING.write(buffer, value.bodyTexture());
Types.OPTIONAL_STRING.write(buffer, value.capeTexture());
Types.OPTIONAL_STRING.write(buffer, value.elytraTexture());
Types.OPTIONAL_BOOLEAN.write(buffer, value.modelType() != null ? value.modelType() == 0 : null);
}
@Override
public void write(final Ops ops, final ResolvableProfile value) {
final String modelType = value.modelType() != null ? (value.modelType() == 0 ? "slim" : "wide") : null;
ops.writeMap(map -> map
.writeInlinedMap(Types.GAME_PROFILE, value.profile())
.writeOptional("texture", Types.RESOURCE_LOCATION, value.bodyTexture() != null ? Key.of(value.bodyTexture()) : null)
.writeOptional("cape", Types.RESOURCE_LOCATION, value.capeTexture() != null ? Key.of(value.capeTexture()) : null)
.writeOptional("elytra", Types.RESOURCE_LOCATION, value.elytraTexture() != null ? Key.of(value.elytraTexture()) : null)
.writeOptional("model", Types.OPTIONAL_STRING, modelType)
);
}
};
@@ -22,12 +22,19 @@
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Key;
import io.netty.buffer.ByteBuf;
public final class SoundEventType extends HolderType<SoundEvent> {
public SoundEventType() {
super(MappingData.MappingType.SOUND);
}
@Override
public SoundEvent readDirect(final ByteBuf buffer) {
final String resourceLocation = Types.STRING.read(buffer);
@@ -41,6 +48,13 @@ public final class SoundEventType extends HolderType<SoundEvent> {
Types.OPTIONAL_FLOAT.write(buffer, value.fixedRange());
}
@Override
public void writeDirect(final Ops ops, final SoundEvent object) {
ops.writeMap(map -> map
.write("sound_id", Types.RESOURCE_LOCATION, Key.of(object.identifier()))
.writeOptional("range", Types.FLOAT, object.fixedRange()));
}
public static final class OptionalSoundEventType extends OptionalHolderType<SoundEvent> {
public OptionalSoundEventType() {
@@ -105,13 +105,13 @@ public class TagType extends Type<Tag> {
} else if (value instanceof CompoundTag compoundTag) {
ops.writeMap(map -> {
for (final Map.Entry<String, Tag> entry : compoundTag.entrySet()) {
map.write(entry.getKey(), Types.TAG, entry.getValue());
map.write(entry.getKey(), this, entry.getValue());
}
});
} else if (value instanceof ListTag<?> listTag) {
ops.writeList(list -> {
for (final Tag tag : listTag) {
list.write(Types.TAG, tag);
list.write(this, tag);
}
});
} else if (value instanceof IntArrayTag intArrayTag) {
@@ -0,0 +1,61 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 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.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Types;
import java.util.Map;
import java.util.Set;
/**
* Only strictly needed for hashing purposes for now.
*/
public class TextComponentTagType extends TagType {
private static final Set<String> BOOLEAN_KEYS = Set.of("bold", "italic", "underlined", "strikethrough", "obfuscated", "interpret");
@Override
public void write(final Ops ops, final Tag value) {
if (value instanceof final CompoundTag compoundTag) {
ops.writeMap(map -> {
for (final Map.Entry<String, Tag> entry : compoundTag.entrySet()) {
write(map, entry.getKey(), entry.getValue());
}
});
} else {
super.write(ops, value);
}
}
private void write(final Ops.MapSerializer map, final String key, final Tag value) {
// Better than fully parsing and re-serializing the component
if (value instanceof final ByteTag byteTag && BOOLEAN_KEYS.contains(key)) {
map.write(key, Types.BOOLEAN, byteTag.asBoolean());
} else {
map.write(key, this, value);
}
}
}
@@ -29,6 +29,7 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21;
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;
/**
* Holds versioned accessors for highly volatile types, specifically around items and data components.
@@ -44,4 +45,5 @@ public final class VersionedTypes {
public static final Types1_20_5<StructuredDataKeys1_21_2, EntityDataTypes1_21_2> V1_21_4 = new Types1_20_5<>(StructuredDataKeys1_21_2::new, EntityDataTypes1_21_2::new);
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> V1_21_5 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_5::new);
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);
}
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.util;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
@@ -76,4 +77,21 @@ public final class ArrayUtil {
}
return boxedArray;
}
public static String toString(final Object o) {
if (o == null || !o.getClass().isArray()) {
return String.valueOf(o);
}
final int length = Array.getLength(o);
final StringBuilder builder = new StringBuilder("[");
for (int i = 0; i < length; i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(Array.get(o, i));
}
builder.append("]");
return builder.toString();
}
}
@@ -25,8 +25,8 @@ package com.viaversion.viaversion.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.libs.mcstructs.text.utils.JsonUtils;
import java.util.Comparator;
import net.lenni0451.mcstructs.text.utils.JsonUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class GsonUtil {
@@ -124,7 +124,7 @@ public final class Key {
}
public static boolean equals(final String firstIdentifier, final String secondIdentifier) {
return of(firstIdentifier).equals(of(secondIdentifier));
return firstIdentifier != null && secondIdentifier != null && of(firstIdentifier).equals(of(secondIdentifier));
}
public static String namespaced(final String identifier) {
@@ -24,6 +24,22 @@ package com.viaversion.viaversion.util;
public final class MathUtil {
/**
* Miniscule value below which positive floats are considered zero
*/
public static final float EPSILON = 1.0E-5F;
/**
* Returns the ceiled integer value of the given float.
*
* @param value float value to ceil
* @return ceiled integer value
*/
public static int ceil(final float value) {
final int intValue = (int) value;
return value > intValue ? intValue + 1 : intValue;
}
/**
* Returns the ceiled log to the base of 2 for the given number.
*
@@ -34,6 +50,11 @@ public final class MathUtil {
return i > 0 ? 32 - Integer.numberOfLeadingZeros(i - 1) : 0;
}
public static long ceilLong(final double d) {
final long l = (long) d;
return d > l ? l + 1 : l;
}
/**
* Returns the clamped number within the given range.
*
@@ -48,4 +69,11 @@ public final class MathUtil {
}
return i > max ? max : i;
}
public static double clamp(final double d, final double min, final double max) {
if (d < min) {
return min;
}
return d > max ? max : d;
}
}
@@ -67,7 +67,12 @@ public interface Rewritable {
static Int2IntFunction soundRewriteFunction(final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
return protocol.getMappingData().getSoundMappings() == null ? Int2IntFunction.identity()
: (clientbound ? protocol.getMappingData()::getNewSoundId : protocol.getMappingData()::getOldSoundId);
: (clientbound ? protocol.getMappingData().getSoundMappings()::getNewId : protocol.getMappingData()::getOldSoundId);
}
static Int2IntFunction entityRewriteFunction(final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
return protocol.getMappingData().getEntityMappings() == null ? Int2IntFunction.identity()
: (clientbound ? protocol.getMappingData().getEntityMappings()::getNewId : protocol.getMappingData().getEntityMappings().inverse()::getNewId);
}
static @Nullable String mappedIdentifier(final FullMappings mappings, final String identifier) {
Loaded 100 of 296 files, more files were not shown because too many files have changed in this diff. Show more