Compare commits

...
71 Commits
Author SHA1 Message Date
Nassim Jahnke 1d566100fb 5.7.0 Release 2025-12-29 12:46:28 +01:00
Nassim Jahnke 212cca1d65 Add null check to uuid in Velocity kick method 2025-12-27 21:45:35 +01:00
Nassim Jahnke 1f40811877 Track merchant offer items for hashing 2025-12-27 12:48:32 +01:00
Nassim Jahnke f45d2f8567 Fix UUID hashing
Fixes #4727
2025-12-26 20:24:34 +01:00
Nassim Jahnke 9b19bfc6df Move logging config options to new section and update defaults 2025-12-25 21:37:43 +01:00
FlorianMichael c2a8400751 Update block connection mapping file (#4759) 2025-12-25 09:11:02 +01:00
David Lüdtke 3cbfbd3b9f Fix world border lerp size set in ticks instead of millis (#4755) (#4757) 2025-12-23 09:54:43 +01:00
Nassim Jahnke ea6808b697 Update sprite atlas in 1.21.9->1.21.11
Fixes #4734
2025-12-21 18:00:08 +01:00
Nassim Jahnke 85f868c37e Put set_objective and set_score packets through component rewriter 2025-12-21 15:39:35 +01:00
Rocco f6e036df76 Restore 1.8 hitbox margin for 1.21.11+ clients (#4733) 2025-12-21 10:52:34 +01:00
FlorianMichael 55ed56668e Fix alignment of pre/post packet debug (#4754) 2025-12-20 20:42:35 +01:00
FlorianMichael 705509489a Support packet types with different states in debug handling (#4751) 2025-12-20 16:33:57 +01:00
Nassim Jahnke 57a42e1156 Handle block_state_property enchantment terms
Fixes #4750
2025-12-20 11:54:41 +01:00
FlorianMichael 7181f485eb Fix pps sub command not working (#4749) 2025-12-19 09:43:26 +01:00
Kichura 5f3dc1be53 [ci skip] Error on absent artifacts, set CI timeout to 30 mins (#4745) 2025-12-19 09:42:26 +01:00
booky 4f06afc2bd Cancel serverbound stab packets (#4744) 2025-12-15 16:05:10 +01:00
RK_01 c267a754e7 Always send extra attributes in 1.20.5 (#4742) 2025-12-15 09:27:42 +01:00
RK_01 7657a59b07 Add step_height and version dependent interaction range 1.20.5 attributes (#4741) 2025-12-14 22:15:03 +01:00
Nassim Jahnke f95ec49d6f Properly pass on packet type in PacketWrapper.create 2025-12-14 20:20:12 +01:00
FlorianMichael 1be574bc21 Handle lit_furnace as furnace in 1.8->1.9 (#4739) 2025-12-14 13:48:22 +01:00
Nassim Jahnke 0640e2468c Don't auto-split long lines when dumping config
Fixes #4740
2025-12-14 10:43:18 +01:00
FlorianMichael 2adfee3b60 [ci skip] Include the newest ViaProxy version from 3.0.0 to 4.0.0 (#4738) 2025-12-13 19:59:00 +01:00
riku6460 b65d7af793 Fix default dripstone particle in 1.21.9->1.21.11 (#4735) 2025-12-13 11:18:06 +01:00
Nassim Jahnke 8f7fd34fa4 Add max-error-length config option 2025-12-13 11:17:41 +01:00
Nassim Jahnke 5bf0e9b22a Bump version to 5.6.1-SNAPSHOT 2025-12-13 10:49:22 +01:00
Nassim Jahnke 808605e06a 5.6.0 Release 2025-12-12 15:59:10 +01:00
Nassim Jahnke fb387bf9c5 Add missing particle readers 2025-12-12 15:59:10 +01:00
Nassim Jahnke a3ff540cb3 Remove empty mapped data component types in tooltip display 2025-12-12 15:59:10 +01:00
Nassim Jahnke 1cafd08326 Fix kinetic weapon condition reading 2025-12-12 15:59:10 +01:00
Nassim Jahnke d5458145a0 Remove snapshot bit 2025-12-12 15:59:10 +01:00
Nassim Jahnke 316e6ac1ba 1.21.11-rc3 2025-12-12 15:59:10 +01:00
Nassim Jahnke 6b66611810 Add new dimension and biome fields to nether and end 2025-12-12 15:59:09 +01:00
Nassim Jahnke 89176f4f11 1.21.11-rc2 2025-12-12 15:59:09 +01:00
Nassim Jahnke 0808c52317 1.21.11-rc1 2025-12-12 15:59:09 +01:00
Nassim Jahnke e93199fcfe 1.21.11-pre5 2025-12-12 15:59:09 +01:00
Nassim Jahnke 04e5dfdc4e 1.21.11-pre4 2025-12-12 15:59:09 +01:00
Nassim Jahnke cba704fe3d 1.21.11-pre3 2025-12-12 15:59:09 +01:00
Nassim Jahnke f2ef57673c 1.21.11-pre2 2025-12-12 15:59:09 +01:00
Nassim Jahnke 6f7e24ac9e 1.21.11-pre1 2025-12-12 15:59:08 +01:00
Nassim Jahnke 54bd8fb5f7 25w46a 2025-12-12 15:59:08 +01:00
Nassim Jahnke 22c0ddc5de Fix avatar arm type 2025-12-12 15:59:08 +01:00
Nassim Jahnke 43bb38f4cf Rename RESOURCE_LOCATION Type to IDENTIFIER
Includes method and local variable names of cross-version code. Key stays unchanged, as it's quite clear what it represents (and is shorter)
2025-12-12 15:59:08 +01:00
Nassim Jahnke b9f110219e 25w45a 2025-12-12 15:59:08 +01:00
Nassim Jahnke 4fc70ad603 25w44a 2025-12-12 15:59:08 +01:00
Nassim Jahnke 8c33faa4f5 Move around environment attributes 2025-12-12 15:59:07 +01:00
Nassim Jahnke 6375718b10 25w43a 2025-12-12 15:59:07 +01:00
Nassim Jahnke e51ea0eeb6 25w42a 2025-12-12 15:59:07 +01:00
Nassim Jahnke 5ce209e0e9 25w41a 2025-12-12 15:59:07 +01:00
github-actions[bot]andgradle-update-robot d232242997 Update Gradle Wrapper from 9.2.0 to 9.2.1 (#4718)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2025-12-12 15:58:01 +01:00
Kichura 3e6d17274d Update workflow configs (#4725) 2025-12-06 20:33:13 +01:00
dependabot[bot] 4350c7f614 Bump actions/checkout from 5 to 6 (#4721)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 21:58:40 +01:00
Nassim Jahnke aea0c6c76f Put set_player_team packets through component rewriter 2025-11-23 19:25:22 +01:00
Lumine1909 5b8b8f5e10 Fix 1.21.9->1.21.7 item entity_data id mapping (#4716) 2025-11-23 12:11:12 +01:00
Nassim Jahnke b46f771103 [ci skip] Update issue template
The "Expected Behavior" field is almost always unneeded and has only really been filled with "not get kicked" or the alike, so this simplifies reporting
2025-11-18 19:48:42 +01:00
Nassim Jahnke fb8430518b Implement painting variant key getter
Fixes #4705
2025-11-03 18:55:52 +01:00
github-actions[bot]andgradle-update-robot 9a686ee527 Update Gradle Wrapper from 9.1.0 to 9.2.0 (#4704)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2025-11-03 16:52:06 +01:00
Nassim Jahnke cb3dd89c78 Implement more data hashing 2025-11-02 09:20:43 +01:00
FlorianMichael 5689389f3a Implement wolf sound & chicken variants hashing (#4698) 2025-11-01 22:20:36 +01:00
FlorianMichael ed07809c84 Fix typo in entity data types (#4697) 2025-10-30 16:57:31 +01:00
dependabot[bot] 081fc0db41 [ci skip] Bump actions/upload-artifact from 4 to 5 (#4695)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-27 21:10:36 +01:00
Nassim Jahnke 74d60c2126 Implement simple variants and instrument hashing 2025-10-20 15:45:58 +02:00
Nassim Jahnke d45f2cdd64 Implement more item data hashing 2025-10-20 13:58:15 +02:00
FlorianMichael 09898c8c1e Implement PROVIDES_TRIM_MATERIAL & TRIM item component hashing (#4691) 2025-10-20 11:38:48 +02:00
Nassim Jahnke 131660d89f Handle entity type changes in enchantment predicates
Fixes #4692
2025-10-20 11:26:33 +02:00
FlorianMichael 1c066873fd Fix InformativeException message (#4690) 2025-10-17 22:38:51 +02:00
Nassim Jahnke 8429689837 Fix test 2025-10-14 17:41:51 +02:00
FlorianMichael 19c8a1ce1b Remove deprecation on PacketTracker#getIntervalPackets & PacketTracker#setIntervalPackets (#4687) 2025-10-14 17:40:27 +02:00
木葉 Scarlet c6fdaf507f Improve mapping loader executor (#4660)
This should result in less thread spam on machines that are fast enough anyways
2025-10-14 17:40:08 +02:00
FlorianMichael 7b097b3e54 Strip trailing on chat messages in 1.10->1.11 (#4686)
Fixes https://github.com/ViaVersion/ViaVersion/issues/4683
2025-10-14 17:39:14 +02:00
Nassim Jahnke c14928defa Implement more item data hashing 2025-10-14 17:36:19 +02:00
Nassim Jahnke 6b4e74abe9 Bump version to 5.5.2-SNAPSHOT 2025-10-14 16:17:29 +02:00
169 changed files with 3256 additions and 562 deletions

No files matched your search

+2 -11
View File
@@ -50,21 +50,12 @@ body:
label: Steps to Reproduce
description: |
List the steps on how we can reproduce the issue. Make sure we can easily understand what you mean with each step.
**Please always include the client version(s) with which the issue happens. Ideally also try to find out, from what specific version onward/in what version range the issue happens.**
placeholder: |
Example:
1. Login with a 1.21.3 client
2. Place a sign
3. The sign text is displayed wrong
validations:
required: true
- type: textarea
attributes:
label: Expected Behavior
description: |
Describe what exactly you expected to happen.
placeholder: |
Example: "Placed sign text should not disappear."
3. The sign text disappears
validations:
required: true
+3 -1
View File
@@ -1,6 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
cooldown:
default-days: 7
directory: "/"
schedule:
interval: "weekly"
interval: "monthly"
+10 -9
View File
@@ -1,23 +1,23 @@
name: Java CI with Gradle
on: [push, pull_request, workflow_dispatch]
name: Build
on: [pull_request, push, workflow_dispatch]
permissions:
contents: read
jobs:
build:
# Only run on PRs if the source branch is on a different repo. We do not need to run everything twice.
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@v5
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v5
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # 5.0.0
- name: Set up JDK 17
uses: actions/setup-java@v5
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # 5.0.0
with:
distribution: 'temurin'
java-version: 17
@@ -27,7 +27,8 @@ jobs:
- name: Upload Artifacts to GitHub
# Only upload on the preview repository as there is no CI job for it.
if: ${{ github.repository == 'ViaVersion/ViaVersionDev' && github.ref_name == 'preview' }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # 5.0.0
with:
name: Artifacts
path: build/libs/
if-no-files-found: error
+8 -4
View File
@@ -6,24 +6,28 @@ on:
- dev
workflow_dispatch:
permissions:
contents: read
jobs:
publish:
if: github.repository_owner == 'ViaVersion'
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@v5
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v5
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # 5.0.0
- name: Set up JDK 17
uses: actions/setup-java@v5
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # 5.0.0
with:
distribution: 'temurin'
java-version: 17
check-latest: true
- name: Build
- name: Build with Gradle
run: ./gradlew build
- name: Publish to Hangar
env:
+8 -2
View File
@@ -4,13 +4,19 @@ on:
schedule:
- cron: "0 0 * * 0"
permissions:
contents: write
pull-requests: write
jobs:
update-gradle-wrapper:
runs-on: ubuntu-24.04
timeout-minutes: 30
steps:
- name: Checkout Repository
uses: actions/checkout@v5
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # 6.0.0
with:
fetch-depth: 0
persist-credentials: false
- name: Update Gradle Wrapper
uses: gradle-update/update-gradle-wrapper-action@v2
uses: gradle-update/update-gradle-wrapper-action@512b1875f3b6270828abfe77b247d5895a2da1e5 # 2.1.0
@@ -27,6 +27,7 @@ import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.WorldIdentifiers;
import com.viaversion.viaversion.api.protocol.version.BlockedProtocolVersions;
import java.util.concurrent.TimeUnit;
public interface ViaVersionConfig extends Config {
@@ -67,11 +68,16 @@ public interface ViaVersionConfig extends Config {
boolean isShowNewDeathMessages();
/**
* Get if entity data errors will be suppressed
* Get if entity data errors will be logged
*
* @return true if entity data errors suppression is enabled
* @return true if entity data error logging is enabled
*/
boolean isSuppressMetadataErrors();
boolean logEntityDataErrors();
@Deprecated(forRemoval = true)
default boolean isSuppressMetadataErrors() {
return !logEntityDataErrors();
}
/**
* Get if blocking in 1.9 &amp; 1.10 appears as a player holding a shield
@@ -148,7 +154,9 @@ public interface ViaVersionConfig extends Config {
* @return The number of packets a client can send per second.
*/
@Deprecated(forRemoval = true)
int getMaxPPS();
default int getMaxPPS() {
return getPacketTrackerConfig().maxRate();
}
/**
* Get the kick message sent if the user hits the max packets per second.
@@ -156,7 +164,9 @@ public interface ViaVersionConfig extends Config {
* @return Kick message, with colour codes using '&amp;amp;'
*/
@Deprecated(forRemoval = true)
String getMaxPPSKickMessage();
default String getMaxPPSKickMessage() {
return getPacketTrackerConfig().maxRateKickMessage();
}
/**
* The time in seconds that should be tracked for warnings
@@ -164,7 +174,9 @@ public interface ViaVersionConfig extends Config {
* @return Time in seconds that should be tracked for warnings
*/
@Deprecated(forRemoval = true)
int getTrackingPeriod();
default int getTrackingPeriod() {
return (int) TimeUnit.NANOSECONDS.toSeconds(getPacketTrackerConfig().trackingPeriodNanos());
}
/**
* The number of packets per second to count as a warning
@@ -172,7 +184,9 @@ public interface ViaVersionConfig extends Config {
* @return The number of packets per second to count as a warning.
*/
@Deprecated(forRemoval = true)
int getWarningPPS();
default int getWarningPPS() {
return getPacketTrackerConfig().warningRate();
}
/**
* Get the maximum number of warnings the client can have in the interval
@@ -180,7 +194,9 @@ public interface ViaVersionConfig extends Config {
* @return The number of packets a client can send per second.
*/
@Deprecated(forRemoval = true)
int getMaxWarnings();
default int getMaxWarnings() {
return getPacketTrackerConfig().maxWarnings();
}
/**
* Get the kick message sent if the user goes over the warnings in the interval
@@ -188,7 +204,9 @@ public interface ViaVersionConfig extends Config {
* @return Kick message, with colour codes using '&amp;amp;'
*/
@Deprecated(forRemoval = true)
String getMaxWarningsKickMessage();
default String getMaxWarningsKickMessage() {
return getPacketTrackerConfig().warningKickMessage();
}
RateLimitConfig getPacketTrackerConfig();
@@ -284,18 +302,28 @@ public interface ViaVersionConfig extends Config {
String getReloadDisconnectMsg();
/**
* Should we hide errors that occur when trying to convert block and item data over versions?
* Should we log warnings on issues when trying to convert data over versions?
*
* @return true if enabled
*/
boolean isSuppressConversionWarnings();
boolean logOtherConversionWarnings();
/**
* Should we hide errors that occur when trying to convert text components?
* Should we log errors that occur when trying to convert text components?
*
* @return true if enabled
*/
boolean isSuppressTextComponentConversionWarnings();
boolean logTextComponentConversionErrors();
@Deprecated(forRemoval = true)
default boolean isSuppressConversionWarnings() {
return !logOtherConversionWarnings();
}
@Deprecated(forRemoval = true)
default boolean isSuppressTextComponentConversionWarnings() {
return !logTextComponentConversionErrors();
}
/**
* Should we disable the 1.13 auto-complete feature to stop spam kicks? (for any server lower than 1.13)
@@ -498,4 +526,19 @@ public interface ViaVersionConfig extends Config {
* @return true if enabled
*/
boolean cancelSwingInInventory();
/**
* Returns the max length of error messages. Longer messages will be truncated unless in debug mode.
*
* @return the max length of error messages
*/
int maxErrorLength();
/**
* If enabled, 1.21.11+ clients on 1.8 (or older) servers will get wider entity hitboxes,
* but only when attacking with an item.
*
* @return true if enabled
*/
boolean use1_8HitboxMargin();
}
@@ -22,10 +22,13 @@
*/
package com.viaversion.viaversion.api.data;
import com.viaversion.viaversion.api.minecraft.RegistryKey;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.TagData;
import com.viaversion.viaversion.util.Key;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.List;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface MappingData {
@@ -172,8 +175,9 @@ public interface MappingData {
default @Nullable FullMappings getFullMappings(final MappingType mappingType) {
return switch (mappingType) {
case ITEM -> getFullItemMappings();
case BLOCK -> getFullBlockMappings();
case SOUND -> getFullSoundMappings();
case ENTITY -> getEntityMappings();
case ENTITY_TYPE -> getEntityMappings();
};
}
@@ -187,7 +191,12 @@ public interface MappingData {
/**
* Type of mappings. Currently only relevant for ops writing of generic holder classes and expanded when needed.
*/
enum MappingType {
ITEM, SOUND, ENTITY
enum MappingType implements RegistryKey {
ITEM, BLOCK, SOUND, ENTITY_TYPE;
@Override
public Key key() {
return Key.of(name().toLowerCase(Locale.ROOT));
}
}
}
@@ -172,7 +172,7 @@ public class MappingDataBase implements MappingData {
}
private void loadTags(final RegistryType type, final CompoundTag data) {
final CompoundTag tag = data.getCompoundTag(type.resourceLocation());
final CompoundTag tag = data.getCompoundTag(type.identifier());
if (tag == null) {
return;
}
@@ -354,7 +354,7 @@ public class MappingDataBase implements MappingData {
*/
protected int checkValidity(final int id, final int mappedId, final String type) {
if (mappedId == -1) {
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getConfig().logOtherConversionWarnings()) {
getLogger().warning(String.format("Missing %s %s for %s %s %d", mappedVersion, type, unmappedVersion, type, id));
}
return 0;
@@ -22,8 +22,6 @@
*/
package com.viaversion.viaversion.api.data.item;
import java.util.List;
/**
* Used for converting items to hashed items and caching them for later use during serverbound packets.
* <p>
@@ -41,11 +39,4 @@ public interface ItemHasher {
boolean isProcessingClientboundInventoryPacket();
void setProcessingClientboundInventoryPacket(boolean processingClientboundInventoryPacket);
/**
* Sets the enchantment registry for this connection.
*
* @param enchantments list of enchantment identifiers
*/
void setEnchantments(List<String> enchantments);
}
@@ -52,7 +52,7 @@ public interface DebugHandler {
void addPacketTypeNameToLog(String packetTypeName);
/**
* Adds a packet id to the list of packet types to log.
* Adds a packet type to the list of packet types to log.
* Packets will be checked on each protocol transformer, so this is best used on single protocol pipes.
*
* @param packetType packet type
@@ -66,6 +66,13 @@ public interface DebugHandler {
*/
boolean removePacketTypeNameToLog(String packetTypeName);
/**
* Removes a packet type from the list of packet types to log.
*
* @param packetType Packet type to remove
*/
boolean removePacketTypeToLog(PacketType packetType);
/**
* Resets packet type filters.
*/
@@ -121,7 +128,12 @@ public interface DebugHandler {
*/
boolean shouldLog(PacketWrapper wrapper, Direction direction);
default void enableAndLogIds(final PacketType... packetTypes) {
/**
* Enables debug mode and adds the given packet types to the log list.
*
* @param packetTypes packet types to log
*/
default void enableAndLogTypes(final PacketType... packetTypes) {
setEnabled(true);
for (final PacketType packetType : packetTypes) {
addPacketTypeToLog(packetType);
@@ -135,7 +147,7 @@ public interface DebugHandler {
* @param t thrown exception
*/
default void error(final String error, final Throwable t) {
if (!Via.getConfig().isSuppressConversionWarnings() || enabled()) {
if (Via.getConfig().logOtherConversionWarnings() || enabled()) {
Via.getPlatform().getLogger().log(Level.SEVERE, error, t);
}
}
@@ -23,8 +23,10 @@
package com.viaversion.viaversion.api.minecraft;
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;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -69,5 +71,21 @@ public record PaintingVariant(int width, int height, String assetId, @Nullable T
Types.OPTIONAL_TAG.write(buffer, variant.title());
Types.OPTIONAL_TAG.write(buffer, variant.author());
}
@Override
public void writeDirect(final Ops ops, final PaintingVariant value) {
// Unused, cannot be direct despite having a direct network codec
ops.writeMap(map -> map
.write("width", Types.INT, value.width())
.write("height", Types.INT, value.height())
.write("asset_id", Types.IDENTIFIER, Key.of(value.assetId()))
.writeOptional("title", Types.TAG, value.title())
.writeOptional("author", Types.TAG, value.author()));
}
@Override
protected Key identifier(final Ops ops, final int id) {
return ops.context().registryAccess().registryKey("painting_variant", id);
}
};
}
@@ -0,0 +1,42 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.api.data.MappingData.MappingType;
import com.viaversion.viaversion.util.Key;
/**
* Holds a key for a registry.
* Depending on the context, the key may be used to get registry entries from either synchronized or hardcoded registries.
*
* @see MappingType
* @see #of(String)
*/
public interface RegistryKey {
Key key();
static RegistryKey of(final String key) {
return new SimpleRegistryKey(Key.of(key));
}
}
@@ -22,11 +22,12 @@
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.util.Key;
import java.util.HashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
public enum RegistryType {
public enum RegistryType implements RegistryKey {
BLOCK("block"),
ITEM("item"),
@@ -40,7 +41,7 @@ public enum RegistryType {
static {
for (RegistryType type : getValues()) {
MAP.put(type.resourceLocation, type);
MAP.put(type.identifier, type);
}
}
@@ -48,17 +49,22 @@ public enum RegistryType {
return VALUES;
}
public static @Nullable RegistryType getByKey(String resourceKey) {
return MAP.get(resourceKey);
public static @Nullable RegistryType getByKey(String identifier) {
return MAP.get(identifier);
}
private final String resourceLocation;
private final String identifier;
RegistryType(final String resourceLocation) {
this.resourceLocation = resourceLocation;
RegistryType(final String identifier) {
this.identifier = identifier;
}
public String resourceLocation() {
return resourceLocation;
public String identifier() {
return identifier;
}
@Override
public Key key() {
return Key.of(identifier);
}
}
@@ -0,0 +1,33 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.util.Key;
record SimpleRegistryKey(Key key) implements RegistryKey {
@Override
public String toString() {
return key.toString();
}
}
@@ -24,8 +24,8 @@ package com.viaversion.viaversion.api.minecraft.codec;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.util.Key;
import java.util.List;
public interface CodecContext {
@@ -39,8 +39,6 @@ public interface CodecContext {
Key item(int id);
Key enchantment(int id);
Key attributeModifier(int id);
Key dataComponentType(int id);
@@ -51,14 +49,37 @@ public interface CodecContext {
Key sound(int id);
/**
* Returns the key for a stored mapping type and its numeric id.
*
* @param mappingType mapping type
* @param id numeric id
* @return the key
*/
Key key(MappingData.MappingType mappingType, int id);
/**
* Returns the numeric id for a stored mapping type and its identifier.
*
* @param mappingType mapping type
* @param identifier identifier
* @return the numeric id, or -1 if not found
*/
int id(MappingData.MappingType mappingType, String identifier);
static RegistryAccess of(final List<String> enchantments, final MappingData mappingData) {
return new RegistryAccessImpl(enchantments, mappingData);
static RegistryAccess of(final Protocol<?, ?, ?, ?> protocol) {
return new RegistryAccessImpl(protocol);
}
/**
* Returns the key for a client-synchronized registry element.
*
* @param registry registry key
* @param id numeric id
* @return the key
*/
Key registryKey(String registry, int id);
RegistryAccess withMapped(boolean mapped);
}
}
@@ -22,26 +22,29 @@
*/
package com.viaversion.viaversion.api.minecraft.codec;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.util.Key;
import java.util.List;
import com.viaversion.viaversion.util.KeyMappings;
import org.checkerframework.checker.nullness.qual.Nullable;
final class RegistryAccessImpl implements CodecContext.RegistryAccess {
private final List<String> enchantments;
private final RegistryDataRewriter registryDataRewriter;
private final MappingData mappingData;
private final boolean mapped;
RegistryAccessImpl(final List<String> enchantments, final MappingData mappingData) {
this.enchantments = enchantments;
this.mappingData = mappingData;
RegistryAccessImpl(final Protocol<?, ?, ?, ?> protocol) {
this.mappingData = protocol.getMappingData();
this.registryDataRewriter = protocol.getRegistryDataRewriter();
this.mapped = false;
}
private RegistryAccessImpl(final List<String> enchantments, final MappingData mappingData, final boolean mapped) {
this.enchantments = enchantments;
private RegistryAccessImpl(final MappingData mappingData, final RegistryDataRewriter registryDataRewriter, final boolean mapped) {
this.mappingData = mappingData;
this.registryDataRewriter = registryDataRewriter;
this.mapped = mapped;
}
@@ -50,12 +53,6 @@ final class RegistryAccessImpl implements CodecContext.RegistryAccess {
return key(mappingData.getFullItemMappings(), id);
}
@Override
public Key enchantment(final int id) {
final String identifier = id >= 0 && id < this.enchantments.size() ? this.enchantments.get(id) : null;
return key(identifier, id);
}
@Override
public Key attributeModifier(final int id) {
return key(mappingData.getAttributeMappings(), id);
@@ -92,6 +89,14 @@ final class RegistryAccessImpl implements CodecContext.RegistryAccess {
return mapped ? mappings.mappedId(identifier) : mappings.id(identifier);
}
@Override
public Key registryKey(final String registry, final int id) {
final KeyMappings mappings = registryDataRewriter.getMappings(registry);
Preconditions.checkNotNull(mappings, "No registry mappings for registry: " + registry);
final String identifier = id >= 0 && id < mappings.size() ? mappings.idToKey(id) : null;
return key(identifier, id);
}
private Key key(final FullMappings mappings, final int id) {
final String identifier = mapped ? mappings.mappedIdentifier(id) : mappings.identifier(id);
return key(identifier, id);
@@ -103,6 +108,6 @@ final class RegistryAccessImpl implements CodecContext.RegistryAccess {
@Override
public CodecContext.RegistryAccess withMapped(final boolean mapped) {
return this.mapped == mapped ? this : new RegistryAccessImpl(this.enchantments, this.mappingData, mapped);
return this.mapped == mapped ? this : new RegistryAccessImpl(this.mappingData, this.registryDataRewriter, mapped);
}
}
@@ -28,13 +28,16 @@ import com.viaversion.viaversion.api.minecraft.EitherHolder;
import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.RegistryKey;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_20_5;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_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.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrim;
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;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer;
@@ -45,11 +48,13 @@ import com.viaversion.viaversion.api.minecraft.item.data.BlocksAttacks;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.CustomModelData1_21_4;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant;
import com.viaversion.viaversion.api.minecraft.item.data.DamageType;
import com.viaversion.viaversion.api.minecraft.item.data.DeathProtection;
import com.viaversion.viaversion.api.minecraft.item.data.DebugStickState;
import com.viaversion.viaversion.api.minecraft.item.data.DyedColor;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantable;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.minecraft.item.data.EntityData;
import com.viaversion.viaversion.api.minecraft.item.data.EnumTypes;
import com.viaversion.viaversion.api.minecraft.item.data.Equippable;
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
@@ -60,26 +65,30 @@ import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.ItemModel;
import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable;
import com.viaversion.viaversion.api.minecraft.item.data.KineticWeapon;
import com.viaversion.viaversion.api.minecraft.item.data.LockCode;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.PiercingWeapon;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
import com.viaversion.viaversion.api.minecraft.item.data.ProvidesTrimMaterial;
import com.viaversion.viaversion.api.minecraft.item.data.Repairable;
import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect;
import com.viaversion.viaversion.api.minecraft.item.data.SwingAnimation;
import com.viaversion.viaversion.api.minecraft.item.data.ToolProperties;
import com.viaversion.viaversion.api.minecraft.item.data.TooltipDisplay;
import com.viaversion.viaversion.api.minecraft.item.data.TropicalFishPattern;
import com.viaversion.viaversion.api.minecraft.item.data.EntityData;
import com.viaversion.viaversion.api.minecraft.item.data.Unbreakable;
import com.viaversion.viaversion.api.minecraft.item.data.UseCooldown;
import com.viaversion.viaversion.api.minecraft.item.data.UseEffects;
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;
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.EitherType;
import com.viaversion.viaversion.api.type.types.misc.SynchronizedRegistryEitherType;
import com.viaversion.viaversion.api.type.types.misc.SynchronizedRegistryValueType;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.util.Either;
import com.viaversion.viaversion.util.Key;
@@ -100,8 +109,11 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Integer> MAX_DAMAGE = new StructuredDataKey<>("max_damage", Types.VAR_INT);
public static final StructuredDataKey<Integer> DAMAGE = new StructuredDataKey<>("damage", Types.VAR_INT);
public static final StructuredDataKey<Unbreakable> UNBREAKABLE1_20_5 = new StructuredDataKey<>("unbreakable", Unbreakable.TYPE);
public static final StructuredDataKey<UseEffects> USE_EFFECTS = new StructuredDataKey<>("use_effects", UseEffects.TYPE);
public static final StructuredDataKey<Unit> UNBREAKABLE1_21_5 = new StructuredDataKey<>("unbreakable", Types.EMPTY);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TEXT_COMPONENT_TAG);
public static final StructuredDataKey<Float> MINIMUM_ATTACK_CHARGE = new StructuredDataKey<>("minimum_attack_charge", Types.FLOAT);
public static final StructuredDataKey<DamageType> DAMAGE_TYPE = new StructuredDataKey<>("damage_type", DamageType.TYPE);
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Types.TEXT_COMPONENT_TAG);
public static final StructuredDataKey<ItemModel> ITEM_MODEL = new StructuredDataKey<>("item_model", ItemModel.TYPE);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", new ArrayType<>(Types.TEXT_COMPONENT_TAG, 256));
@@ -134,15 +146,19 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<ToolProperties> TOOL1_20_5 = new StructuredDataKey<>("tool", ToolProperties.TYPE1_20_5);
public static final StructuredDataKey<ToolProperties> TOOL1_21_5 = new StructuredDataKey<>("tool", ToolProperties.TYPE1_21_5);
public static final StructuredDataKey<Weapon> WEAPON = new StructuredDataKey<>("weapon", Weapon.TYPE);
public static final StructuredDataKey<AttackRange> ATTACK_RANGE = new StructuredDataKey<>("attack_range", AttackRange.TYPE);
public static final StructuredDataKey<Enchantable> ENCHANTABLE = new StructuredDataKey<>("enchantable", Enchantable.TYPE);
public static final StructuredDataKey<Equippable> EQUIPPABLE1_21_2 = new StructuredDataKey<>("equippable", Equippable.TYPE1_21_2);
public static final StructuredDataKey<Equippable> EQUIPPABLE1_21_5 = new StructuredDataKey<>("equippable", Equippable.TYPE1_21_5);
public static final StructuredDataKey<Equippable> EQUIPPABLE1_21_6 = new StructuredDataKey<>("equippable", Equippable.TYPE1_21_6);
public static final StructuredDataKey<Repairable> REPAIRABLE = new StructuredDataKey<>("repairable", Repairable.TYPE);
public static final StructuredDataKey<Unit> GLIDER = new StructuredDataKey<>("glider", Types.EMPTY);
public static final StructuredDataKey<Key> TOOLTIP_STYLE = new StructuredDataKey<>("tooltip_style", Types.RESOURCE_LOCATION);
public static final StructuredDataKey<Key> TOOLTIP_STYLE = new StructuredDataKey<>("tooltip_style", Types.IDENTIFIER);
public static final StructuredDataKey<DeathProtection> DEATH_PROTECTION = new StructuredDataKey<>("death_protection", DeathProtection.TYPE);
public static final StructuredDataKey<BlocksAttacks> BLOCKS_ATTACKS = new StructuredDataKey<>("blocks_attacks", BlocksAttacks.TYPE);
public static final StructuredDataKey<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<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<DyedColor> DYED_COLOR1_20_5 = new StructuredDataKey<>("dyed_color", DyedColor.TYPE1_20_5);
@@ -181,7 +197,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Fireworks> FIREWORKS = new StructuredDataKey<>("fireworks", Fireworks.TYPE);
public static final StructuredDataKey<GameProfile> PROFILE1_20_5 = new StructuredDataKey<>("profile", Types.GAME_PROFILE);
public static final StructuredDataKey<ResolvableProfile> PROFILE1_21_9 = new StructuredDataKey<>("profile", Types.RESOLVABLE_PROFILE);
public static final StructuredDataKey<Key> NOTE_BLOCK_SOUND = new StructuredDataKey<>("note_block_sound", Types.RESOURCE_LOCATION);
public static final StructuredDataKey<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);
@@ -194,8 +210,8 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Holder<SoundEvent>> BREAK_SOUND = new StructuredDataKey<>("break_sound", Types.SOUND_EVENT);
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", Types.VAR_INT);
public static final StructuredDataKey<Integer> WOLF_SOUND_VARIANT = new StructuredDataKey<>("wolf/sound_variant", Types.VAR_INT);
public static final StructuredDataKey<Integer> WOLF_VARIANT = new StructuredDataKey<>("wolf/variant", new SynchronizedRegistryValueType(RegistryKey.of("wolf_variant")));
public static final StructuredDataKey<Integer> WOLF_SOUND_VARIANT = new StructuredDataKey<>("wolf/sound_variant", new SynchronizedRegistryValueType(RegistryKey.of("wolf_sound_variant")));
public static final StructuredDataKey<Integer> WOLF_COLLAR = new StructuredDataKey<>("wolf/collar", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<Integer> FOX_VARIANT = new StructuredDataKey<>("fox/variant", EnumTypes.FOX_VARIANT);
public static final StructuredDataKey<Integer> SALMON_SIZE = new StructuredDataKey<>("salmon/size", EnumTypes.SALMON_VARIANT);
@@ -205,15 +221,16 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Integer> TROPICAL_FISH_PATTERN_COLOR = new StructuredDataKey<>("tropical_fish/pattern_color", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<Integer> MOOSHROOM_VARIANT = new StructuredDataKey<>("mooshroom/variant", EnumTypes.MUSHROOM_COW_VARIANT);
public static final StructuredDataKey<Integer> RABBIT_VARIANT = new StructuredDataKey<>("rabbit/variant", EnumTypes.RABBIT_VARIANT);
public static final StructuredDataKey<Integer> PIG_VARIANT = new StructuredDataKey<>("pig/variant", Types.VAR_INT);
public static final StructuredDataKey<Integer> COW_VARIANT = new StructuredDataKey<>("cow/variant", Types.VAR_INT);
public static final StructuredDataKey<Either<Integer, String>> CHICKEN_VARIANT = new StructuredDataKey<>("chicken/variant", new EitherType<>(Types.VAR_INT, Types.STRING)); // ???
public static final StructuredDataKey<Integer> FROG_VARIANT = new StructuredDataKey<>("frog/variant", Types.VAR_INT);
public static final StructuredDataKey<Integer> PIG_VARIANT = new StructuredDataKey<>("pig/variant", new SynchronizedRegistryValueType(RegistryKey.of("pig_variant")));
public static final StructuredDataKey<Integer> COW_VARIANT = new StructuredDataKey<>("cow/variant", new SynchronizedRegistryValueType(RegistryKey.of("cow_variant")));
public static final StructuredDataKey<Either<Integer, String>> CHICKEN_VARIANT = new StructuredDataKey<>("chicken/variant", new SynchronizedRegistryEitherType(RegistryKey.of("chicken_variant")));
public static final StructuredDataKey<Either<Integer, String>> ZOMBIE_NAUTILUS_VARIANT = new StructuredDataKey<>("zombie_nautilus/variant", new SynchronizedRegistryEitherType(RegistryKey.of("zombie_nautilus_variant"))); // ???
public static final StructuredDataKey<Integer> FROG_VARIANT = new StructuredDataKey<>("frog/variant", new SynchronizedRegistryValueType(RegistryKey.of("frog_variant")));
public static final StructuredDataKey<Integer> HORSE_VARIANT = new StructuredDataKey<>("horse/variant", EnumTypes.HORSE_VARIANT);
public static final StructuredDataKey<Holder<PaintingVariant>> PAINTING_VARIANT = new StructuredDataKey<>("painting/variant", PaintingVariant.TYPE1_21_2);
public static final StructuredDataKey<Integer> LLAMA_VARIANT = new StructuredDataKey<>("llama/variant", EnumTypes.LLAMA_VARIANT);
public static final StructuredDataKey<Integer> AXOLOTL_VARIANT = new StructuredDataKey<>("axolotl/variant", EnumTypes.AXOLOTL_VARIANT);
public static final StructuredDataKey<Integer> CAT_VARIANT = new StructuredDataKey<>("cat/variant", Types.VAR_INT);
public static final StructuredDataKey<Integer> CAT_VARIANT = new StructuredDataKey<>("cat/variant", new SynchronizedRegistryValueType(RegistryKey.of("cat_variant")));
public static final StructuredDataKey<Integer> CAT_COLLAR = new StructuredDataKey<>("cat/collar", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<Integer> SHEEP_COLOR = new StructuredDataKey<>("sheep/color", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<Integer> SHULKER_COLOR = new StructuredDataKey<>("shulker/color", EnumTypes.DYE_COLOR);
@@ -226,6 +243,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKeys1_21_5 V1_21_5 = VersionedTypes.V1_21_5.structuredDataKeys();
public static final StructuredDataKeys1_21_5 V1_21_6 = VersionedTypes.V1_21_6.structuredDataKeys();
public static final StructuredDataKeys1_21_5 V1_21_9 = VersionedTypes.V1_21_9.structuredDataKeys();
public static final StructuredDataKeys1_21_11 V1_21_11 = VersionedTypes.V1_21_11.structuredDataKeys();
@Override
public String toString() {
@@ -30,23 +30,25 @@ public record DataComponentMatchers(StructuredData<?>[] exactPredicates, DataCom
public static final class DataComponentMatchersType extends Type<DataComponentMatchers> {
private final Type<StructuredData<?>[]> dataArrayType;
private final Type<DataComponentPredicate[]> predicateArrayType;
public DataComponentMatchersType(final Type<StructuredData<?>[]> dataArrayType) {
public DataComponentMatchersType(final Type<StructuredData<?>[]> dataArrayType, final Type<DataComponentPredicate[]> predicateArrayType) {
super(DataComponentMatchers.class);
this.dataArrayType = dataArrayType;
this.predicateArrayType = predicateArrayType;
}
@Override
public DataComponentMatchers read(final ByteBuf buffer) {
final StructuredData<?>[] exactPredicates = dataArrayType.read(buffer);
final DataComponentPredicate[] partialPredicates = DataComponentPredicate.ARRAY_TYPE.read(buffer);
final DataComponentPredicate[] partialPredicates = predicateArrayType.read(buffer);
return new DataComponentMatchers(exactPredicates, partialPredicates);
}
@Override
public void write(final ByteBuf buffer, final DataComponentMatchers value) {
dataArrayType.write(buffer, value.exactPredicates());
DataComponentPredicate.ARRAY_TYPE.write(buffer, value.predicates());
predicateArrayType.write(buffer, value.predicates());
}
}
}
@@ -28,9 +28,13 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import io.netty.buffer.ByteBuf;
public record DataComponentPredicate(int id, Tag predicate) {
public record DataComponentPredicate(PredicateType type, Tag predicate) {
public static final Type<DataComponentPredicate> TYPE = new Type<>(DataComponentPredicate.class) {
public DataComponentPredicate(final int predicateType, final Tag predicate) {
this(PredicateType.ofPredicateType(predicateType), predicate);
}
public static final Type<DataComponentPredicate> TYPE1_21_5 = new Type<>(DataComponentPredicate.class) {
@Override
public DataComponentPredicate read(final ByteBuf buffer) {
final int id = Types.VAR_INT.readPrimitive(buffer);
@@ -40,9 +44,38 @@ public record DataComponentPredicate(int id, Tag predicate) {
@Override
public void write(final ByteBuf buffer, final DataComponentPredicate value) {
Types.VAR_INT.writePrimitive(buffer, value.id());
Types.VAR_INT.writePrimitive(buffer, value.type().id());
Types.TAG.write(buffer, value.predicate());
}
};
public static final Type<DataComponentPredicate[]> ARRAY_TYPE = new ArrayType<>(TYPE, 64);
public static final Type<DataComponentPredicate[]> ARRAY_TYPE1_21_5 = new ArrayType<>(TYPE1_21_5, 64);
public static final Type<DataComponentPredicate> TYPE1_21_11 = new Type<>(DataComponentPredicate.class) {
@Override
public DataComponentPredicate read(final ByteBuf buffer) {
final boolean isPredicateType = Types.BOOLEAN.read(buffer);
final PredicateType type = new PredicateType(Types.VAR_INT.readPrimitive(buffer), isPredicateType);
final Tag predicate = Types.TAG.read(buffer);
return new DataComponentPredicate(type, predicate);
}
@Override
public void write(final ByteBuf buffer, final DataComponentPredicate value) {
Types.BOOLEAN.write(buffer, value.type().isPredicateType());
Types.VAR_INT.writePrimitive(buffer, value.type().id());
Types.TAG.write(buffer, value.predicate());
}
};
public static final Type<DataComponentPredicate[]> ARRAY_TYPE1_21_11 = new ArrayType<>(TYPE1_21_11, 64);
public record PredicateType(int id, boolean isPredicateType) {
public static PredicateType ofPredicateType(final int id) {
return new PredicateType(id, true);
}
public static PredicateType ofDataComponentType(final int id) {
return new PredicateType(id, false);
}
}
}
@@ -0,0 +1,44 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.data.version;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.data.predicate.DataComponentPredicate;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate.AdventureModePredicateType1_21_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
public class StructuredDataKeys1_21_11 extends StructuredDataKeys1_21_2 {
public final StructuredDataKey<AdventureModePredicate> canPlaceOn;
public final StructuredDataKey<AdventureModePredicate> canBreak;
public StructuredDataKeys1_21_11(final VersionedTypesHolder types) {
super(types);
final AdventureModePredicateType1_21_5 adventureModePredicateType = new AdventureModePredicateType1_21_5(types.structuredDataArray(), DataComponentPredicate.ARRAY_TYPE1_21_11);
this.canPlaceOn = add("can_place_on", adventureModePredicateType);
this.canBreak = add("can_break", adventureModePredicateType);
this.unsupportedForOps.add(this.canPlaceOn);
this.unsupportedForOps.add(this.canBreak);
}
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.minecraft.data.version;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.data.predicate.DataComponentPredicate;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate.AdventureModePredicateType1_21_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
@@ -34,7 +35,7 @@ public class StructuredDataKeys1_21_5 extends StructuredDataKeys1_21_2 {
public StructuredDataKeys1_21_5(final VersionedTypesHolder types) {
super(types);
final AdventureModePredicateType1_21_5 adventureModePredicateType = new AdventureModePredicateType1_21_5(types.structuredDataArray());
final AdventureModePredicateType1_21_5 adventureModePredicateType = new AdventureModePredicateType1_21_5(types.structuredDataArray(), DataComponentPredicate.ARRAY_TYPE1_21_5);
this.canPlaceOn = add("can_place_on", adventureModePredicateType);
this.canBreak = add("can_break", adventureModePredicateType);
this.unsupportedForOps.add(this.canPlaceOn);
@@ -0,0 +1,329 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entities;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.util.EntityTypeUtil;
import com.viaversion.viaversion.util.Key;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
public enum EntityTypes1_21_11 implements EntityType {
ENTITY(null, null),
AREA_EFFECT_CLOUD(ENTITY),
END_CRYSTAL(ENTITY),
EVOKER_FANGS(ENTITY),
EXPERIENCE_ORB(ENTITY),
EYE_OF_ENDER(ENTITY),
FALLING_BLOCK(ENTITY),
ITEM(ENTITY),
TNT(ENTITY),
OMINOUS_ITEM_SPAWNER(ENTITY),
MARKER(ENTITY),
LIGHTNING_BOLT(ENTITY),
INTERACTION(ENTITY),
DISPLAY(ENTITY, null),
BLOCK_DISPLAY(DISPLAY),
ITEM_DISPLAY(DISPLAY),
TEXT_DISPLAY(DISPLAY),
// Hanging entities
HANGING_ENTITY(ENTITY, null),
LEASH_KNOT(HANGING_ENTITY),
PAINTING(HANGING_ENTITY),
ITEM_FRAME(HANGING_ENTITY),
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
FISHING_BOBBER(PROJECTILE),
WITHER_SKULL(PROJECTILE),
DRAGON_FIREBALL(PROJECTILE), // Doesn't actually inherit fireball
ABSTRACT_THROWN_POTION(ITEM_PROJECTILE, null),
SPLASH_POTION(ABSTRACT_THROWN_POTION),
LINGERING_POTION(ABSTRACT_THROWN_POTION),
ABSTRACT_ARROW(PROJECTILE, null),
ARROW(ABSTRACT_ARROW),
SPECTRAL_ARROW(ABSTRACT_ARROW),
TRIDENT(ABSTRACT_ARROW),
ABSTRACT_FIREBALL(ENTITY, null),
FIREBALL(ABSTRACT_FIREBALL),
SMALL_FIREBALL(ABSTRACT_FIREBALL),
ABSTRACT_WIND_CHARGE(PROJECTILE, null),
WIND_CHARGE(ABSTRACT_WIND_CHARGE),
BREEZE_WIND_CHARGE(ABSTRACT_WIND_CHARGE),
// Vehicles
VEHICLE(ENTITY, null),
ABSTRACT_MINECART(VEHICLE, null),
MINECART(ABSTRACT_MINECART),
FURNACE_MINECART(ABSTRACT_MINECART),
COMMAND_BLOCK_MINECART(ABSTRACT_MINECART),
TNT_MINECART(ABSTRACT_MINECART),
SPAWNER_MINECART(ABSTRACT_MINECART),
ABSTRACT_MINECART_CONTAINER(ABSTRACT_MINECART, null),
CHEST_MINECART(ABSTRACT_MINECART_CONTAINER),
HOPPER_MINECART(ABSTRACT_MINECART_CONTAINER),
ABSTRACT_BOAT(VEHICLE, null),
ABSTRACT_CHEST_BOAT(ABSTRACT_BOAT, null),
ACACIA_BOAT(ABSTRACT_BOAT),
ACACIA_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
BAMBOO_CHEST_RAFT(ABSTRACT_CHEST_BOAT),
BAMBOO_RAFT(ABSTRACT_BOAT),
BIRCH_BOAT(ABSTRACT_BOAT),
BIRCH_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
CHERRY_BOAT(ABSTRACT_BOAT),
CHERRY_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
DARK_OAK_BOAT(ABSTRACT_BOAT),
DARK_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
JUNGLE_BOAT(ABSTRACT_BOAT),
JUNGLE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
MANGROVE_BOAT(ABSTRACT_BOAT),
MANGROVE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
OAK_BOAT(ABSTRACT_BOAT),
OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
PALE_OAK_BOAT(ABSTRACT_BOAT),
PALE_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
SPRUCE_BOAT(ABSTRACT_BOAT),
SPRUCE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
// Living entities as a larger subclass
LIVING_ENTITY(ENTITY, null),
ARMOR_STAND(LIVING_ENTITY),
// Players
AVATAR(LIVING_ENTITY, null),
MANNEQUIN(AVATAR),
PLAYER(AVATAR),
// Mobs as a larger subclass
MOB(LIVING_ENTITY, null),
ENDER_DRAGON(MOB),
SLIME(MOB),
MAGMA_CUBE(SLIME),
// Ambient mobs
AMBIENT_CREATURE(MOB, null),
BAT(AMBIENT_CREATURE),
// Flying mobs
FLYING_MOB(MOB, null),
GHAST(FLYING_MOB),
PHANTOM(FLYING_MOB),
// Pathfinder mobs and its subclasses
PATHFINDER_MOB(MOB, null),
ALLAY(PATHFINDER_MOB),
ABSTRACT_GOLEM(PATHFINDER_MOB, null),
SNOW_GOLEM(ABSTRACT_GOLEM),
IRON_GOLEM(ABSTRACT_GOLEM),
SHULKER(ABSTRACT_GOLEM),
COPPER_GOLEM(ABSTRACT_GOLEM),
// Ageable mobs and (tamable) animals
ABSTRACT_AGEABLE(PATHFINDER_MOB, null),
ABSTRACT_VILLAGER(ABSTRACT_AGEABLE, null),
VILLAGER(ABSTRACT_VILLAGER),
WANDERING_TRADER(ABSTRACT_VILLAGER),
ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null),
AXOLOTL(ABSTRACT_ANIMAL),
CHICKEN(ABSTRACT_ANIMAL),
PANDA(ABSTRACT_ANIMAL),
PIG(ABSTRACT_ANIMAL),
POLAR_BEAR(ABSTRACT_ANIMAL),
RABBIT(ABSTRACT_ANIMAL),
SHEEP(ABSTRACT_ANIMAL),
BEE(ABSTRACT_ANIMAL),
TURTLE(ABSTRACT_ANIMAL),
FOX(ABSTRACT_ANIMAL),
FROG(ABSTRACT_ANIMAL),
GOAT(ABSTRACT_ANIMAL),
HOGLIN(ABSTRACT_ANIMAL),
STRIDER(ABSTRACT_ANIMAL),
SNIFFER(ABSTRACT_ANIMAL),
ARMADILLO(ABSTRACT_ANIMAL),
HAPPY_GHAST(ABSTRACT_ANIMAL),
ABSTRACT_COW(ABSTRACT_ANIMAL, null),
COW(ABSTRACT_COW),
MOOSHROOM(ABSTRACT_COW),
TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null),
CAT(TAMABLE_ANIMAL),
OCELOT(TAMABLE_ANIMAL),
WOLF(TAMABLE_ANIMAL),
PARROT(TAMABLE_ANIMAL),
ABSTRACT_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;
EntityTypes1_21_11(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_21_11(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);
}
}
@@ -44,6 +44,10 @@ public abstract class AbstractEntityDataTypes implements EntityDataTypes {
}
protected EntityDataType add(final int typeId, final Type<?> type) {
if (values[typeId] != null) {
throw new IllegalArgumentException("Entity data type ID " + typeId + " is already registered as " + values[typeId]);
}
final EntityDataType dataType = EntityDataType.create(typeId, type);
values[typeId] = dataType;
return dataType;
@@ -44,7 +44,7 @@ public final class EntityDataTypes1_14 extends AbstractEntityDataTypes {
public final EntityDataType optionalBlockStateType = add(13, Types.VAR_INT);
public final EntityDataType compoundTagType = add(14, Types.NAMED_COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType villagerDatatType = add(16, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(16, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(17, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(18, Types.VAR_INT);
@@ -44,7 +44,7 @@ public final class EntityDataTypes1_19 extends AbstractEntityDataTypes {
public final EntityDataType optionalBlockStateType = add(13, Types.VAR_INT);
public final EntityDataType compoundTagType = add(14, Types.NAMED_COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType villagerDatatType = add(16, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(16, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(17, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(18, Types.VAR_INT);
public final EntityDataType catVariantType = add(19, Types.VAR_INT);
@@ -45,7 +45,7 @@ public final class EntityDataTypes1_19_3 extends AbstractEntityDataTypes {
public final EntityDataType optionalBlockStateType = add(14, Types.VAR_INT);
public final EntityDataType compoundTagType = add(15, Types.NAMED_COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType villagerDatatType = add(17, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(17, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(18, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(19, Types.VAR_INT);
public final EntityDataType catVariantType = add(20, Types.VAR_INT);
@@ -46,7 +46,7 @@ public final class EntityDataTypes1_19_4 extends AbstractEntityDataTypes {
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType compoundTagType = add(16, Types.NAMED_COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType villagerDatatType = add(18, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(18, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(19, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(20, Types.VAR_INT);
public final EntityDataType catVariantType = add(21, Types.VAR_INT);
@@ -46,7 +46,7 @@ public final class EntityDataTypes1_20_2 extends AbstractEntityDataTypes {
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType compoundTagType = add(16, Types.COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType villagerDatatType = add(18, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(18, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(19, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(20, Types.VAR_INT);
public final EntityDataType catVariantType = add(21, Types.VAR_INT);
@@ -46,7 +46,7 @@ public final class EntityDataTypes1_20_3 extends AbstractEntityDataTypes {
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType compoundTagType = add(16, Types.COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType villagerDatatType = add(18, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(18, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(19, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(20, Types.VAR_INT);
public final EntityDataType catVariantType = add(21, Types.VAR_INT);
@@ -47,7 +47,7 @@ public final class EntityDataTypes1_20_5 extends AbstractEntityDataTypes {
public final EntityDataType compoundTagType = add(16, Types.COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = add(19, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(19, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(20, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(21, Types.VAR_INT);
public final EntityDataType catVariantType = add(22, Types.VAR_INT);
@@ -49,7 +49,7 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
public final EntityDataType compoundTagType = add(16, Types.COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = add(19, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(19, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(20, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(21, Types.VAR_INT);
public final EntityDataType catVariantType = add(22, Types.VAR_INT);
@@ -0,0 +1,78 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entitydata.types;
import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
public final class EntityDataTypes1_21_11 extends AbstractEntityDataTypes {
public final EntityDataType byteType = add(0, Types.BYTE);
public final EntityDataType varIntType = add(1, Types.VAR_INT);
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14);
public final EntityDataType optionalBlockPositionType = add(11, Types.OPTIONAL_POSITION_1_14);
public final EntityDataType directionType = add(12, Types.VAR_INT);
public final EntityDataType optionalUUIDType = add(13, Types.OPTIONAL_UUID);
public final EntityDataType blockStateType = add(14, Types.VAR_INT);
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = add(18, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(19, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(20, Types.VAR_INT);
public final EntityDataType catVariantType = add(21, Types.VAR_INT);
public final EntityDataType cowVariantType = add(22, Types.VAR_INT);
public final EntityDataType wolfVariantType = add(23, Types.VAR_INT);
public final EntityDataType wolfSoundVariantType = add(24, Types.VAR_INT);
public final EntityDataType frogVariantType = add(25, Types.VAR_INT);
public final EntityDataType pigVariantType = add(26, Types.VAR_INT);
public final EntityDataType chickenVariantType = add(27, Types.VAR_INT);
public final EntityDataType zombieNautilusVariantType = add(28, Types.VAR_INT);
public final EntityDataType optionalGlobalPosition = add(29, Types.OPTIONAL_GLOBAL_POSITION);
public final EntityDataType paintingVariantType = add(30, PaintingVariant.TYPE1_21_2);
public final EntityDataType snifferState = add(31, Types.VAR_INT);
public final EntityDataType armadilloState = add(32, Types.VAR_INT);
public final EntityDataType copperGolemState = add(33, Types.VAR_INT);
public final EntityDataType weatheringCopperState = add(34, Types.VAR_INT);
public final EntityDataType vector3FType = add(35, Types.VECTOR3F);
public final EntityDataType quaternionType = add(36, Types.QUATERNION);
public final EntityDataType mannequinProfileType = add(37, Types.RESOLVABLE_PROFILE);
public final EntityDataType humanoidArmType = add(38, Types.VAR_INT);
public EntityDataTypes1_21_11(final VersionedTypesHolder types) {
super(39);
this.itemType = add(7, types.item());
this.particleType = add(16, types.particle());
this.particlesType = add(17, types.particles());
}
}
@@ -49,7 +49,7 @@ public final class EntityDataTypes1_21_2 extends AbstractEntityDataTypes {
public final EntityDataType compoundTagType = add(16, Types.COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = add(19, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(19, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(20, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(21, Types.VAR_INT);
public final EntityDataType catVariantType = add(22, Types.VAR_INT);
@@ -48,7 +48,7 @@ public final class EntityDataTypes1_21_5 extends AbstractEntityDataTypes {
public final EntityDataType compoundTagType = add(16, Types.COMPOUND_TAG);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = add(19, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(19, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(20, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(21, Types.VAR_INT);
public final EntityDataType catVariantType = add(22, Types.VAR_INT);
@@ -47,7 +47,7 @@ public final class EntityDataTypes1_21_9 extends AbstractEntityDataTypes {
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = add(18, Types.VILLAGER_DATA);
public final EntityDataType villagerDataType = add(18, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(19, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(20, Types.VAR_INT);
public final EntityDataType catVariantType = add(21, Types.VAR_INT);
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.data.predicate.DataComponentPredicate;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.ArrayType;
@@ -53,12 +54,13 @@ public record AdventureModePredicate(BlockPredicate[] predicates,
}
};
// Shared with 1.21.11 too using the predicate array param
public static final class AdventureModePredicateType1_21_5 extends Type<AdventureModePredicate> {
private final Type<BlockPredicate[]> blockPredicateType;
public AdventureModePredicateType1_21_5(final Type<StructuredData<?>[]> dataArrayType) {
public AdventureModePredicateType1_21_5(final Type<StructuredData<?>[]> dataArrayType, final Type<DataComponentPredicate[]> predicateArrayType) {
super(AdventureModePredicate.class);
this.blockPredicateType = new ArrayType<>(new BlockPredicate.BlockPredicateType1_21_5(dataArrayType));
this.blockPredicateType = new ArrayType<>(new BlockPredicate.BlockPredicateType1_21_5(dataArrayType, predicateArrayType));
}
@Override
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.Rewritable;
@@ -97,6 +98,13 @@ public record ArmorTrim(Holder<ArmorTrimMaterial> material, Holder<ArmorTrimPatt
ArmorTrimMaterial.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) {
ops.writeMap(map -> map
.write("material", ArmorTrimMaterial.TYPE1_21_5, value.material)
.write("pattern", ArmorTrimPattern.TYPE1_21_5, value.pattern));
}
};
@Override
@@ -24,10 +24,12 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
@@ -176,6 +178,26 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd
Types.TAG.write(buffer, value.description());
}
@Override
public void writeDirect(final Ops ops, final ArmorTrimMaterial object) {
ops.writeMap(map -> {
map.write("asset_name", Types.STRING, object.assetName());
if (!object.overrideArmorMaterials.isEmpty()) {
map.writeMap("override_armor_assets", materials -> {
for (final Map.Entry<String, String> entry : object.overrideArmorMaterials.entrySet()) {
materials.write(Types.IDENTIFIER, Key.of(entry.getKey()), Types.STRING, entry.getValue());
}
});
}
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);
}
};
@Override
@@ -24,10 +24,12 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
@@ -70,6 +72,19 @@ public record ArmorTrimPattern(String assetName, int itemId, Tag description, bo
Types.TAG.write(buffer, value.description());
buffer.writeBoolean(value.decal());
}
@Override
public void writeDirect(final Ops ops, final ArmorTrimPattern object) {
ops.writeMap(map -> map
.write("asset_id", Types.IDENTIFIER, Key.of(object.assetName()))
.write("description", Types.TEXT_COMPONENT_TAG, object.description())
.write("decal", Types.BOOLEAN, object.decal()));
}
@Override
protected Key identifier(final Ops ops, final int id) {
return ops.context().registryAccess().registryKey("trim_pattern", id);
}
};
@Override
@@ -0,0 +1,67 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record AttackRange(float minRange, float maxRange,
float minCreativeRange, float maxCreativeRange,
float hitboxMargin, float mobFactor) {
public static final Type<AttackRange> TYPE = new Type<>(AttackRange.class) {
@Override
public AttackRange read(final ByteBuf buffer) {
final float minRange = Types.FLOAT.readPrimitive(buffer);
final float maxRange = Types.FLOAT.readPrimitive(buffer);
final float minCreativeRange = Types.FLOAT.readPrimitive(buffer);
final float maxCreativeRange = Types.FLOAT.readPrimitive(buffer);
final float hitboxMargin = Types.FLOAT.readPrimitive(buffer);
final float mobFactor = Types.FLOAT.readPrimitive(buffer);
return new AttackRange(minRange, maxRange, minCreativeRange, maxCreativeRange, hitboxMargin, mobFactor);
}
@Override
public void write(final ByteBuf buffer, final AttackRange value) {
Types.FLOAT.writePrimitive(buffer, value.minRange);
Types.FLOAT.writePrimitive(buffer, value.maxRange);
Types.FLOAT.writePrimitive(buffer, value.minCreativeRange);
Types.FLOAT.writePrimitive(buffer, value.maxCreativeRange);
Types.FLOAT.writePrimitive(buffer, value.hitboxMargin);
Types.FLOAT.writePrimitive(buffer, value.mobFactor);
}
@Override
public void write(final Ops ops, final AttackRange AttackRange) {
ops.writeMap(map -> map
.writeOptional("min_range", Types.FLOAT, AttackRange.minRange, 0F)
.writeOptional("max_range", Types.FLOAT, AttackRange.maxRange, 3F)
.writeOptional("min_creative_reach", Types.FLOAT, AttackRange.minCreativeRange, 0F)
.writeOptional("max_creative_reach", Types.FLOAT, AttackRange.maxCreativeRange, 5F)
.writeOptional("hitbox_margin", Types.FLOAT, AttackRange.hitboxMargin, 0.3F)
.writeOptional("mob_factor", Types.FLOAT, AttackRange.mobFactor, 1F));
}
};
}
@@ -152,8 +152,8 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
public void write(final Ops ops, final AttributeModifier value) {
final Key attribute = ops.context().registryAccess().attributeModifier(value.attribute);
ops.writeMap(map -> map
.write("type", Types.RESOURCE_LOCATION, attribute)
.write("id", Types.RESOURCE_LOCATION, Key.of(value.modifier.id()))
.write("type", Types.IDENTIFIER, attribute)
.write("id", Types.IDENTIFIER, Key.of(value.modifier.id()))
.write("amount", Types.DOUBLE, value.modifier.amount)
.write("operation", Types.STRING, OPERATION[value.modifier.operation()])
.writeOptional("slot", Types.STRING, EQUIPMENT_SLOT_GROUPS[value.slotType()], "any"));
@@ -184,8 +184,8 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
public void write(final Ops ops, final AttributeModifier value) {
final Key attribute = ops.context().registryAccess().attributeModifier(value.attribute);
ops.writeMap(map -> {
map.write("type", Types.RESOURCE_LOCATION, attribute)
.write("id", Types.RESOURCE_LOCATION, Key.of(value.modifier.id()))
map.write("type", Types.IDENTIFIER, attribute)
.write("id", Types.IDENTIFIER, Key.of(value.modifier.id()))
.write("amount", Types.DOUBLE, value.modifier.amount)
.write("operation", Types.STRING, OPERATION[value.modifier.operation()])
.writeOptional("slot", Types.STRING, EQUIPMENT_SLOT_GROUPS[value.slotType()], "any");
@@ -22,8 +22,10 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
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 BannerPattern(String assetId, String translationKey) {
@@ -41,6 +43,17 @@ public record BannerPattern(String assetId, String translationKey) {
Types.STRING.write(buffer, value.assetId);
Types.STRING.write(buffer, value.translationKey);
}
};
@Override
public void writeDirect(final Ops ops, final BannerPattern object) {
ops.writeMap(map -> map
.write("asset_id", Types.IDENTIFIER, Key.of(object.assetId))
.write("translation_key", Types.STRING, object.translationKey));
}
@Override
protected Key identifier(final Ops ops, final int id) {
return ops.context().registryAccess().registryKey("banner_pattern", id);
}
};
}
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
@@ -43,6 +44,13 @@ public record BannerPatternLayer(Holder<BannerPattern> pattern, int dyeColor) {
BannerPattern.TYPE.write(buffer, value.pattern);
Types.VAR_INT.writePrimitive(buffer, value.dyeColor);
}
@Override
public void write(final Ops ops, final BannerPatternLayer value) {
ops.writeMap(map -> map
.write("pattern", BannerPattern.TYPE, value.pattern)
.write("color", EnumTypes.DYE_COLOR, value.dyeColor));
}
};
public static final Type<BannerPatternLayer[]> ARRAY_TYPE = new ArrayType<>(TYPE);
@@ -50,7 +50,7 @@ public record BlockEntityData(int type, CompoundTag tag) implements Rewritable {
@Override
public void write(final Ops ops, final BlockEntityData data) {
ops.writeMap(map -> map
.write("id", Types.RESOURCE_LOCATION, ops.context().registryAccess().blockEntity(data.type))
.write("id", Types.IDENTIFIER, ops.context().registryAccess().blockEntity(data.type))
.writeInlinedMap(Types.COMPOUND_TAG, data.tag)
);
}
@@ -72,9 +72,9 @@ public record BlockPredicate(@Nullable HolderSet holderSet, StatePropertyMatcher
public static final class BlockPredicateType1_21_5 extends Type<BlockPredicate> {
private final Type<DataComponentMatchers> matchersType;
public BlockPredicateType1_21_5(final Type<StructuredData<?>[]> dataArrayType) {
public BlockPredicateType1_21_5(final Type<StructuredData<?>[]> dataArrayType, final Type<DataComponentPredicate[]> predicateArrayType) {
super(BlockPredicate.class);
this.matchersType = new DataComponentMatchersType(dataArrayType);
this.matchersType = new DataComponentMatchersType(dataArrayType, predicateArrayType);
}
@Override
@@ -25,11 +25,15 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.RegistryKey;
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.util.Key;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -68,6 +72,20 @@ public record BlocksAttacks(
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.blockSound());
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.disableSound());
}
@Override
public void write(final Ops ops, final BlocksAttacks value) {
final DamageReduction[] defaultDamageReductions = {new DamageReduction(90, null, 0, 1)};
final ItemDamageFunction defaultItemDamage = new ItemDamageFunction(1, 0, 1);
ops.writeMap(map -> map
.writeOptional("block_delay_seconds", Types.FLOAT, value.blockDelaySeconds(), 0F)
.writeOptional("disable_cooldown_scale", Types.FLOAT, value.disableCooldownScale(), 1F)
.writeOptional("damage_reductions", DamageReduction.ARRAY_TYPE, value.damageReductions(), defaultDamageReductions)
.writeOptional("item_damage", ItemDamageFunction.TYPE, value.itemDamage(), defaultItemDamage)
.writeOptional("bypassed_by", Types.TAG_KEY, value.bypassedByTag() != null ? Key.of(value.bypassedByTag()) : null)
.writeOptional("block_sound", Types.SOUND_EVENT, value.blockSound())
.writeOptional("disabled_sound", Types.SOUND_EVENT, value.disableSound()));
}
};
@Override
@@ -97,6 +115,15 @@ public record BlocksAttacks(
buffer.writeFloat(value.base());
buffer.writeFloat(value.factor());
}
@Override
public void write(final Ops ops, final DamageReduction value) {
ops.writeMap(map -> map
.writeOptional("horizontal_blocking_angle", Types.FLOAT, value.horizontalBlockingAngle(), 90F)
.writeOptional("type", new HolderSetType(RegistryKey.of("damage_type")), value.type())
.write("base", Types.FLOAT, value.base())
.write("factor", Types.FLOAT, value.factor()));
}
};
public static final ArrayType<DamageReduction> ARRAY_TYPE = new ArrayType<>(TYPE);
}
@@ -119,6 +146,14 @@ public record BlocksAttacks(
buffer.writeFloat(value.base());
buffer.writeFloat(value.factor());
}
@Override
public void write(final Ops ops, final ItemDamageFunction value) {
ops.writeMap(map -> map
.write("threshold", Types.FLOAT, value.threshold())
.write("base", Types.FLOAT, value.base())
.write("factor", Types.FLOAT, value.factor()));
}
};
}
}
@@ -23,12 +23,17 @@
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;
@@ -37,12 +42,51 @@ public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<S
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,
Types.HOLDER_SET, // remove effects
REMOVE_EFFECTS_TYPE,
Types.EMPTY, // clear all effects
Types.FLOAT, // teleport randomly
Types.SOUND_EVENT // play sound
TELEPORT_RANDOMLY_TYPE,
PLAY_SOUND_TYPE
};
public static final Type<Consumable1_21_2> TYPE = new Type<>(Consumable1_21_2.class) {
@@ -64,6 +108,17 @@ public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<S
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) {
@@ -83,6 +138,17 @@ public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<S
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);
@@ -111,6 +177,13 @@ public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<S
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));
}
};
}
@@ -30,7 +30,7 @@ import com.viaversion.viaversion.util.Key;
public record DamageResistant(Key typesTagKey) {
public static final Type<DamageResistant> TYPE = new TransformingType<>(Types.RESOURCE_LOCATION, DamageResistant.class, DamageResistant::new, DamageResistant::typesTagKey) {
public static final Type<DamageResistant> TYPE = new TransformingType<>(Types.IDENTIFIER, DamageResistant.class, DamageResistant::new, DamageResistant::typesTagKey) {
@Override
public void write(final Ops ops, final DamageResistant value) {
@@ -0,0 +1,34 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.EitherType;
import com.viaversion.viaversion.util.Either;
public record DamageType(Either<Integer, String> id) {
public static final Type<DamageType> TYPE = TransformingType.of(new EitherType<>(Types.VAR_INT, Types.STRING), DamageType.class, DamageType::new, DamageType::id);
}
@@ -22,23 +22,18 @@
*/
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.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.Copyable;
import io.netty.buffer.ByteBuf;
public record DeathProtection(ConsumeEffect<?>[] deathEffects) implements Copyable {
public static final Type<DeathProtection> TYPE = new Type<>(DeathProtection.class) {
public static final Type<DeathProtection> TYPE = new TransformingType<>(ConsumeEffect.ARRAY_TYPE, DeathProtection.class, DeathProtection::new, DeathProtection::deathEffects) {
@Override
public DeathProtection read(final ByteBuf buffer) {
final ConsumeEffect<?>[] deathEffects = ConsumeEffect.ARRAY_TYPE.read(buffer);
return new DeathProtection(deathEffects);
}
@Override
public void write(final ByteBuf buffer, final DeathProtection value) {
ConsumeEffect.ARRAY_TYPE.write(buffer, value.deathEffects);
public void write(final Ops ops, final DeathProtection value) {
ops.writeMap(map -> map.write("death_effects", ConsumeEffect.ARRAY_TYPE, value.deathEffects));
}
};
@@ -88,8 +88,8 @@ public record Enchantments(Int2IntMap enchantments, boolean showInTooltip) imple
public void write(final Ops ops, final Enchantments value) {
ops.writeMap(map -> {
for (final Int2IntMap.Entry entry : value.enchantments.int2IntEntrySet()) {
final Key key = ops.context().registryAccess().enchantment(entry.getIntKey());
map.write(Types.RESOURCE_LOCATION, key, Types.VAR_INT, entry.getIntValue());
final Key key = ops.context().registryAccess().registryKey("enchantment", entry.getIntKey());
map.write(Types.IDENTIFIER, key, Types.VAR_INT, entry.getIntValue());
}
});
}
@@ -51,7 +51,7 @@ public record EntityData(int type, CompoundTag tag) implements Rewritable, Copya
@Override
public void write(final Ops ops, final EntityData data) {
ops.writeMap(map -> map
.write("id", Types.RESOURCE_LOCATION, ops.context().registryAccess().entity(data.type))
.write("id", Types.IDENTIFIER, ops.context().registryAccess().entity(data.type))
.writeInlinedMap(Types.COMPOUND_TAG, data.tag)
);
}
@@ -59,7 +59,7 @@ public record EntityData(int type, CompoundTag tag) implements Rewritable, Copya
@Override
public EntityData rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final int mappedType = protocol.getMappingData().getEntityMappings().getNewId(type);
final int mappedType = Rewritable.entityRewriteFunction(protocol, clientbound).applyAsInt(type);
return new EntityData(mappedType, tag);
}
@@ -25,7 +25,8 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.types.EnumType;
import com.viaversion.viaversion.api.type.types.EnumType.Fallback;
import com.viaversion.viaversion.api.type.types.FakeEnumType;
import com.viaversion.viaversion.api.type.types.RegistryValueType;
import com.viaversion.viaversion.api.type.types.misc.RegistryValueType;
import com.viaversion.viaversion.util.Key;
import java.util.List;
import static com.viaversion.viaversion.api.type.types.FakeEnumType.Entry.of;
@@ -45,10 +46,13 @@ 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 ITEM_USE_ANIMATION = new EnumType("none", "eat", "drink", "block", "bow", "trident", "crossbow", "spyglass", "toot_horn", "brush", "bundle", "spear");
// Enums with non-ordinal ids
public static final FakeEnumType RABBIT_VARIANT = new FakeEnumType(List.of("brown", "white", "black", "white_splotched", "gold", "salt"), of(99, "evil"));
// Pretty much enums, but with a resource location
public static final RegistryValueType VILLAGER_TYPE = new RegistryValueType("desert", "jungle", "plains", "savanna", "snow", "swamp", "taiga");
public static final RegistryValueType POTION = new RegistryValueType("water", "mundane", "thick", "awkward", "night_vision", "long_night_vision", "invisibility", "long_invisibility", "leaping", "long_leaping", "strong_leaping", "fire_resistance", "long_fire_resistance", "swiftness", "long_swiftness", "strong_swiftness", "slowness", "long_slowness", "strong_slowness", "turtle_master", "long_turtle_master", "strong_turtle_master", "water_breathing", "long_water_breathing", "healing", "strong_healing", "harming", "strong_harming", "poison", "long_poison", "strong_poison", "regeneration", "long_regeneration", "strong_regeneration", "strength", "long_strength", "strong_strength", "weakness", "long_weakness", "luck", "slow_falling", "long_slow_falling", "wind_charged", "weaving", "oozing", "infested");
public static final RegistryValueType MOB_EFFECT = new RegistryValueType("speed", "slowness", "haste", "mining_fatigue", "strength", "instant_health", "instant_damage", "jump_boost", "nausea", "regeneration", "resistance", "fire_resistance", "water_breathing", "invisibility", "blindness", "night_vision", "hunger", "weakness", "poison", "wither", "health_boost", "absorption", "saturation", "glowing", "levitation", "luck", "unluck", "slow_falling", "conduit_power", "dolphins_grace", "bad_omen", "hero_of_the_village", "darkness", "trial_omen", "raid_omen", "wind_charged", "weaving", "oozing", "infested");
// Hardcoded registries
public static final RegistryValueType VILLAGER_TYPE = new RegistryValueType(Key.of("villager_type"), "desert", "jungle", "plains", "savanna", "snow", "swamp", "taiga");
public static final RegistryValueType POTION = new RegistryValueType(Key.of("potion"), "water", "mundane", "thick", "awkward", "night_vision", "long_night_vision", "invisibility", "long_invisibility", "leaping", "long_leaping", "strong_leaping", "fire_resistance", "long_fire_resistance", "swiftness", "long_swiftness", "strong_swiftness", "slowness", "long_slowness", "strong_slowness", "turtle_master", "long_turtle_master", "strong_turtle_master", "water_breathing", "long_water_breathing", "healing", "strong_healing", "harming", "strong_harming", "poison", "long_poison", "strong_poison", "regeneration", "long_regeneration", "strong_regeneration", "strength", "long_strength", "strong_strength", "weakness", "long_weakness", "luck", "slow_falling", "long_slow_falling", "wind_charged", "weaving", "oozing", "infested");
public static final RegistryValueType MOB_EFFECT = new RegistryValueType(Key.of("mob_effect"), "speed", "slowness", "haste", "mining_fatigue", "strength", "instant_health", "instant_damage", "jump_boost", "nausea", "regeneration", "resistance", "fire_resistance", "water_breathing", "invisibility", "blindness", "night_vision", "hunger", "weakness", "poison", "wither", "health_boost", "absorption", "saturation", "glowing", "levitation", "luck", "unluck", "slow_falling", "conduit_power", "dolphins_grace", "bad_omen", "hero_of_the_village", "darkness", "trial_omen", "raid_omen", "wind_charged", "weaving", "oozing", "infested");
public static final RegistryValueType CONSUME_EFFECT = new RegistryValueType(Key.of("consume_effect_type"), "apply_effects", "remove_effects", "clear_all_effects", "teleport_randomly", "play_sound");
}
@@ -112,9 +112,9 @@ public record Equippable(int equipmentSlot, Holder<SoundEvent> soundEvent, @Null
ops.writeMap(map -> map
.write("slot", EnumTypes.EQUIPMENT_SLOT, value.equipmentSlot)
.writeOptional("equip_sound", Types.SOUND_EVENT, value.soundEvent, defaultEquipSound)
.writeOptional("asset_id", Types.RESOURCE_LOCATION, value.model != null ? Key.of(value.model) : null)
.writeOptional("camera_overlay", Types.RESOURCE_LOCATION, value.cameraOverlay != null ? Key.of(value.cameraOverlay) : null)
.writeOptional("allowed_entities", new HolderSetType(MappingData.MappingType.ENTITY), value.allowedEntities)
.writeOptional("asset_id", Types.IDENTIFIER, value.model != null ? Key.of(value.model) : null)
.writeOptional("camera_overlay", Types.IDENTIFIER, value.cameraOverlay != null ? Key.of(value.cameraOverlay) : null)
.writeOptional("allowed_entities", new HolderSetType(MappingData.MappingType.ENTITY_TYPE), value.allowedEntities)
.writeOptional("dispensable", Types.BOOLEAN, value.dispensable, true)
.writeOptional("swappable", Types.BOOLEAN, value.swappable, true)
.writeOptional("damage_on_hurt", Types.BOOLEAN, value.damageOnHurt, true)
@@ -160,9 +160,9 @@ public record Equippable(int equipmentSlot, Holder<SoundEvent> soundEvent, @Null
ops.writeMap(map -> map
.write("slot", EnumTypes.EQUIPMENT_SLOT, value.equipmentSlot)
.writeOptional("equip_sound", Types.SOUND_EVENT, value.soundEvent, defaultSound)
.writeOptional("asset_id", Types.RESOURCE_LOCATION, value.model != null ? Key.of(value.model) : null)
.writeOptional("camera_overlay", Types.RESOURCE_LOCATION, value.cameraOverlay != null ? Key.of(value.cameraOverlay) : null)
.writeOptional("allowed_entities", new HolderSetType(MappingData.MappingType.ENTITY), value.allowedEntities)
.writeOptional("asset_id", Types.IDENTIFIER, value.model != null ? Key.of(value.model) : null)
.writeOptional("camera_overlay", Types.IDENTIFIER, value.cameraOverlay != null ? Key.of(value.cameraOverlay) : null)
.writeOptional("allowed_entities", new HolderSetType(MappingData.MappingType.ENTITY_TYPE), value.allowedEntities)
.writeOptional("dispensable", Types.BOOLEAN, value.dispensable, true)
.writeOptional("swappable", Types.BOOLEAN, value.swappable, true)
.writeOptional("damage_on_hurt", Types.BOOLEAN, value.damageOnHurt, true)
@@ -26,11 +26,13 @@ import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
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.Types;
import com.viaversion.viaversion.api.type.types.misc.EitherHolderType;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
@@ -54,6 +56,20 @@ public record Instrument1_21_2(Holder<SoundEvent> soundEvent, float useDuration,
Types.FLOAT.writePrimitive(buffer, value.range());
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("description", Types.TAG, value.description()));
}
@Override
protected Key identifier(final Ops ops, final int id) {
return ops.context().registryAccess().registryKey("instrument", id);
}
};
public static final EitherHolderType<Instrument1_21_2> EITHER_HOLDER_TYPE = new EitherHolderType<>(TYPE);
@@ -32,7 +32,7 @@ import com.viaversion.viaversion.util.Rewritable;
public record ItemModel(Key key) implements Rewritable {
public static final Type<ItemModel> TYPE = TransformingType.of(Types.RESOURCE_LOCATION, ItemModel.class, ItemModel::new, ItemModel::key);
public static final Type<ItemModel> TYPE = TransformingType.of(Types.IDENTIFIER, ItemModel.class, ItemModel::new, ItemModel::key);
@Override
public ItemModel rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
@@ -27,11 +27,14 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.EitherHolder;
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.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.EitherHolderType;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
@@ -48,9 +51,9 @@ public record JukeboxPlayable(EitherHolder<JukeboxSong> song, boolean showInTool
public static final Type<JukeboxPlayable> TYPE1_21 = new Type<>(JukeboxPlayable.class) {
@Override
public JukeboxPlayable read(final ByteBuf buffer) {
final EitherHolder<JukeboxSong> position = EitherHolderType.read(buffer, JukeboxSong.TYPE);
final EitherHolder<JukeboxSong> song = EitherHolderType.read(buffer, JukeboxSong.TYPE);
final boolean showInTooltip = buffer.readBoolean();
return new JukeboxPlayable(position, showInTooltip);
return new JukeboxPlayable(song, showInTooltip);
}
@Override
@@ -59,18 +62,10 @@ public record JukeboxPlayable(EitherHolder<JukeboxSong> song, boolean showInTool
buffer.writeBoolean(value.showInTooltip);
}
};
public static final Type<JukeboxPlayable> TYPE1_21_5 = new Type<>(JukeboxPlayable.class) {
@Override
public JukeboxPlayable read(final ByteBuf buffer) {
final EitherHolder<JukeboxSong> position = EitherHolderType.read(buffer, JukeboxSong.TYPE);
return new JukeboxPlayable(position, true);
}
@Override
public void write(final ByteBuf buffer, final JukeboxPlayable value) {
EitherHolderType.write(buffer, value.song, JukeboxSong.TYPE);
}
};
public static final Type<JukeboxPlayable> TYPE1_21_5 = TransformingType.of(
new EitherHolderType<>(JukeboxSong.TYPE), JukeboxPlayable.class,
song -> new JukeboxPlayable(song, true), JukeboxPlayable::song
);
@Override
public JukeboxPlayable rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
@@ -107,6 +102,21 @@ public record JukeboxPlayable(EitherHolder<JukeboxSong> song, boolean showInTool
buffer.writeFloat(value.lengthInSeconds);
Types.VAR_INT.writePrimitive(buffer, value.comparatorOutput);
}
@Override
public void writeDirect(final Ops ops, final JukeboxSong value) {
// Unused, cannot be direct despite having a direct network codec
ops.writeMap(map -> map
.write("sound_event", Types.SOUND_EVENT, value.soundEvent)
.write("description", Types.TAG, value.description)
.write("length_in_seconds", Types.FLOAT, value.lengthInSeconds)
.write("comparator_output", Types.INT, value.comparatorOutput));
}
@Override
protected Key identifier(final Ops ops, final int id) {
return ops.context().registryAccess().registryKey("jukebox_song", id);
}
};
@Override
@@ -0,0 +1,113 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public record KineticWeapon(int contactCooldownTicks, int delayTicks, @Nullable Condition dismountConditions,
@Nullable Condition knockbackConditions, @Nullable Condition damageConditions,
float forwardMovement, float damageMultiplier,
@Nullable Holder<SoundEvent> sound, @Nullable Holder<SoundEvent> hitSound) {
public static final Type<KineticWeapon> TYPE = new Type<>(KineticWeapon.class) {
@Override
public KineticWeapon read(final ByteBuf buffer) {
final int contactCooldownTicks = Types.VAR_INT.readPrimitive(buffer);
final int delayTicks = Types.VAR_INT.readPrimitive(buffer);
final Condition dismountConditions = Condition.OPTIONAL_TYPE.read(buffer);
final Condition knockbackConditions = Condition.OPTIONAL_TYPE.read(buffer);
final Condition damageConditions = Condition.OPTIONAL_TYPE.read(buffer);
final float forwardMovement = Types.FLOAT.readPrimitive(buffer);
final float damageMultiplier = Types.FLOAT.readPrimitive(buffer);
final Holder<SoundEvent> sound = Types.OPTIONAL_SOUND_EVENT.read(buffer);
final Holder<SoundEvent> hitSound = Types.OPTIONAL_SOUND_EVENT.read(buffer);
return new KineticWeapon(contactCooldownTicks, delayTicks, dismountConditions, knockbackConditions, damageConditions, forwardMovement, damageMultiplier, sound, hitSound);
}
@Override
public void write(final ByteBuf buffer, final KineticWeapon value) {
Types.VAR_INT.writePrimitive(buffer, value.contactCooldownTicks);
Types.VAR_INT.writePrimitive(buffer, value.delayTicks);
Condition.OPTIONAL_TYPE.write(buffer, value.dismountConditions);
Condition.OPTIONAL_TYPE.write(buffer, value.knockbackConditions);
Condition.OPTIONAL_TYPE.write(buffer, value.damageConditions);
Types.FLOAT.writePrimitive(buffer, value.forwardMovement);
Types.FLOAT.writePrimitive(buffer, value.damageMultiplier);
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.sound);
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.hitSound);
}
@Override
public void write(final Ops ops, final KineticWeapon value) {
ops.writeMap(map -> map
.writeOptional("contact_cooldown_ticks", Types.INT, value.contactCooldownTicks, 10)
.writeOptional("delay_ticks", Types.INT, value.delayTicks, 0)
.writeOptional("dismount_conditions", Condition.TYPE, value.dismountConditions)
.writeOptional("knockback_conditions", Condition.TYPE, value.knockbackConditions)
.writeOptional("damage_conditions", Condition.TYPE, value.damageConditions)
.writeOptional("forward_movement", Types.FLOAT, value.forwardMovement, 0F)
.writeOptional("damage_multiplier", Types.FLOAT, value.damageMultiplier, 1F)
.writeOptional("sound", Types.SOUND_EVENT, value.sound)
.writeOptional("hit_sound", Types.SOUND_EVENT, value.hitSound)
);
}
};
public record Condition(int maxDurationTicks, float minSpeed, float minRelativeSpeed) {
public static final Type<Condition> TYPE = new Type<>(Condition.class) {
@Override
public Condition read(final ByteBuf buffer) {
final int maxDurationTicks = Types.VAR_INT.readPrimitive(buffer);
final float minSpeed = Types.FLOAT.readPrimitive(buffer);
final float minRelativeSpeed = Types.FLOAT.readPrimitive(buffer);
return new Condition(maxDurationTicks, minSpeed, minRelativeSpeed);
}
@Override
public void write(final ByteBuf buffer, final Condition value) {
Types.VAR_INT.writePrimitive(buffer, value.maxDurationTicks);
Types.FLOAT.writePrimitive(buffer, value.minSpeed);
Types.FLOAT.writePrimitive(buffer, value.minRelativeSpeed);
}
@Override
public void write(final Ops ops, final Condition value) {
ops.writeMap(map -> map
.write("max_duration_ticks", Types.INT, value.maxDurationTicks)
.writeOptional("min_speed", Types.FLOAT, value.minSpeed, 0F)
.writeOptional("min_relative_speed", Types.FLOAT, value.minRelativeSpeed, 0F)
);
}
};
public static final Type<Condition> OPTIONAL_TYPE = new OptionalType<>(TYPE) {
};
}
}
@@ -0,0 +1,64 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
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 PiercingWeapon(boolean dealsKnockback, boolean dismounts,
@Nullable Holder<SoundEvent> sound, @Nullable Holder<SoundEvent> hitSound) {
public static final Type<PiercingWeapon> TYPE = new Type<>(PiercingWeapon.class) {
@Override
public PiercingWeapon read(final ByteBuf buffer) {
final boolean dealsKnockback = Types.BOOLEAN.read(buffer);
final boolean dismounts = Types.BOOLEAN.read(buffer);
final Holder<SoundEvent> sound = Types.OPTIONAL_SOUND_EVENT.read(buffer);
final Holder<SoundEvent> hitSound = Types.OPTIONAL_SOUND_EVENT.read(buffer);
return new PiercingWeapon(dealsKnockback, dismounts, sound, hitSound);
}
@Override
public void write(final ByteBuf buffer, final PiercingWeapon value) {
Types.BOOLEAN.write(buffer, value.dealsKnockback);
Types.BOOLEAN.write(buffer, value.dismounts);
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.sound);
Types.OPTIONAL_SOUND_EVENT.write(buffer, value.hitSound);
}
@Override
public void write(final Ops ops, final PiercingWeapon value) {
ops.writeMap(map -> map
.writeOptional("deals_knockback", Types.BOOLEAN, value.dealsKnockback, true)
.writeOptional("dismounts", Types.BOOLEAN, value.dismounts, false)
.writeOptional("sound", Types.SOUND_EVENT, value.sound)
.writeOptional("hit_sound", Types.SOUND_EVENT, value.hitSound)
);
}
};
}
@@ -23,39 +23,29 @@
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.protocol.Protocol;
import com.viaversion.viaversion.api.type.TransformingType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public final class PotDecorations implements Copyable, Rewritable {
public record PotDecorations(int[] itemIds) implements Copyable, Rewritable {
public static final Type<PotDecorations> TYPE = new Type<>(PotDecorations.class) {
public static final Type<PotDecorations> TYPE = new TransformingType<>(Types.VAR_INT_ARRAY_PRIMITIVE, PotDecorations.class, PotDecorations::new, PotDecorations::itemIds) {
@Override
public PotDecorations read(final ByteBuf buffer) {
return new PotDecorations(Types.VAR_INT_ARRAY_PRIMITIVE.read(buffer));
}
@Override
public void write(final ByteBuf buffer, final PotDecorations value) {
Types.VAR_INT_ARRAY_PRIMITIVE.write(buffer, value.itemIds());
public void write(final Ops ops, final PotDecorations value) {
ops.writeList(list -> {
for (final int itemId : value.itemIds) {
list.write(Types.IDENTIFIER, ops.context().registryAccess().item(itemId));
}
});
}
};
private final int[] itemIds;
public PotDecorations(final int[] itemIds) {
this.itemIds = itemIds;
}
public PotDecorations(final int backItem, final int leftItem, final int rightItem, final int frontItem) {
this.itemIds = new int[]{backItem, leftItem, rightItem, frontItem};
}
public int[] itemIds() {
return itemIds;
this(new int[]{backItem, leftItem, rightItem, frontItem});
}
public int backItem() {
@@ -25,6 +25,7 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.EitherHolder;
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.api.type.types.misc.EitherHolderType;
@@ -45,6 +46,11 @@ public record ProvidesTrimMaterial(EitherHolder<ArmorTrimMaterial> material) imp
public void write(final ByteBuf buffer, final ProvidesTrimMaterial value) {
EitherHolderType.write(buffer, value.material, ArmorTrimMaterial.TYPE1_21_5);
}
@Override
public void write(final Ops ops, final ProvidesTrimMaterial value) {
EitherHolderType.write(ops, value.material, ArmorTrimMaterial.TYPE1_21_5);
}
};
@Override
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
@@ -42,6 +43,13 @@ public record SuspiciousStewEffect(int mobEffect, int duration) {
Types.VAR_INT.writePrimitive(buffer, value.mobEffect);
Types.VAR_INT.writePrimitive(buffer, value.duration);
}
@Override
public void write(final Ops ops, final SuspiciousStewEffect value) {
ops.writeMap(map -> map
.write("id", EnumTypes.MOB_EFFECT, value.mobEffect)
.writeOptional("duration", Types.INT, value.duration, 160));
}
};
public static final Type<SuspiciousStewEffect[]> ARRAY_TYPE = new ArrayType<>(TYPE);
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.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 SwingAnimation(int type, int duration) {
private static final int DEFAULT_TYPE = EnumTypes.SWING_ANIMATION.idFromName("whack");
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);
final int duration = Types.VAR_INT.readPrimitive(buffer);
return new SwingAnimation(type, duration);
}
@Override
public void write(final ByteBuf buffer, final SwingAnimation value) {
Types.VAR_INT.writePrimitive(buffer, value.type);
Types.VAR_INT.writePrimitive(buffer, value.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)
);
}
};
}
@@ -23,6 +23,7 @@
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.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
@@ -69,6 +70,15 @@ public record ToolProperties(ToolRule[] rules, float defaultMiningSpeed, int dam
Types.VAR_INT.writePrimitive(buffer, value.damagePerBlock());
buffer.writeBoolean(value.canDestroyBlocksInCreative());
}
@Override
public void write(final Ops ops, final ToolProperties value) {
ops.writeMap(map -> map
.write("rules", ToolRule.ARRAY_TYPE, value.rules())
.writeOptional("default_mining_speed", Types.FLOAT, value.defaultMiningSpeed(), 1F)
.writeOptional("damage_per_block", Types.INT, value.damagePerBlock(), 1)
.writeOptional("can_destroy_blocks_in_creative", Types.BOOLEAN, value.canDestroyBlocksInCreative(), true));
}
};
@Override
@@ -23,11 +23,14 @@
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.HolderSet;
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.util.Rewritable;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -50,6 +53,14 @@ public record ToolRule(HolderSet blocks, @Nullable Float speed,
Types.OPTIONAL_FLOAT.write(buffer, value.speed);
Types.OPTIONAL_BOOLEAN.write(buffer, value.correctForDrops);
}
@Override
public void write(final Ops ops, final ToolRule value) {
ops.writeMap(map -> map
.write("blocks", new HolderSetType(MappingData.MappingType.BLOCK), value.blocks)
.writeOptional("speed", Types.FLOAT, value.speed)
.writeOptional("correct_for_drops", Types.BOOLEAN, value.correctForDrops));
}
};
public static final Type<ToolRule[]> ARRAY_TYPE = new ArrayType<>(TYPE);
@@ -63,7 +63,7 @@ public record TooltipDisplay(boolean hideTooltip,
final Key[] hiddenComponents = value.hiddenComponents.intStream().mapToObj(id -> ops.context().registryAccess().dataComponentType(id)).toArray(Key[]::new);
ops.writeMap(map -> map
.writeOptional("hide_tooltip", Types.BOOLEAN, value.hideTooltip, false)
.writeOptional("hidden_components", Types.RESOURCE_LOCATION_ARRAY, hiddenComponents, new Key[0]));
.writeOptional("hidden_components", Types.IDENTIFIER_ARRAY, hiddenComponents, new Key[0]));
}
};
@@ -75,7 +75,10 @@ public record TooltipDisplay(boolean hideTooltip,
final IntSortedSet newHiddenComponents = new IntLinkedOpenHashSet();
for (final int hiddenComponent : hiddenComponents) {
newHiddenComponents.add(Rewritable.rewriteDataComponentType(protocol, clientbound, hiddenComponent));
final int mappedId = Rewritable.rewriteDataComponentType(protocol, clientbound, hiddenComponent);
if (mappedId != -1) {
newHiddenComponents.add(mappedId);
}
}
return new TooltipDisplay(hideTooltip, newHiddenComponents);
}
@@ -53,7 +53,7 @@ public record UseCooldown(float seconds, @Nullable String cooldownGroup) impleme
final Key cooldownGroup = value.cooldownGroup != null ? Key.of(value.cooldownGroup) : null;
ops.writeMap(map -> map
.write("seconds", Types.FLOAT, value.seconds())
.writeOptional("cooldown_group", Types.RESOURCE_LOCATION, cooldownGroup));
.writeOptional("cooldown_group", Types.IDENTIFIER, cooldownGroup));
}
};
@@ -0,0 +1,57 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record UseEffects(boolean canSprint, boolean interactVibrations, float speedMultiplier) {
public static final Type<UseEffects> TYPE = new Type<>(UseEffects.class) {
@Override
public UseEffects read(final ByteBuf buffer) {
final boolean canSprint = Types.BOOLEAN.read(buffer);
final boolean interactVibrations = Types.BOOLEAN.read(buffer);
final float speedMultiplier = Types.FLOAT.readPrimitive(buffer);
return new UseEffects(canSprint, interactVibrations, speedMultiplier);
}
@Override
public void write(final ByteBuf buffer, final UseEffects value) {
Types.BOOLEAN.write(buffer, value.canSprint());
Types.BOOLEAN.write(buffer, value.interactVibrations());
Types.FLOAT.writePrimitive(buffer, value.speedMultiplier());
}
@Override
public void write(final Ops ops, final UseEffects value) {
ops.writeMap(map -> map
.writeOptional("can_sprint", Types.BOOLEAN, value.canSprint, false)
.writeOptional("interact_vibrations", Types.BOOLEAN, value.interactVibrations, true)
.writeOptional("speed_multiplier", Types.FLOAT, value.speedMultiplier, 0.2F));
}
};
}
@@ -28,7 +28,7 @@ import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
import com.viaversion.viaversion.api.connection.UserConnection;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
/**
@@ -195,7 +195,7 @@ public interface ViaPlatform<T> {
* @return immutable collection of unsupported software to be checked
*/
default Collection<UnsupportedSoftware> getUnsupportedSoftwareClasses() {
return Collections.emptyList();
return List.of();
}
/**
@@ -37,6 +37,7 @@ import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
import com.viaversion.viaversion.api.rewriter.EntityRewriter;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
import com.viaversion.viaversion.api.rewriter.ParticleRewriter;
import com.viaversion.viaversion.api.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.api.rewriter.TagRewriter;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
@@ -376,6 +377,15 @@ public interface Protocol<CU extends ClientboundPacketType, CM extends Clientbou
return null;
}
/**
* Returns the protocol's registry data rewriter if present.
*
* @return registry data rewriter
*/
default @Nullable RegistryDataRewriter getRegistryDataRewriter() {
return null;
}
/**
* Returns the protocol's particle rewriter if present.
*
@@ -118,12 +118,10 @@ public class PacketTracker {
this.receivedPacketsTotal = receivedPackets;
}
@Deprecated(forRemoval = true)
public long getIntervalPackets() {
return this.packetTracker.intervalValue;
}
@Deprecated(forRemoval = true)
public void setIntervalPackets(long intervalPackets) {
this.packetTracker.intervalValue = Math.toIntExact(intervalPackets);
}
@@ -134,7 +132,7 @@ public class PacketTracker {
public boolean isPacketLimiterEnabled() {
ViaVersionConfig config = Via.getConfig();
return packetLimiterEnabled && config.getPacketTrackerConfig().enabled() && config.getPacketSizeTrackerConfig().enabled();
return packetLimiterEnabled && (config.getPacketTrackerConfig().enabled() || config.getPacketSizeTrackerConfig().enabled());
}
public void setPacketLimiterEnabled(boolean packetLimiterEnabled) {
@@ -258,9 +258,7 @@ public interface PacketWrapper {
* @param packetType packet type of the new packet
* @return The newly created packet wrapper
*/
default PacketWrapper create(PacketType packetType) {
return create(packetType.getId());
}
PacketWrapper create(PacketType packetType);
/**
* Creates a new packet with values.
@@ -269,9 +267,7 @@ public interface PacketWrapper {
* @param handler handler to write to the packet
* @return newly created packet wrapper
*/
default PacketWrapper create(PacketType packetType, PacketHandler handler) throws InformativeException {
return create(packetType.getId(), handler);
}
PacketWrapper create(PacketType packetType, PacketHandler handler) throws InformativeException;
/**
* Creates a new packet for the target of this packet.
@@ -141,7 +141,7 @@ public abstract class PacketHandlers implements PacketHandler {
try {
handler.handle(h);
} catch (Exception e) {
if (!Via.getConfig().isSuppressConversionWarnings()) {
if (Via.getConfig().logOtherConversionWarnings()) {
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to handle packet", e);
}
h.cancel();
@@ -92,6 +92,7 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_21_6 = register(771, "1.21.6");
public static final ProtocolVersion v1_21_7 = register(772, "1.21.7-1.21.8", new SubVersionRange("1.21", 7, 8));
public static final ProtocolVersion v1_21_9 = register(773, "1.21.9-1.21.10", new SubVersionRange("1.21", 9, 10));
public static final ProtocolVersion v1_21_11 = register(774, "1.21.11");
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
static {
@@ -0,0 +1,31 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.rewriter;
import com.viaversion.viaversion.util.KeyMappings;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface RegistryDataRewriter {
@Nullable KeyMappings getMappings(String registryKey);
}
@@ -185,9 +185,9 @@ public final class Types {
/* MC Types */
public static final Type<byte[]> SERVERBOUND_CUSTOM_PAYLOAD_DATA = new RemainingBytesType(Short.MAX_VALUE);
public static final Type<Key> RESOURCE_LOCATION = new KeyType();
public static final Type<Key> OPTIONAL_RESOURCE_LOCATION = new KeyType.OptionalKeyType();
public static final Type<Key[]> RESOURCE_LOCATION_ARRAY = new ArrayType<>(RESOURCE_LOCATION);
public static final Type<Key> IDENTIFIER = new KeyType();
public static final Type<Key> OPTIONAL_IDENTIFIER = new KeyType.OptionalKeyType();
public static final Type<Key[]> IDENTIFIER_ARRAY = new ArrayType<>(IDENTIFIER);
public static final Type<Key> TAG_KEY = new TagKeyType();
public static final Type<BlockPosition> BLOCK_POSITION1_8 = new BlockPositionType1_8();
@@ -27,7 +27,7 @@ import com.viaversion.viaversion.util.Either;
import io.netty.buffer.ByteBuf;
// Yuck - only use when necessary
public final class EitherType<T, V> extends Type<Either<T, V>> {
public class EitherType<T, V> extends Type<Either<T, V>> {
private final Type<T> leftType;
private final Type<V> rightType;
@@ -42,23 +42,37 @@ public final class EnumType extends VarIntType {
@Override
public void write(final Ops ops, final Integer value) {
final String name;
if (value < 0 || value >= names.length) {
name = switch (fallback) {
case ZERO -> names[0];
case WRAP -> names[Math.floorMod(value, names.length)];
case CLAMP -> names[MathUtil.clamp(value, 0, names.length - 1)];
};
} else {
name = names[value];
}
Types.STRING.write(ops, name);
Types.STRING.write(ops, nameFromId(value));
}
public String[] names() {
return names;
}
public String nameFromId(final int id) {
if (id < 0 || id >= names.length) {
return switch (fallback) {
case ZERO -> names[0];
case WRAP -> names[Math.floorMod(id, names.length)];
case CLAMP -> names[MathUtil.clamp(id, 0, names.length - 1)];
};
}
return names[id];
}
public int idFromName(final String name) {
for (int i = 0; i < names.length; i++) {
if (names[i].equals(name)) {
return i;
}
}
return switch (fallback) {
case ZERO -> 0;
case WRAP -> Math.floorMod(name.hashCode(), names.length);
case CLAMP -> names.length - 1;
};
}
public enum Fallback {
ZERO, WRAP, CLAMP
}
@@ -22,9 +22,11 @@
*/
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.Types;
import com.viaversion.viaversion.util.UUIDUtil;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
@@ -45,6 +47,11 @@ public class UUIDType extends Type<UUID> {
buffer.writeLong(object.getLeastSignificantBits());
}
@Override
public void write(final Ops ops, final UUID value) {
ops.write(Types.INT_ARRAY_PRIMITIVE, UUIDUtil.toIntArray(value));
}
public static final class OptionalUUIDType extends OptionalType<UUID> {
public OptionalUUIDType() {
@@ -121,7 +121,7 @@ public class ItemType1_20_5 extends Type<Item> {
@Override
public void write(final Ops ops, final Item item) {
ops.writeMap(map -> {
map.write("id", Types.RESOURCE_LOCATION, ops.context().registryAccess().item(item.identifier()))
map.write("id", Types.IDENTIFIER, ops.context().registryAccess().item(item.identifier()))
.write("count", Types.VAR_INT, item.amount());
if (item.dataContainer().isEmpty()) {
@@ -51,7 +51,7 @@ public class GlobalBlockPositionType extends Type<GlobalBlockPosition> {
@Override
public void write(final Ops ops, final GlobalBlockPosition value) {
ops.writeMap(map -> map
.write("dimension", Types.RESOURCE_LOCATION, Key.of(value.dimension()))
.write("dimension", Types.IDENTIFIER, Key.of(value.dimension()))
.write("pos", Types.BLOCK_POSITION1_14, value));
}
@@ -23,8 +23,10 @@
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.viaversion.api.minecraft.EitherHolder;
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 EitherHolderType<T> extends Type<EitherHolder<T>> {
@@ -45,6 +47,11 @@ public final class EitherHolderType<T> extends Type<EitherHolder<T>> {
write(buffer, object, this.holderType);
}
@Override
public void write(final Ops ops, final EitherHolder<T> value) {
write(ops, value, this.holderType);
}
public static <T> EitherHolder<T> read(final ByteBuf buffer, final HolderType<T> holderType) {
if (buffer.readBoolean()) {
return EitherHolder.of(holderType.read(buffer));
@@ -61,4 +68,12 @@ public final class EitherHolderType<T> extends Type<EitherHolder<T>> {
Types.STRING.write(buffer, object.key());
}
}
public static <T> void write(final Ops ops, final EitherHolder<T> object, final HolderType<T> holderType) {
if (object.hasHolder()) {
holderType.write(ops, object.holder());
} else {
ops.write(Types.IDENTIFIER, Key.of(object.key()));
}
}
}
@@ -31,6 +31,8 @@ import java.util.UUID;
public final class GameProfileType extends Type<GameProfile> {
private static final GameProfile.Property[] EMPTY_PROPERTIES = new GameProfile.Property[0];
public GameProfileType() {
super(GameProfile.class);
}
@@ -54,7 +56,7 @@ public final class GameProfileType extends Type<GameProfile> {
public void write(final Ops ops, final GameProfile value) {
ops.writeMap(map -> map
.writeOptional("name", Types.STRING, value.name())
.writeOptional("id", Types.STRING, value.id() != null ? value.id().toString() : null)
.write("properties", Types.PROFILE_PROPERTY_ARRAY, value.properties()));
.writeOptional("id", Types.UUID, value.id())
.writeOptional("properties", Types.PROFILE_PROPERTY_ARRAY, value.properties(), EMPTY_PROPERTIES));
}
}
@@ -23,8 +23,9 @@
package com.viaversion.viaversion.api.type.types.misc;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.data.MappingData;
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.OptionalType;
import com.viaversion.viaversion.api.type.Type;
@@ -34,15 +35,20 @@ import io.netty.buffer.ByteBuf;
public class HolderSetType extends Type<HolderSet> {
private final MappingDataBase.MappingType mappingType;
private final RegistryKey registryKey;
public HolderSetType() {
this(null);
}
public HolderSetType(final MappingDataBase.MappingType mappingType) {
/**
* Creates a holder set type that is able to write to {@link Ops}.
*
* @param registryKey registry key
*/
public HolderSetType(final RegistryKey registryKey) {
super(HolderSet.class);
this.mappingType = mappingType;
this.registryKey = registryKey;
}
@Override
@@ -79,23 +85,31 @@ public class HolderSetType extends Type<HolderSet> {
if (value.hasTagKey()) {
ops.write(Types.TAG_KEY, Key.of(value.tagKey()));
} else {
Preconditions.checkArgument(mappingType != null, "Cannot write HolderSet with direct ids without a mapping type");
Preconditions.checkArgument(registryKey != null, "Cannot write HolderSet with direct ids without a mapping type");
if (value.ids().length == 1) {
// Single entries are inlined
final Key key = ops.context().registryAccess().key(mappingType, value.ids()[0]);
ops.write(Types.RESOURCE_LOCATION, key);
ops.write(Types.IDENTIFIER, key(ops, value.ids()[0]));
return;
}
ops.writeList(list -> {
for (final int id : value.ids()) {
final Key key = ops.context().registryAccess().key(mappingType, id);
list.write(Types.RESOURCE_LOCATION, key);
list.write(Types.IDENTIFIER, key(ops, id));
}
});
}
}
private Key key(final Ops ops, final int id) {
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));
} else {
return ops.context().registryAccess().registryKey(registryKey.key().toString(), id);
}
}
public static final class OptionalHolderSetType extends OptionalType<HolderSet> {
public OptionalHolderSetType() {
@@ -66,23 +66,23 @@ public abstract class HolderType<T> extends Type<Holder<T>> {
public abstract T readDirect(final ByteBuf buffer);
public abstract void writeDirect(final ByteBuf buffer, final T object);
public abstract void writeDirect(final ByteBuf buffer, final T value);
@Override
public void write(final Ops ops, final Holder<T> value) {
if (value.hasId()) {
ops.write(Types.RESOURCE_LOCATION, identifier(ops, value.id()));
ops.write(Types.IDENTIFIER, identifier(ops, value.id()));
} else {
writeDirect(ops, value.value());
}
}
protected Key identifier(final Ops ops, final int id) {
Preconditions.checkArgument(mappingType != null, "Mapping type is not defined for this HolderType");
Preconditions.checkArgument(mappingType != null, "Mapping type is not defined for this HolderType: " + getClass().getName());
return ops.context().registryAccess().key(mappingType, id);
}
public void writeDirect(final Ops ops, final T object) {
public void writeDirect(final Ops ops, final T value) {
throw new UnsupportedOperationException("Write operation not supported for type: " + getTypeName());
}
@@ -54,7 +54,7 @@ public class KeyType extends Type<Key> {
public static final class OptionalKeyType extends OptionalType<Key> {
public OptionalKeyType() {
super(Types.RESOURCE_LOCATION);
super(Types.IDENTIFIER);
}
}
}
@@ -97,31 +97,31 @@ public class ParticleType extends DynamicType<Particle> {
public static final DataReader<Particle> VIBRATION = (buf, particle) -> {
particle.add(Types.BLOCK_POSITION1_14, Types.BLOCK_POSITION1_14.read(buf)); // From block pos
String resourceLocation = Types.STRING.read(buf);
particle.add(Types.STRING, resourceLocation);
String identifier = Types.STRING.read(buf);
particle.add(Types.STRING, identifier);
resourceLocation = Key.stripMinecraftNamespace(resourceLocation);
if (resourceLocation.equals("block")) {
identifier = Key.stripMinecraftNamespace(identifier);
if (identifier.equals("block")) {
particle.add(Types.BLOCK_POSITION1_14, Types.BLOCK_POSITION1_14.read(buf)); // Target block pos
} else if (resourceLocation.equals("entity")) {
} else if (identifier.equals("entity")) {
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Target entity
} else {
Via.getPlatform().getLogger().warning("Unknown vibration path position source type: " + resourceLocation);
Via.getPlatform().getLogger().warning("Unknown vibration path position source type: " + identifier);
}
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Arrival in ticks
};
public static final DataReader<Particle> VIBRATION1_19 = (buf, particle) -> {
String resourceLocation = Types.STRING.read(buf);
particle.add(Types.STRING, resourceLocation);
String identifier = Types.STRING.read(buf);
particle.add(Types.STRING, identifier);
resourceLocation = Key.stripMinecraftNamespace(resourceLocation);
if (resourceLocation.equals("block")) {
identifier = Key.stripMinecraftNamespace(identifier);
if (identifier.equals("block")) {
particle.add(Types.BLOCK_POSITION1_14, Types.BLOCK_POSITION1_14.read(buf)); // Target block pos
} else if (resourceLocation.equals("entity")) {
} else if (identifier.equals("entity")) {
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Target entity
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Y offset
} else {
Via.getPlatform().getLogger().warning("Unknown vibration path position source type: " + resourceLocation);
Via.getPlatform().getLogger().warning("Unknown vibration path position source type: " + identifier);
}
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Arrival in ticks
};
@@ -20,17 +20,21 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types;
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.viaversion.api.minecraft.RegistryKey;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.VarIntType;
import com.viaversion.viaversion.util.Key;
public final class RegistryValueType extends VarIntType {
public final class RegistryValueType extends VarIntType implements RegistryKey {
private final Key key;
private final String[] names;
public RegistryValueType(final String... names) {
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]);
@@ -39,10 +43,19 @@ public final class RegistryValueType extends VarIntType {
@Override
public void write(final Ops ops, final Integer value) {
Types.STRING.write(ops, names[value]);
Types.IDENTIFIER.write(ops, Key.of(names[value]));
}
public String[] names() {
return names;
}
public String byId(final int id) {
return names[id];
}
@Override
public Key key() {
return key;
}
}
@@ -81,9 +81,9 @@ public final class ResolvableProfileType extends Type<ResolvableProfile> {
final String modelType = value.modelType() != null ? (value.modelType() == 0 ? "slim" : "wide") : null;
ops.writeMap(map -> map
.writeInlinedMap(Types.GAME_PROFILE, value.profile())
.writeOptional("texture", Types.RESOURCE_LOCATION, value.bodyTexture() != null ? Key.of(value.bodyTexture()) : null)
.writeOptional("cape", Types.RESOURCE_LOCATION, value.capeTexture() != null ? Key.of(value.capeTexture()) : null)
.writeOptional("elytra", Types.RESOURCE_LOCATION, value.elytraTexture() != null ? Key.of(value.elytraTexture()) : null)
.writeOptional("texture", Types.IDENTIFIER, value.bodyTexture() != null ? Key.of(value.bodyTexture()) : null)
.writeOptional("cape", Types.IDENTIFIER, value.capeTexture() != null ? Key.of(value.capeTexture()) : null)
.writeOptional("elytra", Types.IDENTIFIER, value.elytraTexture() != null ? Key.of(value.elytraTexture()) : null)
.writeOptional("model", Types.OPTIONAL_STRING, modelType)
);
}
@@ -37,9 +37,9 @@ public final class SoundEventType extends HolderType<SoundEvent> {
@Override
public SoundEvent readDirect(final ByteBuf buffer) {
final String resourceLocation = Types.STRING.read(buffer);
final String identifier = Types.STRING.read(buffer);
final Float fixedRange = Types.OPTIONAL_FLOAT.read(buffer);
return new SoundEvent(resourceLocation, fixedRange);
return new SoundEvent(identifier, fixedRange);
}
@Override
@@ -51,7 +51,7 @@ public final class SoundEventType extends HolderType<SoundEvent> {
@Override
public void writeDirect(final Ops ops, final SoundEvent object) {
ops.writeMap(map -> map
.write("sound_id", Types.RESOURCE_LOCATION, Key.of(object.identifier()))
.write("sound_id", Types.IDENTIFIER, Key.of(object.identifier()))
.writeOptional("range", Types.FLOAT, object.fixedRange()));
}
@@ -0,0 +1,51 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.viaversion.api.minecraft.RegistryKey;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.EitherType;
import com.viaversion.viaversion.util.Either;
import com.viaversion.viaversion.util.Key;
// ???
public final class SynchronizedRegistryEitherType extends EitherType<Integer, String> {
private final RegistryKey registryKey;
public SynchronizedRegistryEitherType(final RegistryKey registryKey) {
super(Types.VAR_INT, Types.STRING);
this.registryKey = registryKey;
}
@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());
Types.IDENTIFIER.write(ops, key);
} else {
Types.IDENTIFIER.write(ops, Key.of(value.right()));
}
}
}
@@ -0,0 +1,44 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.viaversion.api.minecraft.RegistryKey;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.VarIntType;
import com.viaversion.viaversion.util.Key;
public final class SynchronizedRegistryValueType extends VarIntType {
private final RegistryKey registryKey;
public SynchronizedRegistryValueType(final RegistryKey registryKey) {
this.registryKey = registryKey;
}
@Override
public void write(final Ops ops, final Integer value) {
final Key key = ops.context().registryAccess().registryKey(this.registryKey.key().toString(), value);
Types.IDENTIFIER.write(ops, key);
}
}
@@ -23,10 +23,12 @@
package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_20_5;
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.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;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_2;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_9;
@@ -46,4 +48,5 @@ public final class VersionedTypes {
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> V1_21_5 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_5::new);
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> V1_21_6 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_5::new);
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_9> V1_21_9 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_9::new);
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);
}
@@ -29,7 +29,6 @@ import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public class InformativeException extends RuntimeException {
private static final int MAX_MESSAGE_LENGTH = 5_000;
private final List<DataEntry> dataEntries = new ArrayList<>();
private boolean shouldBePrinted = true;
private int sources;
@@ -72,8 +71,9 @@ public class InformativeException extends RuntimeException {
builder.append(entry.name()).append(": ");
String s = String.valueOf(entry.value());
if (!Via.getManager().isDebug() && s.length() > 10 && builder.length() + s.length() > MAX_MESSAGE_LENGTH) {
s = s.substring(0, MAX_MESSAGE_LENGTH - builder.length()) + "...";
if (!Via.getManager().isDebug() && s.length() > 10 && builder.length() + s.length() > Via.getConfig().maxErrorLength()) {
final int remaining = Math.max(0, Via.getConfig().maxErrorLength() - builder.length());
s = s.substring(0, Math.min(remaining, s.length())) + "...";
}
builder.append(StringUtil.forLogging(s));
}
@@ -22,7 +22,6 @@ import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.ViaAPI;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.platform.PlatformTask;
import com.viaversion.viaversion.api.platform.UnsupportedSoftware;
import com.viaversion.viaversion.api.platform.ViaPlatform;
import com.viaversion.viaversion.bukkit.commands.BukkitCommandHandler;
import com.viaversion.viaversion.bukkit.listeners.JoinListener;
@@ -35,12 +34,8 @@ import com.viaversion.viaversion.bukkit.platform.BukkitViaTaskTask;
import com.viaversion.viaversion.bukkit.platform.FoliaViaTask;
import com.viaversion.viaversion.bukkit.platform.PaperViaInjector;
import com.viaversion.viaversion.dump.PluginInfo;
import com.viaversion.viaversion.unsupported.UnsupportedPlugin;
import com.viaversion.viaversion.unsupported.UnsupportedServerSoftware;
import com.viaversion.viaversion.util.GsonUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -219,8 +214,8 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
@Override
public boolean kickPlayer(UserConnection connection, String message) {
UUID uuid = connection.getProtocolInfo().getUuid();
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
Player player;
if (uuid != null && (player = Bukkit.getPlayer(uuid)) != null) {
player.kickPlayer(message);
return true;
} else {
@@ -264,20 +259,6 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
return api;
}
@Override
public final Collection<UnsupportedSoftware> getUnsupportedSoftwareClasses() {
final List<UnsupportedSoftware> list = new ArrayList<>(ViaPlatform.super.getUnsupportedSoftwareClasses());
list.add(new UnsupportedServerSoftware.Builder().name("Yatopia").reason(UnsupportedServerSoftware.Reason.DANGEROUS_SERVER_SOFTWARE)
.addClassName("org.yatopiamc.yatopia.server.YatopiaConfig")
.addClassName("net.yatopia.api.event.PlayerAttackEntityEvent")
.addClassName("yatopiamc.org.yatopia.server.YatopiaConfig") // Only the best kind of software relocates its own classes to hide itself :tinfoilhat:
.addMethod("org.bukkit.Server", "getLastTickTime").build());
list.add(new UnsupportedPlugin.Builder().name("software to mess with message signing").reason(UnsupportedPlugin.Reason.SECURE_CHAT_BYPASS)
.addPlugin("NoEncryption").addPlugin("NoReport")
.addPlugin("NoChatReports").addPlugin("NoChatReport").build());
return Collections.unmodifiableList(list);
}
@Override
public boolean hasPlugin(final String name) {
return getServer().getPluginManager().getPlugin(name) != null;
@@ -30,13 +30,7 @@ public record CodecRegistryContext(Protocol<?, ?, ?, ?> protocol, RegistryAccess
// Generally from hardcoded, but highly variable client data
private static final Set<StructuredDataKey<?>> NOT_IMPLEMENTED = new ReferenceOpenHashSet<>(List.of(
StructuredDataKey.TRIM1_21_5, StructuredDataKey.TOOL1_21_5, StructuredDataKey.PROVIDES_TRIM_MATERIAL,
StructuredDataKey.CONSUMABLE1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE1_21_5, StructuredDataKey.INSTRUMENT1_21_5,
StructuredDataKey.DEATH_PROTECTION, StructuredDataKey.BLOCKS_ATTACKS, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS,
StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.POT_DECORATIONS,
StructuredDataKey.WOLF_VARIANT, StructuredDataKey.WOLF_SOUND_VARIANT, StructuredDataKey.PIG_VARIANT,
StructuredDataKey.COW_VARIANT, StructuredDataKey.CHICKEN_VARIANT, StructuredDataKey.FROG_VARIANT,
StructuredDataKey.PAINTING_VARIANT, StructuredDataKey.CAT_VARIANT
StructuredDataKey.DAMAGE_TYPE
));
public CodecRegistryContext(final Protocol<?, ?, ?, ?> protocol, final RegistryAccess registryAccess, final boolean mapped) {
@@ -52,6 +46,6 @@ public record CodecRegistryContext(Protocol<?, ?, ?, ?> protocol, RegistryAccess
}
final VersionedTypesHolder types = mapped ? protocol.mappedTypes() : protocol.types();
return !NOT_IMPLEMENTED.contains(key) && types.structuredDataKeys().supportsOps(key);
return (NOT_IMPLEMENTED.isEmpty() || !NOT_IMPLEMENTED.contains(key)) && types.structuredDataKeys().supportsOps(key);
}
}
@@ -48,7 +48,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private boolean checkForUpdates;
private boolean preventCollision;
private boolean useNewEffectIndicator;
private boolean suppressMetadataErrors;
private boolean logEntityDataErrors;
private boolean shieldBlocking;
private boolean noDelayShieldBlocking;
private boolean showShieldWhenSwordInHand;
@@ -69,8 +69,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private String blockedDisconnectMessage;
private boolean logBlockedJoins;
private String reloadDisconnectMessage;
private boolean suppressConversionWarnings;
private boolean suppressTextComponentConversionWarnings;
private boolean logOtherConversionErrors;
private boolean logTextComponentConversionErrors;
private boolean disable1_13TabComplete;
private boolean teamColourFix;
private boolean serversideBlockConnections;
@@ -97,6 +97,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private boolean hideScoreboardNumbers;
private boolean fix1_21PlacementRotation;
private boolean cancelSwingInInventory;
private int maxErrorLength;
private boolean use1_8HitboxMargin;
protected AbstractViaConfig(final File configFile, final Logger logger) {
super(configFile, logger);
@@ -105,7 +107,9 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
@Override
public void reload() {
super.reload();
updateConfig();
if (updateConfig()) {
save();
}
loadFields();
}
@@ -113,7 +117,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
checkForUpdates = getBoolean("check-for-updates", true);
preventCollision = getBoolean("prevent-collision", true);
useNewEffectIndicator = getBoolean("use-new-effect-indicator", true);
suppressMetadataErrors = getBoolean("suppress-metadata-errors", false);
shieldBlocking = getBoolean("shield-blocking", true);
noDelayShieldBlocking = getBoolean("no-delay-shield-blocking", false);
showShieldWhenSwordInHand = getBoolean("show-shield-when-sword-in-hand", false);
@@ -130,11 +133,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
autoTeam = getBoolean("auto-team", true);
blockedProtocolVersions = loadBlockedProtocolVersions();
blockedDisconnectMessage = getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
logBlockedJoins = getBoolean("log-blocked-joins", false);
reloadDisconnectMessage = getString("reload-disconnect-msg", "Server reload, please rejoin!");
teamColourFix = getBoolean("team-colour-fix", true);
suppressConversionWarnings = getBoolean("suppress-conversion-warnings", false);
suppressTextComponentConversionWarnings = getBoolean("suppress-text-component-conversion-warnings", true);
disable1_13TabComplete = getBoolean("disable-1_13-auto-complete", false);
serversideBlockConnections = getBoolean("serverside-blockconnections", true);
reduceBlockStorageMemory = getBoolean("reduce-blockstorage-memory", false);
@@ -163,23 +163,68 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
hideScoreboardNumbers = getBoolean("hide-scoreboard-numbers", false);
fix1_21PlacementRotation = getBoolean("fix-1_21-placement-rotation", true);
cancelSwingInInventory = getBoolean("cancel-swing-in-inventory", true);
use1_8HitboxMargin = getBoolean("use-1_8-hitbox-margin", true);
packetTrackerConfig = loadRateLimitConfig(getSection("packet-limiter"), "%pps", 1);
packetSizeTrackerConfig = loadRateLimitConfig(getSection("packet-size-limiter"), "%bps", 1024);
final ConfigSection loggingSection = getSection("logging");
logBlockedJoins = loggingSection.getBoolean("log-blocked-joins", false);
logEntityDataErrors = loggingSection.getBoolean("log-entity-data-errors", true);
logTextComponentConversionErrors = loggingSection.getBoolean("log-text-component-conversion-errors", false);
logOtherConversionErrors = loggingSection.getBoolean("log-other-conversion-warnings", false);
maxErrorLength = loggingSection.getInt("max-error-length", 1500);
}
protected void updateConfig() {
/**
* Updates the config if the existing merging of default and provided config is not enough.
* <p>
* This can for example include renaming config options or changing default values.
*
* @return true if the config should be saved after calling this method
* @see #originalRootSection()
*/
protected boolean updateConfig() {
ConfigSection original = originalRootSection();
if (original != null && original.contains("max-pps")) {
if (original == null) {
return false;
}
boolean modified = false;
if (original.contains("max-pps")) {
// 5.5.0 pps changes
ConfigSection section = getSection("packet-limiter");
section.set("max-per-second", original.getInt("max-pps", -1));
section.set("max-per-second-kick-message", original.getString("max-pps-kick-msg", "You are sending too many packets!"));
section.set("sustained-max-per-second", original.getInt("tracking-warning-pps", -1));
section.set("sustained-threshold", original.getInt("tracking-max-warnings", 3));
section.set("sustained-period-seconds", original.getInt("tracking-period", 6));
section.set("sustained-period-seconds", original.getInt("tracking-period", 7));
section.set("sustained-kick-message", original.getString("tracking-max-kick-msg", "You are sending too many packets, :("));
save();
modified = true;
}
final int initialConfigVersion = original.getInt("init-config-version", 0); // version the config was initially created with
final int configVersion = original.getInt("config-version", 0);
final boolean migrateDefaults = original.getBoolean("migrate-default-config-changes", true);
if (configVersion < 1 && migrateDefaults) {
// 5.5.0/5.7.0 change of defaults
final ConfigSection packetLimiterSection = getSection("packet-limiter");
final int sustainedMax = packetLimiterSection.getInt("sustained-max-per-second", 0);
if (sustainedMax == 120 || sustainedMax == 150) {
packetLimiterSection.set("sustained-max-per-second", 200);
modified = true;
}
if (packetLimiterSection.getInt("sustained-period-seconds", 0) == 6) {
packetLimiterSection.set("sustained-period-seconds", 7);
modified = true;
}
ConfigSection loggingSection = getSection("logging");
loggingSection.set("log-blocked-joins", original.getBoolean("log-blocked-joins", false));
loggingSection.set("log-entity-data-errors", !original.getBoolean("suppress-metadata-errors", false));
loggingSection.set("max-error-length", original.getInt("max-error-length", 1500));
// Don't migrate the others
}
return modified;
}
private BlockedProtocolVersions loadBlockedProtocolVersions() {
@@ -292,8 +337,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
}
@Override
public boolean isSuppressMetadataErrors() {
return suppressMetadataErrors;
public boolean logEntityDataErrors() {
return logEntityDataErrors || Via.getManager().isDebug();
}
@Override
@@ -336,36 +381,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
return hologramOffset;
}
@Override
public int getMaxPPS() {
return packetTrackerConfig.maxRate();
}
@Override
public String getMaxPPSKickMessage() {
return packetTrackerConfig.maxRateKickMessage();
}
@Override
public int getTrackingPeriod() {
return (int) TimeUnit.NANOSECONDS.toSeconds(packetTrackerConfig.trackingPeriodNanos());
}
@Override
public int getWarningPPS() {
return packetTrackerConfig.warningRate();
}
@Override
public int getMaxWarnings() {
return packetTrackerConfig.maxWarnings();
}
@Override
public String getMaxWarningsKickMessage() {
return packetTrackerConfig.warningKickMessage();
}
@Override
public RateLimitConfig getPacketTrackerConfig() {
return packetTrackerConfig;
@@ -453,13 +468,13 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
}
@Override
public boolean isSuppressConversionWarnings() {
return suppressConversionWarnings && !Via.getManager().isDebug(); // Debug mode overrules config
public boolean logOtherConversionWarnings() {
return logOtherConversionErrors || Via.getManager().isDebug();
}
@Override
public boolean isSuppressTextComponentConversionWarnings() {
return suppressTextComponentConversionWarnings && !Via.getManager().isDebug(); // Debug mode overrules config
public boolean logTextComponentConversionErrors() {
return logTextComponentConversionErrors || Via.getManager().isDebug();
}
@Override
@@ -606,4 +621,14 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
public boolean cancelSwingInInventory() {
return cancelSwingInInventory;
}
@Override
public int maxErrorLength() {
return maxErrorLength;
}
@Override
public boolean use1_8HitboxMargin() {
return use1_8HitboxMargin;
}
}
@@ -44,24 +44,17 @@ public class ItemHasherBase implements ItemHasher {
public static int UNKNOWN_HASH = 399825415; // some random-ish number, from hashing Integer.MIN_VALUE+1 with crc32c
private final Map<Integer, HashedItem> hashes = CacheBuilder.newBuilder().concurrencyLevel(1).maximumSize(1024).<Integer, HashedItem>build().asMap();
protected final UserConnection connection;
private final List<String> enchantments = new ArrayList<>();
private boolean processingClientboundInventoryPacket;
private final CodecContext context;
private final CodecContext mappedContext;
public ItemHasherBase(final Protocol<?, ?, ?, ?> protocol, final UserConnection connection) {
final RegistryAccess registryAccess = RegistryAccess.of(this.enchantments, protocol.getMappingData());
final RegistryAccess registryAccess = RegistryAccess.of(protocol);
this.context = new CodecRegistryContext(protocol, registryAccess, false);
this.mappedContext = new CodecRegistryContext(protocol, registryAccess, true);
this.connection = connection;
}
@Override
public void setEnchantments(final List<String> enchantments) {
this.enchantments.clear();
this.enchantments.addAll(enchantments);
}
/**
* Returns the hashed item for the given item. Not all data may be successfully hashed.
*
Loaded 100 of 169 files, more files were not shown because too many files have changed in this diff. Show more