Compare commits

...
129 Commits
Author SHA1 Message Date
Nassim Jahnke 50aa9fa3ad 5.12.0 Release 2026-09-18 16:04:35 +02:00
Nassim Jahnke 7497103bac Null check block state Name
Shouldn't be valid, but ?
2026-09-18 16:00:13 +02:00
Nassim Jahnke ff83e2eb6e Fix brewing stand brewing time and fuel display 2026-09-18 16:00:13 +02:00
Nassim JahnkeandCamden Cove 2a75917ef5 Always create mapped chunk type
Types are cached now and need to be created in case global palette bits count changed

Co-authored-by: Camden Cove <me@camdencove.com>
2026-09-18 16:00:13 +02:00
Nassim Jahnke f634879d64 Handle ambient_particles for block state format changes 2026-09-18 16:00:13 +02:00
Nassim Jahnke e6222b38ef Replace new map decoration types when downgrading items 2026-09-18 16:00:13 +02:00
Nassim Jahnke 745a41322f Remove snapshot bit 2026-09-18 16:00:12 +02:00
Nassim Jahnke 72c679acc6 Fix expected move after teleport
Also changes the ViaCodecHandler to a MessageToMessageCodec, as otherwise sync encodes aren't properly processed due to buffering
2026-09-18 16:00:12 +02:00
Florian Reuth 5996340a33 Handle block_state_property registry changes
Fixes joining an Paper 1.8 server with 26.3

Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:12 +02:00
Florian Reuth a2c1841e25 Fix consume effects hashing key in 1.21.2+
Not related to the 26.3 update but easier than having to deal with merge conflicts after the public release.

Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:12 +02:00
Florian Reuth 3483d652e8 Update shared registrations to 26.3 changes
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:12 +02:00
Florian Reuth da29a96844 Replace mask type in player_chat
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:12 +02:00
Florian Reuth 735a4cacb1 Fix trim plaette id<->asset name conversion
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:11 +02:00
Florian Reuth d236db51e0 Fix resolvable primitive types write
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:11 +02:00
Florian Reuth 44167439dd Handle new type in player_action
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:11 +02:00
Nassim Jahnke 67b7ae4cac Strip namespace in 26.3->26.2 trim data 2026-09-18 16:00:11 +02:00
Florian Reuth cef5abdc73 Handle worldgen/block_state_provider going forward
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:11 +02:00
Florian Reuth ad7f53c3cd Fix states updating in block state provider
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:11 +02:00
Florian Reuth e5554c7a8e Handle decorated_pot block entity data
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:10 +02:00
Florian Reuth cbe42132be Fix consume effect conversion
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:10 +02:00
Florian Reuth 8023d8237b Remove compostable on item downgrade
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:10 +02:00
Florian Reuth 0611b95183 Fix pot decorations network type
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-09-18 16:00:10 +02:00
Nassim Jahnke d647f169e6 26.3-rc-2 2026-09-18 16:00:10 +02:00
Nassim Jahnke c44b94f96a Fix swing animation handling 2026-09-18 16:00:10 +02:00
Nassim Jahnke 29be35be1c 26.3-rc-1 2026-09-18 16:00:10 +02:00
Nassim Jahnke 9d2c429624 26.3-pre-3 2026-09-18 16:00:10 +02:00
Nassim Jahnke d2ab957ceb Update and restore trim material 2026-09-18 16:00:09 +02:00
Nassim Jahnke 4bbae432b4 26.3-pre-2 2026-09-18 16:00:09 +02:00
Nassim Jahnke bfc2713102 26.3-pre-1 2026-09-18 16:00:09 +02:00
Nassim Jahnke 155863a4c4 26.3-snapshot-10 2026-09-18 16:00:09 +02:00
Nassim Jahnke 8fc649fba9 26.3-snapshot-9 2026-09-18 16:00:09 +02:00
Nassim Jahnke 7edc17759f 26.3-snapshot-8 2026-09-18 16:00:08 +02:00
Nassim Jahnke b607f96988 26.3-snapshot-7 2026-09-18 16:00:08 +02:00
Nassim Jahnke f6b2f6b3ad 26.3-snapshot-6 2026-09-18 16:00:08 +02:00
Nassim Jahnke a7186fb162 26.3-snapshot-5 2026-09-18 16:00:08 +02:00
Nassim Jahnke d2e636bc6f 26.3-snapshot-4 2026-09-18 16:00:08 +02:00
Nassim Jahnke 9cbb829853 Fix movement tick offset 2026-09-18 16:00:07 +02:00
Nassim Jahnke f04f0a07a8 26.3-snapshot-3 2026-09-18 16:00:07 +02:00
Nassim Jahnke 7cf85e38c5 Fix DEBUG_SUBSCRIPTION_REQUEST and GAME_TEST_HIGHLIGHT_POS packet names 2026-09-18 16:00:07 +02:00
Nassim Jahnke 55f449ee74 Implement BlockTransformData rewrite
See code comments
2026-09-18 16:00:07 +02:00
Nassim Jahnke 460214efe2 26.3-snapshot-2 2026-09-18 16:00:07 +02:00
Nassim Jahnke e5cf0fc6c5 26.3-snapshot-1 2026-09-18 15:59:58 +02:00
Nassim Jahnke d2eed62794 Fix 1.9 identifiers file 2026-09-18 08:51:56 +02:00
Beanes 9946d3e9f6 Add 1.9 identifiers (#4976) 2026-09-16 18:08:00 +02:00
EvModder 5f98cba45b Preserve legacy world clocks (#5040) 2026-09-04 20:54:17 +02:00
LeonTG 15a7d8c853 Remove removed stats in 1.11->1.11.1 (#5037) 2026-08-30 17:19:12 +02:00
Beanes 2645d83eb7 Improve hide-scoreboard-numbers to only work for sidebar (#5034) 2026-08-29 14:34:20 +02:00
Nassim Jahnke c23ec2c26f [ci skip] Build script updates 2026-08-23 15:10:06 +02:00
Emir 42380596ee [ci skip] Use instanceof check in ConfigSection#getSerializedComponent (#5025) 2026-08-23 15:09:55 +02:00
Nassim Jahnke 03e0f231ea Fix compilation 2026-08-19 20:38:46 +02:00
Nassim Jahnke eed3de9e3d Move index to AbstractProtocol directly 2026-08-19 20:35:14 +02:00
Nassim Jahnke feb08a31a3 Skip base protocols in hasher protocol loop 2026-08-19 20:10:14 +02:00
Nassim Jahnke e8bbb5da5b Update ViaNBT 2026-08-14 16:03:56 +02:00
Nassim Jahnke 034390dd24 Update deps 2026-08-12 21:50:16 +02:00
Nassim Jahnke 89f80172b1 Move a bunch of protocol storables to direct array lookups
Also has the benefit of making them thread-safe
2026-08-05 16:57:54 +02:00
Nassim Jahnke 5f93e73b8a Create NbtOps
Useful for backup tags in VB
2026-08-05 16:09:13 +02:00
Nassim Jahnke c124b309e0 Ignore invalid legacy show_item in 1.11->1.12
Closes #5014
2026-07-30 09:17:59 +02:00
Nassim Jahnke 122b81dd33 Add shears breaking speed block tags in 26.1->26.2
Fixes #5010
2026-07-23 17:46:09 +02:00
Nassim Jahnke a2896b64fa Fix 1.21.11->26.1 damage_resistant rewriting
Fixes #5008
2026-07-23 16:13:03 +02:00
Nassim Jahnke 2d78597a59 Handle nested identifiers in item hover events
Actually rewrite the important ones (i.e. relevant to tooltips) and remove the others.
2026-07-23 15:23:33 +02:00
Nassim Jahnke 432918645e Fix boat rotation unpacking in 1.21->1.21.2 2026-07-18 19:24:44 +02:00
RiceChen_andNassim Jahnke c20c29fa3a Sort stonecutter recipes by output registry key (#5006)
Fixes #4242

Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
2026-07-15 16:58:08 +02:00
Nassim Jahnke ab85b0e0f0 Build script cleanup
This also moves Fabric and Sponge resource files into the universal dir; we do not publish platform specific jars and this otherwise only leads to a more complicated project setup
2026-07-15 13:12:58 +02:00
Nassim Jahnke 3a5d9541c8 Use netty Buf I/O streams on Java 24+
The JDK had already gotten similar (but much better still) allocation and performance improvements to read and writeUtf methods
2026-07-14 12:39:49 +02:00
Nassim Jahnke 356a5e25f4 Bump version to 5.11.1-SNAPSHOT 2026-07-14 12:05:55 +02:00
Nassim Jahnke d9a3a4493d 5.11.0 Release 2026-07-12 18:05:51 +02:00
Nassim Jahnke 0fe1b6d6db Move 1.13 blockstate file reading to separate util 2026-07-12 18:02:19 +02:00
Nassim Jahnke fbb92c0fac Reduce mapping data file size by about 35% (30% uncompressed)
The general idea behind the four storage types is the same, except ids are now
1) written as id deltas instead of absolute values
2) written with zigzag encoding (always positive)
3) written as varints

The previous commit made extra mapping data go down by 85% (both uncompressed and compressed).

Combined, this is about a megabyte less uncompressed and 125kb less compressed data bundled right now (not including ViaBackwards).

Reading has become ever so slightly faster due to the reduced file reads (despite now needing more complex decoding), but that's negligible anyway
2026-07-12 10:55:27 +02:00
Nassim Jahnke 384cf91125 Reduce extra mapping data file size by a lot
Merge en_US properties and lang mappings into a single file that still decodes into the same values; store block connections as shared "profiles", since there are only so many different ways of connecting to neighboring blocks; store block states with shared properties; reduce redundant info in the recipes file and store the rest in a more compact/type-specific way as well.

On top of that, store ranges of ids much more concisely (by far the biggest win)
2026-07-12 09:55:44 +02:00
Nassim Jahnke c6736b3532 Fix 26.1->26.2 multi-field entity predicates
Mainly removing the `return` after handling type_specific key changes, but also handling nested predicates
2026-07-09 20:55:25 +02:00
Nassim Jahnke 8c4bbd1a2f [ci skip] Update deps
Moves actions with immutable releases back to proper tag names. setup-gradle and upload-artifact unfortunately do not have these yet
2026-07-09 18:14:18 +02:00
Nassim Jahnke 386c607917 Small improvements here in there
The main ones are not id checking every single block in the 1.9.3 protocol transition, and caching chunk types
2026-07-09 17:48:21 +02:00
Nassim Jahnke c30c787c63 Fix boat tracker null check 2026-07-09 16:18:25 +02:00
Nassim Jahnke 6951dda36e Simplify StoredEntityData into TrackedEntity; directly return tracked entity in track and untrack methods 2026-07-09 15:07:24 +02:00
Nassim Jahnke c9d8610c05 Fix loom in 1.18.2->1.19
Fixes #2938
2026-07-08 20:24:22 +02:00
Nassim Jahnke 68ad7c115b Bump version to 5.11.0-SNAPSHOT
Slightly late, but this version contains a few smaller breaking, and larger changes
2026-07-08 16:33:44 +02:00
Nassim Jahnke 3c50cdf639 Remove removed environment attributes
At the moment only relevant for ViaBackwards, but the client throws when getting environment attributes it does not recognize in biome or dimension registry data
2026-07-08 16:03:32 +02:00
Nassim Jahnke e211692ca1 Make BlockIdData allocation less dumb 2026-07-08 15:29:20 +02:00
Nassim Jahnke 8937bdd986 Fix custom dimension lighting in 1.21.11->26.1
Fixes #4950
2026-07-08 14:18:16 +02:00
Nassim Jahnke b49f995ef1 Fix missing arm swing on sugar cane placement in 1.21.11->26.1
Fixes #4941
2026-07-08 13:37:48 +02:00
Nassim Jahnke 7ab825cc77 Fix missing door sounds from level events in 1.19.1->1.19.3
Fixes #3376
2026-07-08 12:11:22 +02:00
Nassim Jahnke a00226f452 Add missing block rewriter in 1.17.1->1.18
Fixes #4972
2026-07-08 10:17:45 +02:00
Nassim Jahnke 9370534b23 Fix 26.1->1.21.11 damage resistant id list handling 2026-07-06 21:53:06 +02:00
Florian Reuth 5fe54eb1e5 Fix 26.2 damage event handler on <1.19.4 servers (#4997) 2026-07-05 20:50:02 +02:00
Nassim Jahnke a090a909ee Don't check real entity ids for fake entity 2026-07-05 13:51:07 +02:00
Nassim Jahnke 72084b2599 Refactor passthrough token handling
Only uses a single long now with a simple long set instead of an expiring cache. When an invalid token is read, it no longer throws but moves back the reader and continues to maybe possibly not interfere with other plugins for some reason sending their own data with the packet id 1000
2026-07-05 13:44:53 +02:00
Nassim Jahnke a3dcaa6f56 Use a shared session id; replace UUID generation elsewhere
Entirely negligible on most servers, but if running on the backend with many players and newly added entities / other uses of it across many different threads, random UUID generation is synchronized with its shared SecureRandom use
2026-07-05 13:44:53 +02:00
Nassim Jahnke 88f9c05be0 Add a few early returns/cached checks
The last few things that shouldn't show up in a profile
2026-07-05 11:43:51 +02:00
Nassim Jahnke 7b167b0eed Don't load identifier files twice if loaded concurrently
If two protocols were trying to load the same identifier file very close to one another, the first load attempt would not have been added to the cache yet, so the second would have also started loading the file. This makes it wait for the first load instead
2026-07-05 10:16:39 +02:00
Nassim Jahnke 21ff1758d5 Small improvements to string reading and key path checking
Very very small ones, but given they are (or will be) incredibly hot methods, those easy improvements don't hurt
2026-07-05 10:15:41 +02:00
Nassim Jahnke 9793ca2291 Improve protocol path calc 2026-07-05 10:11:51 +02:00
Nassim Jahnke 5768a5c0da Optimize block checking in chunk packets
Instead of going through each of the 4096 blocks in a chunk section, check the palette values first to then also skip actual id getting and simply check palette indexes via an array lookup
2026-07-05 10:11:51 +02:00
Nassim Jahnke decab8fe7f Optimize chunk I/O by a lot
After the improvements from a month ago it already became a good bit better, but was still the most time and memory consuming task by far. This cuts down up to 90% of it by skipping raw data extraction entirely unless actually needed in fairly rare cases as well as making packing and unpacking much more direct
2026-07-04 12:17:26 +02:00
Florian Reuth 354a736e0c Fix entity id == 0 in 26.1->26.2 (#4985) 2026-07-04 10:41:51 +02:00
Nassim Jahnke 56d23661b0 Split hash storage method in two for VB 2026-07-03 19:54:59 +02:00
Nassim Jahnke ca616c74fe Make some StructuredItemRewriter protected 2026-07-03 16:45:05 +02:00
Nassim Jahnke 168d13e143 Don't load block connection data if not necessary
As opposed to other mapping data that is easy to load and may be needed by VB, this was more expensive and can be loaded separately
2026-07-03 12:49:02 +02:00
itslilscorp 229d4fc6e1 Add option to fix default color of legacy reddust particles (#4954)
The multi count fix is disabled by default as it can spam clients to death with larger particle clouds
2026-07-02 13:51:58 +02:00
Bastit 33e426fddc Fix error when downgrading null lock component (#4984) 2026-07-02 13:14:20 +02:00
Nassim Jahnke 0c6023e489 Keep parsed Keys for registry mappings
Avoids frequent re-parsing and makes use of cached full/minimized output
2026-07-01 21:21:53 +02:00
Nassim Jahnke 8ebe3a523c Add registry key to damage resistant 2026-06-27 13:48:50 +02:00
Nassim Jahnke 8239577c23 Minimize Minecraft Identifier allocations 2026-06-21 15:10:06 +02:00
OverwriteMC 670fde5d0f Fix incorrect pre-size calculation in writeString (#4980) 2026-06-21 09:17:06 +02:00
Nassim JahnkeandOverwriteMC d2a715862a Use faster Java 9+ CRC32C implementation if possible
Co-authored-by: OverwriteMC <artyom030803@gmail.com>
2026-06-20 17:12:03 +02:00
LeonTG 6438f99600 Make 1.21.10 servers and below able to detect left-clicking for spectator mode players (#4977) 2026-06-19 22:30:51 +02:00
Nassim Jahnke 1e31aafd83 Change entity counter on sub 1.14 servers from 0 to 1
26.2 clients no longer accept the entity ID 0. Since this doesn't normally happen, just make sure it won't via a server-specific reflective setter
2026-06-19 21:49:46 +02:00
Nassim Jahnke 736ba3c53c 5.10.0 Release 2026-06-19 19:17:37 +02:00
Pantera 6d47c5af61 Add limit to debug sample subscription count (#4975) 2026-06-19 19:17:19 +02:00
Nassim Jahnke 2b42e38300 Add infiniburn tags if missing
They are from 1.16, but some servers might not send them and they are required now.
2026-06-16 19:10:22 +02:00
Nassim Jahnke 4260095390 Remove snapshot bit 2026-06-16 08:09:51 +02:00
riku6460 769498661d Add recipe rewriter 2026-06-16 08:08:52 +02:00
Florian Reuth 1c25e5011a Hide player list heads on offline mode servers
Signed-off-by: Florian Reuth <git@florianreuth.de>
2026-06-15 11:50:35 +02:00
Nassim Jahnke bb3de8ef8d Update deps 2026-06-13 12:15:45 +02:00
Nassim Jahnke 770dd485ec 26.2-rc-2 2026-06-12 17:59:11 +02:00
Nassim Jahnke 964a1b2581 26.2-rc-1 2026-06-12 17:20:54 +02:00
Nassim Jahnke bb1a5e745a 26.2-pre-6 2026-06-12 17:20:54 +02:00
Nassim Jahnke a0a31641e3 26.2-pre-5 2026-06-12 17:20:54 +02:00
Nassim Jahnke 4e493f61cd 26.2-pre-4 2026-06-12 17:20:53 +02:00
Nassim Jahnke ae7f1f07d5 26.2-pre-3 2026-06-12 17:20:53 +02:00
Nassim Jahnke be89cb52b3 26.2-pre-2 2026-06-12 17:20:53 +02:00
Nassim Jahnke b63765a970 26.2-pre-1 2026-06-12 17:20:53 +02:00
Nassim Jahnke 2047b42d78 26.2-snapshot-8 2026-06-12 17:20:53 +02:00
Nassim Jahnke a1179887cd 26.2-snapshot-7 2026-06-12 17:20:53 +02:00
Nassim Jahnke b2a3512bbd 26.2-snapshot-6 2026-06-12 17:20:52 +02:00
Nassim Jahnke 2fe81b5b70 26.2-snapshot-5 2026-06-12 17:20:52 +02:00
Nassim Jahnke 1da2fb89c4 26.2-snapshot-4 2026-06-12 17:20:52 +02:00
Nassim Jahnke 53e18c1f8d 26.2-snapshot-3 2026-06-12 17:20:52 +02:00
Nassim Jahnke 9460a65f02 26.2-snapshot-2 2026-06-12 17:20:52 +02:00
Nassim Jahnke 150a516006 26.2-snapshot-1 2026-06-12 17:20:52 +02:00
386 changed files with 20135 additions and 29933 deletions

No files matched your search

+3
View File
@@ -1,4 +1,5 @@
version: 2
# Disabled for the time being, being done manually instead
updates:
- package-ecosystem: "github-actions"
cooldown:
@@ -6,9 +7,11 @@ updates:
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 0
- package-ecosystem: "gradle"
cooldown:
default-days: 7
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 0
+3 -3
View File
@@ -11,16 +11,16 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
uses: gradle/actions/setup-gradle@v6.3.0
with:
cache-disabled: false
cache-provider: basic
- name: Set up JDK 17
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@v5.7.0
with:
distribution: 'temurin'
java-version: 17
+3 -3
View File
@@ -16,16 +16,16 @@ jobs:
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
uses: gradle/actions/setup-gradle@v6.3.0
with:
cache-disabled: false
cache-provider: basic
- name: Set up JDK 17
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@v5.7.0
with:
distribution: 'temurin'
java-version: 17
+2
View File
@@ -37,3 +37,5 @@ bin/
run/
AGENTS.override.md
.claude/
!.claude/CLAUDE.md
@@ -66,7 +66,7 @@ public interface ViaAPI<T> {
* @return API version incremented with meaningful API changes
*/
default int apiVersion() {
return 26;
return 27;
}
/**
@@ -261,6 +261,8 @@ public interface ViaVersionConfig extends Config {
*/
boolean isChunkBorderFix();
boolean isMultiReddustColorFix();
/**
* Should we make team colours based on the last colour in team prefix
*
@@ -506,7 +508,7 @@ public interface ViaVersionConfig extends Config {
boolean cancelBlockSounds();
/**
* Hides scoreboard numbers for 1.20.3+ clients on older server versions.
* Hides sidebar scoreboard numbers for 1.20.3+ clients on older server versions.
*
* @return true if enabled
*/
@@ -0,0 +1,45 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.connection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.data.item.ItemHasher;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
/**
* Holds protocol-specific data. Protocols may extend the data wrapper to hold extra data.
*/
public interface ProtocolStorables {
EntityTracker entityTracker();
void setEntityTracker(EntityTracker tracker);
ClientWorld clientWorld();
void setClientWorld(ClientWorld clientWorld);
ItemHasher itemHasher();
void setItemHasher(ItemHasher itemHasher);
}
@@ -22,6 +22,8 @@
*/
package com.viaversion.viaversion.api.connection;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.data.item.ItemHasher;
@@ -36,18 +38,18 @@ import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.CodecException;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface UserConnection {
/**
* Get an object from the storage.
* Get an object from the storage. Useful where protocol instances aren't readily available.
*
* @param objectClass The class of the object to get
* @param <T> The type of the class you want to get.
* @return The requested object
* @see #storables(Protocol)
*/
@Nullable <T extends StorableObject> T get(Class<T> objectClass);
@@ -69,27 +71,56 @@ public interface UserConnection {
@Nullable <T extends StorableObject> T remove(Class<T> objectClass);
/**
* Put an object into the stored objects based on class.
* Put an object into the stored objects based on class. Useful where protocol instances aren't readily available.
*
* @param object The object to store.
* @see #storables(Protocol)
*/
void put(StorableObject object);
/**
* Holds protocol-specific data. Where protocol instances aren't readily available, use {@link #put(StorableObject)}.
*
* @param protocol protocol
* @param <T> protocol-specific storables type
* @return protocol storables
* @throws IllegalArgumentException if the protocol does not have a valid return value for {@link Protocol#index()}
*/
<T extends ProtocolStorables> T storables(Protocol<?, ?, ?, ?> protocol);
/**
* Holds protocol-specific data. Prefer using {@link #storables(Protocol)} where possible.
*
* @param protocolClass protocol class
* @param <T> protocol-specific storables type
* @return protocol storables
* @throws IllegalArgumentException if the protocol does not have a valid return value for {@link Protocol#index()}
* @see #storables(Protocol)
*/
default <T extends ProtocolStorables> T storables(final Class<? extends Protocol> protocolClass) {
return storables(Via.getManager().getProtocolManager().getProtocol(protocolClass));
}
/**
* Returns a collection of entity trackers currently registered.
*
* @return collection of entity trackers currently registered
*/
@Deprecated(forRemoval = true)
Collection<EntityTracker> getEntityTrackers();
@Deprecated(forRemoval = true)
@Nullable <T extends EntityTracker> T getEntityTracker(Class<? extends Protocol> protocolClass);
/**
* Returns the entity tracker by the given protocol class if present.
*
* @param protocolClass protocol class
* @param <T> entity tracker type
* @param protocol protocol
* @param <T> entity tracker type
* @return entity tracker if present
* @see com.viaversion.viaversion.api.rewriter.EntityRewriter#tracker(UserConnection)
*/
@Nullable <T extends EntityTracker> T getEntityTracker(Class<? extends Protocol> protocolClass);
@Nullable <T extends EntityTracker> T getEntityTracker(Protocol<?, ?, ?, ?> protocol);
/**
* Adds an entity tracker to the user connection.
@@ -97,34 +128,43 @@ public interface UserConnection {
*
* @param protocolClass protocol class
* @param tracker entity tracker
* @deprecated use {@link #storables(Protocol)}
*/
@Deprecated(forRemoval = true)
void addEntityTracker(Class<? extends Protocol> protocolClass, EntityTracker tracker);
/**
* Returns the item hasher by the given class if present.
*
* @param protocol protocol
* @param <T> item hasher type
* @return item hasher if present
*/
@Nullable <T extends ItemHasher> T getItemHasher(Protocol<?, ?, ?, ?> protocol);
/**
* Adds an item hasher to the user connection.
*
* @param protocolClass protocol class
* @param itemHasher item hasher
* @deprecated use {@link #storables(Protocol)}
*/
@Deprecated(forRemoval = true)
void addItemHasher(Class<? extends Protocol> protocolClass, ItemHasher itemHasher);
/**
* Returns the item hasher by the given protocol class if present.
*
* @param protocolClass protocol class
* @param <T> item hasher type
* @return item hasher if present
*/
@Deprecated(forRemoval = true)
@Nullable <T extends ItemHasher> T getItemHasher(Class<? extends Protocol> protocolClass);
/**
* Returns the client world by the given protocol class if present.
* Returns the client world by the given class if present.
*
* @param protocolClass protocol class
* @param <T> client world type
* @return client world if present
* @deprecated use {@link #storables(Protocol)}
*/
@Nullable
@Deprecated(forRemoval = true)
<T extends ClientWorld> T getClientWorld(Class<? extends Protocol> protocolClass);
/**
@@ -134,6 +174,7 @@ public interface UserConnection {
* @param protocolClass protocol class
* @param clientWorld client world
*/
@Deprecated(forRemoval = true)
void addClientWorld(Class<? extends Protocol> protocolClass, ClientWorld clientWorld);
/**
@@ -365,10 +406,10 @@ public interface UserConnection {
}
/**
* Returns a newly generated uuid that will let a packet be passed through without
* Returns a newly generated token that will let a packet be passed through without
* transforming its contents if used together with {@link PacketWrapper#PASSTHROUGH_ID}.
*
* @return generated passthrough token
*/
UUID generatePassthroughToken();
long generatePassthroughToken();
}
@@ -22,88 +22,29 @@
*/
package com.viaversion.viaversion.api.data;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.MappingDataLoader.IdentifiersPair;
import com.viaversion.viaversion.util.Key;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import org.checkerframework.checker.nullness.qual.Nullable;
public class FullIdentityMappings implements FullMappings {
private static final String[] EMPTY_ARRAY = new String[0];
private final Object2IntMap<String> stringToId;
private final String[] idToString;
private final Mappings mappings;
public class FullIdentityMappings extends FullMappingsBase {
public FullIdentityMappings(final IdentifiersPair identifiersPair, final Mappings mappings) {
Preconditions.checkNotNull(mappings, "Mappings cannot be null");
this.mappings = mappings;
this.stringToId = FullMappingsBase.toInverseMap(identifiersPair.unmapped());
this.idToString = identifiersPair.unmapped().toArray(EMPTY_ARRAY);
this(toInverseMap(identifiersPair.unmapped()), identifiersPair.unmapped().stream().map(Key::of).toArray(Key[]::new), mappings);
}
private FullIdentityMappings(final Object2IntMap<String> stringToId, final String[] idToString, final Mappings mappings) {
this.stringToId = stringToId;
this.idToString = idToString;
this.mappings = mappings;
}
@Override
public int id(final String identifier) {
return stringToId.getInt(Key.stripMinecraftNamespace(identifier));
}
@Override
public int mappedId(final String mappedIdentifier) {
return id(mappedIdentifier);
}
@Override
public String identifier(final int id) {
if (id < 0 || id >= idToString.length) {
return null;
}
final String identifier = idToString[id];
return Key.namespaced(identifier);
private FullIdentityMappings(final Object2IntMap<String> stringToId, final Key[] idToKey, final Mappings mappings) {
super(stringToId, stringToId, idToKey, idToKey, mappings);
}
@Override
public @Nullable String identifier(final String mappedIdentifier) {
final int mappedId = mappedId(mappedIdentifier);
if (mappedId == -1) {
return null;
}
final int id = mappings.inverse().getNewId(mappedId);
return id != -1 ? identifier(id) : null;
return mappedIdentifier(mappedIdentifier);
}
@Override
public @Nullable String mappedIdentifier(final int mappedId) {
return identifier(mappedId);
}
@Override
public @Nullable String mappedIdentifier(final String identifier) {
return identifier(identifier);
}
@Override
public int getNewId(int id) {
return mappings.getNewId(id);
}
@Override
public void setNewId(int id, int mappedId) {
mappings.setNewId(id, mappedId);
}
@Override
public int size() {
return mappings.size();
}
@Override
public int mappedSize() {
return mappings.mappedSize();
public @Nullable Key keyFromMappedKey(final String mappedIdentifier) {
return mappedKeyFromKey(mappedIdentifier);
}
@Override
@@ -117,7 +58,7 @@ public class FullIdentityMappings implements FullMappings {
}
@Override
public FullMappings inverse() {
return new FullIdentityMappings(stringToId, idToString, mappings.inverse());
public FullIdentityMappings inverse() {
return new FullIdentityMappings(stringToId, idToKey, mappings.inverse());
}
}
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.data;
import com.viaversion.viaversion.util.Key;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
@@ -51,7 +52,10 @@ public interface FullMappings extends BiMappings {
* @param id unmapped id
* @return unmapped string identifier, or null if out of bounds
*/
@Nullable String identifier(int id);
default @Nullable String identifier(int id) {
final Key key = keyFromId(id);
return key != null ? key.toString() : null;
}
/**
* Returns the unmapped string identifier for the given mapped identifier.
@@ -59,7 +63,10 @@ public interface FullMappings extends BiMappings {
* @param mappedIdentifier mapped identifier
* @return unmapped string identifier, or null if not found
*/
@Nullable String identifier(String mappedIdentifier);
default @Nullable String identifier(String mappedIdentifier) {
final Key key = keyFromMappedKey(mappedIdentifier);
return key != null ? key.toString() : null;
}
/**
* Returns the mapped string identifier for the given mapped id.
@@ -67,7 +74,10 @@ public interface FullMappings extends BiMappings {
* @param mappedId mapped id
* @return mapped string identifier, or null if out of bounds
*/
@Nullable String mappedIdentifier(int mappedId);
default @Nullable String mappedIdentifier(int mappedId) {
final Key key = mappedKeyFromMappedId(mappedId);
return key != null ? key.toString() : null;
}
/**
* Returns the mapped string identifier for the given unmapped identifier.
@@ -75,7 +85,42 @@ public interface FullMappings extends BiMappings {
* @param identifier unmapped identifier
* @return mapped string identifier, or null if not found
*/
@Nullable String mappedIdentifier(String identifier);
default @Nullable String mappedIdentifier(String identifier) {
final Key key = mappedKeyFromKey(identifier);
return key != null ? key.toString() : null;
}
/**
* Returns the unmapped key for the given mapped id.
*
* @param id unmapped id
* @return unmapped key, or null if out of bounds
*/
@Nullable Key keyFromId(int id);
/**
* Returns the unmapped key for the given mapped identifier.
*
* @param mappedIdentifier mapped identifier
* @return unmapped key, or null if not found
*/
@Nullable Key keyFromMappedKey(String mappedIdentifier);
/**
* Returns the mapped key for the given mapped id.
*
* @param mappedId mapped id
* @return mapped key, or null if out of bounds
*/
@Nullable Key mappedKeyFromMappedId(int mappedId);
/**
* Returns the mapped key for the given unmapped identifier.
*
* @param identifier unmapped identifier
* @return mapped key, or null if not found
*/
@Nullable Key mappedKeyFromKey(String identifier);
/**
* Returns whether the int id mappings are identity mappings.
@@ -31,27 +31,26 @@ import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public class FullMappingsBase implements FullMappings {
private static final String[] EMPTY_ARRAY = new String[0];
private final Object2IntMap<String> stringToId;
private final Object2IntMap<String> mappedStringToId;
private final String[] idToString;
private final String[] mappedIdToString;
private final Mappings mappings;
protected final Object2IntMap<String> stringToId;
protected final Object2IntMap<String> mappedStringToId;
protected final Key[] idToKey;
protected final Key[] mappedIdToKey;
protected final Mappings mappings;
public FullMappingsBase(final IdentifiersPair identifiersPair, final Mappings mappings) {
Preconditions.checkNotNull(mappings, "Mappings cannot be null");
this.mappings = mappings;
this.stringToId = toInverseMap(identifiersPair.unmapped());
this.idToString = identifiersPair.unmapped().toArray(EMPTY_ARRAY);
this.idToKey = identifiersPair.unmapped().stream().map(Key::of).toArray(Key[]::new);
this.mappedStringToId = toInverseMap(identifiersPair.mapped());
this.mappedIdToString = identifiersPair.mapped().toArray(EMPTY_ARRAY);
this.mappedIdToKey = identifiersPair.mapped().stream().map(Key::of).toArray(Key[]::new);
}
private FullMappingsBase(final Object2IntMap<String> stringToId, final Object2IntMap<String> mappedStringToId, final String[] idToString, final String[] mappedIdToString, final Mappings mappings) {
protected FullMappingsBase(final Object2IntMap<String> stringToId, final Object2IntMap<String> mappedStringToId, final Key[] idToKey, final Key[] mappedIdToKey, final Mappings mappings) {
this.stringToId = stringToId;
this.mappedStringToId = mappedStringToId;
this.idToString = idToString;
this.mappedIdToString = mappedIdToString;
this.idToKey = idToKey;
this.mappedIdToKey = mappedIdToKey;
this.mappings = mappings;
}
@@ -79,45 +78,43 @@ public class FullMappingsBase implements FullMappings {
}
@Override
public String identifier(final int id) {
if (id < 0 || id >= idToString.length) {
public @Nullable Key keyFromId(final int id) {
if (id < 0 || id >= idToKey.length) {
return null;
}
final String identifier = idToString[id];
return Key.namespaced(identifier);
return idToKey[id];
}
@Override
public @Nullable String identifier(final String mappedIdentifier) {
public @Nullable Key keyFromMappedKey(final String mappedIdentifier) {
final int mappedId = mappedId(mappedIdentifier);
if (mappedId == -1) {
return null;
}
final int id = mappings.inverse().getNewId(mappedId);
return id != -1 ? identifier(id) : null;
return id != -1 ? keyFromId(id) : null;
}
@Override
public @Nullable String mappedIdentifier(final int mappedId) {
if (mappedId < 0 || mappedId >= mappedIdToString.length) {
public @Nullable Key mappedKeyFromMappedId(final int mappedId) {
if (mappedId < 0 || mappedId >= mappedIdToKey.length) {
return null;
}
final String identifier = mappedIdToString[mappedId];
return Key.namespaced(identifier);
return mappedIdToKey[mappedId];
}
@Override
public @Nullable String mappedIdentifier(final String identifier) {
public @Nullable Key mappedKeyFromKey(final String identifier) {
final int id = id(identifier);
if (id == -1) {
return null;
}
final int mappedId = mappings.getNewId(id);
return mappedId != -1 ? mappedIdentifier(mappedId) : null;
return mappedId != -1 ? mappedKeyFromMappedId(mappedId) : null;
}
@Override
@@ -147,6 +144,6 @@ public class FullMappingsBase implements FullMappings {
@Override
public FullMappings inverse() {
return new FullMappingsBase(mappedStringToId, stringToId, mappedIdToString, idToString, mappings.inverse());
return new FullMappingsBase(mappedStringToId, stringToId, mappedIdToKey, idToKey, mappings.inverse());
}
}
@@ -0,0 +1,64 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.data;
import com.viaversion.nbt.tag.ByteArrayTag;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.function.IntConsumer;
/**
* Reads sets of non-negative ints stored as ranges, packed into a byte array of varints.
* Each range is stored as an offset and length pair. The offset is the start of the first range and the
* difference to the previous range's exclusive end; the length is the inclusive end minus the start.
*/
public final class IdRanges {
/**
* Returns the encoded id set as an int set.
*
* @param rangesTag tag with the encoded ranges
* @return decoded ids
*/
public static IntSet decode(final ByteArrayTag rangesTag) {
final IntSet ids = new IntOpenHashSet();
forEachId(rangesTag, ids::add);
return ids;
}
public static void forEachId(final ByteArrayTag rangesTag, final IntConsumer consumer) {
final ByteBuf buf = Unpooled.wrappedBuffer(rangesTag.getValue());
int prevEnd = 0;
while (buf.isReadable()) {
final int start = prevEnd + Types.VAR_INT.readPrimitive(buf);
final int end = start + Types.VAR_INT.readPrimitive(buf);
for (int id = start; id <= end; id++) {
consumer.accept(id);
}
prevEnd = end + 1;
}
}
}
@@ -0,0 +1,111 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.data;
import com.viaversion.viaversion.api.data.MappingDataLoader.IdentifiersPair;
import com.viaversion.viaversion.util.Key;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Full mappings for versions where required identifiers hadn't yet followed the resource location format (i.e., pre-1.9.4 sounds).
*/
public class LegacyFullStringMappingsBase extends FullMappingsBase {
private final String[] idToString;
private final String[] mappedIdToString;
public LegacyFullStringMappingsBase(final IdentifiersPair identifiersPair, final Mappings mappings) {
super(toInverseMap(identifiersPair.unmapped()), toInverseMap(identifiersPair.mapped()), new Key[0], new Key[0], mappings);
this.idToString = identifiersPair.unmapped().toArray(new String[0]);
this.mappedIdToString = identifiersPair.mapped().toArray(new String[0]);
}
private LegacyFullStringMappingsBase(final Object2IntMap<String> stringToId, final Object2IntMap<String> mappedStringToId, final String[] idToKey, final String[] mappedIdToString, final Mappings mappings) {
super(stringToId, mappedStringToId, new Key[0], new Key[0], mappings);
this.idToString = idToKey;
this.mappedIdToString = mappedIdToString;
}
@Override
public String identifier(final int id) {
if (id < 0 || id >= idToString.length) {
return null;
}
return Key.namespaced(idToString[id]);
}
@Override
public @Nullable String identifier(final String mappedIdentifier) {
final int mappedId = mappedId(mappedIdentifier);
if (mappedId == -1) {
return null;
}
final int id = mappings.inverse().getNewId(mappedId);
return id != -1 ? identifier(id) : null;
}
@Override
public @Nullable String mappedIdentifier(final int mappedId) {
if (mappedId < 0 || mappedId >= mappedIdToString.length) {
return null;
}
return Key.namespaced(mappedIdToString[mappedId]);
}
@Override
public @Nullable String mappedIdentifier(final String identifier) {
final int id = id(identifier);
if (id == -1) {
return null;
}
final int mappedId = mappings.getNewId(id);
return mappedId != -1 ? mappedIdentifier(mappedId) : null;
}
@Override
public @Nullable Key keyFromId(final int id) {
throw new UnsupportedOperationException();
}
@Override
public @Nullable Key keyFromMappedKey(final String mappedIdentifier) {
throw new UnsupportedOperationException();
}
@Override
public @Nullable Key mappedKeyFromMappedId(final int mappedId) {
throw new UnsupportedOperationException();
}
@Override
public @Nullable Key mappedKeyFromKey(final String identifier) {
throw new UnsupportedOperationException();
}
@Override
public FullMappings inverse() {
return new LegacyFullStringMappingsBase(mappedStringToId, stringToId, mappedIdToString, idToString, mappings.inverse());
}
}
@@ -29,6 +29,7 @@ import com.viaversion.viaversion.util.Key;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface MappingData {
@@ -190,15 +191,27 @@ public interface MappingData {
*/
@Nullable IntSet changedBlocks();
default boolean hasBlockChanged(final int blockId) {
return changedBlocks() != null && changedBlocks().contains(blockId);
}
@Nullable Set<String> changedEnvironmentAttributes();
/**
* Type of mappings. Currently only relevant for ops writing of generic holder classes and expanded when needed.
*/
enum MappingType implements RegistryKey {
ITEM, BLOCK, SOUND, ENTITY_TYPE;
private final Key key;
MappingType() {
this.key = Key.of(name().toLowerCase(Locale.ROOT));
}
@Override
public Key key() {
return Key.of(name().toLowerCase(Locale.ROOT));
public Key registry() {
return this.key;
}
}
}
@@ -24,6 +24,8 @@ package com.viaversion.viaversion.api.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.MappingDataLoader.IdentifiersPair;
@@ -35,7 +37,9 @@ import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.Nullable;
public class MappingDataBase implements MappingData {
@@ -63,6 +67,7 @@ public class MappingDataBase implements MappingData {
* Set of block ids that have had type or property changes.
*/
protected IntSet changedBlocks;
protected Set<String> changedEnvironmentAttributes;
public MappingDataBase(final String unmappedVersion, final String mappedVersion) {
this.unmappedVersion = unmappedVersion;
@@ -118,6 +123,7 @@ public class MappingDataBase implements MappingData {
loadTags(RegistryType.ITEM, tagsTag);
loadTags(RegistryType.BLOCK, tagsTag);
loadTags(RegistryType.ENTITY, tagsTag);
loadTags(RegistryType.FLUID, tagsTag);
}
final IntArrayTag changedBlocks = data.getIntArrayTag("changed_blocks");
@@ -125,6 +131,11 @@ public class MappingDataBase implements MappingData {
this.changedBlocks = new IntOpenHashSet(changedBlocks.getValue());
}
final ListTag<StringTag> changedEnvironmentAttributes = data.getListTag("changed_environment_attributes", StringTag.class);
if (changedEnvironmentAttributes != null) {
this.changedEnvironmentAttributes = changedEnvironmentAttributes.stream().map(StringTag::getValue).collect(Collectors.toSet());
}
loadExtras(data);
}
@@ -167,6 +178,10 @@ public class MappingDataBase implements MappingData {
if (mappings == null) {
mappings = new IdentityMappings(identifiersPair.unmapped().size(), identifiersPair.mapped().size());
}
return createFullMappings(identifiersPair, mappings);
}
protected FullMappings createFullMappings(final IdentifiersPair identifiersPair, final Mappings mappings) {
return FullMappingsBase.of(identifiersPair, mappings);
}
@@ -349,6 +364,11 @@ public class MappingDataBase implements MappingData {
return changedBlocks;
}
@Override
public @Nullable Set<String> changedEnvironmentAttributes() {
return changedEnvironmentAttributes;
}
protected Logger getLogger() {
return Via.getPlatform().getLogger();
}
@@ -31,13 +31,17 @@ import com.google.gson.JsonSyntaxException;
import com.viaversion.nbt.io.NBTIO;
import com.viaversion.nbt.io.TagReader;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntArrayTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.GsonUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.io.BufferedInputStream;
@@ -51,6 +55,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -59,15 +64,16 @@ public class MappingDataLoader {
public static final MappingDataLoader INSTANCE = new MappingDataLoader(MappingDataLoader.class, "assets/viaversion/data/");
public static final TagReader<CompoundTag> MAPPINGS_READER = NBTIO.reader(CompoundTag.class).named();
private static final Map<String, String[]> GLOBAL_IDENTIFIER_INDEXES = new HashMap<>();
private static final int VERSION = 2;
private static final byte DIRECT_ID = 0;
private static final byte SHIFTS_ID = 1;
private static final byte CHANGES_ID = 2;
private static final byte IDENTITY_ID = 3;
private final Map<String, CompoundTag> mappingsCache = new HashMap<>();
private final Map<String, CompoundTag> mappingsCache = new ConcurrentHashMap<>();
private final Class<?> dataLoaderClass;
private final String dataPath;
private boolean cacheValid = true;
private volatile boolean cacheValid = true;
public MappingDataLoader(final Class<?> dataLoaderClass, final String dataPath) {
this.dataLoaderClass = dataLoaderClass;
@@ -104,14 +110,14 @@ public class MappingDataLoader {
throw new IllegalArgumentException("Unknown global identifier key: " + registry);
}
if (globalId < 0 || globalId >= array.length) {
throw new IllegalArgumentException("Unknown global identifier index: " + globalId);
throw new IllegalArgumentException("Unknown global identifier index: " + registry + "/" + globalId);
}
return array[globalId];
}
public void clearCache() {
mappingsCache.clear();
cacheValid = false;
mappingsCache.clear();
}
/**
@@ -160,17 +166,14 @@ public class MappingDataLoader {
return loadNBTFromFile(name);
}
CompoundTag data = mappingsCache.get(name);
if (data != null) {
return data;
if (cache) {
// Also blocks concurrent loaders of the same file until the first one has finished
return mappingsCache.computeIfAbsent(name, this::loadNBTFromFile);
}
data = loadNBTFromFile(name);
if (cache && data != null) {
mappingsCache.put(name, data);
}
return data;
// Still do a lookup, but don't store it
final CompoundTag data = mappingsCache.get(name);
return data != null ? data : loadNBTFromFile(name);
}
public @Nullable CompoundTag loadNBT(final String name) {
@@ -211,15 +214,29 @@ public class MappingDataLoader {
return null;
}
final int version = mappingsTag.getInt("version", -1);
if (version != VERSION) {
throw new IllegalArgumentException("Invalid version: " + version);
}
final int mappedSize = tag.getInt("mappedSize", -1);
final byte strategy = tag.getByteTag("id").asByte();
final V mappings;
if (strategy == DIRECT_ID) {
final IntArrayTag valuesTag = tag.getIntArrayTag("val");
return IntArrayMappings.of(valuesTag.getValue(), mappedSize);
// Zigzag varints of the difference to the previous mapped id
final int size = tag.getIntTag("size").asInt();
final ByteBuf buf = Unpooled.wrappedBuffer(tag.getByteArrayTag("val").getValue());
final int[] values = new int[size];
int prev = 0;
for (int i = 0; i < size; i++) {
prev += readZigZagVarInt(buf);
values[i] = prev;
}
return IntArrayMappings.of(values, mappedSize);
} else if (strategy == SHIFTS_ID) {
final int[] shiftsAt = tag.getIntArrayTag("at").getValue();
final int[] shiftsTo = tag.getIntArrayTag("to").getValue();
final ValuePairs pairs = readAtValuePairs(tag);
final int[] shiftsAt = pairs.first;
final int[] shiftsTo = pairs.second;
final int size = tag.getIntTag("size").asInt();
mappings = holderSupplier.get(size);
@@ -242,8 +259,9 @@ public class MappingDataLoader {
}
}
} else if (strategy == CHANGES_ID) {
final int[] changesAt = tag.getIntArrayTag("at").getValue();
final int[] values = tag.getIntArrayTag("val").getValue();
final ValuePairs pairs = readAtValuePairs(tag);
final int[] changesAt = pairs.first;
final int[] values = pairs.second;
final int size = tag.getIntTag("size").asInt();
final boolean fillBetween = tag.get("nofill") == null;
mappings = holderSupplier.get(size);
@@ -262,6 +280,13 @@ public class MappingDataLoader {
// Assign the changed value
addConsumer.addTo(mappings, changedId, values[i]);
}
// Fill the remainder
if (fillBetween && nextUnhandledId != size) {
for (int id = nextUnhandledId; id < size; id++) {
addConsumer.addTo(mappings, id, id);
}
}
} else if (strategy == IDENTITY_ID) {
final IntTag sizeTag = tag.getIntTag("size");
return new IdentityMappings(sizeTag.asInt(), mappedSize);
@@ -271,6 +296,37 @@ public class MappingDataLoader {
return mappingsSupplier.create(mappings, mappedSize);
}
/**
* Reads alternating id and value pairs from varints. The id as the difference to the previous id,
* the value as the zigzag difference to the previous value.
*
* @param tag tag to read the packed values from
* @return array of ids and array of values
*/
private static ValuePairs readAtValuePairs(final CompoundTag tag) {
final ByteBuf buf = Unpooled.wrappedBuffer(tag.getByteArrayTag("val").getValue());
final IntList at = new IntArrayList();
final IntList values = new IntArrayList();
int prevAt = -1;
int prevValue = 0;
while (buf.isReadable()) {
prevAt = prevAt + 1 + Types.VAR_INT.readPrimitive(buf);
prevValue += readZigZagVarInt(buf);
at.add(prevAt);
values.add(prevValue);
}
return new ValuePairs(at.toIntArray(), values.toIntArray());
}
private static int readZigZagVarInt(final ByteBuf buf) {
// https://lemire.me/blog/2022/11/25/making-all-your-integers-positive-with-zigzag-encoding/
// In short, using deltas to previous ids makes the numbers small, and using zigzag encoding means they're all positive.
// Being all positive means we can use varints to make most of the data much shorter than 8 bytes.
// All of that combined ends up having a decent effect when compressed in the jar file as well.
final int value = Types.VAR_INT.readPrimitive(buf);
return (value >>> 1) ^ -(value & 1);
}
public @Nullable List<String> identifiersFromGlobalIds(final CompoundTag mappingsTag, final String key) {
final Mappings mappings = loadMappings(mappingsTag, key);
return mappings != null ? identifiers(mappings, key) : null;
@@ -315,6 +371,10 @@ public class MappingDataLoader {
continue;
}
if (mappedGlobalId == -1) {
throw new IllegalArgumentException("Mapped global id -1 for unmapped global id: " + key + "/" + unmappedIdentifier + " (" + unmappedGlobalId + ")");
}
identity = false;
unmappedIdentifiers.add(unmappedIdentifier);
mappedIdentifiers.add(identifierFromGlobalId(key, mappedGlobalId));
@@ -323,8 +383,9 @@ public class MappingDataLoader {
}
private List<String> identifiers(final Mappings mappings, final String key) {
final List<String> identifiers = new ArrayList<>(mappings.size());
for (int i = 0; i < mappings.size(); i++) {
final int size = mappings.size();
final List<String> identifiers = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
final int globalId = mappings.getNewId(i);
identifiers.add(identifierFromGlobalId(key, globalId));
}
@@ -401,4 +462,7 @@ public class MappingDataLoader {
this(identifiers, identifiers, true);
}
}
private record ValuePairs(int[] first, int[] second) {
}
}
@@ -23,7 +23,9 @@
package com.viaversion.viaversion.api.data.entity;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.KeyMappings;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -43,8 +45,9 @@ public interface EntityTracker {
*
* @param id entity id
* @param type entity type
* @return tracked entity
*/
void addEntity(int id, EntityType type);
TrackedEntity addEntity(int id, EntityType type);
/**
* Returns whether the entity is currently tracked.
@@ -75,8 +78,9 @@ public interface EntityTracker {
* Untracks an entity.
*
* @param id entity id
* @return previously tracked entity
*/
void removeEntity(int id);
@Nullable TrackedEntity removeEntity(int id);
/**
* Clears stored entity types and data, only leaving behind the client entity.
@@ -88,25 +92,6 @@ public interface EntityTracker {
*/
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.
*
* @param id entity id
* @return stored entity data if an entity with the id is tracked, else null
* @throws IllegalArgumentException if entity data storage has not been enabled via the implementation
*/
@Nullable StoredEntityData entityData(int id);
/**
* Returns stored entity data if it has previously been initialized by {@link #entityData(int)}, else null.
*
* @param id entity id
* @return stored entity data if it has previously been initialized by {@link #entityData(int)}
* @throws IllegalArgumentException if entity data storage has not been enabled via the implementation
*/
@Nullable StoredEntityData entityDataIfPresent(int id);
/**
* Returns whether the client entity id has been set.
*
@@ -204,6 +189,24 @@ public interface EntityTracker {
void setBiomesSent(int biomesSent);
/**
* Returns the cached chunk type for the current dimension if set.
*
* @param mapped whether to return the mapped chunk type
* @return cached chunk type
*/
@Nullable Type<Chunk> chunkType(boolean mapped);
/**
* Caches the chunk type for the current dimension.
* <p>
* Invalidates when the world section height or the number of biomes change.
*
* @param mapped whether to set the mapped chunk type
* @param chunkType chunk type
*/
void setChunkType(boolean mapped, @Nullable Type<Chunk> chunkType);
EntityType playerType();
@Nullable DimensionData dimensionData(String dimension);
@@ -1,69 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.data.entity;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface StoredEntityData {
/**
* Returns the entity type of the stored entity.
*
* @return entity type
*/
EntityType type();
/**
* Checks if the storage contains an object of the given type.
*
* @param objectClass object class to check
* @return whether an object of the given type is in the storage
*/
boolean has(Class<?> objectClass);
/**
* Returns an object from the storage if present.
*
* @param objectClass class of the object to get
* @param <T> object type
* @return object if present
*/
@Nullable <T> T get(Class<T> objectClass);
/**
* Removes and returns an object from the storage if present.
*
* @param objectClass class of the object to remove
* @param <T> object type
* @return removed object if present
*/
@Nullable <T> T remove(Class<T> objectClass);
/**
* Stores an object based on its class.
*
* @param object object to store
*/
void put(Object object);
}
@@ -22,7 +22,9 @@
*/
package com.viaversion.viaversion.api.data.entity;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface TrackedEntity {
@@ -34,18 +36,37 @@ public interface TrackedEntity {
EntityType entityType();
/**
* Object to hold arbitrary additional data.
* Checks if the storage contains an object of the given type.
*
* @return entity data
* @param objectClass object class to check
* @return whether an object of the given type is in the storage
*/
StoredEntityData data();
boolean has(Class<? extends StorableObject> objectClass);
/**
* Returns whether the stored entity currently has any additional data.
* Returns an object from the storage if present.
*
* @return whether the stored entity currently has additional data
* @param objectClass class of the object to get
* @param <T> object type
* @return object if present
*/
boolean hasData();
@Nullable <T extends StorableObject> T get(Class<T> objectClass);
/**
* Removes and returns an object from the storage if present.
*
* @param objectClass class of the object to remove
* @param <T> object type
* @return removed object if present
*/
@Nullable <T extends StorableObject> T remove(Class<T> objectClass);
/**
* Stores an object based on its class.
*
* @param object object to store
*/
void put(StorableObject object);
/**
* Returns whether entity data has already been sent at least once for this entity.
@@ -34,7 +34,7 @@ import com.viaversion.viaversion.util.Key;
*/
public interface RegistryKey {
Key key();
Key registry();
static RegistryKey of(final String key) {
return new SimpleRegistryKey(Key.of(key));
@@ -43,7 +43,7 @@ public enum RegistryType implements RegistryKey {
static {
for (RegistryType type : getValues()) {
MAP.put(type.identifier, type);
MAP.put(type.identifier(), type);
}
}
@@ -55,18 +55,18 @@ public enum RegistryType implements RegistryKey {
return MAP.get(identifier);
}
private final String identifier;
private final Key key;
RegistryType(final String identifier) {
this.identifier = identifier;
this.key = Key.of(identifier);
}
public String identifier() {
return identifier;
return key.path();
}
@Override
public Key key() {
return Key.of(identifier);
public Key registry() {
return this.key;
}
}
@@ -0,0 +1,40 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.util.EitherImpl;
public final class ResolvableFloat extends EitherImpl<Float, String> {
private ResolvableFloat(final Float left, final String right) {
super(left, right);
}
public static ResolvableFloat of(final String value) {
return new ResolvableFloat(null, value);
}
public static ResolvableFloat of(final Float value) {
return new ResolvableFloat(value, null);
}
}
@@ -0,0 +1,40 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.util.EitherImpl;
public final class ResolvableInt extends EitherImpl<Integer, String> {
private ResolvableInt(final Integer left, final String right) {
super(left, right);
}
public static ResolvableInt of(final String value) {
return new ResolvableInt(null, value);
}
public static ResolvableInt of(final Integer value) {
return new ResolvableInt(value, null);
}
}
@@ -24,10 +24,10 @@ package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.util.Key;
record SimpleRegistryKey(Key key) implements RegistryKey {
record SimpleRegistryKey(Key registry) implements RegistryKey {
@Override
public String toString() {
return key.toString();
return registry.toString();
}
}
@@ -22,6 +22,9 @@
*/
package com.viaversion.viaversion.api.minecraft.chunks;
import com.viaversion.viaversion.util.CompactArrayUtil;
import java.util.function.IntConsumer;
import java.util.function.IntPredicate;
import java.util.function.IntUnaryOperator;
public interface DataPalette {
@@ -146,6 +149,27 @@ public interface DataPalette {
}
}
/**
* Runs over all section coordinate indices that match the given predicate.
*
* @param idPredicate predicate to test ids
* @param coordinateConsumer consumer to run over applicable coordinate indices (not ids!)
* @see #idAt(int)
*/
void forEachMatchingCoordinate(IntPredicate idPredicate, IntConsumer coordinateConsumer);
/**
* Packs the section values into a compact long array as used by the protocol.
*
* @param bitsPerValue bits used per value
* @param entries number of values
* @param rawIds whether to pack raw ids instead of palette indexes (direct palette)
* @return compact long array of the values
*/
default long[] createPackedValues(final int bitsPerValue, final int entries, final boolean rawIds) {
return CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, entries, rawIds ? this::idAt : this::paletteIndexAt);
}
/**
* Returns the size of the palette.
*
@@ -22,9 +22,13 @@
*/
package com.viaversion.viaversion.api.minecraft.chunks;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.util.CompactArrayUtil;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import java.util.function.IntConsumer;
import java.util.function.IntPredicate;
import java.util.function.IntUnaryOperator;
public final class DataPaletteImpl implements DataPalette {
@@ -32,8 +36,8 @@ public final class DataPaletteImpl implements DataPalette {
private static final int DEFAULT_INITIAL_SIZE = 16;
private final IntArrayList palette;
private final Int2IntMap inversePalette;
private final int sizeBits;
private Int2IntMap inversePalette;
private ChunkData values;
public DataPaletteImpl(final int valuesLength) {
@@ -43,11 +47,30 @@ public final class DataPaletteImpl implements DataPalette {
public DataPaletteImpl(final int valuesLength, final int initialSize) {
values = new SingleChunkData(valuesLength);
sizeBits = Integer.numberOfTrailingZeros(valuesLength) / 3;
// Pre-size the palette array/map
// Pre-size the palette array
palette = new IntArrayList(initialSize);
// To get an initial table size of initialSize, need to scale it down by load factor.
inversePalette = new Int2IntOpenHashMap((int) (initialSize * Int2IntOpenHashMap.DEFAULT_LOAD_FACTOR));
inversePalette.defaultReturnValue(-1);
}
private Int2IntMap inversePalette() {
// Lazily build the inverse palette. Most palettes never need it
if (inversePalette == null) {
inversePalette = new Int2IntOpenHashMap(palette.size());
inversePalette.defaultReturnValue(-1);
for (int i = 0; i < palette.size(); i++) {
inversePalette.put(palette.getInt(i), i);
}
}
return inversePalette;
}
private Int2IntMap emptyInversePalette() {
if (inversePalette == null) {
inversePalette = new Int2IntOpenHashMap(palette.size());
inversePalette.defaultReturnValue(-1);
} else {
inversePalette.clear();
}
return inversePalette;
}
@Override
@@ -63,7 +86,7 @@ public final class DataPaletteImpl implements DataPalette {
@Override
public void setIdAt(final int sectionCoordinate, final int id) {
int index = inversePalette.get(id);
int index = inversePalette().get(id);
if (index == -1) {
index = palette.size();
palette.add(id);
@@ -83,6 +106,38 @@ public final class DataPaletteImpl implements DataPalette {
values.set(sectionCoordinate, index);
}
/**
* Stores palette indexes from a compact long array, replacing all current values.
* The data is kept packed unless written to; reads extract bits the slow way, since almost all work will use replaceIds or will only have a few reads.
* <p>
* Only valid for local palettes (bitsPerValue &lt;= 8).
*
* @param data compact long array
* @param bitsPerValue bits per value
* @param valuesPerLong packked values per long
*/
public void setPaletteIndexes(final long[] data, final int bitsPerValue, final int valuesPerLong) {
Preconditions.checkArgument(bitsPerValue <= 8, "Cannot pack global palette");
values = new PackedChunkData(data, bitsPerValue, valuesPerLong, values.size());
}
@Override
public long[] createPackedValues(final int bitsPerValue, final int entries, final boolean rawIds) {
if (rawIds) {
return CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, entries, this::idAt);
}
if (values instanceof final PackedChunkData packed && packed.bitsPerValue == bitsPerValue) {
// Values were never modified and the width still matches - write them back as-is
return packed.data;
}
final int valuesPerLong = (char) (64 / bitsPerValue);
final long[] data = new long[(entries + valuesPerLong - 1) / valuesPerLong];
values.packInto(data, bitsPerValue);
return data;
}
@Override
public int size() {
return palette.size();
@@ -96,7 +151,7 @@ public final class DataPaletteImpl implements DataPalette {
@Override
public void setIdByIndex(final int index, final int id) {
final int oldId = palette.set(index, id);
if (oldId == id) return;
if (oldId == id || inversePalette == null) return;
inversePalette.put(id, index);
if (inversePalette.get(oldId) == index) {
@@ -112,7 +167,7 @@ public final class DataPaletteImpl implements DataPalette {
@Override
public void replaceId(final int oldId, final int newId) {
final int index = inversePalette.remove(oldId);
final int index = inversePalette().remove(oldId);
if (index == -1) return;
inversePalette.put(newId, index);
@@ -130,12 +185,12 @@ public final class DataPaletteImpl implements DataPalette {
return;
}
inversePalette.clear();
int writeIndex = 0;
int[] indexRemap = null;
int firstCollision = 0;
final int[] palette = this.palette.elements();
final Int2IntMap inversePalette = emptyInversePalette();
for (int readIndex = 0; readIndex < oldSize; readIndex++) {
final int mappedId = mapper.applyAsInt(palette[readIndex]);
final int existingIndex = inversePalette.putIfAbsent(mappedId, writeIndex);
@@ -172,14 +227,51 @@ public final class DataPaletteImpl implements DataPalette {
@Override
public void addId(final int id) {
inversePalette.put(id, palette.size());
if (inversePalette != null) {
inversePalette.put(id, palette.size());
}
palette.add(id);
}
private static final ThreadLocal<boolean[]> MATCHING_INDEXES = ThreadLocal.withInitial(() -> new boolean[ChunkSection.SIZE]);
@Override
public void forEachMatchingCoordinate(final IntPredicate idPredicate, final IntConsumer coordinateConsumer) {
final int size = size();
if (size > ChunkSection.SIZE) { // Shouldn't ever happen normally, but is technically possible...
for (int idx = 0, len = this.values.size(); idx < len; idx++) {
if (idPredicate.test(idAt(idx))) {
coordinateConsumer.accept(idx);
}
}
return;
}
// Instead of going through every single coordinate value (4096 for block sections), check the palette ids first.
// Reuse a thread-local array for quick checking against palette indexes.
final boolean[] matching = MATCHING_INDEXES.get();
boolean any = false;
for (int i = 0; i < size; i++) {
final boolean match = idPredicate.test(idByIndex(i));
matching[i] = match;
any |= match;
}
if (!any) {
return;
}
for (int idx = 0, len = this.values.size(); idx < len; idx++) {
if (matching[paletteIndexAt(idx)]) {
coordinateConsumer.accept(idx);
}
}
}
@Override
public void clear() {
palette.clear();
inversePalette.clear();
inversePalette = null;
}
interface ChunkData {
@@ -188,6 +280,11 @@ public final class DataPaletteImpl implements DataPalette {
void set(int idx, int val);
int size();
/**
* Packs all values into the given compact long array.
*/
void packInto(long[] data, int bitsPerValue);
}
private final class SingleChunkData implements ChunkData {
@@ -215,6 +312,11 @@ public final class DataPaletteImpl implements DataPalette {
public int size() {
return size;
}
@Override
public void packInto(final long[] data, final int bitsPerValue) {
// All values are 0, nothing to write
}
}
private final class ByteChunkData implements ChunkData {
@@ -224,6 +326,10 @@ public final class DataPaletteImpl implements DataPalette {
this.data = new byte[size];
}
public ByteChunkData(byte[] data) {
this.data = data;
}
@Override
public int get(int idx) {
return data[idx] & 0xFF;
@@ -244,6 +350,11 @@ public final class DataPaletteImpl implements DataPalette {
public int size() {
return data.length;
}
@Override
public void packInto(final long[] out, final int bitsPerValue) {
CompactArrayUtil.packWithPadding(data, out, bitsPerValue);
}
}
private static final class ShortChunkData implements ChunkData {
@@ -270,6 +381,63 @@ public final class DataPaletteImpl implements DataPalette {
public int size() {
return data.length;
}
@Override
public void packInto(final long[] out, final int bitsPerValue) {
CompactArrayUtil.packWithPadding(data, out, bitsPerValue);
}
}
/**
* Raw chunk data as read from the buffer.
*/
private final class PackedChunkData implements ChunkData {
private final long[] data;
private final int bitsPerValue;
private final int valuesPerLong;
private final long maxEntryValue;
private final int size;
private PackedChunkData(final long[] data, final int bitsPerValue, final int valuesPerLong, final int size) {
this.data = data;
this.bitsPerValue = bitsPerValue;
this.valuesPerLong = valuesPerLong;
this.size = size;
this.maxEntryValue = (1L << bitsPerValue) - 1;
}
@Override
public int get(final int idx) {
// Called so rarely that the cheap storage outweighs the more complex getter
final int cellIndex = idx / valuesPerLong;
final int bitIndex = (idx - cellIndex * valuesPerLong) * bitsPerValue;
return (int) (data[cellIndex] >>> bitIndex & maxEntryValue);
}
@Override
public void set(final int idx, final int val) {
// First write access, actually read out for fast value access
final ChunkData byteChunkData = extractData();
values = byteChunkData;
byteChunkData.set(idx, val);
}
private ChunkData extractData() {
final byte[] unpackedData = new byte[size];
CompactArrayUtil.unpackWithPadding(this.data, unpackedData, bitsPerValue);
return new ByteChunkData(unpackedData);
}
@Override
public int size() {
return size;
}
@Override
public void packInto(final long[] out, final int newBitsPerValue) {
// Always called with bitsPerValue != newBitsPerValue, which should only really happen if the server sends an unncessarily high bit width,
// or if the number of ids shrunk in replaceIds. Rare enough to not need its own special method
extractData().packInto(out, newBitsPerValue);
}
}
}
@@ -38,6 +38,8 @@ public interface CodecContext {
UserConnection connection();
Protocol<?, ?, ?, ?> protocol();
interface RegistryAccess {
UserConnection connection();
@@ -58,7 +58,9 @@ public interface Ops {
void writeMap(Consumer<MapSerializer> consumer);
<V> void write(final Type<V> type, final V value);
default <V> void write(final Type<V> type, final V value) {
type.write(this, value);
}
interface ListSerializer {
@@ -39,8 +39,8 @@ final class RegistryAccessImpl implements CodecContext.RegistryAccess {
private final boolean mapped;
RegistryAccessImpl(final Protocol<?, ?, ?, ?> protocol, final UserConnection connection) {
this.mappingData = Preconditions.checkNotNull(protocol.getMappingData());
this.entityTracker = Preconditions.checkNotNull(protocol.getEntityRewriter().tracker(connection));
this.mappingData = Preconditions.checkNotNull(protocol.getMappingData(), "No mapping data present for protocol");
this.entityTracker = Preconditions.checkNotNull(protocol.getEntityRewriter().tracker(connection), "Entity tracker has to be added first");
this.connection = connection;
this.mapped = false;
}
@@ -102,17 +102,16 @@ final class RegistryAccessImpl implements CodecContext.RegistryAccess {
public Key registryKey(final String registry, final int id) {
final KeyMappings mappings = entityTracker.registryKeys(registry);
Preconditions.checkNotNull(mappings, "No registry mappings for registry: %s", registry);
final String identifier = id >= 0 && id < mappings.size() ? mappings.idToKey(id) : null;
return key(identifier, id);
return keyOrUnknown(mappings.key(id), id);
}
private Key key(final FullMappings mappings, final int id) {
final String identifier = mapped ? mappings.mappedIdentifier(id) : mappings.identifier(id);
return key(identifier, id);
final Key key = mapped ? mappings.mappedKeyFromMappedId(id) : mappings.keyFromId(id);
return keyOrUnknown(key, id);
}
private Key key(@Nullable final String identifier, final int id) {
return identifier != null ? Key.of(identifier) : Key.of("viaversion", "unknown/" + id);
private Key keyOrUnknown(@Nullable final Key key, final int id) {
return key != null ? key : Key.of("viaversion", "unknown/" + id);
}
@Override
@@ -270,7 +270,7 @@ public final class StructuredDataContainer implements Copyable {
@Override
public StructuredDataContainer copy() {
final Reference2ObjectOpenHashMap<StructuredDataKey<?>, StructuredData<?>> map = new Reference2ObjectOpenHashMap<>();
final Reference2ObjectOpenHashMap<StructuredDataKey<?>, StructuredData<?>> map = new Reference2ObjectOpenHashMap<>(data.size());
for (final StructuredData<?> value : data.values()) {
map.put(value.key(), value.copy());
}
@@ -36,8 +36,10 @@ import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_2;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_5;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrim;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrimMaterial;
import com.viaversion.viaversion.api.minecraft.item.data.trim.ArmorTrim1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.trim.ArmorTrim26_3;
import com.viaversion.viaversion.api.minecraft.item.data.trim.ArmorTrimMaterial1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.trim.ArmorTrimMaterial26_3;
import com.viaversion.viaversion.api.minecraft.item.data.AttackRange;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21;
@@ -46,7 +48,10 @@ 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.BrewingFuel;
import com.viaversion.viaversion.api.minecraft.item.data.Compostable;
import com.viaversion.viaversion.api.minecraft.item.data.consumable.Consumable1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.CookingFuel;
import com.viaversion.viaversion.api.minecraft.item.data.CustomModelData1_21_4;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant26_1;
@@ -71,12 +76,14 @@ import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable.Jukebox
import com.viaversion.viaversion.api.minecraft.item.data.KineticWeapon;
import com.viaversion.viaversion.api.minecraft.item.data.LockCode;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.MobVisibility;
import com.viaversion.viaversion.api.minecraft.item.data.PiercingWeapon;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
import com.viaversion.viaversion.api.minecraft.item.data.ProvidesBannerPatterns;
import com.viaversion.viaversion.api.minecraft.item.data.ProvidesTrimMaterial;
import com.viaversion.viaversion.api.minecraft.item.data.trim.ProvidesTrimMaterial1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.Repairable;
import com.viaversion.viaversion.api.minecraft.item.data.SignText;
import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect;
import com.viaversion.viaversion.api.minecraft.item.data.SwingAnimation;
import com.viaversion.viaversion.api.minecraft.item.data.ToolProperties;
@@ -85,6 +92,7 @@ import com.viaversion.viaversion.api.minecraft.item.data.TropicalFishPattern;
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.UseEffects;
import com.viaversion.viaversion.api.minecraft.item.data.VillagerFood;
import com.viaversion.viaversion.api.minecraft.item.data.Weapon;
import com.viaversion.viaversion.api.minecraft.item.data.WritableBook;
import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook;
@@ -144,7 +152,8 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<FoodProperties1_20_5> FOOD1_20_5 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_20_5);
public static final StructuredDataKey<FoodProperties1_20_5> FOOD1_21 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_21);
public static final StructuredDataKey<FoodProperties1_21_2> FOOD1_21_2 = new StructuredDataKey<>("food", FoodProperties1_21_2.TYPE);
public static final StructuredDataKey<Consumable1_21_2> CONSUMABLE1_21_2 = new StructuredDataKey<>("consumable", Consumable1_21_2.TYPE);
public static final StructuredDataKey<Consumable1_21_2> CONSUMABLE1_21_2 = new StructuredDataKey<>("consumable", Consumable1_21_2.TYPE1_21_2);
public static final StructuredDataKey<Consumable1_21_2> CONSUMABLE26_3 = new StructuredDataKey<>("consumable", Consumable1_21_2.TYPE26_3);
public static final StructuredDataKey<UseCooldown> USE_COOLDOWN = new StructuredDataKey<>("use_cooldown", UseCooldown.TYPE);
public static final StructuredDataKey<Unit> FIRE_RESISTANT = new StructuredDataKey<>("fire_resistant", Types.EMPTY);
public static final StructuredDataKey<DamageResistant1_21_2> DAMAGE_RESISTANT1_21_2 = new StructuredDataKey<>("damage_resistant", DamageResistant1_21_2.TYPE);
@@ -160,13 +169,18 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
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.IDENTIFIER);
public static final StructuredDataKey<DeathProtection> DEATH_PROTECTION = new StructuredDataKey<>("death_protection", DeathProtection.TYPE);
public static final StructuredDataKey<DeathProtection> DEATH_PROTECTION1_21_2 = new StructuredDataKey<>("death_protection", DeathProtection.TYPE1_21_2);
public static final StructuredDataKey<DeathProtection> DEATH_PROTECTION26_3 = new StructuredDataKey<>("death_protection", DeathProtection.TYPE26_3);
public static final StructuredDataKey<BlocksAttacks> BLOCKS_ATTACKS1_21_5 = new StructuredDataKey<>("blocks_attacks", BlocksAttacks.TYPE1_21_5);
public static final StructuredDataKey<BlocksAttacks> BLOCKS_ATTACKS26_1 = new StructuredDataKey<>("blocks_attacks", BlocksAttacks.TYPE26_1);
public static final StructuredDataKey<PiercingWeapon> PIERCING_WEAPON = new StructuredDataKey<>("piercing_weapon", PiercingWeapon.TYPE);
public static final StructuredDataKey<KineticWeapon> KINETIC_WEAPON = new StructuredDataKey<>("kinetic_weapon", KineticWeapon.TYPE);
public static final StructuredDataKey<SwingAnimation> SWING_ANIMATION = new StructuredDataKey<>("swing_animation", SwingAnimation.TYPE);
public static final StructuredDataKey<SwingAnimation> ATTACK_ANIMATION = new StructuredDataKey<>("attack_animation", SwingAnimation.TYPE);
public static final StructuredDataKey<SwingAnimation> INTERACT_ANIMATION = new StructuredDataKey<>("interact_animation", SwingAnimation.TYPE);
public static final StructuredDataKey<Integer> ADDITIONAL_TRADE_COST = new StructuredDataKey<>("additional_trade_cost", Types.VAR_INT);
public static final StructuredDataKey<Integer> BLOCK_TRANSFORMER = new StructuredDataKey<>("block_transformer", new SynchronizedRegistryValueType(RegistryKey.of("block_transformer")));
public static final StructuredDataKey<VillagerFood> VILLAGER_FOOD = new StructuredDataKey<>("villager_food", VillagerFood.TYPE);
public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS1_20_5 = new StructuredDataKey<>("stored_enchantments", Enchantments.TYPE1_20_5);
public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS1_21_5 = new StructuredDataKey<>("stored_enchantments", Enchantments.TYPE1_21_5);
public static final StructuredDataKey<Integer> DYE = new StructuredDataKey<>("dye", EnumTypes.DYE_COLOR);
@@ -182,10 +196,11 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<SuspiciousStewEffect[]> SUSPICIOUS_STEW_EFFECTS = new StructuredDataKey<>("suspicious_stew_effects", SuspiciousStewEffect.ARRAY_TYPE);
public static final StructuredDataKey<WritableBook> WRITABLE_BOOK_CONTENT = new StructuredDataKey<>("writable_book_content", WritableBook.TYPE);
public static final StructuredDataKey<WrittenBook> WRITTEN_BOOK_CONTENT = new StructuredDataKey<>("written_book_content", WrittenBook.TYPE);
public static final StructuredDataKey<ArmorTrim> TRIM1_20_5 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_20_5);
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<ArmorTrim1_20_5> TRIM1_20_5 = new StructuredDataKey<>("trim", ArmorTrim1_20_5.TYPE1_20_5);
public static final StructuredDataKey<ArmorTrim1_20_5> TRIM1_21_2 = new StructuredDataKey<>("trim", ArmorTrim1_20_5.TYPE1_21_2);
public static final StructuredDataKey<ArmorTrim1_20_5> TRIM1_21_4 = new StructuredDataKey<>("trim", ArmorTrim1_20_5.TYPE1_21_4);
public static final StructuredDataKey<ArmorTrim1_20_5> TRIM1_21_5 = new StructuredDataKey<>("trim", ArmorTrim1_20_5.TYPE1_21_5);
public static final StructuredDataKey<ArmorTrim26_3> TRIM26_3 = new StructuredDataKey<>("trim", ArmorTrim26_3.TYPE);
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);
@@ -193,11 +208,13 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
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<Holder<Instrument1_21_2>> INSTRUMENT1_21_2 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE1_21_2);
public static final StructuredDataKey<EitherHolder<Instrument1_21_2>> INSTRUMENT1_21_5 = new StructuredDataKey<>("instrument", Instrument1_21_2.EITHER_HOLDER_TYPE);
public static final StructuredDataKey<Holder<Instrument1_21_2>> INSTRUMENT26_1 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE);
public static final StructuredDataKey<ProvidesTrimMaterial> PROVIDES_TRIM_MATERIAL1_21_5 = new StructuredDataKey<>("provides_trim_material", ProvidesTrimMaterial.TYPE);
public static final StructuredDataKey<Holder<ArmorTrimMaterial>> PROVIDES_TRIM_MATERIAL26_1 = new StructuredDataKey<>("provides_trim_material", ArmorTrimMaterial.TYPE1_21_5);
public static final StructuredDataKey<Holder<Instrument1_21_2>> INSTRUMENT26_1 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE1_21_2);
public static final StructuredDataKey<Holder<Instrument1_21_2>> INSTRUMENT26_3 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE26_3);
public static final StructuredDataKey<ProvidesTrimMaterial1_20_5> PROVIDES_TRIM_MATERIAL1_21_5 = new StructuredDataKey<>("provides_trim_material", ProvidesTrimMaterial1_20_5.TYPE);
public static final StructuredDataKey<Holder<ArmorTrimMaterial1_20_5>> PROVIDES_TRIM_MATERIAL26_1 = new StructuredDataKey<>("provides_trim_material", ArmorTrimMaterial1_20_5.TYPE1_21_5);
public static final StructuredDataKey<Holder<ArmorTrimMaterial26_3>> PROVIDES_TRIM_MATERIAL26_3 = new StructuredDataKey<>("provides_trim_material", ArmorTrimMaterial26_3.TYPE);
public static final StructuredDataKey<Integer> OMINOUS_BOTTLE_AMPLIFIER = new StructuredDataKey<>("ominous_bottle_amplifier", Types.VAR_INT);
public static final StructuredDataKey<JukeboxPlayable> JUKEBOX_PLAYABLE1_21 = new StructuredDataKey<>("jukebox_playable", JukeboxPlayable.TYPE1_21);
public static final StructuredDataKey<JukeboxPlayable> JUKEBOX_PLAYABLE1_21_5 = new StructuredDataKey<>("jukebox_playable", JukeboxPlayable.TYPE1_21_5);
@@ -213,7 +230,8 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Key> NOTE_BLOCK_SOUND = new StructuredDataKey<>("note_block_sound", Types.IDENTIFIER);
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<PotDecorations1_20_5> POT_DECORATIONS1_20_5 = new StructuredDataKey<>("pot_decorations", PotDecorations1_20_5.TYPE);
// 26.3+ pot decorations are in their own key classes
public static final StructuredDataKey<BlockStateProperties> BLOCK_STATE = new StructuredDataKey<>("block_state", BlockStateProperties.TYPE);
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);
@@ -221,6 +239,15 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
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);
public static final StructuredDataKey<Compostable> COMPOSTABLE = new StructuredDataKey<>("compostable", Compostable.TYPE);
public static final StructuredDataKey<CookingFuel> COOKING_FUEL = new StructuredDataKey<>("cooking_fuel", CookingFuel.TYPE);
public static final StructuredDataKey<BrewingFuel> BREWING_FUEL = new StructuredDataKey<>("brewing_fuel", BrewingFuel.TYPE);
public static final StructuredDataKey<MobVisibility> MOB_VISIBILITY = new StructuredDataKey<>("mob_visibility", MobVisibility.TYPE);
public static final StructuredDataKey<Integer> PROVIDES_POTTERY_PATTERN = new StructuredDataKey<>("provides_pottery_pattern", new SynchronizedRegistryValueType(RegistryKey.of("decorated_pot_pattern")));
public static final StructuredDataKey<SignText> SIGN_TEXT_FRONT = new StructuredDataKey<>("sign_text_front", SignText.TYPE);
public static final StructuredDataKey<SignText> SIGN_TEXT_BACK = new StructuredDataKey<>("sign_text_back", SignText.TYPE);
public static final StructuredDataKey<Unit> WAXED = new StructuredDataKey<>("waxed", Types.EMPTY);
public static final StructuredDataKey<Integer> CUSHION_COLOR = new StructuredDataKey<>("cushion/color", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<Integer> VILLAGER_VARIANT = new StructuredDataKey<>("villager/variant", EnumTypes.VILLAGER_TYPE);
public static final StructuredDataKey<Integer> WOLF_VARIANT = new StructuredDataKey<>("wolf/variant", new SynchronizedRegistryValueType(RegistryKey.of("wolf_variant")));
@@ -34,7 +34,7 @@ public class StructuredDataKeys1_20_5 extends VersionedStructuredDataKeys {
public StructuredDataKeys1_20_5(final VersionedTypesHolder types) {
this.container = add("container", types.itemArray());
this.chargedProjectiles = add("charged_projectiles", types.itemArray());
this.bundleContents = add("bundle_contents", types.itemArray());
this.chargedProjectiles = add("charged_projectiles", types.itemArray().withMaxLength(1024));
this.bundleContents = add("bundle_contents", types.itemArray().withMaxLength(1024));
}
}
@@ -36,8 +36,8 @@ public class StructuredDataKeys1_21_2 extends VersionedStructuredDataKeys {
public StructuredDataKeys1_21_2(final VersionedTypesHolder types) {
this.container = add("container", new ContainerContentsType(types.optionalItemTemplate()));
this.chargedProjectiles = add("charged_projectiles", types.itemTemplateArray());
this.bundleContents = add("bundle_contents", types.itemTemplateArray());
this.chargedProjectiles = add("charged_projectiles", types.itemTemplateArray().withMaxLength(1024));
this.bundleContents = add("bundle_contents", types.itemTemplateArray().withMaxLength(1024));
this.useRemainder = add("use_remainder", types.itemTemplate());
}
}
@@ -0,0 +1,37 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.data.version;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
public class StructuredDataKeys26_2 extends StructuredDataKeys1_21_11 {
public final StructuredDataKey<Item> sulfurCubeContent;
public StructuredDataKeys26_2(final VersionedTypesHolder types) {
super(types);
this.sulfurCubeContent = add("sulfur_cube_content", types.item());
}
}
@@ -0,0 +1,37 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.data.version;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations26_3;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
public class StructuredDataKeys26_3 extends StructuredDataKeys26_2 {
public final StructuredDataKey<PotDecorations26_3> potDecorations;
public StructuredDataKeys26_3(final VersionedTypesHolder types) {
super(types);
this.potDecorations = add("pot_decorations", new PotDecorations26_3.PotDecorationsType(types.optionalItemTemplate()));
}
}
@@ -0,0 +1,332 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.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 EntityTypes26_2 implements EntityType {
ENTITY(null, null),
AREA_EFFECT_CLOUD(ENTITY),
END_CRYSTAL(ENTITY),
EVOKER_FANGS(ENTITY),
EXPERIENCE_ORB(ENTITY),
EYE_OF_ENDER(ENTITY),
FALLING_BLOCK(ENTITY),
ITEM(ENTITY),
TNT(ENTITY),
OMINOUS_ITEM_SPAWNER(ENTITY),
MARKER(ENTITY),
LIGHTNING_BOLT(ENTITY),
INTERACTION(ENTITY),
DISPLAY(ENTITY, null),
BLOCK_DISPLAY(DISPLAY),
ITEM_DISPLAY(DISPLAY),
TEXT_DISPLAY(DISPLAY),
// Hanging entities
HANGING_ENTITY(ENTITY, null),
LEASH_KNOT(HANGING_ENTITY),
PAINTING(HANGING_ENTITY),
ITEM_FRAME(HANGING_ENTITY),
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
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),
// 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_CUBE_MOB(ABSTRACT_AGEABLE, null),
SLIME(ABSTRACT_CUBE_MOB),
MAGMA_CUBE(ABSTRACT_CUBE_MOB),
SULFUR_CUBE(ABSTRACT_CUBE_MOB),
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),
OCELOT(ABSTRACT_ANIMAL),
ABSTRACT_COW(ABSTRACT_ANIMAL, null),
COW(ABSTRACT_COW),
MOOSHROOM(ABSTRACT_COW),
TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null),
CAT(TAMABLE_ANIMAL),
WOLF(TAMABLE_ANIMAL),
PARROT(TAMABLE_ANIMAL),
ABSTRACT_NAUTILUS(TAMABLE_ANIMAL, null),
NAUTILUS(ABSTRACT_NAUTILUS),
ZOMBIE_NAUTILUS(ABSTRACT_NAUTILUS),
ABSTRACT_HORSE(ABSTRACT_ANIMAL, null),
HORSE(ABSTRACT_HORSE),
SKELETON_HORSE(ABSTRACT_HORSE),
ZOMBIE_HORSE(ABSTRACT_HORSE),
CAMEL(ABSTRACT_HORSE),
CAMEL_HUSK(CAMEL),
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),
PARCHED(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;
EntityTypes26_2(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes26_2(final EntityType parent, @Nullable final String identifier) {
this.parent = parent;
this.identifier = identifier;
}
@Override
public int getId() {
if (id == -1) {
throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")");
}
return id;
}
@Override
public String identifier() {
Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type");
return identifier;
}
@Override
public @Nullable EntityType getParent() {
return parent;
}
@Override
public boolean isAbstractType() {
return identifier == null;
}
public static EntityType getTypeFromId(final int typeId) {
return EntityTypeUtil.getTypeFromId(TYPES, typeId, PIG);
}
public static void initialize(final Protocol<?, ?, ?, ?> protocol) {
EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id);
}
}
@@ -0,0 +1,336 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.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 EntityTypes26_3 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),
CUSHION(ENTITY),
// 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),
POPLAR_BOAT(ABSTRACT_BOAT),
POPLAR_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),
// 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_CUBE_MOB(ABSTRACT_AGEABLE, null),
SLIME(ABSTRACT_CUBE_MOB),
MAGMA_CUBE(ABSTRACT_CUBE_MOB),
SULFUR_CUBE(ABSTRACT_CUBE_MOB),
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),
OCELOT(ABSTRACT_ANIMAL),
ABSTRACT_COW(ABSTRACT_ANIMAL, null),
COW(ABSTRACT_COW),
MOOSHROOM(ABSTRACT_COW),
TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null),
CAT(TAMABLE_ANIMAL),
WOLF(TAMABLE_ANIMAL),
PARROT(TAMABLE_ANIMAL),
ABSTRACT_NAUTILUS(TAMABLE_ANIMAL, null),
NAUTILUS(ABSTRACT_NAUTILUS),
ZOMBIE_NAUTILUS(ABSTRACT_NAUTILUS),
ABSTRACT_HORSE(ABSTRACT_ANIMAL, null),
HORSE(ABSTRACT_HORSE),
SKELETON_HORSE(ABSTRACT_HORSE),
ZOMBIE_HORSE(ABSTRACT_HORSE),
CAMEL(ABSTRACT_HORSE),
CAMEL_HUSK(CAMEL),
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),
PARCHED(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;
EntityTypes26_3(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes26_3(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);
}
}
@@ -0,0 +1,83 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entitydata.types;
import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
public final class EntityDataTypes26_3 extends AbstractEntityDataTypes {
public final EntityDataType byteType = add(0, Types.BYTE);
public final EntityDataType varIntType = add(1, Types.VAR_INT);
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TRUSTED_TAG);
public final EntityDataType optionalComponentType = add(6, Types.TRUSTED_OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14);
public final EntityDataType optionalBlockPositionType = add(11, Types.OPTIONAL_POSITION_1_14);
public final EntityDataType directionType = add(12, Types.VAR_INT);
public final EntityDataType optionalUUIDType = add(13, Types.OPTIONAL_UUID);
public final EntityDataType blockStateType = add(14, Types.VAR_INT);
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDataType = add(18, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(19, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(20, Types.VAR_INT);
public final EntityDataType catVariantType = add(21, Types.VAR_INT);
public final EntityDataType catSoundVariant = add(22, Types.VAR_INT);
public final EntityDataType cowVariantType = add(23, Types.VAR_INT);
public final EntityDataType cowSoundVariant = add(24, Types.VAR_INT);
public final EntityDataType wolfVariantType = add(25, Types.VAR_INT);
public final EntityDataType wolfSoundVariantType = add(26, Types.VAR_INT);
public final EntityDataType frogVariantType = add(27, Types.VAR_INT);
public final EntityDataType pigVariantType = add(28, Types.VAR_INT);
public final EntityDataType pigSoundVariant = add(29, Types.VAR_INT);
public final EntityDataType chickenVariantType = add(30, Types.VAR_INT);
public final EntityDataType chickenSoundVariant = add(31, Types.VAR_INT);
public final EntityDataType zombieNautilusVariantType = add(32, Types.VAR_INT);
public final EntityDataType optionalGlobalPosition = add(33, Types.OPTIONAL_GLOBAL_POSITION);
public final EntityDataType paintingVariantType = add(34, PaintingVariant.TYPE1_21_2);
public final EntityDataType snifferState = add(35, Types.VAR_INT);
public final EntityDataType armadilloState = add(36, Types.VAR_INT);
public final EntityDataType copperGolemState = add(37, Types.VAR_INT);
public final EntityDataType weatheringCopperState = add(38, Types.VAR_INT);
public final EntityDataType vector3FType = add(39, Types.VECTOR3F);
public final EntityDataType quaternionType = add(40, Types.QUATERNION);
public final EntityDataType mannequinProfileType = add(41, Types.RESOLVABLE_PROFILE);
public final EntityDataType humanoidArmType = add(42, Types.VAR_INT);
public final EntityDataType dyeColorType = add(43, Types.VAR_INT);
public EntityDataTypes26_3(final VersionedTypesHolder types) {
super(44);
this.itemType = add(7, types.item());
this.particleType = add(16, types.particle());
this.particlesType = add(17, types.particles());
}
}
@@ -0,0 +1,126 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData.MappingType;
import com.viaversion.viaversion.api.minecraft.Holder;
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.ArrayType;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
// TODO move block state provider rewriting to registry data rewriter
public record BlockTransformData(CompoundTag blockStateProvider, Holder<SoundEvent> sound, int transformParticle,
int[] disallowedFaces, @Nullable String loot, int dropStrategy,
boolean updateFromNeighbors, int transformType,
boolean consumeOnUse, int itemDamagePerUse) implements Rewritable, Copyable {
public static final Type<BlockTransformData> TYPE = new Type<>(BlockTransformData.class) {
@Override
public BlockTransformData read(final ByteBuf buffer) {
final CompoundTag blockStateProvider = Types.COMPOUND_TAG.read(buffer);
final Holder<SoundEvent> sound = Types.SOUND_EVENT.read(buffer);
final int transformParticle = Types.VAR_INT.readPrimitive(buffer);
final int[] disallowedFaces = Types.VAR_INT_ARRAY_PRIMITIVE.read(buffer);
final String loot = Types.OPTIONAL_STRING.read(buffer);
final int dropStrategy = Types.VAR_INT.readPrimitive(buffer);
final boolean updateFromNeighbors = Types.BOOLEAN.read(buffer);
final int transformType = Types.VAR_INT.readPrimitive(buffer);
final boolean consumeOnUse = Types.BOOLEAN.read(buffer);
final int itemDamagePerUse = Types.VAR_INT.readPrimitive(buffer);
return new BlockTransformData(blockStateProvider, sound, transformParticle, disallowedFaces, loot, dropStrategy, updateFromNeighbors, transformType, consumeOnUse, itemDamagePerUse);
}
@Override
public void write(final ByteBuf buffer, final BlockTransformData value) {
Types.COMPOUND_TAG.write(buffer, value.blockStateProvider);
Types.SOUND_EVENT.write(buffer, value.sound);
Types.VAR_INT.writePrimitive(buffer, value.transformParticle);
Types.VAR_INT_ARRAY_PRIMITIVE.write(buffer, value.disallowedFaces);
Types.OPTIONAL_STRING.write(buffer, value.loot);
Types.VAR_INT.writePrimitive(buffer, value.dropStrategy);
Types.BOOLEAN.write(buffer, value.updateFromNeighbors);
Types.VAR_INT.writePrimitive(buffer, value.transformType);
Types.BOOLEAN.write(buffer, value.consumeOnUse);
Types.VAR_INT.writePrimitive(buffer, value.itemDamagePerUse);
}
@Override
public void write(final Ops ops, final BlockTransformData data) {
final Holder<SoundEvent> defaultSound = Holder.of(ops.context().registryAccess().id(MappingType.SOUND, "intentionally_empty"));
ops.writeMap(map -> map
.write("block_state_provider", Types.COMPOUND_TAG, data.blockStateProvider)
.writeOptional("sound", Types.SOUND_EVENT, data.sound, defaultSound)
.writeOptional("particle", EnumTypes.TRANSFORM_PARTICLE, data.transformParticle, 0)
.writeOptional("disallowed_faces", EnumTypes.DIRECTION.new EnumArrayType(), data.disallowedFaces, new int[0])
.writeOptional("loot", Types.STRING, data.loot)
.writeOptional("drop_strategy", Types.VAR_INT, data.dropStrategy, 1)
.writeOptional("update_from_neighbors", Types.BOOLEAN, data.updateFromNeighbors, true)
.writeOptional("transform_type", Types.VAR_INT, data.transformType, 0)
.writeOptional("consume_on_use", Types.BOOLEAN, data.consumeOnUse, true)
.writeOptional("item_damage_per_use", Types.VAR_INT, data.itemDamagePerUse, 0)
);
}
};
public static final ArrayType<BlockTransformData> ARRAY_TYPE = new ArrayType<>(TYPE);
@Override
public BlockTransformData rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
CompoundTag updatedTag = blockStateProvider().copy();
if (protocol.getRegistryDataRewriter().updateBlockStateProvider(updatedTag)) {
// Back it up clientbound so server data doesn't disappear; remove it for newly spawned items serverbound.
// Given it's not even encoded properly over the network and would otherwise require keeping full block state mappings
// and is not needed on the client, we only do the bare minimum to guarantee compatibility.
if (clientbound) {
updatedTag.put("backup", this.blockStateProvider);
} else {
final CompoundTag backupTag = updatedTag.getCompoundTag("backup");
updatedTag = backupTag != null ? backupTag : dummyBlockStateProvider();
}
}
return new BlockTransformData(updatedTag, sound, transformParticle, disallowedFaces, loot, dropStrategy, updateFromNeighbors, transformType, consumeOnUse, itemDamagePerUse);
}
private CompoundTag dummyBlockStateProvider() {
final CompoundTag state = new CompoundTag();
state.putString("Name", "dirt");
final CompoundTag tag = new CompoundTag();
tag.putString("type", "simple");
tag.put("state", state);
return tag;
}
@Override
public BlockTransformData copy() {
return new BlockTransformData(blockStateProvider.copy(), sound, transformParticle, disallowedFaces, loot, dropStrategy, updateFromNeighbors, transformType, consumeOnUse, itemDamagePerUse);
}
}
@@ -0,0 +1,55 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.ResolvableFloat;
import com.viaversion.viaversion.api.minecraft.ResolvableInt;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record BrewingFuel(ResolvableInt uses, ResolvableFloat speedMultiplier) {
public static final Type<BrewingFuel> TYPE = new Type<>(BrewingFuel.class) {
@Override
public BrewingFuel read(final ByteBuf buffer) {
final ResolvableInt uses = Types.RESOLVABLE_INT.read(buffer);
final ResolvableFloat speedMultiplier = Types.RESOLVABLE_FLOAT.read(buffer);
return new BrewingFuel(uses, speedMultiplier);
}
@Override
public void write(final ByteBuf buffer, final BrewingFuel value) {
Types.RESOLVABLE_INT.write(buffer, value.uses);
Types.RESOLVABLE_FLOAT.write(buffer, value.speedMultiplier);
}
@Override
public void write(final Ops ops, final BrewingFuel value) {
ops.writeMap(map -> map
.write("uses", Types.RESOLVABLE_INT, value.uses)
.write("speed_multiplier", Types.RESOLVABLE_FLOAT, value.speedMultiplier));
}
};
}
@@ -0,0 +1,40 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.ResolvableInt;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
public record Compostable(ResolvableInt layers) {
public static final Type<Compostable> TYPE = new TransformingType<>(Types.RESOLVABLE_INT, Compostable.class, Compostable::new, Compostable::layers) {
@Override
public void write(final Ops ops, final Compostable value) {
ops.writeMap(map -> map.write("layers", Types.RESOLVABLE_INT, value.layers));
}
};
}
@@ -1,200 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.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.ArrayType;
import com.viaversion.viaversion.api.type.types.misc.HolderSetType;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<SoundEvent> sound,
boolean hasConsumeParticles,
ConsumeEffect<?>[] consumeEffects) implements Copyable, Rewritable {
private static final HolderSetType REMOVE_EFFECTS_TYPE = new HolderSetType() {
@Override
public void write(final Ops ops, final HolderSet value) {
ops.writeMap(map -> map.write("effects", new HolderSetType(EnumTypes.MOB_EFFECT), value));
}
};
private static final Type<Float> TELEPORT_RANDOMLY_TYPE = new Type<>(Float.class) {
@Override
public void write(final ByteBuf buffer, final Float value) {
Types.FLOAT.writePrimitive(buffer, value);
}
@Override
public Float read(final ByteBuf buffer) {
return Types.FLOAT.readPrimitive(buffer);
}
@Override
public void write(final Ops ops, final Float value) {
ops.writeMap(map -> map.write("diameter", Types.FLOAT, 16F));
}
};
private static final HolderType<SoundEvent> PLAY_SOUND_TYPE = new HolderType<>(MappingData.MappingType.SOUND) {
@Override
public SoundEvent readDirect(final ByteBuf buffer) {
return Types.SOUND_EVENT.readDirect(buffer);
}
@Override
public void writeDirect(final ByteBuf buffer, final SoundEvent value) {
Types.SOUND_EVENT.writeDirect(buffer, value);
}
@Override
public void write(final Ops ops, final Holder<SoundEvent> value) {
ops.writeMap(map -> map.write("sound", Types.SOUND_EVENT, value));
}
};
public static final Type<?>[] EFFECT_TYPES = {
ApplyStatusEffects.TYPE,
REMOVE_EFFECTS_TYPE,
Types.EMPTY, // clear all effects
TELEPORT_RANDOMLY_TYPE,
PLAY_SOUND_TYPE
};
public static final Type<Consumable1_21_2> TYPE = new Type<>(Consumable1_21_2.class) {
@Override
public Consumable1_21_2 read(final ByteBuf buffer) {
final float consumeSeconds = buffer.readFloat();
final int animationType = Types.VAR_INT.readPrimitive(buffer);
final Holder<SoundEvent> sound = Types.SOUND_EVENT.read(buffer);
final boolean hasConsumeParticles = buffer.readBoolean();
final ConsumeEffect<?>[] consumeEffects = ConsumeEffect.ARRAY_TYPE.read(buffer);
return new Consumable1_21_2(consumeSeconds, animationType, sound, hasConsumeParticles, consumeEffects);
}
@Override
public void write(final ByteBuf buffer, final Consumable1_21_2 value) {
buffer.writeFloat(value.consumeSeconds);
Types.VAR_INT.writePrimitive(buffer, value.animationType);
Types.SOUND_EVENT.write(buffer, value.sound);
buffer.writeBoolean(value.hasConsumeParticles);
ConsumeEffect.ARRAY_TYPE.write(buffer, value.consumeEffects);
}
@Override
public void write(final Ops ops, final Consumable1_21_2 value) {
final Holder<SoundEvent> defaultSound = Holder.of(ops.context().registryAccess().id(MappingData.MappingType.SOUND, "entity.generic.eat"));
ops.writeMap(map -> map
.writeOptional("consume_seconds", Types.FLOAT, value.consumeSeconds, 1.6F)
.writeOptional("animation", EnumTypes.ITEM_USE_ANIMATION, value.animationType, 1)
.writeOptional("sound", Types.SOUND_EVENT, value.sound, defaultSound)
.writeOptional("has_consume_particles", Types.BOOLEAN, value.hasConsumeParticles, true)
.writeOptional("consume_effects", ConsumeEffect.ARRAY_TYPE, value.consumeEffects, new ConsumeEffect<?>[0]));
}
};
public record ConsumeEffect<T>(int id, Type<T> type, T value) {
public static final Type<ConsumeEffect<?>> TYPE = new Type<>(ConsumeEffect.class) {
@Override
public ConsumeEffect<?> read(final ByteBuf buffer) {
// Oh no...
final int effectType = Types.VAR_INT.readPrimitive(buffer);
final Type<?> type = EFFECT_TYPES[effectType];
final Object value = type.read(buffer);
return ConsumeEffect.of(effectType, type, value);
}
@Override
public void write(final ByteBuf buffer, final ConsumeEffect<?> value) {
Types.VAR_INT.writePrimitive(buffer, value.id);
value.writeValue(buffer);
}
@Override
public void write(final Ops ops, final ConsumeEffect<?> value) {
writeGeneric(ops, value);
}
private <E> void writeGeneric(final Ops ops, final ConsumeEffect<E> value) {
ops.writeMap(map -> map
.write("type", EnumTypes.CONSUME_EFFECT, value.id)
.writeInlinedMap(value.type, value.value));
}
};
public static final Type<ConsumeEffect<?>[]> ARRAY_TYPE = new ArrayType<>(TYPE);
static <T> ConsumeEffect<T> of(final int id, final Type<T> type, final Object value) {
//noinspection unchecked
return new ConsumeEffect<>(id, type, (T) value);
}
void writeValue(final ByteBuf buf) {
this.type.write(buf, this.value);
}
}
public record ApplyStatusEffects(PotionEffect[] effects, float probability) {
public static final Type<ApplyStatusEffects> TYPE = new Type<>(ApplyStatusEffects.class) {
@Override
public ApplyStatusEffects read(final ByteBuf buffer) {
final PotionEffect[] effects = PotionEffect.ARRAY_TYPE.read(buffer);
final float probability = buffer.readFloat();
return new ApplyStatusEffects(effects, probability);
}
@Override
public void write(final ByteBuf buffer, final ApplyStatusEffects value) {
PotionEffect.ARRAY_TYPE.write(buffer, value.effects);
buffer.writeFloat(value.probability);
}
@Override
public void write(final Ops ops, final ApplyStatusEffects value) {
ops.writeMap(map -> map
.write("effects", PotionEffect.ARRAY_TYPE, value.effects)
.writeOptional("probability", Types.FLOAT, value.probability, 1F));
}
};
}
@Override
public Consumable1_21_2 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean 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);
}
@Override
public Consumable1_21_2 copy() {
return new Consumable1_21_2(consumeSeconds, animationType, sound, hasConsumeParticles, Copyable.copy(consumeEffects));
}
}
@@ -0,0 +1,55 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.ResolvableFloat;
import com.viaversion.viaversion.api.minecraft.ResolvableInt;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record CookingFuel(ResolvableInt burnTime, ResolvableFloat speedMultiplier) {
public static final Type<CookingFuel> TYPE = new Type<>(CookingFuel.class) {
@Override
public CookingFuel read(final ByteBuf buffer) {
final ResolvableInt burnTime = Types.RESOLVABLE_INT.read(buffer);
final ResolvableFloat speedMultiplier = Types.RESOLVABLE_FLOAT.read(buffer);
return new CookingFuel(burnTime, speedMultiplier);
}
@Override
public void write(final ByteBuf buffer, final CookingFuel value) {
Types.RESOLVABLE_INT.write(buffer, value.burnTime);
Types.RESOLVABLE_FLOAT.write(buffer, value.speedMultiplier);
}
@Override
public void write(final Ops ops, final CookingFuel value) {
ops.writeMap(map -> map
.write("burn_time", Types.RESOLVABLE_INT, value.burnTime)
.write("speed_multiplier", Types.RESOLVABLE_FLOAT, value.speedMultiplier));
}
};
}
@@ -23,10 +23,12 @@
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.RegistryKey;
import com.viaversion.viaversion.api.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.api.type.types.misc.HolderSetType;
public record DamageResistant26_1(HolderSet types) {
@@ -34,7 +36,7 @@ public record DamageResistant26_1(HolderSet types) {
@Override
public void write(final Ops ops, final DamageResistant26_1 value) {
ops.writeMap(map -> map.write("types", Types.HOLDER_SET, value.types));
ops.writeMap(map -> map.write("types", new HolderSetType(RegistryKey.of("damage_type")), value.types));
}
};
}
@@ -23,17 +23,23 @@
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2.ConsumeEffect;
import com.viaversion.viaversion.api.minecraft.item.data.consumable.ConsumeEffect;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.Copyable;
public record DeathProtection(ConsumeEffect<?>[] deathEffects) implements Copyable {
public static final Type<DeathProtection> TYPE = new TransformingType<>(ConsumeEffect.ARRAY_TYPE, DeathProtection.class, DeathProtection::new, DeathProtection::deathEffects) {
public static final Type<DeathProtection> TYPE1_21_2 = new TransformingType<>(ConsumeEffect.ARRAY_TYPE1_21_2, DeathProtection.class, DeathProtection::new, DeathProtection::deathEffects) {
@Override
public void write(final Ops ops, final DeathProtection value) {
ops.writeMap(map -> map.write("death_effects", ConsumeEffect.ARRAY_TYPE, value.deathEffects));
ops.writeMap(map -> map.write("death_effects", ConsumeEffect.ARRAY_TYPE1_21_2, value.deathEffects));
}
};
public static final Type<DeathProtection> TYPE26_3 = new TransformingType<>(ConsumeEffect.ARRAY_TYPE26_3, DeathProtection.class, DeathProtection::new, DeathProtection::deathEffects) {
@Override
public void write(final Ops ops, final DeathProtection value) {
ops.writeMap(map -> map.write("death_effects", ConsumeEffect.ARRAY_TYPE26_3, value.deathEffects));
}
};
@@ -38,12 +38,12 @@ public record DebugStickState(CompoundTag tag) implements Rewritable, Copyable {
@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) {
if (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 blockId == -1 || protocol.getMappingData().changedBlocks().contains(blockId);
});
}
return new DebugStickState(updatedTag);
@@ -46,8 +46,12 @@ public final class EnumTypes {
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");
public static final EnumType SWING_ANIMATION = new EnumType("none", "whack", "stab");
public static final EnumType SWING_ANIMATION1_21_11 = new EnumType("none", "whack", "stab");
public static final EnumType ITEM_USE_ANIMATION = new EnumType("none", "eat", "drink", "block", "bow", "trident", "crossbow", "spyglass", "toot_horn", "brush", "bundle", "spear");
public static final EnumType DIRECTION = new EnumType("down", "up", "north", "south", "west", "east");
public static final EnumType TRANSFORM_PARTICLE = new EnumType("none", "scrape", "wax_on", "wax_off");
public static final EnumType TRAMNSFORM_DROP_STRATEGY = new EnumType("clicked_face", "from_middle");
public static final EnumType TRAMNSFORM_TYPE = new EnumType("single_block", "copper_chest");
// 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"));
// Hardcoded registries
@@ -37,9 +37,13 @@ import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record Instrument1_21_2(Holder<SoundEvent> soundEvent, float useDuration, float range,
Tag description) implements Copyable, Rewritable {
int durabilityDamage, Tag description) implements Copyable, Rewritable {
public static final HolderType<Instrument1_21_2> TYPE = new HolderType<>() {
public Instrument1_21_2(final Holder<SoundEvent> soundEvent, final float useDuration, final float range, final Tag description) {
this(soundEvent, useDuration, range, 0, description);
}
public static final HolderType<Instrument1_21_2> TYPE1_21_2 = new HolderType<>() {
@Override
public Instrument1_21_2 readDirect(final ByteBuf buffer) {
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
@@ -71,16 +75,52 @@ public record Instrument1_21_2(Holder<SoundEvent> soundEvent, float useDuration,
return ops.context().registryAccess().registryKey("instrument", id);
}
};
public static final EitherHolderType<Instrument1_21_2> EITHER_HOLDER_TYPE = new EitherHolderType<>(TYPE);
public static final EitherHolderType<Instrument1_21_2> EITHER_HOLDER_TYPE = new EitherHolderType<>(TYPE1_21_2);
public static final HolderType<Instrument1_21_2> TYPE26_3 = new HolderType<>() {
@Override
public Instrument1_21_2 readDirect(final ByteBuf buffer) {
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final float useDuration = Types.FLOAT.readPrimitive(buffer);
final float range = Types.FLOAT.readPrimitive(buffer);
final int durabilityDamage = Types.VAR_INT.readPrimitive(buffer);
final Tag description = Types.TAG.read(buffer);
return new Instrument1_21_2(soundEvent, useDuration, range, durabilityDamage, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final Instrument1_21_2 value) {
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.FLOAT.writePrimitive(buffer, value.useDuration());
Types.FLOAT.writePrimitive(buffer, value.range());
Types.VAR_INT.writePrimitive(buffer, value.durabilityDamage());
Types.TAG.write(buffer, value.description());
}
@Override
public void writeDirect(final Ops ops, final Instrument1_21_2 value) {
ops.writeMap(map -> map
.write("sound_event", Types.SOUND_EVENT, value.soundEvent())
.write("use_duration", Types.FLOAT, value.useDuration())
.write("range", Types.FLOAT, value.range())
.write("durability_damage", Types.VAR_INT, value.durabilityDamage())
.write("description", Types.TAG, value.description()));
}
@Override
protected Key identifier(final Ops ops, final int id) {
return ops.context().registryAccess().registryKey("instrument", id);
}
};
@Override
public Instrument1_21_2 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean 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);
return soundEvent == this.soundEvent ? this : new Instrument1_21_2(soundEvent, useDuration, range, durabilityDamage, description);
}
@Override
public Instrument1_21_2 copy() {
return new Instrument1_21_2(soundEvent, useDuration, range, description.copy());
return new Instrument1_21_2(soundEvent, useDuration, range, durabilityDamage, description.copy());
}
}
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.minecraft.HolderSet;
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.misc.HolderSetType;
import io.netty.buffer.ByteBuf;
public record MobVisibility(HolderSet targetingEntityTypes, float visibility) {
public static final Type<MobVisibility> TYPE = new Type<>(MobVisibility.class) {
@Override
public MobVisibility read(final ByteBuf buffer) {
final HolderSet targetingEntityTypes = Types.HOLDER_SET.read(buffer);
final float visibility = Types.FLOAT.readPrimitive(buffer);
return new MobVisibility(targetingEntityTypes, visibility);
}
@Override
public void write(final ByteBuf buffer, final MobVisibility value) {
Types.HOLDER_SET.write(buffer, value.targetingEntityTypes);
Types.FLOAT.writePrimitive(buffer, value.visibility);
}
@Override
public void write(final Ops ops, final MobVisibility value) {
ops.writeMap(map -> map
.write("targeting_entity_types", new HolderSetType(MappingData.MappingType.ENTITY_TYPE), value.targetingEntityTypes)
.write("visibility", Types.FLOAT, value.visibility));
}
};
}
@@ -31,11 +31,11 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
public record PotDecorations(int[] itemIds) implements Copyable, Rewritable {
public record PotDecorations1_20_5(int[] itemIds) implements Copyable, Rewritable {
public static final Type<PotDecorations> TYPE = new TransformingType<>(Types.VAR_INT_ARRAY_PRIMITIVE, PotDecorations.class, PotDecorations::new, PotDecorations::itemIds) {
public static final Type<PotDecorations1_20_5> TYPE = new TransformingType<>(Types.VAR_INT_ARRAY_PRIMITIVE, PotDecorations1_20_5.class, PotDecorations1_20_5::new, PotDecorations1_20_5::itemIds) {
@Override
public void write(final Ops ops, final PotDecorations value) {
public void write(final Ops ops, final PotDecorations1_20_5 value) {
ops.writeList(list -> {
for (final int itemId : value.itemIds) {
list.write(Types.IDENTIFIER, ops.context().registryAccess().item(itemId));
@@ -44,7 +44,7 @@ public record PotDecorations(int[] itemIds) implements Copyable, Rewritable {
}
};
public PotDecorations(final int backItem, final int leftItem, final int rightItem, final int frontItem) {
public PotDecorations1_20_5(final int backItem, final int leftItem, final int rightItem, final int frontItem) {
this(new int[]{backItem, leftItem, rightItem, frontItem});
}
@@ -69,16 +69,16 @@ public record PotDecorations(int[] itemIds) implements Copyable, Rewritable {
}
@Override
public PotDecorations rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
public PotDecorations1_20_5 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final int[] newItems = new int[itemIds.length];
for (int i = 0; i < itemIds.length; i++) {
newItems[i] = Rewritable.rewriteItem(protocol, clientbound, itemIds[i]);
}
return new PotDecorations(newItems);
return new PotDecorations1_20_5(newItems);
}
@Override
public PotDecorations copy() {
return new PotDecorations(Copyable.copy(itemIds));
public PotDecorations1_20_5 copy() {
return new PotDecorations1_20_5(Copyable.copy(itemIds));
}
}
@@ -0,0 +1,96 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
import static com.viaversion.viaversion.util.Rewritable.rewriteItem;
public record PotDecorations26_3(@Nullable Item back, @Nullable Item left, @Nullable Item right,
@Nullable Item front) implements Copyable, Rewritable {
public static final class PotDecorationsType extends Type<PotDecorations26_3> {
private final Type<Item> itemTemplateType;
public PotDecorationsType(final Type<Item> itemTemplateType) {
super(PotDecorations26_3.class);
this.itemTemplateType = itemTemplateType;
}
@Override
public void write(final ByteBuf buffer, final PotDecorations26_3 value) {
itemTemplateType.write(buffer, value.back());
itemTemplateType.write(buffer, value.left());
itemTemplateType.write(buffer, value.right());
itemTemplateType.write(buffer, value.front());
}
@Override
public PotDecorations26_3 read(final ByteBuf buffer) {
final Item back = itemTemplateType.read(buffer);
final Item left = itemTemplateType.read(buffer);
final Item right = itemTemplateType.read(buffer);
final Item front = itemTemplateType.read(buffer);
return new PotDecorations26_3(back, left, right, front);
}
@Override
public void write(final Ops ops, final PotDecorations26_3 value) {
ops.writeMap(map -> map
.writeOptional("back", itemTemplateType, value.back())
.writeOptional("left", itemTemplateType, value.left())
.writeOptional("right", itemTemplateType, value.right())
.writeOptional("front", itemTemplateType, value.front())
);
}
}
@Override
public PotDecorations26_3 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
return new PotDecorations26_3(
rewriteItem(connection, protocol, clientbound, back),
rewriteItem(connection, protocol, clientbound, left),
rewriteItem(connection, protocol, clientbound, right),
rewriteItem(connection, protocol, clientbound, front)
);
}
@Override
public PotDecorations26_3 copy() {
return new PotDecorations26_3(
back == null ? null : back.copy(),
left == null ? null : left.copy(),
right == null ? null : right.copy(),
front == null ? null : front.copy()
);
}
}
@@ -0,0 +1,61 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public record SignText(Tag[] messages, Tag @Nullable [] filteredMessages, int color, boolean hasGlowingText) {
public static final Type<SignText> TYPE = new Type<>(SignText.class) {
@Override
public SignText read(final ByteBuf buffer) {
final Tag[] messages = Types.SIGN_TEXT.read(buffer);
final Tag[] filteredMessages = Types.OPTIONAL_SIGN_TEXT.read(buffer);
final int color = Types.VAR_INT.readPrimitive(buffer);
final boolean hasGlowingText = buffer.readBoolean();
return new SignText(messages, filteredMessages, color, hasGlowingText);
}
@Override
public void write(final ByteBuf buffer, final SignText value) {
Types.SIGN_TEXT.write(buffer, value.messages);
Types.OPTIONAL_SIGN_TEXT.write(buffer, value.filteredMessages);
Types.VAR_INT.writePrimitive(buffer, value.color);
Types.BOOLEAN.write(buffer, value.hasGlowingText);
}
@Override
public void write(final Ops ops, final SignText value) {
ops.writeMap(map -> map
.write("messages", Types.SIGN_TEXT, value.messages)
.writeOptional("filtered_messages", Types.SIGN_TEXT, value.filteredMessages)
.write("color", Types.VAR_INT, value.color, 15)
.write("has_glowing_text", Types.BOOLEAN, value.hasGlowingText, false));
}
};
}
@@ -29,9 +29,17 @@ import io.netty.buffer.ByteBuf;
public record SwingAnimation(int type, int duration) {
private static final int DEFAULT_TYPE = EnumTypes.SWING_ANIMATION.idFromName("whack");
public static final Type<SwingAnimation> TYPE = new SwingAnimationType(EnumTypes.SWING_ANIMATION1_21_11.idFromName("whack"));
private static class SwingAnimationType extends Type<SwingAnimation> {
private final int defaultType;
public SwingAnimationType(final int defaultType) {
super(SwingAnimation.class);
this.defaultType = defaultType;
}
public static final Type<SwingAnimation> TYPE = new Type<>(SwingAnimation.class) {
@Override
public SwingAnimation read(final ByteBuf buffer) {
final int type = Types.VAR_INT.readPrimitive(buffer);
@@ -48,9 +56,8 @@ public record SwingAnimation(int type, int duration) {
@Override
public void write(final Ops ops, final SwingAnimation value) {
ops.writeMap(map -> map
.writeOptional("type", EnumTypes.SWING_ANIMATION, value.type, DEFAULT_TYPE)
.writeOptional("duration", Types.INT, value.duration, 6)
);
.writeOptional("type", EnumTypes.SWING_ANIMATION1_21_11, value.type, this.defaultType)
.writeOptional("duration", Types.INT, value.duration, 6));
}
};
}
}
@@ -0,0 +1,39 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
public record VillagerFood(int nutrition) {
public static final Type<VillagerFood> TYPE = new TransformingType<>(Types.VAR_INT, VillagerFood.class, VillagerFood::new, VillagerFood::nutrition) {
@Override
public void write(final Ops ops, final VillagerFood value) {
ops.writeMap(map -> map.write("nutrition", Types.VAR_INT, value.nutrition));
}
};
}
@@ -0,0 +1,54 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data.consumable;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.minecraft.item.data.PotionEffect;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record ApplyStatusEffects(PotionEffect[] effects, float probability) {
public static final Type<ApplyStatusEffects> TYPE = new Type<>(ApplyStatusEffects.class) {
@Override
public ApplyStatusEffects read(final ByteBuf buffer) {
final PotionEffect[] effects = PotionEffect.ARRAY_TYPE.read(buffer);
final float probability = buffer.readFloat();
return new ApplyStatusEffects(effects, probability);
}
@Override
public void write(final ByteBuf buffer, final ApplyStatusEffects value) {
PotionEffect.ARRAY_TYPE.write(buffer, value.effects);
buffer.writeFloat(value.probability);
}
@Override
public void write(final Ops ops, final ApplyStatusEffects value) {
ops.writeMap(map -> map
.write("effects", PotionEffect.ARRAY_TYPE, value.effects)
.writeOptional("probability", Types.FLOAT, value.probability, 1F));
}
};
}
@@ -0,0 +1,95 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data.consumable;
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.SoundEvent;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.minecraft.item.data.EnumTypes;
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 Consumable1_21_2(float consumeSeconds, int animationType, Holder<SoundEvent> sound,
boolean hasConsumeParticles,
ConsumeEffect<?>[] consumeEffects) implements Copyable, Rewritable {
public static final Type<Consumable1_21_2> TYPE1_21_2 = new ConsumableType(ConsumeEffect.ARRAY_TYPE1_21_2);
public static final Type<Consumable1_21_2> TYPE26_3 = new ConsumableType(ConsumeEffect.ARRAY_TYPE26_3);
private static final class ConsumableType extends Type<Consumable1_21_2> {
private final Type<ConsumeEffect<?>[]> consumeEffectType;
private ConsumableType(final Type<ConsumeEffect<?>[]> consumeEffectType) {
super(Consumable1_21_2.class);
this.consumeEffectType = consumeEffectType;
}
@Override
public Consumable1_21_2 read(final ByteBuf buffer) {
final float consumeSeconds = buffer.readFloat();
final int animationType = Types.VAR_INT.readPrimitive(buffer);
final Holder<SoundEvent> sound = Types.SOUND_EVENT.read(buffer);
final boolean hasConsumeParticles = buffer.readBoolean();
final ConsumeEffect<?>[] consumeEffects = consumeEffectType.read(buffer);
return new Consumable1_21_2(consumeSeconds, animationType, sound, hasConsumeParticles, consumeEffects);
}
@Override
public void write(final ByteBuf buffer, final Consumable1_21_2 value) {
buffer.writeFloat(value.consumeSeconds);
Types.VAR_INT.writePrimitive(buffer, value.animationType);
Types.SOUND_EVENT.write(buffer, value.sound);
buffer.writeBoolean(value.hasConsumeParticles);
consumeEffectType.write(buffer, value.consumeEffects);
}
@Override
public void write(final Ops ops, final Consumable1_21_2 value) {
final Holder<SoundEvent> defaultSound = Holder.of(ops.context().registryAccess().id(MappingData.MappingType.SOUND, "entity.generic.eat"));
ops.writeMap(map -> map
.writeOptional("consume_seconds", Types.FLOAT, value.consumeSeconds, 1.6F)
.writeOptional("animation", EnumTypes.ITEM_USE_ANIMATION, value.animationType, 1)
.writeOptional("sound", Types.SOUND_EVENT, value.sound, defaultSound)
.writeOptional("has_consume_particles", Types.BOOLEAN, value.hasConsumeParticles, true)
.writeOptional("on_consume_effects", consumeEffectType, value.consumeEffects, new ConsumeEffect<?>[0]));
}
}
@Override
public Consumable1_21_2 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean 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);
}
@Override
public Consumable1_21_2 copy() {
return new Consumable1_21_2(consumeSeconds, animationType, sound, hasConsumeParticles, Copyable.copy(consumeEffects));
}
}
@@ -0,0 +1,165 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data.consumable;
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.minecraft.item.data.EnumTypes;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.misc.HolderSetType;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
public record ConsumeEffect<T>(int id, Type<T> type, T value) {
private static final HolderSetType REMOVE_EFFECTS_TYPE = new HolderSetType() {
@Override
public void write(final Ops ops, final HolderSet value) {
ops.writeMap(map -> map.write("effects", new HolderSetType(EnumTypes.MOB_EFFECT), value));
}
};
public static final Type<Float> TELEPORT_RANDOMLY_TYPE1_21_2 = new Type<>(Float.class) {
@Override
public void write(final ByteBuf buffer, final Float value) {
Types.FLOAT.writePrimitive(buffer, value);
}
@Override
public Float read(final ByteBuf buffer) {
return Types.FLOAT.readPrimitive(buffer);
}
@Override
public void write(final Ops ops, final Float value) {
ops.writeMap(map -> map.write("diameter", Types.FLOAT, value, 16F));
}
};
public static final Type<TeleportRandomlyConsumeEffect> TELEPORT_RANDOMLY_TYPE26_3 = new Type<>(TeleportRandomlyConsumeEffect.class) {
@Override
public void write(final ByteBuf buffer, final TeleportRandomlyConsumeEffect value) {
Types.FLOAT.writePrimitive(buffer, value.diameter());
Types.BOOLEAN.write(buffer, value.directionalParticles());
}
@Override
public TeleportRandomlyConsumeEffect read(final ByteBuf buffer) {
final float diameter = Types.FLOAT.readPrimitive(buffer);
final boolean directionalParticles = Types.BOOLEAN.read(buffer);
return new TeleportRandomlyConsumeEffect(diameter, directionalParticles);
}
@Override
public void write(final Ops ops, final TeleportRandomlyConsumeEffect value) {
ops.writeMap(map -> map
.write("diameter", Types.FLOAT, value.diameter(), 16F)
.write("directional_particles", Types.BOOLEAN, value.directionalParticles(), true)
);
}
};
private static final HolderType<SoundEvent> PLAY_SOUND_TYPE = new HolderType<>(MappingData.MappingType.SOUND) {
@Override
public SoundEvent readDirect(final ByteBuf buffer) {
return Types.SOUND_EVENT.readDirect(buffer);
}
@Override
public void writeDirect(final ByteBuf buffer, final SoundEvent value) {
Types.SOUND_EVENT.writeDirect(buffer, value);
}
@Override
public void write(final Ops ops, final Holder<SoundEvent> value) {
ops.writeMap(map -> map.write("sound", Types.SOUND_EVENT, value));
}
};
public static final Type<?>[] EFFECT_TYPES1_21_2 = {
ApplyStatusEffects.TYPE,
REMOVE_EFFECTS_TYPE,
Types.EMPTY, // clear all effects
TELEPORT_RANDOMLY_TYPE1_21_2,
PLAY_SOUND_TYPE
};
public static final Type<?>[] EFFECT_TYPES26_3 = {
ApplyStatusEffects.TYPE,
REMOVE_EFFECTS_TYPE,
Types.EMPTY, // clear all effects
TELEPORT_RANDOMLY_TYPE26_3,
PLAY_SOUND_TYPE
};
public static final Type<ConsumeEffect<?>> TYPE1_21_2 = new ConsumeEffectType(EFFECT_TYPES1_21_2);
public static final Type<ConsumeEffect<?>[]> ARRAY_TYPE1_21_2 = new ArrayType<>(TYPE1_21_2);
public static final Type<ConsumeEffect<?>> TYPE26_3 = new ConsumeEffectType(EFFECT_TYPES26_3);
public static final Type<ConsumeEffect<?>[]> ARRAY_TYPE26_3 = new ArrayType<>(TYPE26_3);
static <T> ConsumeEffect<T> of(final int id, final Type<T> type, final Object value) {
//noinspection unchecked
return new ConsumeEffect<>(id, type, (T) value);
}
void writeValue(final ByteBuf buf) {
this.type.write(buf, this.value);
}
private static final class ConsumeEffectType extends Type<ConsumeEffect<?>> {
private final Type<?>[] types;
private ConsumeEffectType(final Type<?>[] types) {
super(ConsumeEffect.class);
this.types = types;
}
@Override
public ConsumeEffect<?> read(final ByteBuf buffer) {
// Oh no...
final int effectType = Types.VAR_INT.readPrimitive(buffer);
final Type<?> type = types[effectType];
final Object value = type.read(buffer);
return ConsumeEffect.of(effectType, type, value);
}
@Override
public void write(final ByteBuf buffer, final ConsumeEffect<?> value) {
Types.VAR_INT.writePrimitive(buffer, value.id);
value.writeValue(buffer);
}
@Override
public void write(final Ops ops, final ConsumeEffect<?> value) {
writeGeneric(ops, value);
}
private <E> void writeGeneric(final Ops ops, final ConsumeEffect<E> value) {
ops.writeMap(map -> map
.write("type", EnumTypes.CONSUME_EFFECT, value.id)
.writeInlinedMap(value.type, value.value));
}
}
}
@@ -0,0 +1,26 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data.consumable;
public record TeleportRandomlyConsumeEffect(float diameter, boolean directionalParticles) {
}
@@ -20,7 +20,7 @@
* 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;
package com.viaversion.viaversion.api.minecraft.item.data.trim;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Holder;
@@ -30,86 +30,86 @@ import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record ArmorTrim(Holder<ArmorTrimMaterial> material, Holder<ArmorTrimPattern> pattern,
boolean showInTooltip) implements Rewritable {
public record ArmorTrim1_20_5(Holder<ArmorTrimMaterial1_20_5> material, Holder<ArmorTrimPattern> pattern,
boolean showInTooltip) implements Rewritable {
public ArmorTrim(Holder<ArmorTrimMaterial> material, Holder<ArmorTrimPattern> pattern) {
public ArmorTrim1_20_5(Holder<ArmorTrimMaterial1_20_5> material, Holder<ArmorTrimPattern> pattern) {
this(material, pattern, true);
}
public static final Type<ArmorTrim> TYPE1_20_5 = new Type<>(ArmorTrim.class) {
public static final Type<ArmorTrim1_20_5> TYPE1_20_5 = new Type<>(ArmorTrim1_20_5.class) {
@Override
public ArmorTrim read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial> material = ArmorTrimMaterial.TYPE1_20_5.read(buffer);
public ArmorTrim1_20_5 read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial1_20_5> material = ArmorTrimMaterial1_20_5.TYPE1_20_5.read(buffer);
final Holder<ArmorTrimPattern> pattern = ArmorTrimPattern.TYPE1_20_5.read(buffer);
final boolean showInTooltip = buffer.readBoolean();
return new ArmorTrim(material, pattern, showInTooltip);
return new ArmorTrim1_20_5(material, pattern, showInTooltip);
}
@Override
public void write(final ByteBuf buffer, final ArmorTrim value) {
ArmorTrimMaterial.TYPE1_20_5.write(buffer, value.material);
public void write(final ByteBuf buffer, final ArmorTrim1_20_5 value) {
ArmorTrimMaterial1_20_5.TYPE1_20_5.write(buffer, value.material);
ArmorTrimPattern.TYPE1_20_5.write(buffer, value.pattern);
buffer.writeBoolean(value.showInTooltip);
}
};
public static final Type<ArmorTrim> TYPE1_21_2 = new Type<>(ArmorTrim.class) {
public static final Type<ArmorTrim1_20_5> TYPE1_21_2 = new Type<>(ArmorTrim1_20_5.class) {
@Override
public ArmorTrim read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial> material = ArmorTrimMaterial.TYPE1_21_2.read(buffer);
public ArmorTrim1_20_5 read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial1_20_5> material = ArmorTrimMaterial1_20_5.TYPE1_21_2.read(buffer);
final Holder<ArmorTrimPattern> pattern = ArmorTrimPattern.TYPE1_20_5.read(buffer);
final boolean showInTooltip = buffer.readBoolean();
return new ArmorTrim(material, pattern, showInTooltip);
return new ArmorTrim1_20_5(material, pattern, showInTooltip);
}
@Override
public void write(final ByteBuf buffer, final ArmorTrim value) {
ArmorTrimMaterial.TYPE1_21_2.write(buffer, value.material);
public void write(final ByteBuf buffer, final ArmorTrim1_20_5 value) {
ArmorTrimMaterial1_20_5.TYPE1_21_2.write(buffer, value.material);
ArmorTrimPattern.TYPE1_20_5.write(buffer, value.pattern);
buffer.writeBoolean(value.showInTooltip);
}
};
public static final Type<ArmorTrim> TYPE1_21_4 = new Type<>(ArmorTrim.class) {
public static final Type<ArmorTrim1_20_5> TYPE1_21_4 = new Type<>(ArmorTrim1_20_5.class) {
@Override
public ArmorTrim read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial> material = ArmorTrimMaterial.TYPE1_21_4.read(buffer);
public ArmorTrim1_20_5 read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial1_20_5> material = ArmorTrimMaterial1_20_5.TYPE1_21_4.read(buffer);
final Holder<ArmorTrimPattern> pattern = ArmorTrimPattern.TYPE1_20_5.read(buffer);
final boolean showInTooltip = buffer.readBoolean();
return new ArmorTrim(material, pattern, showInTooltip);
return new ArmorTrim1_20_5(material, pattern, showInTooltip);
}
@Override
public void write(final ByteBuf buffer, final ArmorTrim value) {
ArmorTrimMaterial.TYPE1_21_4.write(buffer, value.material);
public void write(final ByteBuf buffer, final ArmorTrim1_20_5 value) {
ArmorTrimMaterial1_20_5.TYPE1_21_4.write(buffer, value.material);
ArmorTrimPattern.TYPE1_20_5.write(buffer, value.pattern);
buffer.writeBoolean(value.showInTooltip);
}
};
public static final Type<ArmorTrim> TYPE1_21_5 = new Type<>(ArmorTrim.class) {
public static final Type<ArmorTrim1_20_5> TYPE1_21_5 = new Type<>(ArmorTrim1_20_5.class) {
@Override
public ArmorTrim read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial> material = ArmorTrimMaterial.TYPE1_21_5.read(buffer);
public ArmorTrim1_20_5 read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial1_20_5> material = ArmorTrimMaterial1_20_5.TYPE1_21_5.read(buffer);
final Holder<ArmorTrimPattern> pattern = ArmorTrimPattern.TYPE1_21_5.read(buffer);
return new ArmorTrim(material, pattern);
return new ArmorTrim1_20_5(material, pattern);
}
@Override
public void write(final ByteBuf buffer, final ArmorTrim value) {
ArmorTrimMaterial.TYPE1_21_5.write(buffer, value.material);
public void write(final ByteBuf buffer, final ArmorTrim1_20_5 value) {
ArmorTrimMaterial1_20_5.TYPE1_21_5.write(buffer, value.material);
ArmorTrimPattern.TYPE1_21_5.write(buffer, value.pattern);
}
@Override
public void write(final Ops ops, final ArmorTrim value) {
public void write(final Ops ops, final ArmorTrim1_20_5 value) {
ops.writeMap(map -> map
.write("material", ArmorTrimMaterial.TYPE1_21_5, value.material)
.write("material", ArmorTrimMaterial1_20_5.TYPE1_21_5, value.material)
.write("pattern", ArmorTrimPattern.TYPE1_21_5, value.pattern));
}
};
@Override
public ArmorTrim rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
Holder<ArmorTrimMaterial> material = this.material;
public ArmorTrim1_20_5 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
Holder<ArmorTrimMaterial1_20_5> material = this.material;
if (material.isDirect()) {
material = Holder.of(material.value().rewrite(connection, protocol, clientbound));
}
@@ -118,6 +118,6 @@ public record ArmorTrim(Holder<ArmorTrimMaterial> material, Holder<ArmorTrimPatt
if (pattern.isDirect()) {
pattern = Holder.of(pattern.value().rewrite(connection, protocol, clientbound));
}
return new ArmorTrim(material, pattern, showInTooltip);
return new ArmorTrim1_20_5(material, pattern, showInTooltip);
}
}
@@ -0,0 +1,66 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data.trim;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Holder;
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.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record ArmorTrim26_3(Holder<ArmorTrimMaterial26_3> material,
Holder<ArmorTrimPattern> pattern) implements Rewritable {
public static final Type<ArmorTrim26_3> TYPE = new Type<>(ArmorTrim26_3.class) {
@Override
public ArmorTrim26_3 read(final ByteBuf buffer) {
final Holder<ArmorTrimMaterial26_3> material = ArmorTrimMaterial26_3.TYPE.read(buffer);
final Holder<ArmorTrimPattern> pattern = ArmorTrimPattern.TYPE1_21_5.read(buffer);
return new ArmorTrim26_3(material, pattern);
}
@Override
public void write(final ByteBuf buffer, final ArmorTrim26_3 value) {
ArmorTrimMaterial26_3.TYPE.write(buffer, value.material);
ArmorTrimPattern.TYPE1_21_5.write(buffer, value.pattern);
}
@Override
public void write(final Ops ops, final ArmorTrim26_3 value) {
ops.writeMap(map -> map
.write("material", ArmorTrimMaterial26_3.TYPE, value.material)
.write("pattern", ArmorTrimPattern.TYPE1_21_5, value.pattern));
}
};
@Override
public ArmorTrim26_3 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
Holder<ArmorTrimPattern> pattern = this.pattern;
if (pattern.isDirect()) {
pattern = Holder.of(pattern.value().rewrite(connection, protocol, clientbound));
}
return new ArmorTrim26_3(material, pattern);
}
}
@@ -20,7 +20,7 @@
* 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;
package com.viaversion.viaversion.api.minecraft.item.data.trim;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -35,23 +35,23 @@ import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import java.util.Map;
public record ArmorTrimMaterial(String assetName, int itemId, float itemModelIndex,
Map<String, String> overrideArmorMaterials,
Tag description) implements Copyable, Rewritable {
public record ArmorTrimMaterial1_20_5(String assetName, int itemId, float itemModelIndex,
Map<String, String> overrideArmorMaterials,
Tag description) implements Copyable, Rewritable {
public ArmorTrimMaterial(final String assetName, final int itemId, final Map<String, String> overrideArmorMaterials, final Tag description) {
public ArmorTrimMaterial1_20_5(final String assetName, final int itemId, final Map<String, String> overrideArmorMaterials, final Tag description) {
this(assetName, itemId, 0F, overrideArmorMaterials, description);
}
public ArmorTrimMaterial(final String assetName, final Map<String, String> overrideArmorMaterials, final Tag description) {
public ArmorTrimMaterial1_20_5(final String assetName, final Map<String, String> overrideArmorMaterials, final Tag description) {
this(assetName, 0, 0F, overrideArmorMaterials, description);
}
public static final HolderType<ArmorTrimMaterial> TYPE1_20_5 = new HolderType<>() {
public static final HolderType<ArmorTrimMaterial1_20_5> TYPE1_20_5 = new HolderType<>() {
// The override key is an int, but given we don't use it at all and that creating a new type is annoying,
// we'll just store it in the string map:tm:
@Override
public ArmorTrimMaterial readDirect(final ByteBuf buffer) {
public ArmorTrimMaterial1_20_5 readDirect(final ByteBuf buffer) {
final String assetName = Types.STRING.read(buffer);
final int item = Types.VAR_INT.readPrimitive(buffer);
final float itemModelIndex = buffer.readFloat();
@@ -65,11 +65,11 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
}
final Tag description = Types.TAG.read(buffer);
return new ArmorTrimMaterial(assetName, item, itemModelIndex, overrideArmorMaterials, description);
return new ArmorTrimMaterial1_20_5(assetName, item, itemModelIndex, overrideArmorMaterials, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial value) {
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial1_20_5 value) {
Types.STRING.write(buffer, value.assetName());
Types.VAR_INT.writePrimitive(buffer, value.itemId());
buffer.writeFloat(value.itemModelIndex());
@@ -83,9 +83,9 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
Types.TAG.write(buffer, value.description());
}
};
public static final HolderType<ArmorTrimMaterial> TYPE1_21_2 = new HolderType<>() {
public static final HolderType<ArmorTrimMaterial1_20_5> TYPE1_21_2 = new HolderType<>() {
@Override
public ArmorTrimMaterial readDirect(final ByteBuf buffer) {
public ArmorTrimMaterial1_20_5 readDirect(final ByteBuf buffer) {
final String assetName = Types.STRING.read(buffer);
final int item = Types.VAR_INT.readPrimitive(buffer);
final float itemModelIndex = buffer.readFloat();
@@ -99,11 +99,11 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
}
final Tag description = Types.TAG.read(buffer);
return new ArmorTrimMaterial(assetName, item, itemModelIndex, overrideArmorMaterials, description);
return new ArmorTrimMaterial1_20_5(assetName, item, itemModelIndex, overrideArmorMaterials, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial value) {
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial1_20_5 value) {
Types.STRING.write(buffer, value.assetName());
Types.VAR_INT.writePrimitive(buffer, value.itemId());
buffer.writeFloat(value.itemModelIndex());
@@ -117,9 +117,9 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
Types.TAG.write(buffer, value.description());
}
};
public static final HolderType<ArmorTrimMaterial> TYPE1_21_4 = new HolderType<>() {
public static final HolderType<ArmorTrimMaterial1_20_5> TYPE1_21_4 = new HolderType<>() {
@Override
public ArmorTrimMaterial readDirect(final ByteBuf buffer) {
public ArmorTrimMaterial1_20_5 readDirect(final ByteBuf buffer) {
final String assetName = Types.STRING.read(buffer);
final int item = Types.VAR_INT.readPrimitive(buffer);
@@ -132,11 +132,11 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
}
final Tag description = Types.TAG.read(buffer);
return new ArmorTrimMaterial(assetName, item, overrideArmorMaterials, description);
return new ArmorTrimMaterial1_20_5(assetName, item, overrideArmorMaterials, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial value) {
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial1_20_5 value) {
Types.STRING.write(buffer, value.assetName());
Types.VAR_INT.writePrimitive(buffer, value.itemId());
@@ -149,9 +149,9 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
Types.TAG.write(buffer, value.description());
}
};
public static final HolderType<ArmorTrimMaterial> TYPE1_21_5 = new HolderType<>() {
public static final HolderType<ArmorTrimMaterial1_20_5> TYPE1_21_5 = new HolderType<>() {
@Override
public ArmorTrimMaterial readDirect(final ByteBuf buffer) {
public ArmorTrimMaterial1_20_5 readDirect(final ByteBuf buffer) {
final String assetName = Types.STRING.read(buffer);
final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer);
@@ -163,11 +163,11 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
}
final Tag description = Types.TAG.read(buffer);
return new ArmorTrimMaterial(assetName, overrideArmorMaterials, description);
return new ArmorTrimMaterial1_20_5(assetName, overrideArmorMaterials, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial value) {
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial1_20_5 value) {
Types.STRING.write(buffer, value.assetName());
Types.VAR_INT.writePrimitive(buffer, value.overrideArmorMaterials().size());
@@ -180,7 +180,7 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
}
@Override
public void writeDirect(final Ops ops, final ArmorTrimMaterial object) {
public void writeDirect(final Ops ops, final ArmorTrimMaterial1_20_5 object) {
ops.writeMap(map -> {
map.write("asset_name", Types.STRING, object.assetName());
if (!object.overrideArmorMaterials.isEmpty()) {
@@ -201,12 +201,12 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
};
@Override
public ArmorTrimMaterial rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
return new ArmorTrimMaterial(assetName, Rewritable.rewriteItem(protocol, clientbound, itemId), itemModelIndex, overrideArmorMaterials, description);
public ArmorTrimMaterial1_20_5 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
return new ArmorTrimMaterial1_20_5(assetName, Rewritable.rewriteItem(protocol, clientbound, itemId), itemModelIndex, overrideArmorMaterials, description);
}
@Override
public ArmorTrimMaterial copy() {
return new ArmorTrimMaterial(assetName, itemId, itemModelIndex, new Object2ObjectArrayMap<>(overrideArmorMaterials), description);
public ArmorTrimMaterial1_20_5 copy() {
return new ArmorTrimMaterial1_20_5(assetName, itemId, itemModelIndex, new Object2ObjectArrayMap<>(overrideArmorMaterials), description);
}
}
@@ -0,0 +1,61 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data.trim;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.util.Key;
import io.netty.buffer.ByteBuf;
public record ArmorTrimMaterial26_3(String paletteId, Tag description) {
public static final HolderType<ArmorTrimMaterial26_3> TYPE = new HolderType<>() {
@Override
public ArmorTrimMaterial26_3 readDirect(final ByteBuf buffer) {
final String paletteId = Types.STRING.read(buffer);
final Tag description = Types.TAG.read(buffer);
return new ArmorTrimMaterial26_3(paletteId, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial26_3 value) {
Types.STRING.write(buffer, value.paletteId());
Types.TAG.write(buffer, value.description());
}
@Override
public void writeDirect(final Ops ops, final ArmorTrimMaterial26_3 object) {
ops.writeMap(map -> {
map.write("palette_id", Types.IDENTIFIER, Key.of(object.paletteId()));
map.write("description", Types.TEXT_COMPONENT_TAG, object.description());
});
}
@Override
protected Key identifier(final Ops ops, final int id) {
return ops.context().registryAccess().registryKey("trim_material", id);
}
};
}
@@ -20,7 +20,7 @@
* 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;
package com.viaversion.viaversion.api.minecraft.item.data.trim;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
@@ -20,7 +20,7 @@
* 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;
package com.viaversion.viaversion.api.minecraft.item.data.trim;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.EitherHolder;
@@ -32,34 +32,34 @@ import com.viaversion.viaversion.api.type.types.misc.EitherHolderType;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record ProvidesTrimMaterial(EitherHolder<ArmorTrimMaterial> material) implements Rewritable {
public record ProvidesTrimMaterial1_20_5(EitherHolder<ArmorTrimMaterial1_20_5> material) implements Rewritable {
public static final Type<ProvidesTrimMaterial> TYPE = new Type<>(ProvidesTrimMaterial.class) {
public static final Type<ProvidesTrimMaterial1_20_5> TYPE = new Type<>(ProvidesTrimMaterial1_20_5.class) {
@Override
public ProvidesTrimMaterial read(final ByteBuf buffer) {
final EitherHolder<ArmorTrimMaterial> position = EitherHolderType.read(buffer, ArmorTrimMaterial.TYPE1_21_5);
return new ProvidesTrimMaterial(position);
public ProvidesTrimMaterial1_20_5 read(final ByteBuf buffer) {
final EitherHolder<ArmorTrimMaterial1_20_5> position = EitherHolderType.read(buffer, ArmorTrimMaterial1_20_5.TYPE1_21_5);
return new ProvidesTrimMaterial1_20_5(position);
}
@Override
public void write(final ByteBuf buffer, final ProvidesTrimMaterial value) {
EitherHolderType.write(buffer, value.material, ArmorTrimMaterial.TYPE1_21_5);
public void write(final ByteBuf buffer, final ProvidesTrimMaterial1_20_5 value) {
EitherHolderType.write(buffer, value.material, ArmorTrimMaterial1_20_5.TYPE1_21_5);
}
@Override
public void write(final Ops ops, final ProvidesTrimMaterial value) {
EitherHolderType.write(ops, value.material, ArmorTrimMaterial.TYPE1_21_5);
public void write(final Ops ops, final ProvidesTrimMaterial1_20_5 value) {
EitherHolderType.write(ops, value.material, ArmorTrimMaterial1_20_5.TYPE1_21_5);
}
};
@Override
public ProvidesTrimMaterial rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
public ProvidesTrimMaterial1_20_5 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
if (material.hasKey() || material.holder().hasId()) {
return this;
}
final ArmorTrimMaterial trimMaterial = material.holder().value();
return new ProvidesTrimMaterial(EitherHolder.of(Holder.of(trimMaterial.rewrite(connection, protocol, clientbound))));
final ArmorTrimMaterial1_20_5 trimMaterial = material.holder().value();
return new ProvidesTrimMaterial1_20_5(EitherHolder.of(Holder.of(trimMaterial.rewrite(connection, protocol, clientbound))));
}
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.protocol;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.connection.ProtocolStorables;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
@@ -33,6 +34,7 @@ import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
import com.viaversion.viaversion.api.rewriter.EntityRewriter;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
@@ -58,6 +60,22 @@ import org.checkerframework.checker.nullness.qual.Nullable;
*/
public interface Protocol<CU extends ClientboundPacketType, CM extends ClientboundPacketType, SM extends ServerboundPacketType, SU extends ServerboundPacketType> {
/**
* Returns the server protocol version for this protocol,
* or null if not set (e.g. for base protocols).
*
* @return the server protocol version
*/
@Nullable ProtocolVersion getServerVersion();
/**
* Returns the client protocol version for this protocol,
* or null if not set (e.g. for base protocols).
*
* @return the client protocol version for this protocol
*/
@Nullable ProtocolVersion getClientVersion();
default void registerClientbound(State state, ClientboundPacketType packetType, @Nullable PacketHandler handler) {
Preconditions.checkArgument(packetType.state() == state);
registerClientbound(state, packetType.getId(), packetType.getId(), handler, false);
@@ -460,6 +478,15 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
return false;
}
/**
* Returns the index assigned to this protocol during registration.
*
* @return protocol index, or -1 if not yet registered
*/
int index();
ProtocolStorables createStorables();
/**
* Marks this protocol as dependent on another. Before being initialized, it will wait for the dependency's completion.
*
@@ -318,4 +318,12 @@ public interface ProtocolManager {
* @return whether the mappings have been loaded
*/
boolean hasLoadedMappings();
/**
* Returns the number of registered protocols.
* Used to size per-connection protocol data arrays.
*
* @return number of registered protocols
*/
int registeredProtocolCount();
}
@@ -28,5 +28,11 @@ public enum State {
STATUS,
LOGIN,
CONFIGURATION,
PLAY
PLAY;
private static final int STATES_COUNT = values().length;
public static int statesCount() {
return STATES_COUNT;
}
}
@@ -27,7 +27,7 @@ import java.util.Arrays;
import org.checkerframework.checker.nullness.qual.Nullable;
final class PacketArrayMappings implements PacketMappings {
private final PacketMapping[][] packets = new PacketMapping[State.values().length][];
private final PacketMapping[][] packets = new PacketMapping[State.statesCount()][];
@Override
public @Nullable PacketMapping mappedPacket(final State state, final int unmappedId) {
@@ -94,6 +94,8 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_21_9 = register(773, "1.21.9-1.21.10", new SubVersionRange("1.21", 9, 10));
public static final ProtocolVersion v1_21_11 = register(774, "1.21.11");
public static final ProtocolVersion v26_1 = register(775, "26.1-26.1.2", new SubVersionRange("26.1", 0, 2));
public static final ProtocolVersion v26_2 = register(776, "26.2");
public static final ProtocolVersion v26_3 = register(777, "26.3");
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
static {
@@ -87,6 +87,6 @@ public interface EntityRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter
* @return entity tracker
*/
default <E extends EntityTracker> E tracker(UserConnection connection) {
return connection.getEntityTracker(protocol().getClass());
return connection.getEntityTracker(protocol());
}
}
@@ -36,6 +36,8 @@ public interface RegistryDataRewriter {
void updateDialog(UserConnection connection, CompoundTag tag);
boolean updateBlockStateProvider(CompoundTag tag);
/**
* Sends registries that had additional entries configured, but weren't sent by the server at all
* by the time finish_configuration was sent to the client.
@@ -36,6 +36,8 @@ 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.ResolvableFloat;
import com.viaversion.viaversion.api.minecraft.ResolvableInt;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.Vector;
@@ -58,6 +60,7 @@ import com.viaversion.viaversion.api.type.types.ByteType;
import com.viaversion.viaversion.api.type.types.ComponentType;
import com.viaversion.viaversion.api.type.types.DoubleType;
import com.viaversion.viaversion.api.type.types.EmptyType;
import com.viaversion.viaversion.api.type.types.FixedLengthArrayType;
import com.viaversion.viaversion.api.type.types.FloatArrayType;
import com.viaversion.viaversion.api.type.types.FloatType;
import com.viaversion.viaversion.api.type.types.IntArrayType;
@@ -105,6 +108,7 @@ 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.LowPrecisionVectorType;
import com.viaversion.viaversion.api.type.types.math.QuaternionType;
import com.viaversion.viaversion.api.type.types.math.Vector3dType;
import com.viaversion.viaversion.api.type.types.math.Vector3fType;
import com.viaversion.viaversion.api.type.types.math.VectorType;
import com.viaversion.viaversion.api.type.types.misc.CompoundTagHolderType;
@@ -118,6 +122,8 @@ import com.viaversion.viaversion.api.type.types.misc.NamedCompoundTagType;
import com.viaversion.viaversion.api.type.types.misc.PlayerMessageSignatureType;
import com.viaversion.viaversion.api.type.types.misc.ProfileKeyType;
import com.viaversion.viaversion.api.type.types.misc.ProfilePropertyType;
import com.viaversion.viaversion.api.type.types.misc.ResolvableFloatType;
import com.viaversion.viaversion.api.type.types.misc.ResolvableIntType;
import com.viaversion.viaversion.api.type.types.misc.ResolvableProfileType;
import com.viaversion.viaversion.api.type.types.misc.SoundEventType;
import com.viaversion.viaversion.api.type.types.misc.TagKeyType;
@@ -179,10 +185,13 @@ public final class Types {
public static final Type<UUID[]> UUID_ARRAY = new ArrayType<>(Types.UUID);
public static final VarIntType VAR_INT = new VarIntType();
public static final OptionalVarIntType OPTIONAL_VAR_INT = new OptionalVarIntType();
public static final OptionalVarIntType OPTIONAL_VAR_INT = new OptionalVarIntType(); // compact
public static final OptionalType<Integer> BOOL_OPTIONAL_VAR_INT = new VarIntType.OptionalVarIntType(); // regular boolean prefixed
public static final Type<int[]> VAR_INT_ARRAY_PRIMITIVE = new VarIntArrayType();
public static final VarLongType VAR_LONG = new VarLongType();
public static final BitSetType BIT_SET = new BitSetType(); // Generic length
/* MC Types */
public static final Type<byte[]> SERVERBOUND_CUSTOM_PAYLOAD_DATA = new RemainingBytesType(Short.MAX_VALUE);
@@ -191,6 +200,9 @@ public final class Types {
public static final Type<Key[]> IDENTIFIER_ARRAY = new ArrayType<>(IDENTIFIER);
public static final Type<Key> TAG_KEY = new TagKeyType();
public static final Type<ResolvableFloat> RESOLVABLE_FLOAT = new ResolvableFloatType();
public static final Type<ResolvableInt> RESOLVABLE_INT = new ResolvableIntType();
public static final Type<BlockPosition> BLOCK_POSITION1_8 = new BlockPositionType1_8();
public static final Type<BlockPosition> OPTIONAL_POSITION1_8 = new BlockPositionType1_8.OptionalBlockPositionType();
public static final Type<BlockPosition> BLOCK_POSITION1_14 = new BlockPositionType1_14();
@@ -198,6 +210,7 @@ public final class Types {
public static final Type<EulerAngle> ROTATIONS = new EulerAngleType();
public static final Type<Vector> VECTOR = new VectorType();
public static final Type<Vector3f> VECTOR3F = new Vector3fType();
public static final Type<Vector3d> VECTOR3D = new Vector3dType();
public static final Type<Quaternion> QUATERNION = new QuaternionType();
public static final Type<Vector3d> LOW_PRECISION_VECTOR = new LowPrecisionVectorType();
@Deprecated(forRemoval = true)
@@ -214,7 +227,10 @@ public final class Types {
public static final Type<Tag[]> TAG_ARRAY = new ArrayType<>(TAG);
public static final Type<Tag> OPTIONAL_TAG = TagType.OptionalTagType.type();
public static final Type<Tag> TEXT_COMPONENT_TAG = new TextComponentTagType(); // only strictly needed for hashing
public static final Type<Tag> CUSTOM_CLICK_ACTION_TAG = new LengthPrefixedTagType(65536);
public static final FixedLengthArrayType<Tag> SIGN_TEXT = new FixedLengthArrayType<>(TAG, 4);
public static final Type<Tag[]> OPTIONAL_SIGN_TEXT = SIGN_TEXT.new OptionalFixedLengthArrayType();
public static final Type<Tag> TRUSTED_TAG = new TagType(false);
public static final Type<Tag> TRUSTED_OPTIONAL_TAG = TagType.OptionalTagType.trustedType();
@@ -279,6 +295,7 @@ public final class Types {
public static final Type<List<EntityData>> ENTITY_DATA_LIST1_9 = new EntityDataListType(ENTITY_DATA1_9);
public static final Type<List<EntityData>> ENTITY_DATA_LIST1_12 = new EntityDataListType(ENTITY_DATA1_12);
// No longer used past 1.20.2
public static final Type<Item> ITEM1_8 = new ItemType1_8();
public static final Type<Item> ITEM1_13 = new ItemType1_13();
@@ -31,7 +31,7 @@ import java.util.ArrayList;
import java.util.List;
public class ArrayType<T> extends Type<T[]> {
private final Type<T> elementType;
protected final Type<T> elementType;
private final int maxLength;
public ArrayType(Type<T> type) {
@@ -45,6 +45,12 @@ public class ArrayType<T> extends Type<T[]> {
this.maxLength = maxLength;
}
private ArrayType(Class<? super T[]> outputClass, Type<T> type, int maxLength) {
super(type.getTypeName() + " Array", outputClass);
this.elementType = type;
this.maxLength = maxLength;
}
public static Class<?> getArrayClass(Class<?> componentType) {
// Should only happen once per class init.
return Array.newInstance(componentType, 0).getClass();
@@ -60,7 +66,7 @@ public class ArrayType<T> extends Type<T[]> {
return amount < Short.MAX_VALUE ? readArray(buffer, amount) : readList(buffer, amount);
}
private T[] readArray(ByteBuf buffer, int length) {
protected T[] readArray(ByteBuf buffer, int length) {
T[] array = createArray(length);
for (int i = 0; i < length; i++) {
array[i] = elementType.read(buffer);
@@ -101,4 +107,8 @@ public class ArrayType<T> extends Type<T[]> {
}
});
}
public ArrayType<T> withMaxLength(final int maxLength) {
return new ArrayType<>(this.getOutputClass(), this.elementType, maxLength);
}
}
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.type.types;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import java.util.Arrays;
import java.util.BitSet;
@@ -39,17 +40,31 @@ public class BitSetType extends Type<BitSet> {
this.bytesLength = (int) Math.ceil(length / 8D);
}
public BitSetType() {
super(BitSet.class);
this.length = -1;
this.bytesLength = -1;
}
@Override
public BitSet read(ByteBuf buffer) {
final byte[] bytes = new byte[bytesLength];
buffer.readBytes(bytes);
return BitSet.valueOf(bytes);
if (this.length != -1) {
final byte[] bytes = new byte[bytesLength];
buffer.readBytes(bytes);
return BitSet.valueOf(bytes);
} else {
return BitSet.valueOf(Types.BYTE_ARRAY_PRIMITIVE.read(buffer));
}
}
@Override
public void write(ByteBuf buffer, BitSet object) {
Preconditions.checkArgument(object.length() <= length, "BitSet of length %s larger than max length %s", object.length(), length);
final byte[] bytes = object.toByteArray();
buffer.writeBytes(bytes.length == bytesLength ? bytes : Arrays.copyOf(bytes, bytesLength));
if (this.length != -1) {
Preconditions.checkArgument(object.length() <= length, "BitSet of length %s larger than max length %s", object.length(), length);
final byte[] bytes = object.toByteArray();
buffer.writeBytes(bytes.length == bytesLength ? bytes : Arrays.copyOf(bytes, bytesLength));
} else {
Types.BYTE_ARRAY_PRIMITIVE.write(buffer, object.toByteArray());
}
}
}
@@ -76,4 +76,16 @@ public final class EnumType extends VarIntType {
public enum Fallback {
ZERO, WRAP, CLAMP
}
public final class EnumArrayType extends VarIntArrayType {
@Override
public void write(final Ops ops, final int[] value) {
ops.writeList(list -> {
for (final int ordinal : value) {
list.write(Types.STRING, nameFromId(ordinal));
}
});
}
}
}
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public class FixedLengthArrayType<T> extends ArrayType<T> {
private final int length;
public FixedLengthArrayType(final Type<T> type, final int length) {
super(type);
this.length = length;
}
@Override
public T[] read(final ByteBuf buffer) {
return readArray(buffer, this.length);
}
@Override
public void write(final ByteBuf buffer, final T[] object) {
for (final T o : object) {
elementType.write(buffer, o);
}
}
public final class OptionalFixedLengthArrayType extends OptionalType<T[]> {
public OptionalFixedLengthArrayType() {
super(FixedLengthArrayType.this);
}
}
}
@@ -22,7 +22,6 @@
*/
package com.viaversion.viaversion.api.type.types;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
@@ -35,6 +34,7 @@ public class StringType extends Type<String> {
private static final int MAX_CHAR_UTF_8_LENGTH = Character.toString(Character.MAX_VALUE)
.getBytes(StandardCharsets.UTF_8).length;
private final int maxLength;
private final int maxByteLength;
public StringType() {
this(Short.MAX_VALUE);
@@ -43,21 +43,22 @@ public class StringType extends Type<String> {
public StringType(int maxLength) {
super(String.class);
this.maxLength = maxLength;
this.maxByteLength = maxLength * MAX_CHAR_UTF_8_LENGTH;
}
@Override
public String read(ByteBuf buffer) {
int len = Types.VAR_INT.readPrimitive(buffer);
Preconditions.checkArgument(len <= maxLength * MAX_CHAR_UTF_8_LENGTH,
"Cannot receive string longer than " + maxLength + " * " + MAX_CHAR_UTF_8_LENGTH + " bytes (got %s bytes)", len);
if (len > maxByteLength) {
throw new IllegalArgumentException("Cannot receive string longer than " + maxLength + " * " + MAX_CHAR_UTF_8_LENGTH + " bytes (got " + len + " bytes)");
}
String string = buffer.toString(buffer.readerIndex(), len, StandardCharsets.UTF_8);
buffer.skipBytes(len);
Preconditions.checkArgument(string.length() <= maxLength,
"Cannot receive string longer than " + maxLength + " characters (got %s bytes)", string.length());
if (string.length() > maxLength) {
throw new IllegalArgumentException("Cannot receive string longer than " + maxLength + " characters (got " + string.length() + ")");
}
return string;
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.type.types;
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.TypeConverter;
import com.viaversion.viaversion.api.type.Types;
@@ -108,4 +109,11 @@ public class VarIntType extends Type<Integer> implements TypeConverter<Integer>
public static int varIntLength(final int value) {
return VAR_INT_LENGTHS[Integer.numberOfLeadingZeros(value)];
}
public static final class OptionalVarIntType extends OptionalType<Integer> {
public OptionalVarIntType() {
super(Types.VAR_INT);
}
}
}
@@ -83,8 +83,11 @@ public class PaletteType1_18 extends PaletteTypeBase {
final int valuesPerLong = (char) (64 / bitsPerValue);
final int expectedLength = (type.size() + valuesPerLong - 1) / valuesPerLong;
if (values.length == expectedLength) {
CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerValue, type.size(), values,
bitsPerValue == globalPaletteBits ? palette::setIdAt : palette::setPaletteIndexAt);
if (bitsPerValue == globalPaletteBits) {
CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerValue, type.size(), values, palette::setIdAt);
} else {
palette.setPaletteIndexes(values, bitsPerValue, valuesPerLong);
}
}
}
@@ -120,11 +123,7 @@ public class PaletteType1_18 extends PaletteTypeBase {
return;
}
final long[] values = CompactArrayUtil.createCompactArrayWithPadding(
bitsPerValue,
type.size(),
bitsPerValue == globalPaletteBits ? palette::idAt : palette::paletteIndexAt
);
final long[] values = palette.createPackedValues(bitsPerValue, type.size(), bitsPerValue == globalPaletteBits);
Types.LONG_ARRAY_PRIMITIVE.write(buffer, values);
}
@@ -46,12 +46,11 @@ public final class PaletteType1_21_5 extends PaletteType1_18 {
final int expectedLength = (type.size() + valuesPerLong - 1) / valuesPerLong;
final long[] values = LongArrayType.readFixedLength(buffer, expectedLength);
if (values.length != 0) {
CompactArrayUtil.iterateCompactArrayWithPadding(
bitsPerValue,
type.size(),
values,
bitsPerValue == globalPaletteBits ? palette::setIdAt : palette::setPaletteIndexAt
);
if (bitsPerValue == globalPaletteBits) {
CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerValue, type.size(), values, palette::setIdAt);
} else {
palette.setPaletteIndexes(values, bitsPerValue, valuesPerLong);
}
}
}
@@ -61,11 +60,7 @@ public final class PaletteType1_21_5 extends PaletteType1_18 {
return;
}
final long[] values = CompactArrayUtil.createCompactArrayWithPadding(
bitsPerValue,
type.size(),
bitsPerValue == globalPaletteBits ? palette::idAt : palette::paletteIndexAt
);
final long[] values = palette.createPackedValues(bitsPerValue, type.size(), bitsPerValue == globalPaletteBits);
LongArrayType.writeFixedLength(buffer, values);
}
@@ -133,8 +133,7 @@ public class ItemType1_20_5 extends Type<Item> {
}
map.writeMap("components", components -> {
for (final Map.Entry<StructuredDataKey<?>, StructuredData<?>> entry : item.dataContainer().data().entrySet()) {
final StructuredData<?> data = entry.getValue();
for (final StructuredData<?> data : item.dataContainer().data().values()) {
String key = Key.namespaced(data.key().identifier());
if (data.isEmpty()) {
key = "!" + key;
@@ -0,0 +1,49 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.math;
import com.viaversion.viaversion.api.minecraft.Vector3d;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public class Vector3dType extends Type<Vector3d> {
public Vector3dType() {
super(Vector3d.class);
}
@Override
public Vector3d read(final ByteBuf buffer) {
final double x = buffer.readDouble();
final double y = buffer.readDouble();
final double z = buffer.readDouble();
return new Vector3d(x, y, z);
}
@Override
public void write(final ByteBuf buffer, final Vector3d object) {
buffer.writeDouble(object.x());
buffer.writeDouble(object.y());
buffer.writeDouble(object.z());
}
}
@@ -100,9 +100,9 @@ public class HolderSetType extends Type<HolderSet> {
if (registryKey instanceof final MappingData.MappingType mappingType) {
return ops.context().registryAccess().key(mappingType, id);
} else if (registryKey instanceof final RegistryValueType registryValueType) {
return Key.of(registryValueType.byId(id));
return registryValueType.byId(id);
} else {
return ops.context().registryAccess().registryKey(registryKey.key().toString(), id);
return ops.context().registryAccess().registryKey(registryKey.registry().toString(), id);
}
}
@@ -31,6 +31,10 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.io.FastByteBufInputStream;
import com.viaversion.viaversion.io.FastByteBufOutputStream;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -72,7 +76,8 @@ public class NamedCompoundTagType extends Type<CompoundTag> {
}
final TagLimiter tagLimiter = TagLimiter.create(maxBytes, TagLimiter.DEFAULT_MAX_NESTING_LEVEL);
return CompoundTag.read(new FastByteBufInputStream(buffer), tagLimiter, 0);
final DataInput in = TagType.USE_JAVA_DATA_IO ? new ByteBufInputStream(buffer) : new FastByteBufInputStream(buffer);
return CompoundTag.read(in, tagLimiter, 0);
}
public static void write(final ByteBuf buffer, final Tag tag, final @Nullable String name) throws IOException {
@@ -81,7 +86,7 @@ public class NamedCompoundTagType extends Type<CompoundTag> {
return;
}
final FastByteBufOutputStream out = new FastByteBufOutputStream(buffer);
final DataOutput out = TagType.USE_JAVA_DATA_IO ? new ByteBufOutputStream(buffer) : new FastByteBufOutputStream(buffer);
out.writeByte(tag.getTagId());
if (name != null) {
out.writeUTF(name);
@@ -163,6 +163,13 @@ public class ParticleType extends DynamicType<Particle> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Power
};
public static final DataReader<Particle> GEYSER_BASE = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Water blocks
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Burst impulse base
};
public static final DataReader<Particle> GEYSER = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Water blocks
};
public static DataReader<Particle> item(Type<Item> item) {
return (buf, particle) -> particle.add(item, item.read(buf));
@@ -259,12 +266,20 @@ public class ParticleType extends DynamicType<Particle> {
return fill1_21_4(protocol).reader("tinted_leaves", Readers.COLOR);
}
public static void fill1_21_9(final Protocol<?, ?, ?, ?> protocol) {
fill1_21_5(protocol)
public static DataFiller fill1_21_9(final Protocol<?, ?, ?, ?> protocol) {
return fill1_21_5(protocol)
.reader("dragon_breath", Readers.POWER)
.reader("effect", Readers.SPELL)
.reader("instant_effect", Readers.SPELL)
.reader("flash", Readers.COLOR);
}
public static void fill26_2(final Protocol<?, ?, ?, ?> protocol) {
fill1_21_9(protocol)
.reader("geyser", Readers.GEYSER)
.reader("geyser_base", Readers.GEYSER_BASE)
.reader("geyser_poof", Readers.GEYSER_BASE)
.reader("geyser_plume", Readers.GEYSER);
}
}
}
@@ -30,32 +30,32 @@ import com.viaversion.viaversion.util.Key;
public final class RegistryValueType extends VarIntType implements RegistryKey {
private final Key key;
private final String[] names;
private final Key registry;
private final Key[] keys;
public RegistryValueType(final Key key, final String... names) {
this.key = key;
this.names = names;
for (int i = 0; i < names.length; i++) {
names[i] = Key.namespaced(names[i]);
public RegistryValueType(final Key registry, final String... keys) {
this.registry = registry;
this.keys = new Key[keys.length];
for (int i = 0; i < keys.length; i++) {
this.keys[i] = Key.of(keys[i]);
}
}
@Override
public void write(final Ops ops, final Integer value) {
Types.IDENTIFIER.write(ops, Key.of(names[value]));
Types.IDENTIFIER.write(ops, keys[value]);
}
public String[] names() {
return names;
public Key[] keys() {
return keys;
}
public String byId(final int id) {
return names[id];
public Key byId(final int id) {
return keys[id];
}
@Override
public Key key() {
return key;
public Key registry() {
return registry;
}
}
@@ -0,0 +1,66 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.viaversion.api.minecraft.ResolvableFloat;
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;
public final class ResolvableFloatType extends Type<ResolvableFloat> {
public ResolvableFloatType() {
super(ResolvableFloat.class);
}
@Override
public ResolvableFloat read(final ByteBuf buffer) {
if (buffer.readBoolean()) {
return ResolvableFloat.of(Types.FLOAT.readPrimitive(buffer));
} else {
return ResolvableFloat.of(Types.STRING.read(buffer));
}
}
@Override
public void write(final ByteBuf buffer, final ResolvableFloat value) {
if (value.isLeft()) {
buffer.writeBoolean(true);
Types.FLOAT.writePrimitive(buffer, value.left());
} else {
buffer.writeBoolean(false);
Types.IDENTIFIER.write(buffer, Key.of(value.right()));
}
}
@Override
public void write(final Ops ops, final ResolvableFloat value) {
if (value.isLeft()) {
Types.FLOAT.write(ops, value.left());
} else {
Types.IDENTIFIER.write(ops, Key.of(value.right()));
}
}
}
@@ -0,0 +1,66 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.viaversion.api.minecraft.ResolvableInt;
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;
public final class ResolvableIntType extends Type<ResolvableInt> {
public ResolvableIntType() {
super(ResolvableInt.class);
}
@Override
public ResolvableInt read(final ByteBuf buffer) {
if (buffer.readBoolean()) {
return ResolvableInt.of(Types.INT.readPrimitive(buffer));
} else {
return ResolvableInt.of(Types.STRING.read(buffer));
}
}
@Override
public void write(final ByteBuf buffer, final ResolvableInt value) {
if (value.isLeft()) {
buffer.writeBoolean(true);
Types.INT.writePrimitive(buffer, value.left());
} else {
buffer.writeBoolean(false);
Types.IDENTIFIER.write(buffer, Key.of(value.right()));
}
}
@Override
public void write(final Ops ops, final ResolvableInt value) {
if (value.isLeft()) {
Types.INT.write(ops, value.left());
} else {
Types.IDENTIFIER.write(ops, Key.of(value.right()));
}
}
}
@@ -87,4 +87,4 @@ public final class ResolvableProfileType extends Type<ResolvableProfile> {
.writeOptional("model", Types.OPTIONAL_STRING, modelType)
);
}
};
}
@@ -42,7 +42,7 @@ public final class SynchronizedRegistryEitherType extends EitherType<Integer, St
@Override
public void write(final Ops ops, final Either<Integer, String> value) {
if (value.isLeft()) {
final Key key = ops.context().registryAccess().registryKey(this.registryKey.key().toString(), value.left());
final Key key = ops.context().registryAccess().registryKey(this.registryKey.registry().toString(), value.left());
Types.IDENTIFIER.write(ops, key);
} else {
Types.IDENTIFIER.write(ops, Key.of(value.right()));
@@ -38,7 +38,7 @@ public final class SynchronizedRegistryValueType extends VarIntType {
@Override
public void write(final Ops ops, final Integer value) {
final Key key = ops.context().registryAccess().registryKey(this.registryKey.key().toString(), value);
final Key key = ops.context().registryAccess().registryKey(this.registryKey.registry().toString(), value);
Types.IDENTIFIER.write(ops, key);
}
}
@@ -45,11 +45,14 @@ import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.io.FastByteBufInputStream;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import java.io.DataInput;
import java.io.IOException;
import java.util.Map;
public class TagType extends Type<Tag> {
static final boolean USE_JAVA_DATA_IO = Runtime.version().feature() >= 24; // Improved by a lot in JDK 24
private final int maxBytes;
public TagType() {
@@ -70,7 +73,8 @@ public class TagType extends Type<Tag> {
final TagLimiter tagLimiter = TagLimiter.create(this.maxBytes, TagLimiter.DEFAULT_MAX_NESTING_LEVEL);
try {
return TagRegistry.read(id, new FastByteBufInputStream(buffer), tagLimiter, 0);
final DataInput in = USE_JAVA_DATA_IO ? new ByteBufInputStream(buffer) : new FastByteBufInputStream(buffer);
return TagRegistry.read(id, in, tagLimiter, 0);
} catch (final IOException e) {
if (Via.getManager().isDebug()) {
throw new RuntimeException(e);
@@ -47,7 +47,7 @@ public class Types1_20_5<K extends VersionedStructuredDataKeys, E extends Abstra
public final Type<StructuredData<?>[]> structuredDataArray = new ArrayType<>(structuredData);
public final Type<Item> item = new ItemType1_20_5(structuredData);
public final Type<Item> lengthPrefixedItem = new ItemType1_20_5(lengthPrefixedStructuredData);
public final Type<Item[]> itemArray = new ArrayType<>(item);
public final ArrayType<Item> itemArray = new ArrayType<>(item);
public final Type<Item> itemCost = new ItemCostType1_20_5(structuredDataArray);
public final Type<Item> optionalItemCost = new ItemCostType1_20_5.OptionalItemCostType(itemCost);
private K structuredDataKeys;
@@ -77,7 +77,7 @@ public class Types1_20_5<K extends VersionedStructuredDataKeys, E extends Abstra
}
@Override
public Type<Item[]> itemArray() {
public ArrayType<Item> itemArray() {
return itemArray;
}
@@ -92,7 +92,7 @@ public class Types1_20_5<K extends VersionedStructuredDataKeys, E extends Abstra
}
@Override
public Type<Item[]> itemTemplateArray() {
public ArrayType<Item> itemTemplateArray() {
return itemArray;
}
@@ -34,7 +34,7 @@ public class Types26_1<K extends VersionedStructuredDataKeys, E extends Abstract
public final Type<Item> itemTemplate = new ItemTemplateType26_1(structuredData);
public final Type<Item> optionalItemTemplate = new ItemTemplateType26_1.OptionalItemTemplateType(itemTemplate);
public final Type<Item[]> itemTemplateArray = new ArrayType<>(itemTemplate);
public final ArrayType<Item> itemTemplateArray = new ArrayType<>(itemTemplate);
public Types26_1(final Function<VersionedTypesHolder, K> keysSupplier, final Function<VersionedTypesHolder, E> entityDataTypesSupplier) {
super(null, entityDataTypesSupplier);
@@ -52,7 +52,7 @@ public class Types26_1<K extends VersionedStructuredDataKeys, E extends Abstract
}
@Override
public Type<Item[]> itemTemplateArray() {
public ArrayType<Item> itemTemplateArray() {
return itemTemplateArray;
}
}
@@ -26,6 +26,8 @@ import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_11;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_2;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_5;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys26_2;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys26_3;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_20_5;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_11;
@@ -33,6 +35,7 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_9;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes26_1;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes26_3;
/**
* Holds versioned accessors for highly volatile types, specifically around items and data components.
@@ -51,4 +54,6 @@ public final class VersionedTypes {
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_9> V1_21_9 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_9::new);
public static final Types1_20_5<StructuredDataKeys1_21_11, EntityDataTypes1_21_11> V1_21_11 = new Types1_20_5<>(StructuredDataKeys1_21_11::new, EntityDataTypes1_21_11::new);
public static final Types26_1<StructuredDataKeys1_21_11, EntityDataTypes26_1> V26_1 = new Types26_1<>(StructuredDataKeys1_21_11::new, EntityDataTypes26_1::new);
public static final Types26_1<StructuredDataKeys26_2, EntityDataTypes26_1> V26_2 = new Types26_1<>(StructuredDataKeys26_2::new, EntityDataTypes26_1::new);
public static final Types26_1<StructuredDataKeys26_3, EntityDataTypes26_3> V26_3 = new Types26_1<>(StructuredDataKeys26_3::new, EntityDataTypes26_3::new);
}
@@ -46,7 +46,7 @@ public interface VersionedTypesHolder {
*/
Type<Item> item();
Type<Item[]> itemArray();
ArrayType<Item> itemArray();
/**
* Returns the unmapped item stack template type, used for certain recipes/templates in 26.1+.
@@ -57,7 +57,7 @@ public interface VersionedTypesHolder {
Type<Item> optionalItemTemplate();
Type<Item[]> itemTemplateArray();
ArrayType<Item> itemTemplateArray();
/**
* Returns the unmapped item cost type, used in merchant offers.
@@ -88,6 +88,67 @@ public final class CompactArrayUtil {
}
}
// ------------------------------------------------------
// Utility methods for packing/unpacking raw data at once and without indirection.
// They go value-first instead of cell-first
public static void packWithPadding(final byte[] values, final long[] out, final int bitsPerEntry) {
final long maxEntryValue = (1L << bitsPerEntry) - 1;
long cell = 0L;
int bitIndex = 0;
int outIndex = 0;
for (final byte value : values) {
cell |= (value & maxEntryValue) << bitIndex;
bitIndex += bitsPerEntry;
if (bitIndex + bitsPerEntry > 64) {
out[outIndex++] = cell;
cell = 0L;
bitIndex = 0;
}
}
if (bitIndex != 0) {
out[outIndex] = cell;
}
}
public static void packWithPadding(final short[] values, final long[] out, final int bitsPerEntry) {
final long maxEntryValue = (1L << bitsPerEntry) - 1;
long cell = 0L;
int bitIndex = 0;
int outIndex = 0;
for (final short value : values) {
cell |= (value & maxEntryValue) << bitIndex;
bitIndex += bitsPerEntry;
if (bitIndex + bitsPerEntry > 64) {
out[outIndex++] = cell;
cell = 0L;
bitIndex = 0;
}
}
if (bitIndex != 0) {
out[outIndex] = cell;
}
}
public static void unpackWithPadding(final long[] data, final byte[] out, final int bitsPerEntry) {
final long maxEntryValue = (1L << bitsPerEntry) - 1;
final int valuesPerLong = 64 / bitsPerEntry;
long cell = 0L;
int cellIndex = 0;
int remaining = 0;
for (int i = 0; i < out.length; i++) {
if (remaining == 0) {
cell = data[cellIndex++];
remaining = valuesPerLong;
}
out[i] = (byte) (cell & maxEntryValue);
cell >>>= bitsPerEntry;
remaining--;
}
}
// ------------------------------------------------------
public static long[] createCompactArray(int bitsPerEntry, int entries, IntToLongFunction valueGetter) {
long maxEntryValue = (1L << bitsPerEntry) - 1;
long[] data = new long[(int) Math.ceil(entries * bitsPerEntry / 64.0)];
@@ -0,0 +1,91 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.util;
final class CustomKey extends Key {
private final String original;
private final String namespace;
private final String path;
/**
* Non-Minecraft key.
*
* @param original full key including the ':' separator
* @param namespace non-Minecraft namespace
* @param path path
*/
CustomKey(final String original, final String namespace, final String path) {
if (!MinecraftKey.isValidNamespace(namespace)) {
throw new IllegalArgumentException("Invalid namespace: " + namespace);
}
if (!MinecraftKey.isValidPath(path)) {
throw new IllegalArgumentException("Invalid path: " + path);
}
this.original = original;
this.namespace = namespace;
this.path = path;
}
@Override
public String namespace() {
return namespace;
}
@Override
public String path() {
return path;
}
@Override
public String original() {
return original;
}
@Override
public String minimized() {
return this.original;
}
@Override
public boolean hasMinecraftNamespace() {
return false;
}
@Override
public final boolean equals(final Object o) {
if (this == o) return true;
if (!(o instanceof final CustomKey key)) return false;
return this.original.equals(key.original);
}
@Override
public int hashCode() {
return this.original.hashCode();
}
@Override
public String toString() {
return this.original;
}
}
@@ -29,11 +29,11 @@ public class EitherImpl<X, Y> implements Either<X, Y> {
private final X left;
private final Y right;
protected EitherImpl(final X left, final Y value) {
protected EitherImpl(final X left, final Y right) {
this.left = left;
this.right = value;
Preconditions.checkArgument(left == null || value == null, "Either.left and Either.right are both present");
Preconditions.checkArgument(left != null || value != null, "Either.left and Either.right are both null");
this.right = right;
Preconditions.checkArgument(left == null || right == null, "Either.left and Either.right are both present");
Preconditions.checkArgument(left != null || right != null, "Either.left and Either.right are both null");
}
@Override
@@ -71,6 +71,7 @@ public final class EntityTypeUtil {
final int id = mappings.mappedId(type.identifier());
Preconditions.checkArgument(id != -1, "Entity type %s has no id", type.identifier());
Preconditions.checkArgument(id < typesToFill.length, "Types array too small (missing enum entry?). Tried setting id %s into array of size %s", id, typesToFill.length);
idSetter.setId(type, id);
typesToFill[id] = type;
}
Loaded 100 of 386 files, more files were not shown because too many files have changed in this diff. Show more