Compare commits

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

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

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

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 08:23:33 +02:00
Nassim Jahnke de9cec36c7 Don't hash empty items in container 2025-08-10 15:39:45 +02:00
Nassim Jahnke 6eb561607c Fix bad reference 2025-08-10 15:12:22 +02:00
Nassim Jahnke db3e1f605a Fix hashing of maps in lists 2025-08-10 15:04:39 +02:00
Nassim Jahnke 31583fc2d3 Update deps 2025-08-09 18:43:37 +02:00
Nassim Jahnke 6096ce4eea Add option to log blocked joins
Closes #4613
2025-08-09 18:21:15 +02:00
Nassim Jahnke 873da12233 Check if custom_name lock data is actually present in 1.21.2
Fixes #4622
2025-08-09 17:50:04 +02:00
EnZaXD 78191ea366 [ci skip] Gradle & Shadow 9.0.0; Rewrite .gitignore file (#4606) 2025-08-09 14:18:03 +02:00
EnZaXD f8d7c5c193 [ci skip] Fix packet id comments (#4621) 2025-08-09 13:11:52 +02:00
EnZaXD bc9c979e7d Don't make the protocol pipeline depend on simple protocol (#4619) 2025-08-08 18:59:19 +02:00
EnZaXD d686a9ddf0 Move protocol logger creation to AbstractProtocol#createLogger (#4620)
Allows VB to delegate the used logger to the VB platform logger
2025-08-08 15:36:25 +02:00
EnZaXD 9dd610605f Don't put legacy show_text value through json conversion in 1.21.1->.5 (#4611) 2025-08-05 09:19:31 +02:00
EnZaXD 219e163ac2 Add statistic mappings for 1.21.5->1.21.6 (#4609) 2025-08-03 09:33:56 +02:00
EnZaXD 925e7b4664 Add some backwards compatibility functions to PacketTracker (#4607) 2025-08-02 15:09:46 +02:00
criticalcynical 5a9f040af8 Fix wrong connections being removed when switching servers on proxy platforms (#4576) 2025-07-29 20:35:20 +02:00
Nassim Jahnke 992ad7f35a Fix max packet size check 2025-07-29 20:28:37 +02:00
EnZaXD bb93ac011c Null check original root section (#4604) 2025-07-29 19:38:13 +02:00
Nassim Jahnke 4070ea9f02 Revamp max-pps config
Add a config section for setting max packet size, add a toggle for disabling each tracker fully
2025-07-29 12:27:51 +02:00
EnZaXD 499efa1608 Convert HIDE_ADDITIONAL_TOOLTIP in both directions in 1.21.4->1.21.5 (#4600) 2025-07-29 12:19:10 +02:00
Nassim Jahnke 0196d9c83e Bump version to 5.5.0-SNAPSHOT 2025-07-29 12:11:59 +02:00
140 changed files with 3418 additions and 815 deletions

No files matched your search

+2 -2
View File
@@ -11,13 +11,13 @@ jobs:
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 17
+2 -2
View File
@@ -12,13 +12,13 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 17
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
persist-credentials: false
- name: Update Gradle Wrapper
+19 -98
View File
@@ -1,115 +1,36 @@
### Java files ###
*.class
# Gradle
# Package Files
#*.jar
*.war
*.ear
.gradle/
build/
out/
classes/
.kotlin/
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# Eclipse
*.launch
# Idea
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
# Ignore project files
*.iml
# Ignore IDEA directory
.idea/*
.idea/
!.idea/copyright/*
!.idea/scopes/*
# Include the project's dictionary
!.idea/dictionaries/
!.idea/dictionaries/*
# File-based project format:
*.iml
*.ipr
*.iws
### Plugin-specific files: ###
# IntelliJ
/out/
# VSCode
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# Eclipse Core
.vscode/
bin/
.classpath
.project
# External tool builders
.externalToolBuilders/
# macOS
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml
.nb-gradle/
### MacOS ###
.DS_Store
### Run Folder (ViaProxy) ###
common/run/
# Misc
run/
@@ -123,7 +123,7 @@ public interface ViaAPI<T> {
boolean isInjected(UUID uuid);
/**
* Returns whether Via injected into this player connection. Note that this method may not work on
* Returns the injected UserConnection if present. Note that this method may not work on
* clientside implementations and is generally not recommended to be used. Use {@link ConnectionManager} instead.
*
* @param uuid uuid of the player
@@ -0,0 +1,27 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.configuration;
public record RateLimitConfig(boolean enabled, int maxRate, String maxRateKickMessage, int warningRate, int maxWarnings,
long trackingPeriodNanos, String warningKickMessage, String ratePlaceholder) {
}
@@ -147,6 +147,7 @@ public interface ViaVersionConfig extends Config {
*
* @return The number of packets a client can send per second.
*/
@Deprecated(forRemoval = true)
int getMaxPPS();
/**
@@ -154,6 +155,7 @@ public interface ViaVersionConfig extends Config {
*
* @return Kick message, with colour codes using '&amp;amp;'
*/
@Deprecated(forRemoval = true)
String getMaxPPSKickMessage();
/**
@@ -161,6 +163,7 @@ public interface ViaVersionConfig extends Config {
*
* @return Time in seconds that should be tracked for warnings
*/
@Deprecated(forRemoval = true)
int getTrackingPeriod();
/**
@@ -168,6 +171,7 @@ public interface ViaVersionConfig extends Config {
*
* @return The number of packets per second to count as a warning.
*/
@Deprecated(forRemoval = true)
int getWarningPPS();
/**
@@ -175,6 +179,7 @@ public interface ViaVersionConfig extends Config {
*
* @return The number of packets a client can send per second.
*/
@Deprecated(forRemoval = true)
int getMaxWarnings();
/**
@@ -182,8 +187,13 @@ public interface ViaVersionConfig extends Config {
*
* @return Kick message, with colour codes using '&amp;amp;'
*/
@Deprecated(forRemoval = true)
String getMaxWarningsKickMessage();
RateLimitConfig getPacketTrackerConfig();
RateLimitConfig getPacketSizeTrackerConfig();
/**
* Send supported versions in the status response packet
*
@@ -263,6 +273,8 @@ public interface ViaVersionConfig extends Config {
*/
String getBlockedDisconnectMsg();
boolean logBlockedJoins();
/**
* Get the message sent to players being kicked on reload.
* Players are kicked to stop the server crashing
@@ -194,9 +194,15 @@ public interface UserConnection {
/**
* Monitors serverbound packets and returns whether a packet can/should be processed.
*
* @param bytes the number of bytes in the packet
* @return false if this packet should be cancelled
*/
boolean checkServerboundPacket();
boolean checkServerboundPacket(int bytes);
@Deprecated(forRemoval = true)
default boolean checkServerboundPacket() {
return checkServerboundPacket(0);
}
/**
* Monitors clientbound packets and returns whether a packet can/should be processed.
@@ -209,6 +215,11 @@ public interface UserConnection {
* @see #checkClientboundPacket()
* @see #checkServerboundPacket()
*/
default boolean checkIncomingPacket(final int bytes) {
return isClientSide() ? checkClientboundPacket() : checkServerboundPacket(bytes);
}
@Deprecated(forRemoval = true)
default boolean checkIncomingPacket() {
return isClientSide() ? checkClientboundPacket() : checkServerboundPacket();
}
@@ -140,8 +140,6 @@ public interface MappingData {
@Nullable Mappings getBlockMappings();
@Nullable Mappings getBlockEntityMappings();
@Nullable Mappings getBlockStateMappings();
@Nullable Mappings getSoundMappings();
@@ -154,6 +152,8 @@ public interface MappingData {
@Nullable Mappings getPaintingMappings();
@Nullable FullMappings getBlockEntityMappings();
@Nullable FullMappings getAttributeMappings();
@Nullable FullMappings getEntityMappings();
@@ -44,11 +44,11 @@ public class MappingDataBase implements MappingData {
protected FullMappings recipeSerializerMappings;
protected FullMappings itemDataSerializerMappings;
protected FullMappings attributeMappings;
protected FullMappings blockEntityMappings;
protected ParticleMappings particleMappings;
protected BiMappings itemMappings;
protected BiMappings blockMappings;
protected Mappings blockStateMappings;
protected Mappings blockEntityMappings;
protected Mappings soundMappings;
protected Mappings statisticsMappings;
protected Mappings enchantmentMappings;
@@ -70,7 +70,6 @@ public class MappingDataBase implements MappingData {
final CompoundTag data = readMappingsFile("mappings-" + unmappedVersion + "to" + mappedVersion + ".nbt");
blockMappings = loadBiMappings(data, "blocks");
blockStateMappings = loadMappings(data, "blockstates");
blockEntityMappings = loadMappings(data, "blockentities");
soundMappings = loadMappings(data, "sounds");
statisticsMappings = loadMappings(data, "statistics");
menuMappings = loadMappings(data, "menus");
@@ -86,6 +85,7 @@ public class MappingDataBase implements MappingData {
recipeSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "recipe_serializers");
itemDataSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "data_component_type");
attributeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "attributes");
blockEntityMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "blockentities");
final List<String> unmappedParticles = identifiersFromGlobalIds(unmappedIdentifierData, "particles");
final List<String> mappedParticles = identifiersFromGlobalIds(mappedIdentifierData, "particles");
@@ -241,7 +241,7 @@ public class MappingDataBase implements MappingData {
}
@Override
public @Nullable Mappings getBlockEntityMappings() {
public @Nullable FullMappings getBlockEntityMappings() {
return blockEntityMappings;
}
@@ -82,6 +82,11 @@ public interface EntityTracker {
*/
void clearEntities();
/**
* Clears all stored data, including entity types, entity data and client entity id.
*/
void clear();
/**
* Returns the stored entity data if an entity with the id is tracked, else null.
* If no data has been initialized yet, it will be done and returned by this method.
@@ -29,7 +29,11 @@ import java.util.Map;
import java.util.UUID;
import org.checkerframework.checker.nullness.qual.Nullable;
public record GameProfile(@Nullable String name, @Nullable UUID id, Property[] properties) {
public record GameProfile(@Nullable String name, @Nullable UUID id, Property[] properties, boolean dynamic) {
public GameProfile(@Nullable final String name, @Nullable final UUID id, final Property[] properties) {
this(name, id, properties, true);
}
public GameProfile(@Nullable final String name, @Nullable final UUID id) {
this(name, id, new Property[0]);
@@ -0,0 +1,37 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Profile that can be either dynamically filled by the client or is already static.
* The additional fields are optional overrides.
*/
public record ResolvableProfile(GameProfile profile, @Nullable String bodyTexture, @Nullable String capeTexture,
@Nullable String elytraTexture, @Nullable Integer modelType) {
public ResolvableProfile(final GameProfile profile) {
this(profile, null, null, null, null);
}
}
@@ -0,0 +1,28 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft;
public record Vector3d(double x, double y, double z) {
public static final Vector3d ZERO = new Vector3d(0, 0, 0);
}
@@ -45,6 +45,10 @@ public interface CodecContext {
Key dataComponentType(int id);
Key entity(int id);
Key blockEntity(int id);
static RegistryAccess of(final List<String> enchantments, final MappingData mappingData) {
return new RegistryAccessImpl(enchantments, mappingData);
}
@@ -66,6 +66,16 @@ final class RegistryAccessImpl implements CodecContext.RegistryAccess {
return key(mappingData.getDataComponentSerializerMappings(), id);
}
@Override
public Key entity(final int id) {
return key(mappingData.getEntityMappings(), id);
}
@Override
public Key blockEntity(final int id) {
return key(mappingData.getBlockEntityMappings(), id);
}
private Key key(final FullMappings mappings, final int id) {
final String identifier = mapped ? mappings.mappedIdentifier(id) : mappings.identifier(id);
return key(identifier, id);
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.minecraft.data;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.util.ArrayUtil;
import com.viaversion.viaversion.util.Copyable;
import io.netty.buffer.ByteBuf;
import java.util.Objects;
@@ -102,7 +103,7 @@ final class FilledStructuredData<T> implements StructuredData<T> {
public String toString() {
return "FilledStructuredData{" +
"key=" + key +
", value=" + value +
", value=" + ArrayUtil.toString(value) +
", id=" + id +
'}';
}
@@ -29,6 +29,7 @@ import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_20_5;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_2;
@@ -39,6 +40,7 @@ import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_20_
import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21;
import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer;
import com.viaversion.viaversion.api.minecraft.item.data.Bee;
import com.viaversion.viaversion.api.minecraft.item.data.BlockEntityData;
import com.viaversion.viaversion.api.minecraft.item.data.BlockStateProperties;
import com.viaversion.viaversion.api.minecraft.item.data.BlocksAttacks;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2;
@@ -56,6 +58,7 @@ import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.ItemModel;
import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
@@ -65,6 +68,7 @@ import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect;
import com.viaversion.viaversion.api.minecraft.item.data.ToolProperties;
import com.viaversion.viaversion.api.minecraft.item.data.TooltipDisplay;
import com.viaversion.viaversion.api.minecraft.item.data.TropicalFishPattern;
import com.viaversion.viaversion.api.minecraft.item.data.EntityData;
import com.viaversion.viaversion.api.minecraft.item.data.Unbreakable;
import com.viaversion.viaversion.api.minecraft.item.data.UseCooldown;
import com.viaversion.viaversion.api.minecraft.item.data.Weapon;
@@ -97,7 +101,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Unit> UNBREAKABLE1_21_5 = new StructuredDataKey<>("unbreakable", Types.EMPTY);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TEXT_COMPONENT_TAG);
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Types.TEXT_COMPONENT_TAG);
public static final StructuredDataKey<Key> ITEM_MODEL = new StructuredDataKey<>("item_model", Types.RESOURCE_LOCATION);
public static final StructuredDataKey<ItemModel> ITEM_MODEL = new StructuredDataKey<>("item_model", ItemModel.TYPE);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", new ArrayType<>(Types.TEXT_COMPONENT_TAG, 256));
public static final StructuredDataKey<Integer> RARITY = new StructuredDataKey<>("rarity", EnumTypes.RARITY);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS1_20_5 = new StructuredDataKey<>("enchantments", Enchantments.TYPE1_20_5);
@@ -156,9 +160,11 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<ArmorTrim> TRIM1_21_4 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_21_4);
public static final StructuredDataKey<ArmorTrim> TRIM1_21_5 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_21_5);
public static final StructuredDataKey<CompoundTag> DEBUG_STICK_STATE = new StructuredDataKey<>("debug_stick_state", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> ENTITY_DATA = new StructuredDataKey<>("entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> ENTITY_DATA1_20_5 = new StructuredDataKey<>("entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<EntityData> ENTITY_DATA1_21_9 = new StructuredDataKey<>("entity_data", EntityData.TYPE);
public static final StructuredDataKey<CompoundTag> BUCKET_ENTITY_DATA = new StructuredDataKey<>("bucket_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BLOCK_ENTITY_DATA = new StructuredDataKey<>("block_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<CompoundTag> BLOCK_ENTITY_DATA1_20_5 = new StructuredDataKey<>("block_entity_data", Types.COMPOUND_TAG);
public static final StructuredDataKey<BlockEntityData> BLOCK_ENTITY_DATA1_21_9 = new StructuredDataKey<>("block_entity_data", BlockEntityData.TYPE);
public static final StructuredDataKey<Holder<Instrument1_20_5>> INSTRUMENT1_20_5 = new StructuredDataKey<>("instrument", Instrument1_20_5.TYPE);
public static final StructuredDataKey<Holder<Instrument1_21_2>> INSTRUMENT1_21_2 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE);
public static final StructuredDataKey<EitherHolder<Instrument1_21_2>> INSTRUMENT1_21_5 = new StructuredDataKey<>("instrument", Instrument1_21_2.EITHER_HOLDER_TYPE);
@@ -171,13 +177,15 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<LodestoneTracker> LODESTONE_TRACKER = new StructuredDataKey<>("lodestone_tracker", LodestoneTracker.TYPE);
public static final StructuredDataKey<FireworkExplosion> FIREWORK_EXPLOSION = new StructuredDataKey<>("firework_explosion", FireworkExplosion.TYPE);
public static final StructuredDataKey<Fireworks> FIREWORKS = new StructuredDataKey<>("fireworks", Fireworks.TYPE);
public static final StructuredDataKey<GameProfile> PROFILE = new StructuredDataKey<>("profile", Types.GAME_PROFILE);
public static final StructuredDataKey<GameProfile> PROFILE1_20_5 = new StructuredDataKey<>("profile", Types.GAME_PROFILE);
public static final StructuredDataKey<ResolvableProfile> PROFILE1_21_9 = new StructuredDataKey<>("profile", Types.RESOLVABLE_PROFILE);
public static final StructuredDataKey<Key> NOTE_BLOCK_SOUND = new StructuredDataKey<>("note_block_sound", Types.RESOURCE_LOCATION);
public static final StructuredDataKey<BannerPatternLayer[]> BANNER_PATTERNS = new StructuredDataKey<>("banner_patterns", BannerPatternLayer.ARRAY_TYPE);
public static final StructuredDataKey<Integer> BASE_COLOR = new StructuredDataKey<>("base_color", EnumTypes.DYE_COLOR);
public static final StructuredDataKey<PotDecorations> POT_DECORATIONS = new StructuredDataKey<>("pot_decorations", PotDecorations.TYPE);
public static final StructuredDataKey<BlockStateProperties> BLOCK_STATE = new StructuredDataKey<>("block_state", BlockStateProperties.TYPE);
public static final StructuredDataKey<Bee[]> BEES = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE);
public static final StructuredDataKey<Bee[]> BEES1_20_5 = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE1_20_5);
public static final StructuredDataKey<Bee[]> BEES1_21_9 = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE1_21_9);
public static final StructuredDataKey<Tag> LOCK = new StructuredDataKey<>("lock", Types.TAG);
public static final StructuredDataKey<CompoundTag> CONTAINER_LOOT = new StructuredDataKey<>("container_loot", Types.COMPOUND_TAG);
public static final StructuredDataKey<Holder<SoundEvent>> BREAK_SOUND = new StructuredDataKey<>("break_sound", Types.SOUND_EVENT);
@@ -214,6 +222,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKeys1_21_2 V1_21_4 = VersionedTypes.V1_21_4.structuredDataKeys();
public static final StructuredDataKeys1_21_5 V1_21_5 = VersionedTypes.V1_21_5.structuredDataKeys();
public static final StructuredDataKeys1_21_5 V1_21_6 = VersionedTypes.V1_21_6.structuredDataKeys();
public static final StructuredDataKeys1_21_5 V1_21_9 = VersionedTypes.V1_21_9.structuredDataKeys();
@Override
public String toString() {
@@ -0,0 +1,323 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entities;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.util.EntityTypeUtil;
import com.viaversion.viaversion.util.Key;
import java.util.Locale;
import org.checkerframework.checker.nullness.qual.Nullable;
public enum EntityTypes1_21_9 implements EntityType {
ENTITY(null, null),
AREA_EFFECT_CLOUD(ENTITY),
END_CRYSTAL(ENTITY),
EVOKER_FANGS(ENTITY),
EXPERIENCE_ORB(ENTITY),
EYE_OF_ENDER(ENTITY),
FALLING_BLOCK(ENTITY),
ITEM(ENTITY),
TNT(ENTITY),
OMINOUS_ITEM_SPAWNER(ENTITY),
MARKER(ENTITY),
LIGHTNING_BOLT(ENTITY),
INTERACTION(ENTITY),
DISPLAY(ENTITY, null),
BLOCK_DISPLAY(DISPLAY),
ITEM_DISPLAY(DISPLAY),
TEXT_DISPLAY(DISPLAY),
// Hanging entities
HANGING_ENTITY(ENTITY, null),
LEASH_KNOT(HANGING_ENTITY),
PAINTING(HANGING_ENTITY),
ITEM_FRAME(HANGING_ENTITY),
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
EXPERIENCE_BOTTLE(ITEM_PROJECTILE),
FIREWORK_ROCKET(PROJECTILE),
LLAMA_SPIT(PROJECTILE),
SHULKER_BULLET(PROJECTILE),
FISHING_BOBBER(PROJECTILE),
WITHER_SKULL(PROJECTILE),
DRAGON_FIREBALL(PROJECTILE), // Doesn't actually inherit fireball
ABSTRACT_THROWN_POTION(ITEM_PROJECTILE, null),
SPLASH_POTION(ABSTRACT_THROWN_POTION),
LINGERING_POTION(ABSTRACT_THROWN_POTION),
ABSTRACT_ARROW(PROJECTILE, null),
ARROW(ABSTRACT_ARROW),
SPECTRAL_ARROW(ABSTRACT_ARROW),
TRIDENT(ABSTRACT_ARROW),
ABSTRACT_FIREBALL(ENTITY, null),
FIREBALL(ABSTRACT_FIREBALL),
SMALL_FIREBALL(ABSTRACT_FIREBALL),
ABSTRACT_WIND_CHARGE(PROJECTILE, null),
WIND_CHARGE(ABSTRACT_WIND_CHARGE),
BREEZE_WIND_CHARGE(ABSTRACT_WIND_CHARGE),
// Vehicles
VEHICLE(ENTITY, null),
ABSTRACT_MINECART(VEHICLE, null),
MINECART(ABSTRACT_MINECART),
FURNACE_MINECART(ABSTRACT_MINECART),
COMMAND_BLOCK_MINECART(ABSTRACT_MINECART),
TNT_MINECART(ABSTRACT_MINECART),
SPAWNER_MINECART(ABSTRACT_MINECART),
ABSTRACT_MINECART_CONTAINER(ABSTRACT_MINECART, null),
CHEST_MINECART(ABSTRACT_MINECART_CONTAINER),
HOPPER_MINECART(ABSTRACT_MINECART_CONTAINER),
ABSTRACT_BOAT(VEHICLE, null),
ABSTRACT_CHEST_BOAT(ABSTRACT_BOAT, null),
ACACIA_BOAT(ABSTRACT_BOAT),
ACACIA_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
BAMBOO_CHEST_RAFT(ABSTRACT_CHEST_BOAT),
BAMBOO_RAFT(ABSTRACT_BOAT),
BIRCH_BOAT(ABSTRACT_BOAT),
BIRCH_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
CHERRY_BOAT(ABSTRACT_BOAT),
CHERRY_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
DARK_OAK_BOAT(ABSTRACT_BOAT),
DARK_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
JUNGLE_BOAT(ABSTRACT_BOAT),
JUNGLE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
MANGROVE_BOAT(ABSTRACT_BOAT),
MANGROVE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
OAK_BOAT(ABSTRACT_BOAT),
OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
PALE_OAK_BOAT(ABSTRACT_BOAT),
PALE_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
SPRUCE_BOAT(ABSTRACT_BOAT),
SPRUCE_CHEST_BOAT(ABSTRACT_CHEST_BOAT),
// Living entities as a larger subclass
LIVING_ENTITY(ENTITY, null),
ARMOR_STAND(LIVING_ENTITY),
// Players
AVATAR(LIVING_ENTITY, null),
MANNEQUIN(AVATAR),
PLAYER(AVATAR),
// Mobs as a larger subclass
MOB(LIVING_ENTITY, null),
ENDER_DRAGON(MOB),
SLIME(MOB),
MAGMA_CUBE(SLIME),
// Ambient mobs
AMBIENT_CREATURE(MOB, null),
BAT(AMBIENT_CREATURE),
// Flying mobs
FLYING_MOB(MOB, null),
GHAST(FLYING_MOB),
PHANTOM(FLYING_MOB),
// Pathfinder mobs and its subclasses
PATHFINDER_MOB(MOB, null),
ALLAY(PATHFINDER_MOB),
ABSTRACT_GOLEM(PATHFINDER_MOB, null),
SNOW_GOLEM(ABSTRACT_GOLEM),
IRON_GOLEM(ABSTRACT_GOLEM),
SHULKER(ABSTRACT_GOLEM),
COPPER_GOLEM(ABSTRACT_GOLEM),
// Ageable mobs and (tamable) animals
ABSTRACT_AGEABLE(PATHFINDER_MOB, null),
ABSTRACT_VILLAGER(ABSTRACT_AGEABLE, null),
VILLAGER(ABSTRACT_VILLAGER),
WANDERING_TRADER(ABSTRACT_VILLAGER),
ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null),
AXOLOTL(ABSTRACT_ANIMAL),
CHICKEN(ABSTRACT_ANIMAL),
PANDA(ABSTRACT_ANIMAL),
PIG(ABSTRACT_ANIMAL),
POLAR_BEAR(ABSTRACT_ANIMAL),
RABBIT(ABSTRACT_ANIMAL),
SHEEP(ABSTRACT_ANIMAL),
BEE(ABSTRACT_ANIMAL),
TURTLE(ABSTRACT_ANIMAL),
FOX(ABSTRACT_ANIMAL),
FROG(ABSTRACT_ANIMAL),
GOAT(ABSTRACT_ANIMAL),
HOGLIN(ABSTRACT_ANIMAL),
STRIDER(ABSTRACT_ANIMAL),
SNIFFER(ABSTRACT_ANIMAL),
ARMADILLO(ABSTRACT_ANIMAL),
HAPPY_GHAST(ABSTRACT_ANIMAL),
ABSTRACT_COW(ABSTRACT_ANIMAL, null),
COW(ABSTRACT_COW),
MOOSHROOM(ABSTRACT_COW),
TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null),
CAT(TAMABLE_ANIMAL),
OCELOT(TAMABLE_ANIMAL),
WOLF(TAMABLE_ANIMAL),
PARROT(TAMABLE_ANIMAL),
ABSTRACT_HORSE(ABSTRACT_ANIMAL, null),
HORSE(ABSTRACT_HORSE),
SKELETON_HORSE(ABSTRACT_HORSE),
ZOMBIE_HORSE(ABSTRACT_HORSE),
CAMEL(ABSTRACT_HORSE),
ABSTRACT_CHESTED_HORSE(ABSTRACT_HORSE, null),
DONKEY(ABSTRACT_CHESTED_HORSE),
MULE(ABSTRACT_CHESTED_HORSE),
LLAMA(ABSTRACT_CHESTED_HORSE),
TRADER_LLAMA(LLAMA),
// Monsters
ABSTRACT_MONSTER(PATHFINDER_MOB, null),
BLAZE(ABSTRACT_MONSTER),
CREEPER(ABSTRACT_MONSTER),
ENDERMITE(ABSTRACT_MONSTER),
ENDERMAN(ABSTRACT_MONSTER),
GIANT(ABSTRACT_MONSTER),
SILVERFISH(ABSTRACT_MONSTER),
VEX(ABSTRACT_MONSTER),
WITHER(ABSTRACT_MONSTER),
BREEZE(ABSTRACT_MONSTER),
ZOGLIN(ABSTRACT_MONSTER),
WARDEN(ABSTRACT_MONSTER),
CREAKING(ABSTRACT_MONSTER),
ABSTRACT_SKELETON(ABSTRACT_MONSTER, null),
SKELETON(ABSTRACT_SKELETON),
STRAY(ABSTRACT_SKELETON),
WITHER_SKELETON(ABSTRACT_SKELETON),
BOGGED(ABSTRACT_SKELETON),
ZOMBIE(ABSTRACT_MONSTER),
DROWNED(ZOMBIE),
HUSK(ZOMBIE),
ZOMBIFIED_PIGLIN(ZOMBIE),
ZOMBIE_VILLAGER(ZOMBIE),
GUARDIAN(ABSTRACT_MONSTER),
ELDER_GUARDIAN(GUARDIAN),
SPIDER(ABSTRACT_MONSTER),
CAVE_SPIDER(SPIDER),
ABSTRACT_PIGLIN(ABSTRACT_MONSTER, null),
PIGLIN(ABSTRACT_PIGLIN),
PIGLIN_BRUTE(ABSTRACT_PIGLIN),
// Water mobs
AGEABLE_WATER_CREATURE(ABSTRACT_AGEABLE, null),
DOLPHIN(AGEABLE_WATER_CREATURE),
SQUID(AGEABLE_WATER_CREATURE),
GLOW_SQUID(SQUID),
WATER_ANIMAL(PATHFINDER_MOB, null),
ABSTRACT_FISH(WATER_ANIMAL, null),
PUFFERFISH(ABSTRACT_FISH),
TADPOLE(ABSTRACT_FISH),
ABSTRACT_SCHOOLING_FISH(ABSTRACT_FISH, null),
COD(ABSTRACT_SCHOOLING_FISH),
SALMON(ABSTRACT_SCHOOLING_FISH),
TROPICAL_FISH(ABSTRACT_SCHOOLING_FISH),
// Raiders
ABSTRACT_RAIDER(ABSTRACT_MONSTER, null),
WITCH(ABSTRACT_RAIDER),
RAVAGER(ABSTRACT_RAIDER),
ABSTRACT_ILLAGER(ABSTRACT_RAIDER, null),
SPELLCASTER_ILLAGER(ABSTRACT_ILLAGER, null),
VINDICATOR(ABSTRACT_ILLAGER),
PILLAGER(ABSTRACT_ILLAGER),
EVOKER(SPELLCASTER_ILLAGER),
ILLUSIONER(SPELLCASTER_ILLAGER);
private static final EntityType[] TYPES = EntityTypeUtil.createSizedArray(values());
private final EntityType parent;
private final String identifier;
private int id = -1;
EntityTypes1_21_9(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_21_9(final EntityType parent, @Nullable final String identifier) {
this.parent = parent;
this.identifier = identifier;
}
@Override
public int getId() {
if (id == -1) {
throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")");
}
return id;
}
@Override
public String identifier() {
Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type");
return identifier;
}
@Override
public @Nullable EntityType getParent() {
return parent;
}
@Override
public boolean isAbstractType() {
return identifier == null;
}
public static EntityType getTypeFromId(final int typeId) {
return EntityTypeUtil.getTypeFromId(TYPES, typeId, PIG);
}
public static void initialize(final Protocol<?, ?, ?, ?> protocol) {
EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id);
}
}
@@ -0,0 +1,76 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.entitydata.types;
import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
public final class EntityDataTypes1_21_9 extends AbstractEntityDataTypes {
public final EntityDataType byteType = add(0, Types.BYTE);
public final EntityDataType varIntType = add(1, Types.VAR_INT);
public final EntityDataType longType = add(2, Types.VAR_LONG);
public final EntityDataType floatType = add(3, Types.FLOAT);
public final EntityDataType stringType = add(4, Types.STRING);
public final EntityDataType componentType = add(5, Types.TAG);
public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG);
public final EntityDataType itemType;
public final EntityDataType booleanType = add(8, Types.BOOLEAN);
public final EntityDataType rotationsType = add(9, Types.ROTATIONS);
public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14);
public final EntityDataType optionalBlockPositionType = add(11, Types.OPTIONAL_POSITION_1_14);
public final EntityDataType directionType = add(12, Types.VAR_INT);
public final EntityDataType optionalUUIDType = add(13, Types.OPTIONAL_UUID);
public final EntityDataType blockStateType = add(14, Types.VAR_INT);
public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT);
public final EntityDataType particleType;
public final EntityDataType particlesType;
public final EntityDataType villagerDatatType = add(18, Types.VILLAGER_DATA);
public final EntityDataType optionalVarIntType = add(19, Types.OPTIONAL_VAR_INT);
public final EntityDataType poseType = add(20, Types.VAR_INT);
public final EntityDataType catVariantType = add(21, Types.VAR_INT);
public final EntityDataType cowVariantType = add(22, Types.VAR_INT);
public final EntityDataType wolfVariantType = add(23, Types.VAR_INT);
public final EntityDataType wolfSoundVariantType = add(24, Types.VAR_INT);
public final EntityDataType frogVariantType = add(25, Types.VAR_INT);
public final EntityDataType pigVariantType = add(26, Types.VAR_INT);
public final EntityDataType chickenVariantType = add(27, Types.VAR_INT);
public final EntityDataType optionalGlobalPosition = add(28, Types.OPTIONAL_GLOBAL_POSITION);
public final EntityDataType paintingVariantType = add(29, PaintingVariant.TYPE1_21_2);
public final EntityDataType snifferState = add(30, Types.VAR_INT);
public final EntityDataType armadilloState = add(31, Types.VAR_INT);
public final EntityDataType copperGolemState = add(32, Types.VAR_INT);
public final EntityDataType weatheringCopperState = add(33, Types.VAR_INT);
public final EntityDataType vector3FType = add(34, Types.VECTOR3F);
public final EntityDataType quaternionType = add(35, Types.QUATERNION);
public final EntityDataType mannequinProfileType = add(36, Types.RESOLVABLE_PROFILE);
public EntityDataTypes1_21_9(final VersionedTypesHolder types) {
super(37);
this.itemType = add(7, types.item());
this.particleType = add(16, types.particle());
this.particlesType = add(17, types.particles());
}
}
@@ -30,20 +30,24 @@ import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.util.Copyable;
import io.netty.buffer.ByteBuf;
public record Bee(CompoundTag entityData, int ticksInHive, int minTicksInHive) implements Copyable {
public record Bee(EntityData entityData, int ticksInHive, int minTicksInHive) implements Copyable {
public static final Type<Bee> TYPE = new Type<>(Bee.class) {
public Bee(final CompoundTag entityData, final int ticksInHive, final int minTicksInHive) {
this(new EntityData(-1, entityData), ticksInHive, minTicksInHive);
}
public static final Type<Bee> TYPE1_20_5 = new Type<>(Bee.class) {
@Override
public Bee read(final ByteBuf buffer) {
final CompoundTag entityData = Types.COMPOUND_TAG.read(buffer);
final int ticksInHive = Types.VAR_INT.readPrimitive(buffer);
final int minTicksInHive = Types.VAR_INT.readPrimitive(buffer);
return new Bee(entityData, ticksInHive, minTicksInHive);
return new Bee(new EntityData(-1, entityData), ticksInHive, minTicksInHive);
}
@Override
public void write(final ByteBuf buffer, final Bee value) {
Types.COMPOUND_TAG.write(buffer, value.entityData);
Types.COMPOUND_TAG.write(buffer, value.entityData.tag());
Types.VAR_INT.writePrimitive(buffer, value.ticksInHive);
Types.VAR_INT.writePrimitive(buffer, value.minTicksInHive);
}
@@ -51,12 +55,38 @@ public record Bee(CompoundTag entityData, int ticksInHive, int minTicksInHive) i
@Override
public void write(final Ops ops, final Bee value) {
ops.writeMap(map -> map
.writeOptional("entity_data", Types.COMPOUND_TAG, value.entityData, new CompoundTag())
.writeOptional("entity_data", Types.COMPOUND_TAG, value.entityData.tag(), new CompoundTag())
.write("ticks_in_hive", Types.INT, value.ticksInHive)
.write("min_ticks_in_hive", Types.INT, value.minTicksInHive));
}
};
public static final Type<Bee[]> ARRAY_TYPE = new ArrayType<>(TYPE);
public static final Type<Bee[]> ARRAY_TYPE1_20_5 = new ArrayType<>(TYPE1_20_5);
public static final Type<Bee> TYPE1_21_9 = new Type<>(Bee.class) {
@Override
public Bee read(final ByteBuf buffer) {
final EntityData entityData = EntityData.TYPE.read(buffer);
final int ticksInHive = Types.VAR_INT.readPrimitive(buffer);
final int minTicksInHive = Types.VAR_INT.readPrimitive(buffer);
return new Bee(entityData, ticksInHive, minTicksInHive);
}
@Override
public void write(final ByteBuf buffer, final Bee value) {
EntityData.TYPE.write(buffer, value.entityData);
Types.VAR_INT.writePrimitive(buffer, value.ticksInHive);
Types.VAR_INT.writePrimitive(buffer, value.minTicksInHive);
}
@Override
public void write(final Ops ops, final Bee value) {
ops.writeMap(map -> map
.write("entity_data", EntityData.TYPE, value.entityData)
.write("ticks_in_hive", Types.INT, value.ticksInHive)
.write("min_ticks_in_hive", Types.INT, value.minTicksInHive));
}
};
public static final Type<Bee[]> ARRAY_TYPE1_21_9 = new ArrayType<>(TYPE1_21_9);
@Override
public Bee copy() {
@@ -0,0 +1,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.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record BlockEntityData(int type, CompoundTag tag) implements Rewritable {
public static final Type<BlockEntityData> TYPE = new Type<>(BlockEntityData.class) {
@Override
public BlockEntityData read(final ByteBuf buffer) {
final int type = Types.VAR_INT.readPrimitive(buffer);
final CompoundTag tag = Types.COMPOUND_TAG.read(buffer);
return new BlockEntityData(type, tag);
}
@Override
public void write(final ByteBuf buffer, final BlockEntityData value) {
Types.VAR_INT.writePrimitive(buffer, value.type);
Types.COMPOUND_TAG.write(buffer, value.tag);
}
@Override
public void write(final Ops ops, final BlockEntityData data) {
ops.writeMap(map -> map
.write("id", Types.RESOURCE_LOCATION, ops.context().registryAccess().blockEntity(data.type))
.writeInlinedMap(Types.COMPOUND_TAG, data.tag)
);
}
};
@Override
public BlockEntityData rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final int mappedType = protocol.getMappingData().getBlockEntityMappings().getNewId(type);
return new BlockEntityData(mappedType, tag);
}
}
@@ -44,6 +44,10 @@ public final class ContainterContents {
ops.writeList(list -> {
for (int i = 0; i < value.length; i++) {
final Item item = value[i];
if (item.isEmpty()) {
continue;
}
final int slot = i;
list.writeMap(map -> map
.write("slot", Types.INT, slot)
@@ -0,0 +1,70 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Copyable;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record EntityData(int type, CompoundTag tag) implements Rewritable, Copyable {
public static final Type<EntityData> TYPE = new Type<>(EntityData.class) {
@Override
public EntityData read(final ByteBuf buffer) {
final int type = Types.VAR_INT.readPrimitive(buffer);
final CompoundTag tag = Types.COMPOUND_TAG.read(buffer);
return new EntityData(type, tag);
}
@Override
public void write(final ByteBuf buffer, final EntityData value) {
Types.VAR_INT.writePrimitive(buffer, value.type);
Types.COMPOUND_TAG.write(buffer, value.tag);
}
@Override
public void write(final Ops ops, final EntityData data) {
ops.writeMap(map -> map
.write("id", Types.RESOURCE_LOCATION, ops.context().registryAccess().entity(data.type))
.writeInlinedMap(Types.COMPOUND_TAG, data.tag)
);
}
};
@Override
public EntityData rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final int mappedType = protocol.getMappingData().getEntityMappings().getNewId(type);
return new EntityData(mappedType, tag);
}
@Override
public EntityData copy() {
return new EntityData(type, tag.copy());
}
}
@@ -0,0 +1,61 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.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;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
public record ItemModel(Key key) implements Rewritable {
public static final Type<ItemModel> TYPE = new Type<>(ItemModel.class) {
@Override
public ItemModel read(final ByteBuf buffer) {
final Key key = Types.RESOURCE_LOCATION.read(buffer);
return new ItemModel(key);
}
@Override
public void write(final ByteBuf buffer, final ItemModel value) {
Types.RESOURCE_LOCATION.write(buffer, value.key());
}
@Override
public void write(final Ops ops, final ItemModel data) {
ops.write(Types.RESOURCE_LOCATION, data.key());
}
};
@Override
public ItemModel rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
// This data specifically will often be used with Vanilla items, so the key should be rewritten
final String type = key().toString();
final String mappedType = Rewritable.rewriteItem(protocol, clientbound, type);
return mappedType == null || type.equals(mappedType) ? this : new ItemModel(Key.of(mappedType));
}
}
@@ -100,9 +100,9 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
Preconditions.checkArgument(!initialized, "Protocol has already been initialized");
initialized = true;
// Create logger if protocol does not have one
if (getLogger() == null) {
logger = new ProtocolLogger(getClass());
// Create logger if the protocol doesn't have one
if (logger == null) {
logger = createLogger();
}
registerPackets();
registerConfigurationChangeHandlers();
@@ -128,6 +128,10 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
}
}
protected ProtocolLogger createLogger() {
return new ProtocolLogger(getClass());
}
protected void registerConfigurationChangeHandlers() {
// Register handlers for protocol state switching
// Assuming ids will change too often, it is cleaner to register them here instead of the base protocols,
@@ -139,7 +143,7 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
final CU startConfigurationPacket = startConfigurationPacket();
if (startConfigurationPacket != null) {
appendClientbound(startConfigurationPacket, setServerStateHandler(State.CONFIGURATION));
appendClientbound(startConfigurationPacket, startConfigurationHandler());
}
final SU finishConfigurationPacket = serverboundFinishConfigurationPacket();
@@ -476,6 +480,16 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
return wrapper -> wrapper.user().getProtocolInfo().setServerState(state);
}
private PacketHandler startConfigurationHandler() {
return setServerStateHandler(State.CONFIGURATION).then(wrapper -> {
// Mimic client behaviour
final EntityTracker tracker = wrapper.user().getEntityTracker(getClass());
if (tracker != null) {
tracker.clear();
}
});
}
@Override
public final PacketTypesProvider<CU, CM, SM, SU> getPacketTypesProvider() {
return packetTypesProvider;
@@ -24,11 +24,15 @@ package com.viaversion.viaversion.api.protocol;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.exception.InformativeException;
import java.util.Collection;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
public interface ProtocolPipeline extends SimpleProtocol {
public interface ProtocolPipeline {
/**
* Adds a protocol to the current pipeline.
@@ -67,6 +71,15 @@ public interface ProtocolPipeline extends SimpleProtocol {
@Deprecated
@Nullable <P extends Protocol> P getProtocol(Class<P> pipeClass);
/**
* Transform a packet using the protocols in this pipeline.
*
* @param direction The direction the packet is going in
* @param state The current protocol state
* @param packetWrapper The packet wrapper to transform
*/
void transform(Direction direction, State state, PacketWrapper packetWrapper) throws InformativeException, CancelException;
List<Protocol> pipes(@Nullable Class<? extends Protocol> protocolClass, boolean skipCurrentPipeline, Direction direction);
/**
@@ -23,152 +23,219 @@
package com.viaversion.viaversion.api.protocol.packet;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.configuration.RateLimitConfig;
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
import com.viaversion.viaversion.api.connection.UserConnection;
import java.util.Arrays;
public class PacketTracker {
private final UserConnection connection;
private static final long SECOND_NANOS = 1_000_000_000L;
private final RateTracker packetTracker = new RateTracker(5);
private final RateTracker packetSizeTracker = new RateTracker(3);
private long startTime = System.nanoTime();
private boolean packetLimiterEnabled = true;
private long sentPackets;
private long receivedPackets;
// Used for tracking pps
private long startTime;
private long intervalPackets;
private long packetsPerSecond = -1L;
// Used for handling warnings (over time)
private int secondsObserved;
private int warnings;
private final UserConnection connection;
private long sentPacketsTotal;
private long receivedPacketsTotal;
public PacketTracker(UserConnection connection) {
this.connection = connection;
}
/**
* Used for incrementing the number of packets sent to the client.
* Increments the number of packets sent to the client.
*/
public void incrementSent() {
this.sentPackets++;
this.sentPacketsTotal++;
}
/**
* Used for incrementing the number of packets received from the client.
*
* @return true if the interval has reset and can now be checked for the packets sent
*/
@Deprecated(forRemoval = true)
public boolean incrementReceived() {
// handle stats
long diff = System.currentTimeMillis() - startTime;
if (diff >= 1000) {
packetsPerSecond = intervalPackets;
startTime = System.currentTimeMillis();
intervalPackets = 1;
return true;
} else {
intervalPackets++;
}
// increase total
this.receivedPackets++;
return false;
return incrementReceived(0);
}
/**
* Checks for packet flood with the packets sent in the last second.
* ALWAYS check for {@link #incrementReceived()} before using this method.
* Increments the number of packets received from the client.
*
* @return true if the packet should be cancelled
* @see #incrementReceived()
* @return true if the interval has reset
*/
public boolean exceedsMaxPPS() {
if (connection.isClientSide()) return false; // Don't apply PPS limiting for client-side
ViaVersionConfig conf = Via.getConfig();
// Max PPS Checker
if (conf.getMaxPPS() > 0 && packetsPerSecond >= conf.getMaxPPS()) {
connection.disconnect(conf.getMaxPPSKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
return true; // don't send current packet
}
public boolean incrementReceived(int packetSize) {
receivedPacketsTotal++;
// Tracking PPS Checker
if (conf.getMaxWarnings() > 0 && conf.getTrackingPeriod() > 0) {
if (secondsObserved > conf.getTrackingPeriod()) {
// Reset
warnings = 0;
secondsObserved = 1;
} else {
secondsObserved++;
if (packetsPerSecond >= conf.getWarningPPS()) {
warnings++;
}
if (warnings >= conf.getMaxWarnings()) {
connection.disconnect(conf.getMaxWarningsKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
return true; // don't send current packet
}
ViaVersionConfig config = Via.getConfig();
long currentTime = System.nanoTime();
long elapsed = currentTime - startTime;
if (elapsed < SECOND_NANOS) {
// Add to current interval
if (config.getPacketTrackerConfig().enabled()) {
packetTracker.addIntervalValue(1);
}
if (config.getPacketSizeTrackerConfig().enabled()) {
packetSizeTracker.addIntervalValue(packetSize);
}
return false;
}
return false;
// Reset interval tracking
if (config.getPacketTrackerConfig().enabled()) {
packetTracker.updateRate(elapsed);
packetTracker.addIntervalValue(1);
}
if (config.getPacketSizeTrackerConfig().enabled()) {
packetSizeTracker.updateRate(elapsed);
packetSizeTracker.addIntervalValue(packetSize);
}
startTime = currentTime;
return true;
}
public boolean exceedsLimits() {
if (connection.isClientSide()) {
return false;
}
ViaVersionConfig config = Via.getConfig();
return packetTracker.exceedsLimit(connection, config.getPacketTrackerConfig())
|| packetSizeTracker.exceedsLimit(connection, config.getPacketSizeTrackerConfig());
}
public long getSentPackets() {
return sentPackets;
return sentPacketsTotal;
}
@Deprecated(forRemoval = true)
public void setSentPackets(long sentPackets) {
this.sentPackets = sentPackets;
this.sentPacketsTotal = sentPackets;
}
public long getReceivedPackets() {
return receivedPackets;
return receivedPacketsTotal;
}
@Deprecated(forRemoval = true)
public void setReceivedPackets(long receivedPackets) {
this.receivedPackets = receivedPackets;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
this.receivedPacketsTotal = receivedPackets;
}
@Deprecated(forRemoval = true)
public long getIntervalPackets() {
return intervalPackets;
return this.packetTracker.intervalValue;
}
@Deprecated(forRemoval = true)
public void setIntervalPackets(long intervalPackets) {
this.intervalPackets = intervalPackets;
this.packetTracker.intervalValue = Math.toIntExact(intervalPackets);
}
public long getPacketsPerSecond() {
return packetsPerSecond;
}
public void setPacketsPerSecond(long packetsPerSecond) {
this.packetsPerSecond = packetsPerSecond;
}
public int getSecondsObserved() {
return secondsObserved;
}
public void setSecondsObserved(int secondsObserved) {
this.secondsObserved = secondsObserved;
}
public int getWarnings() {
return warnings;
}
public void setWarnings(int warnings) {
this.warnings = warnings;
public int getPacketsPerSecond() {
return packetTracker.currentRate;
}
public boolean isPacketLimiterEnabled() {
return packetLimiterEnabled;
ViaVersionConfig config = Via.getConfig();
return packetLimiterEnabled && config.getPacketTrackerConfig().enabled() && config.getPacketSizeTrackerConfig().enabled();
}
public void setPacketLimiterEnabled(boolean packetLimiterEnabled) {
this.packetLimiterEnabled = packetLimiterEnabled;
}
@Deprecated(forRemoval = true)
public void setWarnings(int warnings) {
this.packetTracker.warnings = warnings;
}
private static final class RateTracker {
private final int[] history;
private int historyIndex;
private int historyCount;
private int currentRate = -1;
// Interval tracking
int intervalValue;
// Warning system
private long warningPeriodStart = System.nanoTime();
private int warnings;
public RateTracker(int windowSize) {
this.history = new int[windowSize];
}
public void addIntervalValue(int value) {
intervalValue += value;
}
public void updateRate(long elapsedNanos) {
// Update sliding window
history[historyIndex] = (int) ((intervalValue * SECOND_NANOS) / elapsedNanos);
historyIndex = (historyIndex + 1) % history.length;
if (historyCount < history.length) {
historyCount++;
}
// Calculate smoothed average
int sum = 0;
for (int i = 0; i < historyCount; i++) {
sum += history[i];
}
currentRate = sum / historyCount;
intervalValue = 0; // Reset
}
public boolean exceedsLimit(UserConnection connection, RateLimitConfig limitConfig) {
if (!limitConfig.enabled() || currentRate < 0) {
return false;
}
// Immediate limit check
if (limitConfig.maxRate() > 0 && currentRate >= limitConfig.maxRate()) {
connection.disconnect(limitConfig.maxRateKickMessage().replace(limitConfig.ratePlaceholder(), Integer.toString(currentRate)));
return true;
}
// Interval warnings
if (limitConfig.maxWarnings() > 0 && limitConfig.trackingPeriodNanos() > 0 && limitConfig.warningRate() > 0) {
return checkTrackedInterval(connection, limitConfig);
}
return false;
}
private boolean checkTrackedInterval(UserConnection connection, RateLimitConfig config) {
long currentTime = System.nanoTime();
if (currentTime - warningPeriodStart >= config.trackingPeriodNanos()) {
// Reset
warnings = 0;
warningPeriodStart = currentTime;
return false;
}
if (currentRate >= config.warningRate() && ++warnings >= config.maxWarnings()) {
connection.disconnect(config.warningKickMessage().replace(config.ratePlaceholder(), Integer.toString(currentRate)));
return true;
}
return false;
}
public void reset() {
intervalValue = 0;
currentRate = -1;
warnings = 0;
warningPeriodStart = System.nanoTime();
historyIndex = 0;
historyCount = 0;
Arrays.fill(history, 0);
}
}
public void reset() {
sentPacketsTotal = 0;
receivedPacketsTotal = 0;
startTime = System.nanoTime();
packetTracker.reset();
packetSizeTracker.reset();
}
}
@@ -91,6 +91,7 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_21_5 = register(770, "1.21.5");
public static final ProtocolVersion v1_21_6 = register(771, "1.21.6");
public static final ProtocolVersion v1_21_7 = register(772, "1.21.7-1.21.8", new SubVersionRange("1.21", 7, 8));
public static final ProtocolVersion v1_21_9 = register(773, "1.21.9");
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
static {
@@ -36,8 +36,10 @@ import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature;
import com.viaversion.viaversion.api.minecraft.ProfileKey;
import com.viaversion.viaversion.api.minecraft.Quaternion;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.Vector;
import com.viaversion.viaversion.api.minecraft.Vector3d;
import com.viaversion.viaversion.api.minecraft.Vector3f;
import com.viaversion.viaversion.api.minecraft.VillagerData;
import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity;
@@ -70,6 +72,7 @@ import com.viaversion.viaversion.api.type.types.ShortType;
import com.viaversion.viaversion.api.type.types.StringType;
import com.viaversion.viaversion.api.type.types.UUIDType;
import com.viaversion.viaversion.api.type.types.UnsignedByteType;
import com.viaversion.viaversion.api.type.types.UnsignedIntType;
import com.viaversion.viaversion.api.type.types.UnsignedShortType;
import com.viaversion.viaversion.api.type.types.VarIntArrayType;
import com.viaversion.viaversion.api.type.types.VarIntType;
@@ -100,6 +103,7 @@ import com.viaversion.viaversion.api.type.types.math.BlockPositionType1_8;
import com.viaversion.viaversion.api.type.types.math.ChunkPositionType;
import com.viaversion.viaversion.api.type.types.math.EulerAngleType;
import com.viaversion.viaversion.api.type.types.math.GlobalBlockPositionType;
import com.viaversion.viaversion.api.type.types.math.MovementVectorType;
import com.viaversion.viaversion.api.type.types.math.QuaternionType;
import com.viaversion.viaversion.api.type.types.math.Vector3fType;
import com.viaversion.viaversion.api.type.types.math.VectorType;
@@ -114,6 +118,7 @@ import com.viaversion.viaversion.api.type.types.misc.PlayerMessageSignatureType;
import com.viaversion.viaversion.api.type.types.misc.ProfileKeyType;
import com.viaversion.viaversion.api.type.types.misc.ProfilePropertyType;
import com.viaversion.viaversion.api.type.types.misc.SoundEventType;
import com.viaversion.viaversion.api.type.types.misc.ResolvableProfileType;
import com.viaversion.viaversion.api.type.types.misc.TagKeyType;
import com.viaversion.viaversion.api.type.types.misc.TagType;
import com.viaversion.viaversion.api.type.types.misc.TextComponentTagType;
@@ -144,6 +149,7 @@ public final class Types {
public static final IntType INT = new IntType();
public static final Type<int[]> INT_ARRAY_PRIMITIVE = new IntArrayType();
public static final UnsignedIntType UNSIGNED_INT = new UnsignedIntType();
public static final FloatType FLOAT = new FloatType();
public static final FloatType.OptionalFloatType OPTIONAL_FLOAT = new FloatType.OptionalFloatType();
@@ -192,6 +198,7 @@ public final class Types {
public static final Type<Vector> VECTOR = new VectorType();
public static final Type<Vector3f> VECTOR3F = new Vector3fType();
public static final Type<Quaternion> QUATERNION = new QuaternionType();
public static final Type<Vector3d> MOVEMENT_VECTOR = new MovementVectorType();
public static final Type<CompoundTag> NAMED_COMPOUND_TAG = new NamedCompoundTagType();
public static final Type<CompoundTag> OPTIONAL_NAMED_COMPOUND_TAG = new NamedCompoundTagType.OptionalNamedCompoundTagType();
@@ -224,6 +231,7 @@ public final class Types {
public static final Type<VillagerData> VILLAGER_DATA = new VillagerDataType();
public static final Type<GameProfile> GAME_PROFILE = new GameProfileType();
public static final Type<ResolvableProfile> RESOLVABLE_PROFILE = new ResolvableProfileType();
public static final Type<GameProfile.Property> PROFILE_PROPERTY = new ProfilePropertyType();
public static final Type<GameProfile.Property[]> PROFILE_PROPERTY_ARRAY = new ArrayType<>(PROFILE_PROPERTY);
public static final Type<ProfileKey> PROFILE_KEY = new ProfileKeyType();
@@ -0,0 +1,63 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.TypeConverter;
import io.netty.buffer.ByteBuf;
public class UnsignedIntType extends Type<Long> implements TypeConverter<Long> {
public static final long MAX_UNSIGNED_INT = 0xFFFFFFFFL;
public UnsignedIntType() {
super(Long.class);
}
@Override
public Long read(ByteBuf buffer) {
return buffer.readUnsignedInt();
}
public long readPrimitive(ByteBuf buffer) {
return buffer.readUnsignedInt();
}
@Override
public void write(ByteBuf buffer, Long l) {
buffer.writeInt(l.intValue());
}
public void writePrimitive(ByteBuf buffer, long l) {
buffer.writeInt((int) l);
}
@Override
public Long from(Object o) {
if (o instanceof Number number) {
return number.longValue();
} else if (o instanceof Boolean boo) {
return boo ? 1L : 0L;
}
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,116 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.math;
import com.viaversion.viaversion.api.minecraft.Vector3d;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.UnsignedIntType;
import com.viaversion.viaversion.util.MathUtil;
import io.netty.buffer.ByteBuf;
public class MovementVectorType extends Type<Vector3d> {
// Using 15 bits, steal short constants for it
private static final double MAX_QUANTIZED_VALUE = Short.MAX_VALUE - 1;
private static final int SCALE_BITS = 2; // first 2 bits for the scale
private static final int SCALE_BITS_MASK = 3;
private static final int CONTINUATION_FLAG = 1 << 2; // 3rd bit to indicate more scale data
private static final double ABS_MAX_VALUE = (1L << Integer.SIZE + SCALE_BITS) - 1; // Unsigned int + the first two scale bits
private static final double ABS_MIN_VALUE = 1 / MAX_QUANTIZED_VALUE;
public MovementVectorType() {
super(Vector3d.class);
}
@Override
public Vector3d read(final ByteBuf buffer) {
// Pack values back into a single long
final int first = Types.UNSIGNED_BYTE.read(buffer);
if (first == 0) {
return Vector3d.ZERO;
}
final int second = Types.UNSIGNED_BYTE.read(buffer);
final long remaining = Types.UNSIGNED_INT.read(buffer);
final long packed = remaining << 16 | second << 8 | first;
long scale = first & SCALE_BITS_MASK;
if ((first & CONTINUATION_FLAG) != 0) {
// Read the remaining bits and add them to the first two
scale |= (Types.VAR_INT.readPrimitive(buffer) & UnsignedIntType.MAX_UNSIGNED_INT) << SCALE_BITS;
}
// 15 bits for each part after removing the scale bits
return new Vector3d(
unpack(packed >> (0 + SCALE_BITS_MASK)) * scale,
unpack(packed >> (15 + SCALE_BITS_MASK)) * scale,
unpack(packed >> (30 + SCALE_BITS_MASK)) * scale
);
}
@Override
public void write(final ByteBuf buffer, final Vector3d vec) {
final double x = sanitize(vec.x());
final double y = sanitize(vec.y());
final double z = sanitize(vec.z());
final double maxPart = Math.max(Math.abs(x), Math.max(Math.abs(y), Math.abs(z)));
if (maxPart < ABS_MIN_VALUE) {
buffer.writeByte(0);
return;
}
final long scale = MathUtil.ceilLong(maxPart);
final boolean scaleTooLargeForBits = (scale & SCALE_BITS_MASK) != scale;
final long scaleBits = scaleTooLargeForBits ? (scale & SCALE_BITS_MASK) | CONTINUATION_FLAG : scale;
final long packed = scaleBits
| (pack(x / scale) << (0 + SCALE_BITS_MASK))
| (pack(y / scale) << (15 + SCALE_BITS_MASK))
| (pack(z / scale) << (30 + SCALE_BITS_MASK));
buffer.writeByte((byte) packed);
buffer.writeByte((byte) (packed >> 8));
buffer.writeInt((int) (packed >> 16));
if (scaleTooLargeForBits) {
// First two bits have already been written
Types.VAR_INT.writePrimitive(buffer, (int) (scale >> SCALE_BITS));
}
}
private double sanitize(final double value) {
return Double.isNaN(value) ? 0 : MathUtil.clamp(value, -ABS_MAX_VALUE, ABS_MAX_VALUE);
}
private long pack(final double value) {
// Shift to [0, 1] and quantize to 15 bits
final double shifted = (value * 0.5) + 0.5;
return Math.round(shifted * MAX_QUANTIZED_VALUE);
}
private double unpack(final long value) {
// Normalize to [-1, 1]
final double clamped = Math.min(value & Short.MAX_VALUE, MAX_QUANTIZED_VALUE);
return (clamped * 2) / MAX_QUANTIZED_VALUE - 1;
}
}
@@ -160,6 +160,13 @@ public class ParticleType extends DynamicType<Particle> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Duration
};
public static final DataReader<Particle> POWER = (buf, particle) -> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf));
};
public static final DataReader<Particle> SPELL = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Power
};
public static DataReader<Particle> item(Type<Item> item) {
return (buf, particle) -> particle.add(item, item.read(buf));
@@ -0,0 +1,90 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.viaversion.api.minecraft.GameProfile;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Key;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
public final class ResolvableProfileType extends Type<ResolvableProfile> {
public ResolvableProfileType() {
super(ResolvableProfile.class);
}
@Override
public ResolvableProfile read(final ByteBuf buffer) {
final GameProfile profile;
if (buffer.readBoolean()) {
final UUID id = Types.UUID.read(buffer);
final String name = Types.STRING.read(buffer);
final GameProfile.Property[] properties = Types.PROFILE_PROPERTY_ARRAY.read(buffer);
profile = new GameProfile(name, id, properties, false);
} else {
profile = Types.GAME_PROFILE.read(buffer);
}
final String texture = Types.OPTIONAL_STRING.read(buffer);
final String capeTexture = Types.OPTIONAL_STRING.read(buffer);
final String elytraTexture = Types.OPTIONAL_STRING.read(buffer);
final Boolean encodedModelType = Types.OPTIONAL_BOOLEAN.read(buffer); // ...
final Integer modelType = encodedModelType != null ? (encodedModelType ? 0 : 1) : null;
return new ResolvableProfile(profile, texture, capeTexture, elytraTexture, modelType);
}
@Override
public void write(final ByteBuf buffer, final ResolvableProfile value) {
final GameProfile profile = value.profile();
if (!profile.dynamic()) {
buffer.writeBoolean(true);
Types.UUID.write(buffer, profile.id());
Types.STRING.write(buffer, profile.name());
Types.PROFILE_PROPERTY_ARRAY.write(buffer, profile.properties());
} else {
buffer.writeBoolean(false);
Types.GAME_PROFILE.write(buffer, profile);
}
Types.OPTIONAL_STRING.write(buffer, value.bodyTexture());
Types.OPTIONAL_STRING.write(buffer, value.capeTexture());
Types.OPTIONAL_STRING.write(buffer, value.elytraTexture());
Types.OPTIONAL_BOOLEAN.write(buffer, value.modelType() != null ? value.modelType() == 0 : null);
}
@Override
public void write(final Ops ops, final ResolvableProfile value) {
final String modelType = value.modelType() != null ? (value.modelType() == 0 ? "slim" : "wide") : null;
ops.writeMap(map -> map
.writeInlinedMap(Types.GAME_PROFILE, value.profile())
.writeOptional("texture", Types.RESOURCE_LOCATION, value.bodyTexture() != null ? Key.of(value.bodyTexture()) : null)
.writeOptional("cape", Types.RESOURCE_LOCATION, value.capeTexture() != null ? Key.of(value.capeTexture()) : null)
.writeOptional("elytra", Types.RESOURCE_LOCATION, value.elytraTexture() != null ? Key.of(value.elytraTexture()) : null)
.writeOptional("model", Types.OPTIONAL_STRING, modelType)
);
}
};
@@ -29,6 +29,7 @@ import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_2;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_9;
/**
* Holds versioned accessors for highly volatile types, specifically around items and data components.
@@ -44,4 +45,5 @@ public final class VersionedTypes {
public static final Types1_20_5<StructuredDataKeys1_21_2, EntityDataTypes1_21_2> V1_21_4 = new Types1_20_5<>(StructuredDataKeys1_21_2::new, EntityDataTypes1_21_2::new);
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> V1_21_5 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_5::new);
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> V1_21_6 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_5::new);
public static final Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_9> V1_21_9 = new Types1_20_5<>(StructuredDataKeys1_21_5::new, EntityDataTypes1_21_9::new);
}
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.util;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
@@ -76,4 +77,21 @@ public final class ArrayUtil {
}
return boxedArray;
}
public static String toString(final Object o) {
if (o == null || !o.getClass().isArray()) {
return String.valueOf(o);
}
final int length = Array.getLength(o);
final StringBuilder builder = new StringBuilder("[");
for (int i = 0; i < length; i++) {
if (i > 0) {
builder.append(", ");
}
builder.append(Array.get(o, i));
}
builder.append("]");
return builder.toString();
}
}
@@ -24,6 +24,11 @@ package com.viaversion.viaversion.util;
public final class MathUtil {
/**
* Miniscule value below which positive floats are considered zero
*/
public static final float EPSILON = 1.0E-5F;
/**
* Returns the ceiled integer value of the given float.
*
@@ -45,6 +50,11 @@ public final class MathUtil {
return i > 0 ? 32 - Integer.numberOfLeadingZeros(i - 1) : 0;
}
public static long ceilLong(final double d) {
final long l = (long) d;
return d > l ? l + 1 : l;
}
/**
* Returns the clamped number within the given range.
*
@@ -59,4 +69,11 @@ public final class MathUtil {
}
return i > max ? max : i;
}
public static double clamp(final double d, final double min, final double max) {
if (d < min) {
return min;
}
return d > max ? max : d;
}
}
+3 -1
View File
@@ -8,5 +8,7 @@ repositories {
dependencies {
// version must be manually kept in sync with the one in root project settings.gradle.kts
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.8")
implementation("com.gradleup.shadow:shadow-gradle-plugin:9.1.0")
// A nice no-conflict comment for patching in downgrading
}
@@ -9,7 +9,7 @@ tasks {
val ver = project.version.toString()
val desc = project.description
filesMatching(listOf("plugin.yml", "META-INF/sponge_plugins.json", "fabric.mod.json")) {
expand("version" to ver, "description" to desc)
expand(mapOf("version" to ver, "description" to desc))
}
}
javadoc {
@@ -19,6 +19,7 @@ tasks {
compileJava {
options.encoding = Charsets.UTF_8.name()
options.compilerArgs.addAll(listOf("-nowarn", "-Xlint:-unchecked", "-Xlint:-deprecation"))
options.isFork = true
}
test {
useJUnitPlatform()
@@ -13,6 +13,7 @@ tasks {
from(project.rootProject.file("LICENSE"))
}
val shadowJar = named<ShadowJar>("shadowJar") {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
archiveClassifier.set("")
configureRelocations()
configureExcludes()
@@ -61,7 +61,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
private static ViaVersionPlugin instance;
private final BukkitCommandHandler commandHandler = new BukkitCommandHandler();
private final BukkitViaConfig conf;
private final ViaAPI<Player> api = new BukkitViaAPI(this);
private final ViaAPI<Player> api = new BukkitViaAPI();
private boolean lateBind;
public ViaVersionPlugin() {
@@ -18,7 +18,6 @@
package com.viaversion.viaversion.bukkit.handlers;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.bukkit.platform.PaperViaInjector;
import com.viaversion.viaversion.connection.UserConnectionImpl;
import com.viaversion.viaversion.platform.WrappedChannelInitializer;
import com.viaversion.viaversion.protocol.ProtocolPipelineImpl;
@@ -74,10 +73,6 @@ public final class BukkitChannelInitializer extends ChannelInitializer<Channel>
final UserConnection connection = new UserConnectionImpl(channel);
new ProtocolPipelineImpl(connection);
if (PaperViaInjector.PAPER_PACKET_LIMITER) {
connection.getPacketTracker().setPacketLimiterEnabled(false);
}
// Add our transformers
final ChannelPipeline pipeline = channel.pipeline();
final String encoderName = pipeline.get(MINECRAFT_OUTBOUND_CONFIG) != null ? MINECRAFT_OUTBOUND_CONFIG : MINECRAFT_ENCODER;
@@ -41,7 +41,7 @@ public final class BukkitDecodeHandler extends MessageToMessageDecoder<ByteBuf>
@Override
protected void decode(final ChannelHandlerContext ctx, final ByteBuf bytebuf, final List<Object> out) {
if (!connection.checkServerboundPacket()) {
if (!connection.checkServerboundPacket(bytebuf.readableBytes())) {
throw CancelDecoderException.generate(null);
}
if (!connection.shouldTransformPacket()) {
@@ -18,35 +18,17 @@
package com.viaversion.viaversion.bukkit.platform;
import com.viaversion.viaversion.ViaAPIBase;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import io.netty.buffer.ByteBuf;
import java.util.UUID;
import org.bukkit.entity.Player;
public class BukkitViaAPI extends ViaAPIBase<Player> {
private final ViaVersionPlugin plugin;
public BukkitViaAPI(ViaVersionPlugin plugin) {
this.plugin = plugin;
}
@Override
public ProtocolVersion getPlayerProtocolVersion(Player player) {
return getPlayerProtocolVersion(player.getUniqueId());
}
@Override
public ProtocolVersion getPlayerProtocolVersion(UUID uuid) {
UserConnection connection = Via.getManager().getConnectionManager().getServerConnection(uuid);
if (connection != null) {
return connection.getProtocolInfo().protocolVersion();
}
return ProtocolVersion.unknown;
}
@Override
public void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException {
sendRawPacket(player.getUniqueId(), packet);
@@ -27,7 +27,6 @@ import org.bukkit.Bukkit;
public final class PaperViaInjector {
public static final boolean PAPER_INJECTION_METHOD = hasPaperInjectionMethod();
public static final boolean PAPER_PROTOCOL_METHOD = hasServerProtocolMethod();
public static final boolean PAPER_PACKET_LIMITER = hasPacketLimiter();
public static final boolean PAPER_IS_STOPPING_METHOD = hasIsStoppingMethod();
private PaperViaInjector() {
@@ -76,10 +75,6 @@ public final class PaperViaInjector {
return hasMethod(Bukkit.class, "isStopping");
}
private static boolean hasPacketLimiter() {
return hasClass("com.destroystokyo.paper.PaperConfig$PacketLimit") || hasClass("io.papermc.paper.configuration.GlobalConfiguration$PacketLimiter");
}
public static boolean hasClass(final String className) {
try {
Class.forName(className);
@@ -114,14 +114,23 @@ public class BukkitViaMovementTransmitter extends MovementTransmitterProvider {
}
} else {
ChannelHandlerContext context = PipelineUtil.getContextBefore("decoder", info.getChannel().pipeline());
if (context != null) {
if (info.get(MovementTracker.class).isGround()) {
if (context == null) {
return;
}
info.getChannel().eventLoop().execute(() -> {
MovementTracker movementTracker = info.get(MovementTracker.class);
if (movementTracker == null) {
return;
}
if (movementTracker.isGround()) {
context.fireChannelRead(getGroundPacket());
} else {
context.fireChannelRead(getFlyingPacket());
}
info.get(MovementTracker.class).incrementIdlePacket();
}
movementTracker.incrementIdlePacket();
});
}
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ tasks.named<Jar>("sourcesJar") {
val prepareViaProxyFiles by tasks.registering(Copy::class) {
dependsOn(project.tasks.shadowJar)
from(project.tasks.shadowJar.get().archiveFile.get().asFile)
from(project.tasks.shadowJar.map { it.archiveFile.get().asFile })
into(layout.projectDirectory.dir("run/jars"))
val projectName = project.name
@@ -21,13 +21,11 @@ import com.viaversion.viaversion.api.minecraft.codec.CodecContext;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.types.version.VersionedTypesHolder;
import com.viaversion.viaversion.util.SerializerVersion;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
import java.util.List;
import java.util.Set;
public record CodecRegistryContext(Protocol<?, ?, ?, ?> protocol, SerializerVersion serializerVersion,
SerializerVersion mappedSerializerVersion, RegistryAccess registryAccess,
public record CodecRegistryContext(Protocol<?, ?, ?, ?> protocol, RegistryAccess registryAccess,
boolean mapped) implements CodecContext {
// Generally from hardcoded, but highly variable client data
@@ -42,10 +40,8 @@ public record CodecRegistryContext(Protocol<?, ?, ?, ?> protocol, SerializerVers
StructuredDataKey.PAINTING_VARIANT, StructuredDataKey.CAT_VARIANT, StructuredDataKey.EQUIPPABLE1_21_6
));
public CodecRegistryContext(final Protocol<?, ?, ?, ?> protocol, final SerializerVersion serializerVersion, final SerializerVersion mappedSerializerVersion, final RegistryAccess registryAccess, final boolean mapped) {
public CodecRegistryContext(final Protocol<?, ?, ?, ?> protocol, final RegistryAccess registryAccess, final boolean mapped) {
this.protocol = protocol;
this.serializerVersion = serializerVersion;
this.mappedSerializerVersion = mappedSerializerVersion;
this.registryAccess = registryAccess.withMapped(mapped);
this.mapped = mapped;
}
@@ -182,7 +182,7 @@ public class HashOps extends OpsBase implements Hasher {
final ListHashBuilder listHasher = hasher.new ListHashBuilder();
consumer.accept(listHasher);
listHasher.applyHashToParent();
return HashOps.this.hash();
return hasher.hash();
}
protected int mapHash(final Consumer<MapSerializer> consumer) {
@@ -190,7 +190,7 @@ public class HashOps extends OpsBase implements Hasher {
final MapHashBuilder mapHasher = hasher.new MapHashBuilder();
consumer.accept(mapHasher);
mapHasher.applyHashToParent();
return HashOps.this.hash();
return hasher.hash();
}
protected <V> int hash(final Type<V> type, final V value) {
@@ -19,12 +19,14 @@ package com.viaversion.viaversion.configuration;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.configuration.RateLimitConfig;
import com.viaversion.viaversion.api.configuration.ViaVersionConfig;
import com.viaversion.viaversion.api.minecraft.WorldIdentifiers;
import com.viaversion.viaversion.api.protocol.version.BlockedProtocolVersions;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.protocol.BlockedProtocolVersionsImpl;
import com.viaversion.viaversion.util.Config;
import com.viaversion.viaversion.util.ConfigSection;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import java.io.File;
@@ -32,6 +34,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -54,12 +57,8 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private boolean bossbarPatch;
private boolean bossbarAntiFlicker;
private double hologramOffset;
private int maxPPS;
private String maxPPSKickMessage;
private int trackingPeriod;
private int warningPPS;
private int maxPPSWarnings;
private String maxPPSWarningsKickMessage;
private RateLimitConfig packetTrackerConfig;
private RateLimitConfig packetSizeTrackerConfig;
private boolean sendSupportedVersions;
private boolean simulatePlayerTick;
private boolean replacePistons;
@@ -68,6 +67,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private boolean autoTeam;
private BlockedProtocolVersions blockedProtocolVersions;
private String blockedDisconnectMessage;
private boolean logBlockedJoins;
private String reloadDisconnectMessage;
private boolean suppressConversionWarnings;
private boolean suppressTextComponentConversionWarnings;
@@ -105,6 +105,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
@Override
public void reload() {
super.reload();
updateConfig();
loadFields();
}
@@ -121,12 +122,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
bossbarPatch = getBoolean("bossbar-patch", true);
bossbarAntiFlicker = getBoolean("bossbar-anti-flicker", false);
hologramOffset = getDouble("hologram-y", -0.96D);
maxPPS = getInt("max-pps", 800);
maxPPSKickMessage = getString("max-pps-kick-msg", "Sending packets too fast? lag?");
trackingPeriod = getInt("tracking-period", 6);
warningPPS = getInt("tracking-warning-pps", 120);
maxPPSWarnings = getInt("tracking-max-warnings", 3);
maxPPSWarningsKickMessage = getString("tracking-max-kick-msg", "You are sending too many packets, :(");
sendSupportedVersions = getBoolean("send-supported-versions", false);
simulatePlayerTick = getBoolean("simulate-pt", true);
replacePistons = getBoolean("replace-pistons", false);
@@ -135,6 +130,7 @@ 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);
@@ -167,6 +163,23 @@ 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);
packetTrackerConfig = loadRateLimitConfig(getSection("packet-limiter"), "%pps", 1);
packetSizeTrackerConfig = loadRateLimitConfig(getSection("packet-size-limiter"), "%bps", 1024);
}
protected void updateConfig() {
ConfigSection original = originalRootSection();
if (original != null && 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-kick-message", original.getString("tracking-max-kick-msg", "You are sending too many packets, :("));
save();
}
}
private BlockedProtocolVersions loadBlockedProtocolVersions() {
@@ -228,6 +241,21 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
return new BlockedProtocolVersionsImpl(blockedProtocols, lowerBound, upperBound);
}
private RateLimitConfig loadRateLimitConfig(ConfigSection section, String placeholder, int countMultiplier) {
final int maxPerSecond = section.getInt("max-per-second", -1);
final int sustainedMaxPerSecond = section.getInt("sustained-max-per-second", -1);
return new RateLimitConfig(
section.getBoolean("enabled", true),
maxPerSecond != -1 ? maxPerSecond * countMultiplier : -1,
section.getString("max-per-second-kick-message", "You are sending too many packets!"),
sustainedMaxPerSecond != -1 ? sustainedMaxPerSecond * countMultiplier : -1,
section.getInt("sustained-threshold", 3),
TimeUnit.SECONDS.toNanos(section.getInt("sustained-period-seconds", 6)),
section.getString("sustained-kick-message", "You are sending too many packets, :("),
placeholder
);
}
private @Nullable ProtocolVersion protocolVersion(String s) {
ProtocolVersion protocolVersion = ProtocolVersion.getClosest(s);
if (protocolVersion == null) {
@@ -310,32 +338,42 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
@Override
public int getMaxPPS() {
return maxPPS;
return packetTrackerConfig.maxRate();
}
@Override
public String getMaxPPSKickMessage() {
return maxPPSKickMessage;
return packetTrackerConfig.maxRateKickMessage();
}
@Override
public int getTrackingPeriod() {
return trackingPeriod;
return (int) TimeUnit.NANOSECONDS.toSeconds(packetTrackerConfig.trackingPeriodNanos());
}
@Override
public int getWarningPPS() {
return warningPPS;
return packetTrackerConfig.warningRate();
}
@Override
public int getMaxWarnings() {
return maxPPSWarnings;
return packetTrackerConfig.maxWarnings();
}
@Override
public String getMaxWarningsKickMessage() {
return maxPPSWarningsKickMessage;
return packetTrackerConfig.warningKickMessage();
}
@Override
public RateLimitConfig getPacketTrackerConfig() {
return packetTrackerConfig;
}
@Override
public RateLimitConfig getPacketSizeTrackerConfig() {
return packetSizeTrackerConfig;
}
@Override
@@ -399,6 +437,11 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
return blockedDisconnectMessage;
}
@Override
public boolean logBlockedJoins() {
return logBlockedJoins;
}
@Override
public String getReloadDisconnectMsg() {
return reloadDisconnectMessage;
@@ -72,16 +72,20 @@ public class ConnectionManagerImpl implements ConnectionManager {
@Override
public void onDisconnect(UserConnection connection) {
Objects.requireNonNull(connection, "connection is null!");
connection.setActive(false);
connections.remove(connection);
UUID id = connection.getProtocolInfo().getUuid();
if (connection.isServerSide()) {
serverConnections.remove(id);
serverConnections.remove(id, connection);
} else {
clientConnections.remove(id);
clientConnections.remove(id, connection);
}
connection.clearStoredObjects();
// There might be a packet still going through the handlers after we set the connection as inactive
// Make sure that we remove stored objects after those have been handled, otherwise this might introduce NPEs
connection.getChannel().eventLoop().execute(connection::clearStoredObjects);
}
@Override
@@ -15,35 +15,38 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocol;
package com.viaversion.viaversion.connection;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
/**
* Instance of {@link Runnable} that will run {@link #run(UserConnection)} for all active user connections.
* Instance of {@link Runnable} that will run {@link #run(UserConnection, StorableObject)} for all active user connections.
*/
public abstract class ProtocolRunnable implements Runnable {
public abstract class StorableObjectTask<T extends StorableObject> implements Runnable {
private final Class<? extends AbstractProtocol<?, ?, ?, ?>> protocolClass;
private final Class<T> storableObject;
public ProtocolRunnable(final Class<? extends AbstractProtocol<?, ?, ?, ?>> protocolClass) {
this.protocolClass = protocolClass;
protected StorableObjectTask(final Class<T> storableObject) {
this.storableObject = storableObject;
}
public abstract void run(final UserConnection connection);
public abstract void run(final UserConnection connection, final T storableObject);
@Override
public void run() {
for (final UserConnection connection : Via.getManager().getConnectionManager().getConnections()) {
final ProtocolInfo protocolInfo = connection.getProtocolInfo();
if (!connection.isActive() || !protocolInfo.getPipeline().contains(this.protocolClass)) {
if (!connection.isActive() || !connection.has(storableObject)) {
continue;
}
run(connection);
connection.getChannel().eventLoop().execute(() -> {
final T object = connection.get(storableObject);
if (object != null) {
this.run(connection, object);
}
});
}
}
}
@@ -179,7 +179,7 @@ public class UserConnectionImpl implements UserConnection {
sendRawPacketNow(packet);
} else {
try {
channel.eventLoop().submit(() -> sendRawPacketNow(packet));
channel.eventLoop().execute(() -> sendRawPacketNow(packet));
} catch (Throwable e) {
packet.release(); // Couldn't schedule
e.printStackTrace();
@@ -269,7 +269,7 @@ public class UserConnectionImpl implements UserConnection {
fireChannelRead(context, buf);
} else {
try {
channel.eventLoop().submit(() -> fireChannelRead(context, buf));
channel.eventLoop().execute(() -> fireChannelRead(context, buf));
} catch (Throwable t) {
// Couldn't schedule
buf.release();
@@ -294,7 +294,7 @@ public class UserConnectionImpl implements UserConnection {
writeAndFlush(packet);
} else {
try {
getChannel().eventLoop().submit(() -> writeAndFlush(packet));
getChannel().eventLoop().execute(() -> writeAndFlush(packet));
} catch (Throwable e) {
e.printStackTrace();
packet.release(); // Couldn't schedule
@@ -307,12 +307,16 @@ public class UserConnectionImpl implements UserConnection {
}
@Override
public boolean checkServerboundPacket() {
public boolean checkServerboundPacket(final int bytes) {
if (pendingDisconnect) {
return false;
return false; // Cancel everything while disconnecting
}
// Increment received + Check PPS
return !packetTracker.isPacketLimiterEnabled() || !packetTracker.incrementReceived() || !packetTracker.exceedsMaxPPS();
if (!packetTracker.isPacketLimiterEnabled()) {
return true;
}
packetTracker.incrementReceived(bytes);
return !packetTracker.exceedsLimits();
}
@Override
@@ -106,6 +106,16 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis
}
}
@Override
public void clear() {
// Call wrapper function in case protocols need to do additional removals
for (final int id : entities.keySet().toIntArray()) {
removeEntity(id);
}
clientEntityId = null;
}
@Override
public boolean hasClientEntityId() {
return clientEntityId != null;
@@ -33,7 +33,6 @@ import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.codec.CodecRegistryContext;
import com.viaversion.viaversion.codec.hash.HashFunction;
import com.viaversion.viaversion.codec.hash.HashOps;
import com.viaversion.viaversion.util.SerializerVersion;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import java.util.ArrayList;
import java.util.List;
@@ -50,10 +49,10 @@ public class ItemHasherBase implements ItemHasher {
private final CodecContext context;
private final CodecContext mappedContext;
public ItemHasherBase(final Protocol<?, ?, ?, ?> protocol, final UserConnection connection, final SerializerVersion serializerVersion, final SerializerVersion mappedSerializerVersion) {
public ItemHasherBase(final Protocol<?, ?, ?, ?> protocol, final UserConnection connection) {
final RegistryAccess registryAccess = RegistryAccess.of(this.enchantments, protocol.getMappingData());
this.context = new CodecRegistryContext(protocol, serializerVersion, mappedSerializerVersion, registryAccess, false);
this.mappedContext = new CodecRegistryContext(protocol, serializerVersion, mappedSerializerVersion, registryAccess, true);
this.context = new CodecRegistryContext(protocol, registryAccess, false);
this.mappedContext = new CodecRegistryContext(protocol, registryAccess, true);
this.connection = connection;
}
@@ -81,6 +81,7 @@ import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.Protocol1_21_5To1_21_6;
import com.viaversion.viaversion.protocols.v1_21_6to1_21_7.Protocol1_21_6To1_21_7;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.Protocol1_21_7To1_21_9;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2;
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.Protocol1_9_1To1_9_3;
@@ -205,6 +206,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
registerProtocol(new Protocol1_21_5To1_21_6(), ProtocolVersion.v1_21_6, ProtocolVersion.v1_21_5);
registerProtocol(new Protocol1_21_6To1_21_7(), ProtocolVersion.v1_21_7, ProtocolVersion.v1_21_6);
registerProtocol(new Protocol1_21_7To1_21_9(), ProtocolVersion.v1_21_9, ProtocolVersion.v1_21_7);
}
@Override
@@ -21,7 +21,6 @@ import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.debug.DebugHandler;
import com.viaversion.viaversion.api.protocol.AbstractSimpleProtocol;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.ProtocolPipeline;
import com.viaversion.viaversion.api.protocol.packet.Direction;
@@ -40,7 +39,7 @@ import java.util.Set;
import java.util.logging.Level;
import org.checkerframework.checker.nullness.qual.Nullable;
public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements ProtocolPipeline {
public class ProtocolPipelineImpl implements ProtocolPipeline {
private final List<Protocol> protocolList = new ArrayList<>();
private final Set<Class<? extends Protocol>> protocolSet = new HashSet<>();
private final UserConnection userConnection;
@@ -50,20 +49,9 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot
public ProtocolPipelineImpl(UserConnection userConnection) {
this.userConnection = userConnection;
userConnection.getProtocolInfo().setPipeline(this);
registerPackets(); // Not registered as a standard "protocol", so we have to call the method manually
}
@Override
protected void registerPackets() {
// This is a pipeline so we register basic pipes
this.add(Via.getManager().getProtocolManager().getBaseProtocol());
}
@Override
public void init(UserConnection userConnection) {
throw new UnsupportedOperationException("ProtocolPipeline can only be initialized once");
}
@Override
public void add(final Protocol protocol) {
reversedProtocolList.add(baseProtocols, protocol);
@@ -120,7 +108,6 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot
// Apply protocols
packetWrapper.apply(direction, state, protocolListFor(direction));
super.transform(direction, state, packetWrapper);
if (debug && debugHandler.logPostPacketTransform() && debugHandler.shouldLog(packetWrapper, direction)) {
logPacket(direction, state, packetWrapper, originalID, true);
@@ -235,7 +222,7 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot
protocolSet.clear();
baseProtocols = 0;
registerPackets();
this.add(Via.getManager().getProtocolManager().getBaseProtocol());
}
@Override
@@ -29,39 +29,39 @@ import org.checkerframework.checker.nullness.qual.Nullable;
* Compares equal to the given origin version and allows base protocol determination via {@link #getBaseProtocolVersion()}
* which can be null for special cases where there is no base protocol.
*/
public class RedirectProtocolVersion extends ProtocolVersion {
public class SpecialProtocolVersion extends ProtocolVersion {
private final ProtocolVersion origin;
private final ProtocolVersion delegate;
public RedirectProtocolVersion(final int version, final String name, final ProtocolVersion origin) {
this(version, -1, name, null, origin);
public SpecialProtocolVersion(final int version, final String name, final ProtocolVersion delegate) {
this(version, -1, name, null, delegate);
}
/**
* See {@link ProtocolVersion} for more information.
*/
public RedirectProtocolVersion(final int version, final int snapshotVersion, final String name, @Nullable final SubVersionRange versionRange, final ProtocolVersion origin) {
public SpecialProtocolVersion(final int version, final int snapshotVersion, final String name, @Nullable final SubVersionRange versionRange, final ProtocolVersion delegate) {
super(VersionType.SPECIAL, version, snapshotVersion, name, versionRange);
this.origin = origin;
this.delegate = delegate;
}
@Override
protected @Nullable Comparator<ProtocolVersion> customComparator() {
return (o1, o2) -> {
if (o1 == this) o1 = this.origin;
if (o2 == this) o2 = this.origin;
if (o1 == this) o1 = this.delegate;
if (o2 == this) o2 = this.delegate;
return o1.compareTo(o2);
};
}
public ProtocolVersion getOrigin() {
return origin;
public ProtocolVersion getDelegate() {
return delegate;
}
/**
* @return the protocol version used to determine the base protocol, null in case there is no base protocol.
*/
public @Nullable ProtocolVersion getBaseProtocolVersion() {
return origin;
return delegate;
}
}
@@ -307,7 +307,7 @@ public class PacketWrapperImpl implements PacketWrapper {
if (currentThread) {
sendNow(protocol, skipCurrentPipeline);
} else {
connection.getChannel().eventLoop().submit(() -> sendNow(protocol, skipCurrentPipeline));
connection.getChannel().eventLoop().execute(() -> sendNow(protocol, skipCurrentPipeline));
}
}
@@ -524,7 +524,7 @@ public class PacketWrapperImpl implements PacketWrapper {
return;
}
connection.getChannel().eventLoop().submit(() -> {
connection.getChannel().eventLoop().execute(() -> {
try {
final ByteBuf output = constructPacket(protocol, skipCurrentPipeline, Direction.SERVERBOUND);
connection.sendRawPacketToServer(output);
@@ -35,7 +35,7 @@ import com.viaversion.viaversion.api.protocol.version.VersionType;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.exception.InformativeException;
import com.viaversion.viaversion.protocol.RedirectProtocolVersion;
import com.viaversion.viaversion.protocol.SpecialProtocolVersion;
import com.viaversion.viaversion.protocol.version.BaseVersionProvider;
import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
import com.viaversion.viaversion.protocols.base.packet.BasePacketTypesProvider;
@@ -101,11 +101,11 @@ public class InitialBaseProtocol extends AbstractProtocol<BaseClientboundPacket,
List<Protocol> alreadyAdded = new ArrayList<>(pipeline.pipes());
// Special versions might compare equal to normal versions and would the normal lookup,
// platforms can use the RedirectProtocolVersion API or need to manually handle their base protocols.
// platforms can use a SpecialProtocolVersion or need to manually handle their base protocols.
ProtocolVersion clientboundBaseProtocolVersion = null;
if (serverProtocol.getVersionType() != VersionType.SPECIAL) {
clientboundBaseProtocolVersion = serverProtocol;
} else if (serverProtocol instanceof RedirectProtocolVersion version) {
} else if (serverProtocol instanceof SpecialProtocolVersion version) {
clientboundBaseProtocolVersion = version.getBaseProtocolVersion();
}
// Add base protocols
@@ -35,6 +35,7 @@ import com.viaversion.viaversion.protocols.base.packet.BaseServerboundPacket;
import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.ComponentUtil;
import io.netty.channel.ChannelFuture;
import java.util.logging.Level;
public class ServerboundBaseProtocol1_7 extends AbstractProtocol<BaseClientboundPacket, BaseClientboundPacket, BaseServerboundPacket, BaseServerboundPacket> {
@@ -74,6 +75,10 @@ public class ServerboundBaseProtocol1_7 extends AbstractProtocol<BaseClientbound
// Send and close
final ChannelFuture future = disconnectPacket.sendFutureRaw();
future.addListener(f -> user.getChannel().close());
if (Via.getConfig().logBlockedJoins()) {
Via.getPlatform().getLogger().log(Level.INFO, "Blocked join due to unsupported version from " + user.getChannel().remoteAddress() + " (" + protocol.getName() + ")");
}
}
});
}
@@ -22,11 +22,11 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.RecipeDisplayRewriter1_21_5;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
@@ -35,7 +35,7 @@ import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
// ChunkType1_21_5
// RecipeDisplayRewriter
// Types1_21_4, Types1_OLD
final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<ClientboundPacket1_21_2, ServerboundPacket1_21_4, Protocol1_98To1_99> {
final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<ClientboundPacket1_21_6, ServerboundPacket1_21_6, Protocol1_98To1_99> {
public BlockItemPacketRewriter1_99(final Protocol1_98To1_99 protocol) {
super(protocol);
@@ -46,32 +46,32 @@ final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<Clientbou
// Register block and block state id changes
// Other places using block state id mappings: Spawn particle, entity data, entity spawn (falling blocks)
// Tags and statistics use block (!) ids
final BlockRewriter<ClientboundPacket1_21_2> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21_2.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21_2.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_2.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_2.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_2.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_21_5::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21_2.BLOCK_ENTITY_DATA);
final BlockRewriter<ClientboundPacket1_21_6> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21_6.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21_6.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_6.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_6.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_6.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_21_5::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21_6.BLOCK_ENTITY_DATA);
// Registers item id changes
// Other places using item ids are: Entity data, tags, statistics, effect
// registerOpenScreen(ClientboundPackets1_21_2.OPEN_SCREEN); If a new container type was added; also remove from the component rewriter registration
registerSetCursorItem(ClientboundPackets1_21_2.SET_CURSOR_ITEM);
registerSetPlayerInventory(ClientboundPackets1_21_2.SET_PLAYER_INVENTORY);
registerCooldown1_21_2(ClientboundPackets1_21_2.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21_2.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21_2.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21_2.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21_2.SET_EQUIPMENT);
registerMerchantOffers1_20_5(ClientboundPackets1_21_2.MERCHANT_OFFERS);
registerContainerClick1_21_5(ServerboundPackets1_21_4.CONTAINER_CLICK);
registerSetCreativeModeSlot1_21_5(ServerboundPackets1_21_4.SET_CREATIVE_MODE_SLOT);
// registerOpenScreen(ClientboundPackets1_21_6.OPEN_SCREEN); If a new container type was added; also remove from the component rewriter registration
registerSetCursorItem(ClientboundPackets1_21_6.SET_CURSOR_ITEM);
registerSetPlayerInventory(ClientboundPackets1_21_6.SET_PLAYER_INVENTORY);
registerCooldown1_21_2(ClientboundPackets1_21_6.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21_6.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21_6.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21_6.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21_6.SET_EQUIPMENT);
registerMerchantOffers1_20_5(ClientboundPackets1_21_6.MERCHANT_OFFERS);
registerContainerClick1_21_5(ServerboundPackets1_21_6.CONTAINER_CLICK);
registerSetCreativeModeSlot1_21_5(ServerboundPackets1_21_6.SET_CREATIVE_MODE_SLOT);
final RecipeDisplayRewriter<ClientboundPacket1_21_2> recipeRewriter = new RecipeDisplayRewriter1_21_5<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_2.UPDATE_RECIPES);
recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_2.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_2.PLACE_GHOST_RECIPE);
final RecipeDisplayRewriter<ClientboundPacket1_21_6> recipeRewriter = new RecipeDisplayRewriter1_21_5<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_6.UPDATE_RECIPES);
recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_6.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_6.PLACE_GHOST_RECIPE);
// OR do this if serialization of recipes changed and override the relevant method
// Add new serializers to RecipeDisplayRewriter, or extend the last one for changes
}
@@ -19,10 +19,10 @@ package com.viaversion.viaversion.protocols.template;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.rewriter.text.NBTComponentRewriter;
final class ComponentRewriter1_99 extends NBTComponentRewriter<ClientboundPacket1_21_2> {
final class ComponentRewriter1_99 extends NBTComponentRewriter<ClientboundPacket1_21_6> {
public ComponentRewriter1_99(final Protocol1_98To1_99 protocol) {
super(protocol);
@@ -18,19 +18,18 @@
package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_9;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_9;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
// Replace if needed
// Types1_OLD
// VersionedTypes
// EntityTypes1_21_4
final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_21_2, Protocol1_98To1_99> {
// EntityTypes1_21_9
final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_21_6, Protocol1_98To1_99> {
public EntityPacketRewriter1_99(final Protocol1_98To1_99 protocol) {
super(protocol);
@@ -39,21 +38,21 @@ final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_2
@Override
public void registerPackets() {
// Tracks entities, applies entity data rewrites registered below, untracks entities
registerTrackerWithData1_19(ClientboundPackets1_21_2.ADD_ENTITY, EntityTypes1_21_4.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21_2.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_2.REMOVE_ENTITIES);
registerPlayerAbilities(ClientboundPackets1_21_2.PLAYER_ABILITIES);
registerGameEvent(ClientboundPackets1_21_2.GAME_EVENT);
registerLogin1_20_5(ClientboundPackets1_21_2.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_2.RESPAWN);
registerTrackerWithData1_21_9(ClientboundPackets1_21_6.ADD_ENTITY, EntityTypes1_21_9.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21_6.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_6.REMOVE_ENTITIES);
registerPlayerAbilities(ClientboundPackets1_21_6.PLAYER_ABILITIES);
registerGameEvent(ClientboundPackets1_21_6.GAME_EVENT);
registerLogin1_20_5(ClientboundPackets1_21_6.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_6.RESPAWN);
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
protocol.registerClientbound(ClientboundConfigurationPackets1_21_6.REGISTRY_DATA, registryDataRewriter::handle);
}
@Override
protected void registerRewrites() {
final EntityDataTypes1_21_5 entityDataTypes = protocol.types().entityDataTypes();
final EntityDataTypes1_21_9 entityDataTypes = protocol.mappedTypes().entityDataTypes();
/* Uncomment if entity data classes changed
filter().mapDataType(typeId -> {
int id = typeId;
@@ -83,6 +82,6 @@ final class EntityPacketRewriter1_99 extends EntityRewriter<ClientboundPacket1_2
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_4.getTypeFromId(type);
return EntityTypes1_21_9.getTypeFromId(type);
}
}
@@ -21,8 +21,8 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_5;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_9;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_9;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
@@ -30,76 +30,74 @@ import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.NBTComponentRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
// Placeholders to replace (in the entire package):
// Protocol1_98To1_99, EntityPacketRewriter1_99, BlockItemPacketRewriter1_99 - move the latter two to a rewriter package
// ClientboundPacket1_21_2
// ServerboundPacket1_21_4
// EntityTypes1_21_4 (MAPPED type)
// VersionedTypes.V1_21_5
// SerializerVersion.V1_21_5
// ClientboundPacket1_21_6
// ServerboundPacket1_21_6
// EntityTypes1_21_9 (MAPPED type)
// VersionedTypes.V1_21_9
// 1.99, 1.98
final class Protocol1_98To1_99 extends AbstractProtocol<ClientboundPacket1_21_2, ClientboundPacket1_21_2, ServerboundPacket1_21_4, ServerboundPacket1_21_4> {
final class Protocol1_98To1_99 extends AbstractProtocol<ClientboundPacket1_21_6, ClientboundPacket1_21_6, ServerboundPacket1_21_6, ServerboundPacket1_21_6> {
public static final MappingData MAPPINGS = new MappingDataBase("1.98", "1.99");
private final EntityPacketRewriter1_99 entityRewriter = new EntityPacketRewriter1_99(this);
private final BlockItemPacketRewriter1_99 itemRewriter = new BlockItemPacketRewriter1_99(this);
private final ParticleRewriter<ClientboundPacket1_21_2> particleRewriter = new ParticleRewriter<>(this);
private final TagRewriter<ClientboundPacket1_21_2> tagRewriter = new TagRewriter<>(this);
private final NBTComponentRewriter<ClientboundPacket1_21_2> componentRewriter = new ComponentRewriter1_99(this);
private final ParticleRewriter<ClientboundPacket1_21_6> particleRewriter = new ParticleRewriter<>(this);
private final TagRewriter<ClientboundPacket1_21_6> tagRewriter = new TagRewriter<>(this);
private final NBTComponentRewriter<ClientboundPacket1_21_6> componentRewriter = new ComponentRewriter1_99(this);
public Protocol1_98To1_99() {
// Passing the class types into the super constructor is needed for automatic packet type id remapping, but can otherwise be omitted
super(ClientboundPacket1_21_2.class, ClientboundPacket1_21_2.class, ServerboundPacket1_21_4.class, ServerboundPacket1_21_4.class);
super(ClientboundPacket1_21_6.class, ClientboundPacket1_21_6.class, ServerboundPacket1_21_6.class, ServerboundPacket1_21_6.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
tagRewriter.registerGeneric(ClientboundPackets1_21_2.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundPackets1_21_6.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21_6.UPDATE_TAGS);
// If needed for item or component changes
componentRewriter.registerOpenScreen1_14(ClientboundPackets1_21_2.OPEN_SCREEN);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_21_2.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_21_2.TAB_LIST);
componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_2.PLAYER_COMBAT_KILL);
componentRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_2.PLAYER_INFO_UPDATE);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SYSTEM_CHAT);
componentRewriter.registerDisguisedChat(ClientboundPackets1_21_2.DISGUISED_CHAT);
componentRewriter.registerPlayerChat1_21_5(ClientboundPackets1_21_2.PLAYER_CHAT);
componentRewriter.registerOpenScreen1_14(ClientboundPackets1_21_6.OPEN_SCREEN);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_21_6.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_21_6.TAB_LIST);
componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_6.PLAYER_COMBAT_KILL);
componentRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_6.PLAYER_INFO_UPDATE);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.SYSTEM_CHAT);
componentRewriter.registerDisguisedChat(ClientboundPackets1_21_6.DISGUISED_CHAT);
componentRewriter.registerPlayerChat1_21_5(ClientboundPackets1_21_6.PLAYER_CHAT);
componentRewriter.registerPing();
// If needed for any particle, item, or block changes. Extend ParticleRewriter for particle serializer changes
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_2.LEVEL_PARTICLES);
particleRewriter.registerExplode1_21_2(ClientboundPackets1_21_2.EXPLODE); // Rewrites the included sound and particles
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_6.LEVEL_PARTICLES);
particleRewriter.registerExplode1_21_9(ClientboundPackets1_21_6.EXPLODE); // Rewrites the included sound and particles
final SoundRewriter<ClientboundPacket1_21_2> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_2.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_2.SOUND_ENTITY);
final SoundRewriter<ClientboundPacket1_21_6> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND_ENTITY);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21_2.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21_2.UPDATE_ATTRIBUTES);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21_6.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21_6.UPDATE_ATTRIBUTES);
// Uncomment if an existing type changed serialization format. Mappings for argument type keys can also be defined in mapping files
/*new CommandRewriter1_19_4<>(this) {
@@ -112,13 +110,13 @@ final class Protocol1_98To1_99 extends AbstractProtocol<ClientboundPacket1_21_2,
super.handleArgument(wrapper, argumentType);
}
}
}.registerDeclareCommands1_19(ClientboundPackets1_21_2.COMMANDS);*/
}.registerDeclareCommands1_19(ClientboundPackets1_21_6.COMMANDS);*/
}
@Override
protected void onMappingDataLoaded() {
// Uncomment this if the entity types enum has been newly added specifically for this Protocol
// EntityTypes1_21_4.initialize(this);
// EntityTypes1_21_9.initialize(this);
// Uncomment if a new particle was added = ids shifted; requires a new Types_ class copied from the last
/*mappedTypes().particle.filler(this)
@@ -143,8 +141,8 @@ final class Protocol1_98To1_99 extends AbstractProtocol<ClientboundPacket1_21_2,
@Override
public void init(final UserConnection connection) {
// Register the entity tracker - used for entity id/entity data rewriting AND for tracking world data sent to the client (then used for chunk data rewriting)
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_4.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_6, SerializerVersion.V1_21_6));
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_9.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection));
}
// Overriding these methods is important as they are relied on various rewriter classes
@@ -165,37 +163,37 @@ final class Protocol1_98To1_99 extends AbstractProtocol<ClientboundPacket1_21_2,
}
@Override
public ParticleRewriter<ClientboundPacket1_21_2> getParticleRewriter() {
public ParticleRewriter<ClientboundPacket1_21_6> getParticleRewriter() {
return particleRewriter;
}
@Override
public TagRewriter<ClientboundPacket1_21_2> getTagRewriter() {
public TagRewriter<ClientboundPacket1_21_6> getTagRewriter() {
return tagRewriter;
}
@Override
public NBTComponentRewriter<ClientboundPacket1_21_2> getComponentRewriter() {
public NBTComponentRewriter<ClientboundPacket1_21_6> getComponentRewriter() {
return componentRewriter;
}
@Override
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> types() {
return VersionedTypes.V1_21_5;
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_9> types() {
return VersionedTypes.V1_21_9;
}
@Override
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> mappedTypes() {
return VersionedTypes.V1_21_5;
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_9> mappedTypes() {
return VersionedTypes.V1_21_9;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21_2, ClientboundPacket1_21_2, ServerboundPacket1_21_4, ServerboundPacket1_21_4> createPacketTypesProvider() {
protected PacketTypesProvider<ClientboundPacket1_21_6, ClientboundPacket1_21_6, ServerboundPacket1_21_6, ServerboundPacket1_21_6> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_4.class, ServerboundConfigurationPackets1_20_5.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_4.class, ServerboundConfigurationPackets1_20_5.class)
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_6.class, ClientboundConfigurationPackets1_21_6.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_6.class, ClientboundConfigurationPackets1_21_6.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_6.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_6.class)
);
}
}
@@ -40,7 +40,7 @@ public class TabCompleteTracker implements StorableObject {
wrapper.write(Types.BOOLEAN, false);
final BlockPosition playerLookTarget = Via.getManager().getProviders().get(PlayerLookTargetProvider.class).getPlayerLookTarget(connection);
wrapper.write(Types.OPTIONAL_POSITION1_8, playerLookTarget);
wrapper.scheduleSendToServer(Protocol1_12_2To1_13.class);
wrapper.sendToServer(Protocol1_12_2To1_13.class);
lastTabComplete = null;
}
@@ -18,18 +18,17 @@
package com.viaversion.viaversion.protocols.v1_12_2to1_13.task;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocol.ProtocolRunnable;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.connection.StorableObjectTask;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.storage.TabCompleteTracker;
public final class TabCompleteTask extends ProtocolRunnable {
public final class TabCompleteTask extends StorableObjectTask<TabCompleteTracker> {
public TabCompleteTask() {
super(Protocol1_12_2To1_13.class);
super(TabCompleteTracker.class);
}
@Override
public void run(final UserConnection connection) {
connection.get(TabCompleteTracker.class).sendPacketToServer(connection);
public void run(final UserConnection connection, final TabCompleteTracker storableObject) {
storableObject.sendPacketToServer(connection);
}
}
@@ -52,6 +52,7 @@ import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter.EntityPacket
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter.ParticleRewriter1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.AcknowledgedMessagesStorage;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.ArmorTrimStorage;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.ScoreboardTeamStorage;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.TagKeys;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.rewriter.SoundRewriter;
@@ -60,6 +61,7 @@ import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter;
import com.viaversion.viaversion.util.ProtocolLogger;
import java.util.BitSet;
import java.util.Objects;
import java.util.UUID;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -222,6 +224,51 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
wrapper.write(Types.BOOLEAN, strictErrorHandling);
});
registerClientbound(ClientboundPackets1_20_3.SET_PLAYER_TEAM, wrapper -> {
final String teamName = wrapper.passthrough(Types.STRING);
final byte action = wrapper.passthrough(Types.BYTE);
if (action == 2) {
return;
}
final ScoreboardTeamStorage storage = wrapper.user().get(ScoreboardTeamStorage.class);
if (action == 1) {
storage.removeTeam(teamName);
return;
} else if (action == 0) {
storage.createTeam(teamName);
wrapper.passthrough(Types.TAG); // Display name
wrapper.passthrough(Types.BYTE); // Flags
wrapper.passthrough(Types.STRING); // Name Tag Visibility
wrapper.passthrough(Types.STRING); // Collision rule
wrapper.passthrough(Types.VAR_INT); // Color
wrapper.passthrough(Types.TAG); // Prefix
wrapper.passthrough(Types.TAG); // Suffix
final String[] players = wrapper.passthrough(Types.STRING_ARRAY);
storage.addPlayerToTeam(teamName, players);
return;
}
final String[] players = wrapper.passthrough(Types.STRING_ARRAY);
if (action == 3) {
storage.addPlayerToTeam(teamName, players);
} else if (action != 4) {
return;
}
// Drop invalid remove packets to not break when plugins do that, since strict error handling is enforced in newer protocols.
for (final String player : players) {
final String team = storage.getPlayerTeam(player);
if (!Objects.equals(team, teamName)) {
wrapper.cancel();
return;
}
storage.removeFromTeam(teamName, player);
}
});
cancelServerbound(State.LOGIN, ServerboundLoginPackets.COOKIE_RESPONSE.getId());
cancelServerbound(ServerboundConfigurationPackets1_20_5.COOKIE_RESPONSE);
cancelServerbound(ServerboundConfigurationPackets1_20_5.SELECT_KNOWN_PACKS);
@@ -277,12 +324,12 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
.add(StructuredDataKey.MAP_ID).add(StructuredDataKey.MAP_DECORATIONS).add(StructuredDataKey.MAP_POST_PROCESSING)
.add(StructuredDataKey.POTION_CONTENTS1_20_5)
.add(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS).add(StructuredDataKey.WRITABLE_BOOK_CONTENT).add(StructuredDataKey.WRITTEN_BOOK_CONTENT)
.add(StructuredDataKey.TRIM1_20_5).add(StructuredDataKey.DEBUG_STICK_STATE).add(StructuredDataKey.ENTITY_DATA)
.add(StructuredDataKey.BUCKET_ENTITY_DATA).add(StructuredDataKey.BLOCK_ENTITY_DATA).add(StructuredDataKey.INSTRUMENT1_20_5)
.add(StructuredDataKey.TRIM1_20_5).add(StructuredDataKey.DEBUG_STICK_STATE).add(StructuredDataKey.ENTITY_DATA1_20_5)
.add(StructuredDataKey.BUCKET_ENTITY_DATA).add(StructuredDataKey.BLOCK_ENTITY_DATA1_20_5).add(StructuredDataKey.INSTRUMENT1_20_5)
.add(StructuredDataKey.RECIPES).add(StructuredDataKey.LODESTONE_TRACKER).add(StructuredDataKey.FIREWORK_EXPLOSION)
.add(StructuredDataKey.FIREWORKS).add(StructuredDataKey.PROFILE).add(StructuredDataKey.NOTE_BLOCK_SOUND)
.add(StructuredDataKey.FIREWORKS).add(StructuredDataKey.PROFILE1_20_5).add(StructuredDataKey.NOTE_BLOCK_SOUND)
.add(StructuredDataKey.BANNER_PATTERNS).add(StructuredDataKey.BASE_COLOR).add(StructuredDataKey.POT_DECORATIONS)
.add(StructuredDataKey.BLOCK_STATE).add(StructuredDataKey.BEES)
.add(StructuredDataKey.BLOCK_STATE).add(StructuredDataKey.BEES1_20_5)
.add(StructuredDataKey.LOCK).add(StructuredDataKey.CONTAINER_LOOT).add(StructuredDataKey.TOOL1_20_5)
.add(StructuredDataKey.ITEM_NAME).add(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER)
.add(VersionedTypes.V1_20_5.structuredDataKeys().keys());
@@ -300,6 +347,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_20_5.PLAYER));
connection.put(new AcknowledgedMessagesStorage());
connection.put(new ArmorTrimStorage());
connection.put(new ScoreboardTeamStorage());
}
@Override
@@ -480,7 +480,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
}
if (entityTag.contains("id")) {
data.set(StructuredDataKey.ENTITY_DATA, entityTag);
data.set(StructuredDataKey.ENTITY_DATA1_20_5, entityTag);
}
}
@@ -502,7 +502,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
// Not always needed, e.g. shields that had the base color in a block entity tag before
if (clonedTag.contains("id")) {
item.dataContainer().set(StructuredDataKey.BLOCK_ENTITY_DATA, clonedTag);
item.dataContainer().set(StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, clonedTag);
}
}
@@ -1300,7 +1300,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
if (skullOwnerTag instanceof StringTag nameTag) {
final String name = nameTag.getValue();
if (isValidName(name)) {
data.set(StructuredDataKey.PROFILE, new GameProfile(name, null, EMPTY_PROPERTIES));
data.set(StructuredDataKey.PROFILE1_20_5, new GameProfile(name, null, EMPTY_PROPERTIES));
}
} else if (skullOwnerTag instanceof CompoundTag skullOwner) {
String name = skullOwner.getString("Name", "");
@@ -1320,7 +1320,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
updateProperties(propertiesTag, properties);
}
data.set(StructuredDataKey.PROFILE, new GameProfile(name, uuid, properties.toArray(EMPTY_PROPERTIES)));
data.set(StructuredDataKey.PROFILE1_20_5, new GameProfile(name, uuid, properties.toArray(EMPTY_PROPERTIES)));
}
}
@@ -1344,7 +1344,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
return new Bee(entityData, ticksInHive, minOccupationTicks);
}).filter(Objects::nonNull).toArray(Bee[]::new);
data.set(StructuredDataKey.BEES, bees);
data.set(StructuredDataKey.BEES1_20_5, bees);
}
private void updateProperties(final CompoundTag propertiesTag, final List<GameProfile.Property> properties) {
@@ -156,23 +156,23 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Js
register(StructuredDataKey.WRITTEN_BOOK_CONTENT, this::writtenBookContentToTag, this::writtenBookContentFromTag);
register(StructuredDataKey.TRIM1_20_5, this::trimToTag, this::trimFromTag);
register(StructuredDataKey.DEBUG_STICK_STATE, this::debugStickRateToTag, this::debugStickRateFromTag);
register(StructuredDataKey.ENTITY_DATA, this::entityDataToTag, this::entityDataFromTag);
register(StructuredDataKey.ENTITY_DATA1_20_5, this::entityDataToTag, this::entityDataFromTag);
register(StructuredDataKey.BUCKET_ENTITY_DATA, this::bucketEntityDataToTag, this::bucketEntityDataFromTag);
register(StructuredDataKey.BLOCK_ENTITY_DATA, this::blockEntityDataToTag, this::blockEntityDataFromTag);
register(StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, this::blockEntityDataToTag, this::blockEntityDataFromTag);
register(StructuredDataKey.INSTRUMENT1_20_5, this::instrumentToTag, this::instrumentFromTag);
register(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, this::ominousBottleAmplifierToTag, this::ominousBottleAmplifierFromTag);
register(StructuredDataKey.RECIPES, this::recipesToTag, this::recipesFromTag);
register(StructuredDataKey.LODESTONE_TRACKER, this::lodestoneTrackerToTag, this::lodestoneTrackerFromTag);
register(StructuredDataKey.FIREWORK_EXPLOSION, this::fireworkExplosionToTag, this::fireworkExplosionFromTag);
register(StructuredDataKey.FIREWORKS, this::fireworksToTag, this::fireworksFromTag);
register(StructuredDataKey.PROFILE, this::profileToTag, this::profileFromTag);
register(StructuredDataKey.PROFILE1_20_5, this::profileToTag, this::profileFromTag);
register(StructuredDataKey.NOTE_BLOCK_SOUND, this::noteBlockSoundToTag, this::noteBlockSoundFromTag);
register(StructuredDataKey.BANNER_PATTERNS, this::bannerPatternsToTag, this::bannerPatternsFromTag);
register(StructuredDataKey.BASE_COLOR, this::baseColorToTag, this::baseColorFromTag);
register(StructuredDataKey.POT_DECORATIONS, this::potDecorationsToTag, this::potDecorationsFromTag);
register(StructuredDataKey.V1_20_5.container, this::containerToTag, this::containerFromTag);
register(StructuredDataKey.BLOCK_STATE, this::blockStateToTag, this::blockStateFromTag);
register(StructuredDataKey.BEES, this::beesToTag, this::beesFromTag);
register(StructuredDataKey.BEES1_20_5, this::beesToTag, this::beesFromTag);
register(StructuredDataKey.LOCK, this::lockToTag, this::lockFromTag);
register(StructuredDataKey.CONTAINER_LOOT, this::containerLootToTag, this::containerLootFromTag);
}
@@ -1386,8 +1386,8 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Js
final ListTag<CompoundTag> tag = new ListTag<>(CompoundTag.class);
for (final Bee bee : value) {
final CompoundTag beeTag = new CompoundTag();
if (!bee.entityData().isEmpty()) {
beeTag.put("entity_data", nbtToTag(bee.entityData()));
if (!bee.entityData().tag().isEmpty()) {
beeTag.put("entity_data", nbtToTag(bee.entityData().tag()));
}
beeTag.putInt("ticks_in_hive", bee.ticksInHive());
beeTag.putInt("min_ticks_in_hive", bee.minTicksInHive());
@@ -48,6 +48,7 @@ import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundCon
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.AcknowledgedMessagesStorage;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.ArmorTrimStorage;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.ScoreboardTeamStorage;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.KeyMappings;
@@ -297,6 +298,8 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter<Clientbound
final byte gamemode = wrapper.passthrough(Types.BYTE);
sendRangeAttributes(wrapper.user(), gamemode == GameMode.CREATIVE.id());
wrapper.user().put(new ScoreboardTeamStorage());
});
protocol.registerClientbound(ClientboundPackets1_20_3.UPDATE_MOB_EFFECT, wrapper -> {
@@ -250,7 +250,7 @@ public final class StructuredDataConverter {
}
});
register(StructuredDataKey.FIREWORK_EXPLOSION, (data, tag) -> tag.put("Explosion", convertExplosion(data)));
register(StructuredDataKey.PROFILE, (data, tag) -> {
register(StructuredDataKey.PROFILE1_20_5, (data, tag) -> {
if (data.name() != null && data.id() == null && data.properties().length == 0) {
tag.putString("SkullOwner", data.name());
return;
@@ -307,11 +307,11 @@ public final class StructuredDataConverter {
tag.putString("instrument", identifier);
}
});
register(StructuredDataKey.BEES, (data, tag) -> {
register(StructuredDataKey.BEES1_20_5, (data, tag) -> {
final ListTag<CompoundTag> bees = new ListTag<>(CompoundTag.class);
for (final Bee bee : data) {
final CompoundTag beeTag = new CompoundTag();
beeTag.put("EntityData", bee.entityData());
beeTag.put("EntityData", bee.entityData().tag());
beeTag.putInt("TicksInHive", bee.ticksInHive());
beeTag.putInt("MinOccupationTicks", bee.minTicksInHive());
bees.add(beeTag);
@@ -343,7 +343,7 @@ public final class StructuredDataConverter {
});
register(StructuredDataKey.DEBUG_STICK_STATE, (data, tag) -> tag.put("DebugProperty", data));
register(StructuredDataKey.RECIPES, (data, tag) -> tag.put("Recipes", data));
register(StructuredDataKey.ENTITY_DATA, (data, tag) -> tag.put("EntityTag", data));
register(StructuredDataKey.ENTITY_DATA1_20_5, (data, tag) -> tag.put("EntityTag", data));
register(StructuredDataKey.BUCKET_ENTITY_DATA, (data, tag) -> {
for (final String mobTagName : BlockItemPacketRewriter1_20_5.MOB_TAGS) {
if (data.contains(mobTagName)) {
@@ -351,7 +351,7 @@ public final class StructuredDataConverter {
}
}
});
register(StructuredDataKey.BLOCK_ENTITY_DATA, (data, tag) -> {
register(StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, (data, tag) -> {
// Handling of previously block entity tags is done using the getBlockEntityTag method
// Merge with already added tag if needed
final CompoundTag blockEntityTag = tag.getCompoundTag("BlockEntityTag");
@@ -0,0 +1,64 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public final class ScoreboardTeamStorage implements StorableObject {
private final Map<String, Set<String>> teams = new HashMap<>();
public void createTeam(final String name) {
if (this.teams.containsKey(name)) {
return;
}
this.teams.put(name, new HashSet<>());
}
public void removeTeam(final String name) {
this.teams.remove(name);
}
public void addPlayerToTeam(final String team, final String[] player) {
final Set<String> players = this.teams.computeIfAbsent(team, k -> new HashSet<>());
Collections.addAll(players, player);
}
public void removeFromTeam(final String team, final String player) {
final Set<String> players = this.teams.get(team);
if (players != null) {
players.remove(player);
}
}
public String getPlayerTeam(final String player) {
for (final Map.Entry<String, Set<String>> entry : this.teams.entrySet()) {
if (entry.getValue().contains(player)) {
return entry.getKey();
}
}
return null;
}
}
@@ -211,12 +211,12 @@ public final class Protocol1_20_5To1_21 extends AbstractProtocol<ClientboundPack
.add(StructuredDataKey.MAP_ID).add(StructuredDataKey.MAP_DECORATIONS).add(StructuredDataKey.MAP_POST_PROCESSING)
.add(StructuredDataKey.POTION_CONTENTS1_20_5)
.add(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS).add(StructuredDataKey.WRITABLE_BOOK_CONTENT).add(StructuredDataKey.WRITTEN_BOOK_CONTENT)
.add(StructuredDataKey.TRIM1_20_5).add(StructuredDataKey.DEBUG_STICK_STATE).add(StructuredDataKey.ENTITY_DATA)
.add(StructuredDataKey.BUCKET_ENTITY_DATA).add(StructuredDataKey.BLOCK_ENTITY_DATA).add(StructuredDataKey.INSTRUMENT1_20_5)
.add(StructuredDataKey.TRIM1_20_5).add(StructuredDataKey.DEBUG_STICK_STATE).add(StructuredDataKey.ENTITY_DATA1_20_5)
.add(StructuredDataKey.BUCKET_ENTITY_DATA).add(StructuredDataKey.BLOCK_ENTITY_DATA1_20_5).add(StructuredDataKey.INSTRUMENT1_20_5)
.add(StructuredDataKey.RECIPES).add(StructuredDataKey.LODESTONE_TRACKER).add(StructuredDataKey.FIREWORK_EXPLOSION)
.add(StructuredDataKey.FIREWORKS).add(StructuredDataKey.PROFILE).add(StructuredDataKey.NOTE_BLOCK_SOUND)
.add(StructuredDataKey.FIREWORKS).add(StructuredDataKey.PROFILE1_20_5).add(StructuredDataKey.NOTE_BLOCK_SOUND)
.add(StructuredDataKey.BANNER_PATTERNS).add(StructuredDataKey.BASE_COLOR).add(StructuredDataKey.POT_DECORATIONS)
.add(StructuredDataKey.BLOCK_STATE).add(StructuredDataKey.BEES)
.add(StructuredDataKey.BLOCK_STATE).add(StructuredDataKey.BEES1_20_5)
.add(StructuredDataKey.LOCK).add(StructuredDataKey.CONTAINER_LOOT).add(StructuredDataKey.TOOL1_20_5)
.add(StructuredDataKey.ITEM_NAME).add(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER)
.add(StructuredDataKey.FOOD1_21).add(StructuredDataKey.JUKEBOX_PLAYABLE1_21).add(StructuredDataKey.ATTRIBUTE_MODIFIERS1_21);
@@ -239,6 +239,14 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol<ClientboundPack
if (channel.equals("minecraft:brand")) {
wrapper.passthrough(Types.STRING);
wrapper.clearInputBuffer();
} else if (channel.equals("minecraft:debug/game_test_add_marker")) {
wrapper.passthrough(Types.BLOCK_POSITION1_14);
wrapper.passthrough(Types.INT);
wrapper.passthrough(Types.STRING);
wrapper.passthrough(Types.INT);
wrapper.clearInputBuffer();
} else if (channel.equals("minecraft:debug/game_test_clear")) {
wrapper.clearInputBuffer();
}
}
@@ -282,11 +290,15 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol<ClientboundPack
}
if (configurationBridge.queuedOrSentJoinGame()) {
if (!packetWrapper.user().isClientSide() && !Via.getPlatform().isProxy() && unmappedId == ClientboundPackets1_19_4.SYSTEM_CHAT.getId()) {
// Cancelling this on the Vanilla server will cause it to exceptionally resend a message
// Assume that we have already sent the login packet and just let it through
super.transform(direction, State.PLAY, packetWrapper);
return;
final ProtocolVersion serverProtocolVersion = Via.getAPI().getServerVersion().lowestSupportedProtocolVersion();
if (serverProtocolVersion.newerThanOrEqualTo(ProtocolVersion.v1_13)) {
if (!packetWrapper.user().isClientSide() && !Via.getPlatform().isProxy() && unmappedId == ClientboundPackets1_19_4.SYSTEM_CHAT.getId()) {
// Cancelling this on a 1.13+ Vanilla server will cause it to exceptionally resend a message
// Assume that we have already sent the login packet and just let it through
super.transform(direction, State.PLAY, packetWrapper);
return;
}
}
configurationBridge.addPacketToQueue(packetWrapper, true);
@@ -173,11 +173,11 @@ public final class Protocol1_21_2To1_21_4 extends AbstractProtocol<ClientboundPa
StructuredDataKey.INTANGIBLE_PROJECTILE, StructuredDataKey.STORED_ENCHANTMENTS1_20_5, StructuredDataKey.DYED_COLOR1_20_5,
StructuredDataKey.MAP_COLOR, StructuredDataKey.MAP_ID, StructuredDataKey.MAP_DECORATIONS, StructuredDataKey.MAP_POST_PROCESSING,
StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, StructuredDataKey.WRITABLE_BOOK_CONTENT,
StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_4, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA, StructuredDataKey.INSTRUMENT1_21_2,
StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_4, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA1_20_5,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, StructuredDataKey.INSTRUMENT1_21_2,
StructuredDataKey.RECIPES, StructuredDataKey.LODESTONE_TRACKER, StructuredDataKey.FIREWORK_EXPLOSION, StructuredDataKey.FIREWORKS,
StructuredDataKey.PROFILE, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR,
StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES, StructuredDataKey.LOCK,
StructuredDataKey.PROFILE1_20_5, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR,
StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES1_20_5, StructuredDataKey.LOCK,
StructuredDataKey.CONTAINER_LOOT, StructuredDataKey.TOOL1_20_5, StructuredDataKey.ITEM_NAME, StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER,
StructuredDataKey.FOOD1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE1_21, StructuredDataKey.ATTRIBUTE_MODIFIERS1_21,
StructuredDataKey.REPAIRABLE, StructuredDataKey.ENCHANTABLE, StructuredDataKey.CONSUMABLE1_21_2,
@@ -185,11 +185,11 @@ public final class Protocol1_21_4To1_21_5 extends AbstractProtocol<ClientboundPa
StructuredDataKey.INTANGIBLE_PROJECTILE, StructuredDataKey.STORED_ENCHANTMENTS1_21_5, StructuredDataKey.DYED_COLOR1_21_5,
StructuredDataKey.MAP_COLOR, StructuredDataKey.MAP_ID, StructuredDataKey.MAP_DECORATIONS, StructuredDataKey.MAP_POST_PROCESSING,
StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, StructuredDataKey.WRITABLE_BOOK_CONTENT,
StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_5, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA, StructuredDataKey.INSTRUMENT1_21_5,
StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_5, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA1_20_5,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, StructuredDataKey.INSTRUMENT1_21_5,
StructuredDataKey.RECIPES, StructuredDataKey.LODESTONE_TRACKER, StructuredDataKey.FIREWORK_EXPLOSION, StructuredDataKey.FIREWORKS,
StructuredDataKey.PROFILE, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR,
StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES, StructuredDataKey.LOCK,
StructuredDataKey.PROFILE1_20_5, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR,
StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES1_20_5, StructuredDataKey.LOCK,
StructuredDataKey.CONTAINER_LOOT, StructuredDataKey.TOOL1_21_5, StructuredDataKey.ITEM_NAME, StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER,
StructuredDataKey.FOOD1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE1_21_5, StructuredDataKey.ATTRIBUTE_MODIFIERS1_21_5,
StructuredDataKey.REPAIRABLE, StructuredDataKey.ENCHANTABLE, StructuredDataKey.CONSUMABLE1_21_2,
@@ -90,7 +90,7 @@ import static com.viaversion.viaversion.util.MathUtil.ceilLog2;
public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<ClientboundPacket1_21_2, ServerboundPacket1_21_5, Protocol1_21_4To1_21_5> {
public static final List<StructuredDataKey<?>> HIDE_ADDITIONAL_KEYS = List.of(
StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BEES, StructuredDataKey.BLOCK_ENTITY_DATA,
StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BEES1_20_5, StructuredDataKey.BLOCK_ENTITY_DATA1_20_5,
StructuredDataKey.BLOCK_STATE, StructuredDataKey.V1_21_5.bundleContents, StructuredDataKey.V1_21_5.chargedProjectiles, StructuredDataKey.V1_21_5.container,
StructuredDataKey.CONTAINER_LOOT, StructuredDataKey.FIREWORK_EXPLOSION, StructuredDataKey.FIREWORKS, StructuredDataKey.INSTRUMENT1_21_5, StructuredDataKey.MAP_ID,
StructuredDataKey.PAINTING_VARIANT, StructuredDataKey.POT_DECORATIONS, StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.TROPICAL_FISH_PATTERN,
@@ -290,10 +290,19 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
private void handleBlockEntity(final UserConnection connection, final BlockEntity blockEntity) {
final CompoundTag tag = blockEntity.tag();
if (tag != null && (blockEntity.typeId() == SIGN_BOCK_ENTITY_ID || blockEntity.typeId() == HANGING_SIGN_BOCK_ENTITY_ID)) {
if (tag == null) {
return;
}
if (blockEntity.typeId() == SIGN_BOCK_ENTITY_ID || blockEntity.typeId() == HANGING_SIGN_BOCK_ENTITY_ID) {
updateSignMessages(connection, tag.getCompoundTag("front_text"));
updateSignMessages(connection, tag.getCompoundTag("back_text"));
}
final String customName = tag.getString("CustomName");
if (customName != null) {
tag.put("CustomName", protocol.getComponentRewriter().uglyJsonToTag(connection, customName));
}
}
private void updateSignMessages(final UserConnection connection, final CompoundTag tag) {
@@ -342,12 +351,6 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
handleItemDataComponentsToClient(connection, item, dataContainer);
if (dataContainer.hasValue(StructuredDataKey.HIDE_ADDITIONAL_TOOLTIP)) {
final CompoundTag backupTag = new CompoundTag();
backupTag.putBoolean("hide_additional_tooltip", true);
saveTag(createCustomTag(item), backupTag, "backup");
}
// Add data components to fix issues in older protocols
appendItemDataFixComponents(connection, item);
@@ -368,16 +371,6 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
super.handleItemDataComponentsToServer(connection, item, container);
}
@Override
protected void restoreBackupData(final Item item, final StructuredDataContainer container, final CompoundTag customData) {
super.restoreBackupData(item, container, customData);
if (customData.remove(nbtTagName("backup")) instanceof final CompoundTag backupTag) {
if (backupTag.getBoolean("hide_additional_tooltip")) {
container.set(StructuredDataKey.HIDE_ADDITIONAL_TOOLTIP);
}
}
}
public static void updateItemData(final Item item) {
final StructuredDataContainer dataContainer = item.dataContainer();
dataContainer.replaceKey(StructuredDataKey.TOOL1_20_5, StructuredDataKey.TOOL1_21_5);
@@ -472,8 +465,15 @@ public final class BlockItemPacketRewriter1_21_5 extends StructuredItemRewriter<
dataContainer.replace(StructuredDataKey.INSTRUMENT1_21_5, StructuredDataKey.INSTRUMENT1_21_2, instrument -> instrument.hasHolder() ? instrument.holder() : null);
final TooltipDisplay tooltipDisplay = dataContainer.get(StructuredDataKey.TOOLTIP_DISPLAY);
if (tooltipDisplay != null && tooltipDisplay.hideTooltip()) {
dataContainer.set(StructuredDataKey.HIDE_TOOLTIP);
if (tooltipDisplay != null) {
if (tooltipDisplay.hideTooltip()) {
dataContainer.set(StructuredDataKey.HIDE_TOOLTIP);
}
final FullMappings mappings = Protocol1_21_4To1_21_5.MAPPINGS.getDataComponentSerializerMappings();
if (tooltipDisplay.hiddenComponents().containsAll(HIDE_ADDITIONAL_KEYS.stream().map(key -> mappings.id(key.identifier())).toList())) {
dataContainer.set(StructuredDataKey.HIDE_ADDITIONAL_TOOLTIP);
}
}
dataContainer.replace(StructuredDataKey.UNBREAKABLE1_21_5, StructuredDataKey.UNBREAKABLE1_20_5, unbreakable -> new Unbreakable(shouldShowToServer(tooltipDisplay, StructuredDataKey.UNBREAKABLE1_20_5)));
@@ -204,9 +204,9 @@ public final class ComponentRewriter1_21_5 extends JsonNBTComponentRewriter<Clie
}
private void updateShowTextHover(final UserConnection connection, final CompoundTag hoverEventTag) {
if (hoverEventTag.remove("value") instanceof final StringTag value) {
final Tag contents = uglyJsonToTag(connection, value.getValue());
hoverEventTag.put("value", contents);
final Tag value = hoverEventTag.get("value");
if (value != null) {
processTag(connection, value);
return;
}
@@ -29,7 +29,6 @@ import com.viaversion.viaversion.codec.hash.HashFunction;
import com.viaversion.viaversion.codec.hash.HashOps;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_5;
import com.viaversion.viaversion.util.SerializerVersion;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
@@ -43,7 +42,7 @@ public class ItemHashStorage1_21_5 implements ItemHasher {
public ItemHashStorage1_21_5(final Protocol1_21_4To1_21_5 protocol) {
final RegistryAccess registryAccess = RegistryAccess.of(this.enchantmentRegistry, protocol.getMappingData());
this.context = new CodecRegistryContext(protocol, SerializerVersion.V1_21_5, SerializerVersion.V1_21_5, registryAccess, true); // always using 1.21.5 items as input
this.context = new CodecRegistryContext(protocol, registryAccess, true); // always using 1.21.5 items as input
}
@Override
@@ -55,7 +55,6 @@ import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.NBTComponentRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
import java.util.Locale;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -150,11 +149,11 @@ public final class Protocol1_21_5To1_21_6 extends AbstractProtocol<ClientboundPa
StructuredDataKey.INTANGIBLE_PROJECTILE, StructuredDataKey.STORED_ENCHANTMENTS1_21_5, StructuredDataKey.DYED_COLOR1_21_5,
StructuredDataKey.MAP_COLOR, StructuredDataKey.MAP_ID, StructuredDataKey.MAP_DECORATIONS, StructuredDataKey.MAP_POST_PROCESSING,
StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, StructuredDataKey.WRITABLE_BOOK_CONTENT,
StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_5, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA, StructuredDataKey.INSTRUMENT1_21_5,
StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_5, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA1_20_5,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, StructuredDataKey.INSTRUMENT1_21_5,
StructuredDataKey.RECIPES, StructuredDataKey.LODESTONE_TRACKER, StructuredDataKey.FIREWORK_EXPLOSION, StructuredDataKey.FIREWORKS,
StructuredDataKey.PROFILE, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR,
StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES, StructuredDataKey.LOCK,
StructuredDataKey.PROFILE1_20_5, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR,
StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES1_20_5, StructuredDataKey.LOCK,
StructuredDataKey.CONTAINER_LOOT, StructuredDataKey.TOOL1_21_5, StructuredDataKey.ITEM_NAME, StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER,
StructuredDataKey.FOOD1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE1_21_5, StructuredDataKey.ATTRIBUTE_MODIFIERS1_21_6,
StructuredDataKey.REPAIRABLE, StructuredDataKey.ENCHANTABLE, StructuredDataKey.CONSUMABLE1_21_2,
@@ -173,7 +172,7 @@ public final class Protocol1_21_5To1_21_6 extends AbstractProtocol<ClientboundPa
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_6.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_5, SerializerVersion.V1_21_6));
addItemHasher(connection, new ItemHasherBase(this, connection));
connection.put(new SneakStorage());
}
@@ -17,74 +17,76 @@
*/
package com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet;
public enum ServerboundPackets1_21_6 implements ServerboundPacket1_21_6 {
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
public enum ServerboundPackets1_21_6 implements ServerboundPacket1_21_6, ServerboundPacket1_21_9 {
ACCEPT_TELEPORTATION, // 0x00
BLOCK_ENTITY_TAG_QUERY, // 0x01
BUNDLE_ITEM_SELECTED, // 0x02
CHANGE_DIFFICULTY, // 0x03
CHANGE_GAME_MODE, // 0x03
CHAT_ACK, // 0x04
CHAT_COMMAND, // 0x05
CHAT_COMMAND_SIGNED, // 0x06
CHAT, // 0x07
CHAT_SESSION_UPDATE, // 0x08
CHUNK_BATCH_RECEIVED, // 0x09
CLIENT_COMMAND, // 0x0A
CLIENT_TICK_END, // 0x0B
CLIENT_INFORMATION, // 0x0C
COMMAND_SUGGESTION, // 0x0D
CONFIGURATION_ACKNOWLEDGED, // 0x0E
CONTAINER_BUTTON_CLICK, // 0x0F
CONTAINER_CLICK, // 0x10
CONTAINER_CLOSE, // 0x11
CONTAINER_SLOT_STATE_CHANGED, // 0x12
COOKIE_RESPONSE, // 0x13
CUSTOM_PAYLOAD, // 0x14
DEBUG_SAMPLE_SUBSCRIPTION, // 0x15
EDIT_BOOK, // 0x16
ENTITY_TAG_QUERY, // 0x17
INTERACT, // 0x18
JIGSAW_GENERATE, // 0x19
KEEP_ALIVE, // 0x1A
LOCK_DIFFICULTY, // 0x1B
MOVE_PLAYER_POS, // 0x1C
MOVE_PLAYER_POS_ROT, // 0x1D
MOVE_PLAYER_ROT, // 0x1E
MOVE_PLAYER_STATUS_ONLY, // 0x1F
MOVE_VEHICLE, // 0x20
PADDLE_BOAT, // 0x21
PICK_ITEM_FROM_BLOCK, // 0x22
PICK_ITEM_FROM_ENTITY, // 0x23
PING_REQUEST, // 0x24
PLACE_RECIPE, // 0x25
PLAYER_ABILITIES, // 0x26
PLAYER_ACTION, // 0x27
PLAYER_COMMAND, // 0x28
PLAYER_INPUT, // 0x29
PLAYER_LOADED, // 0x2A
PONG, // 0x2B
RECIPE_BOOK_CHANGE_SETTINGS, // 0x2C
RECIPE_BOOK_SEEN_RECIPE, // 0x2D
RENAME_ITEM, // 0x2E
RESOURCE_PACK, // 0x2F
SEEN_ADVANCEMENTS, // 0x30
SELECT_TRADE, // 0x31
SET_BEACON, // 0x32
SET_CARRIED_ITEM, // 0x33
SET_COMMAND_BLOCK, // 0x34
SET_COMMAND_MINECART, // 0x35
SET_CREATIVE_MODE_SLOT, // 0x36
SET_JIGSAW_BLOCK, // 0x37
SET_STRUCTURE_BLOCK, // 0x38
SET_TEST_BLOCK, // 0x39
SIGN_UPDATE, // 0x3A
SWING, // 0x3B
TELEPORT_TO_ENTITY, // 0x3C
TEST_INSTANCE_BLOCK_ACTION, // 0x3D
USE_ITEM_ON, // 0x3E
USE_ITEM, // 0x3F
CUSTOM_CLICK_ACTION; // 0x40
CHANGE_GAME_MODE, // 0x04
CHAT_ACK, // 0x05
CHAT_COMMAND, // 0x06
CHAT_COMMAND_SIGNED, // 0x07
CHAT, // 0x08
CHAT_SESSION_UPDATE, // 0x09
CHUNK_BATCH_RECEIVED, // 0x0A
CLIENT_COMMAND, // 0x0B
CLIENT_TICK_END, // 0x0C
CLIENT_INFORMATION, // 0x0D
COMMAND_SUGGESTION, // 0x0E
CONFIGURATION_ACKNOWLEDGED, // 0x0F
CONTAINER_BUTTON_CLICK, // 0x10
CONTAINER_CLICK, // 0x11
CONTAINER_CLOSE, // 0x12
CONTAINER_SLOT_STATE_CHANGED, // 0x13
COOKIE_RESPONSE, // 0x14
CUSTOM_PAYLOAD, // 0x15
DEBUG_SAMPLE_SUBSCRIPTION, // 0x16
EDIT_BOOK, // 0x17
ENTITY_TAG_QUERY, // 0x18
INTERACT, // 0x19
JIGSAW_GENERATE, // 0x1A
KEEP_ALIVE, // 0x1B
LOCK_DIFFICULTY, // 0x1C
MOVE_PLAYER_POS, // 0x1D
MOVE_PLAYER_POS_ROT, // 0x1E
MOVE_PLAYER_ROT, // 0x1F
MOVE_PLAYER_STATUS_ONLY, // 0x20
MOVE_VEHICLE, // 0x21
PADDLE_BOAT, // 0x22
PICK_ITEM_FROM_BLOCK, // 0x23
PICK_ITEM_FROM_ENTITY, // 0x24
PING_REQUEST, // 0x25
PLACE_RECIPE, // 0x26
PLAYER_ABILITIES, // 0x27
PLAYER_ACTION, // 0x28
PLAYER_COMMAND, // 0x29
PLAYER_INPUT, // 0x2A
PLAYER_LOADED, // 0x2B
PONG, // 0x2C
RECIPE_BOOK_CHANGE_SETTINGS, // 0x2D
RECIPE_BOOK_SEEN_RECIPE, // 0x2E
RENAME_ITEM, // 0x2F
RESOURCE_PACK, // 0x30
SEEN_ADVANCEMENTS, // 0x31
SELECT_TRADE, // 0x32
SET_BEACON, // 0x33
SET_CARRIED_ITEM, // 0x34
SET_COMMAND_BLOCK, // 0x35
SET_COMMAND_MINECART, // 0x36
SET_CREATIVE_MODE_SLOT, // 0x37
SET_JIGSAW_BLOCK, // 0x38
SET_STRUCTURE_BLOCK, // 0x39
SET_TEST_BLOCK, // 0x3A
SIGN_UPDATE, // 0x3B
SWING, // 0x3C
TELEPORT_TO_ENTITY, // 0x3D
TEST_INSTANCE_BLOCK_ACTION, // 0x3E
USE_ITEM_ON, // 0x3F
USE_ITEM, // 0x40
CUSTOM_CLICK_ACTION; // 0x41
@Override
public int getId() {
@@ -42,7 +42,6 @@ import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -78,7 +77,7 @@ public final class Protocol1_21_6To1_21_7 extends AbstractProtocol<ClientboundPa
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_6.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_6, SerializerVersion.V1_21_6));
addItemHasher(connection, new ItemHasherBase(this, connection));
}
@Override
@@ -49,7 +49,7 @@ public final class EntityPacketRewriter1_21_7 extends EntityRewriter<Clientbound
@Override
protected void registerRewrites() {
final EntityDataTypes1_21_5 entityDataTypes = protocol.types().entityDataTypes();
final EntityDataTypes1_21_5 entityDataTypes = protocol.mappedTypes().entityDataTypes();
registerEntityDataTypeHandler(
entityDataTypes.itemType,
entityDataTypes.blockStateType,
@@ -0,0 +1,240 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_5;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_9;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_9;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundConfigurationPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ClientboundPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundConfigurationPackets1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter.BlockItemPacketRewriter1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter.ComponentRewriter1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter.EntityPacketRewriter1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter.ParticleRewriter1_21_9;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.LastExplosionPowerStorage;
import com.viaversion.viaversion.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.NBTComponentRewriter;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
public final class Protocol1_21_7To1_21_9 extends AbstractProtocol<ClientboundPacket1_21_6, ClientboundPacket1_21_9, ServerboundPacket1_21_6, ServerboundPacket1_21_9> {
public static final MappingData MAPPINGS = new MappingDataBase("1.21.7", "1.21.9");
private final EntityPacketRewriter1_21_9 entityRewriter = new EntityPacketRewriter1_21_9(this);
private final BlockItemPacketRewriter1_21_9 itemRewriter = new BlockItemPacketRewriter1_21_9(this);
private final ParticleRewriter<ClientboundPacket1_21_6> particleRewriter = new ParticleRewriter1_21_9(this);
private final TagRewriter<ClientboundPacket1_21_6> tagRewriter = new TagRewriter<>(this);
private final NBTComponentRewriter<ClientboundPacket1_21_6> componentRewriter = new ComponentRewriter1_21_9(this);
public Protocol1_21_7To1_21_9() {
super(ClientboundPacket1_21_6.class, ClientboundPacket1_21_9.class, ServerboundPacket1_21_6.class, ServerboundPacket1_21_9.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
tagRewriter.registerGeneric(ClientboundPackets1_21_6.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21_6.UPDATE_TAGS);
componentRewriter.registerOpenScreen1_14(ClientboundPackets1_21_6.OPEN_SCREEN);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_21_6.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_21_6.TAB_LIST);
componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_6.PLAYER_COMBAT_KILL);
componentRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_6.PLAYER_INFO_UPDATE);
componentRewriter.registerComponentPacket(ClientboundPackets1_21_6.SYSTEM_CHAT);
componentRewriter.registerDisguisedChat(ClientboundPackets1_21_6.DISGUISED_CHAT);
componentRewriter.registerPlayerChat1_21_5(ClientboundPackets1_21_6.PLAYER_CHAT);
componentRewriter.registerPing();
final SoundRewriter<ClientboundPacket1_21_6> soundRewriter = new SoundRewriter<>(this);
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_6.LEVEL_PARTICLES);
registerClientbound(ClientboundPackets1_21_6.EXPLODE, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
final LastExplosionPowerStorage lastExplosionPowerStorage = wrapper.user().get(LastExplosionPowerStorage.class);
float radius = 0;
int affectedBlocks = 0;
if (lastExplosionPowerStorage != null) {
radius = lastExplosionPowerStorage.power();
affectedBlocks = lastExplosionPowerStorage.affectedBlocks();
}
wrapper.write(Types.FLOAT, radius);
wrapper.write(Types.INT, affectedBlocks); // For some reason a plain int
if (wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.DOUBLE); // Knockback X
wrapper.passthrough(Types.DOUBLE); // Knockback Y
wrapper.passthrough(Types.DOUBLE); // Knockback Z
}
particleRewriter.passthroughParticle(wrapper); // Explosion particle
soundRewriter.soundHolderHandler().handle(wrapper);
wrapper.write(Types.VAR_INT, 0); // Number of block particles
});
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND_ENTITY);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21_6.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21_6.UPDATE_ATTRIBUTES);
cancelServerbound(ServerboundConfigurationPackets1_21_9.ACCEPT_CODE_OF_CONDUCT);
cancelServerbound(ServerboundPackets1_21_6.DEBUG_SAMPLE_SUBSCRIPTION);
}
@Override
protected void onMappingDataLoaded() {
EntityTypes1_21_9.initialize(this);
mappedTypes().particle.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust_pillar", ParticleType.Readers.BLOCK)
.reader("falling_dust", ParticleType.Readers.BLOCK)
.reader("block_crumble", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST1_21_2)
.reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION1_21_2)
.reader("vibration", ParticleType.Readers.VIBRATION1_20_3)
.reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE)
.reader("shriek", ParticleType.Readers.SHRIEK)
.reader("entity_effect", ParticleType.Readers.COLOR)
.reader("tinted_leaves", ParticleType.Readers.COLOR)
.reader("trail", ParticleType.Readers.TRAIL1_21_4)
.reader("dragon_breath", ParticleType.Readers.POWER)
.reader("effect", ParticleType.Readers.SPELL)
.reader("instant_effect", ParticleType.Readers.SPELL)
.reader("flash", ParticleType.Readers.COLOR)
.reader("item", ParticleType.Readers.item(itemRewriter.mappedItemType()));
mappedTypes().structuredData.filler(this).add(StructuredDataKey.CUSTOM_DATA, StructuredDataKey.MAX_STACK_SIZE, StructuredDataKey.MAX_DAMAGE,
StructuredDataKey.UNBREAKABLE1_21_5, StructuredDataKey.RARITY, StructuredDataKey.TOOLTIP_DISPLAY, StructuredDataKey.DAMAGE_RESISTANT,
StructuredDataKey.CUSTOM_NAME, StructuredDataKey.LORE, StructuredDataKey.ENCHANTMENTS1_21_5,
StructuredDataKey.CUSTOM_MODEL_DATA1_21_4, StructuredDataKey.BLOCKS_ATTACKS, StructuredDataKey.PROVIDES_BANNER_PATTERNS,
StructuredDataKey.REPAIR_COST, StructuredDataKey.CREATIVE_SLOT_LOCK, StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE,
StructuredDataKey.INTANGIBLE_PROJECTILE, StructuredDataKey.STORED_ENCHANTMENTS1_21_5, StructuredDataKey.DYED_COLOR1_21_5,
StructuredDataKey.MAP_COLOR, StructuredDataKey.MAP_ID, StructuredDataKey.MAP_DECORATIONS, StructuredDataKey.MAP_POST_PROCESSING,
StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, StructuredDataKey.WRITABLE_BOOK_CONTENT,
StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_5, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA1_21_9,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA1_21_9, StructuredDataKey.INSTRUMENT1_21_5,
StructuredDataKey.RECIPES, StructuredDataKey.LODESTONE_TRACKER, StructuredDataKey.FIREWORK_EXPLOSION, StructuredDataKey.FIREWORKS,
StructuredDataKey.PROFILE1_21_9, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR,
StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES1_21_9, StructuredDataKey.LOCK,
StructuredDataKey.CONTAINER_LOOT, StructuredDataKey.TOOL1_21_5, StructuredDataKey.ITEM_NAME, StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER,
StructuredDataKey.FOOD1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE1_21_5, StructuredDataKey.ATTRIBUTE_MODIFIERS1_21_6,
StructuredDataKey.REPAIRABLE, StructuredDataKey.ENCHANTABLE, StructuredDataKey.CONSUMABLE1_21_2,
StructuredDataKey.USE_COOLDOWN, StructuredDataKey.DAMAGE, StructuredDataKey.EQUIPPABLE1_21_6, StructuredDataKey.ITEM_MODEL,
StructuredDataKey.GLIDER, StructuredDataKey.TOOLTIP_STYLE, StructuredDataKey.DEATH_PROTECTION, StructuredDataKey.WEAPON,
StructuredDataKey.POTION_DURATION_SCALE, StructuredDataKey.VILLAGER_VARIANT, StructuredDataKey.WOLF_VARIANT, StructuredDataKey.WOLF_COLLAR,
StructuredDataKey.FOX_VARIANT, StructuredDataKey.SALMON_SIZE, StructuredDataKey.PARROT_VARIANT, StructuredDataKey.TROPICAL_FISH_PATTERN,
StructuredDataKey.TROPICAL_FISH_BASE_COLOR, StructuredDataKey.TROPICAL_FISH_PATTERN_COLOR, StructuredDataKey.MOOSHROOM_VARIANT,
StructuredDataKey.RABBIT_VARIANT, StructuredDataKey.PIG_VARIANT, StructuredDataKey.FROG_VARIANT, StructuredDataKey.HORSE_VARIANT,
StructuredDataKey.PAINTING_VARIANT, StructuredDataKey.LLAMA_VARIANT, StructuredDataKey.AXOLOTL_VARIANT, StructuredDataKey.CAT_VARIANT,
StructuredDataKey.CAT_COLLAR, StructuredDataKey.SHEEP_COLOR, StructuredDataKey.SHULKER_COLOR, StructuredDataKey.PROVIDES_TRIM_MATERIAL,
StructuredDataKey.BREAK_SOUND, StructuredDataKey.COW_VARIANT, StructuredDataKey.CHICKEN_VARIANT, StructuredDataKey.WOLF_SOUND_VARIANT);
super.onMappingDataLoaded();
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_9.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection));
}
@Override
public MappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter1_21_9 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter1_21_9 getItemRewriter() {
return itemRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket1_21_6> getParticleRewriter() {
return particleRewriter;
}
@Override
public TagRewriter<ClientboundPacket1_21_6> getTagRewriter() {
return tagRewriter;
}
@Override
public NBTComponentRewriter<ClientboundPacket1_21_6> getComponentRewriter() {
return componentRewriter;
}
@Override
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> types() {
return VersionedTypes.V1_21_6;
}
@Override
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_9> mappedTypes() {
return VersionedTypes.V1_21_9;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21_6, ClientboundPacket1_21_9, ServerboundPacket1_21_6, ServerboundPacket1_21_9> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_6.class, ClientboundConfigurationPackets1_21_6.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_9.class, ClientboundConfigurationPackets1_21_9.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_6.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_9.class)
);
}
}
@@ -0,0 +1,59 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet;
import com.viaversion.viaversion.api.protocol.packet.State;
public enum ClientboundConfigurationPackets1_21_9 implements ClientboundPacket1_21_9 {
COOKIE_REQUEST, // 0x00
CUSTOM_PAYLOAD, // 0x01
DISCONNECT, // 0x02
FINISH_CONFIGURATION, // 0x03
KEEP_ALIVE, // 0x04
PING, // 0x05
RESET_CHAT, // 0x06
REGISTRY_DATA, // 0x07
RESOURCE_PACK_POP, // 0x08
RESOURCE_PACK_PUSH, // 0x09
STORE_COOKIE, // 0x0A
TRANSFER, // 0x0B
UPDATE_ENABLED_FEATURES, // 0x0C
UPDATE_TAGS, // 0x0D
SELECT_KNOWN_PACKS, // 0x0E
CUSTOM_REPORT_DETAILS, // 0x0F
SERVER_LINKS, // 0x10
CLEAR_DIALOG, // 0x11
SHOW_DIALOG, // 0x12
CODE_OF_CONDUCT; // 0x13
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
@Override
public State state() {
return State.CONFIGURATION;
}
}
@@ -0,0 +1,23 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
public interface ClientboundPacket1_21_9 extends ClientboundPacketType {
}
@@ -0,0 +1,171 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet;
public enum ClientboundPackets1_21_9 implements ClientboundPacket1_21_9 {
BUNDLE_DELIMITER, // 0x00
ADD_ENTITY, // 0x01
ANIMATE, // 0x02
AWARD_STATS, // 0x03
BLOCK_CHANGED_ACK, // 0x04
BLOCK_DESTRUCTION, // 0x05
BLOCK_ENTITY_DATA, // 0x06
BLOCK_EVENT, // 0x07
BLOCK_UPDATE, // 0x08
BOSS_EVENT, // 0x09
CHANGE_DIFFICULTY, // 0x0A
CHUNK_BATCH_FINISHED, // 0x0B
CHUNK_BATCH_START, // 0x0C
CHUNKS_BIOMES, // 0x0D
CLEAR_TITLES, // 0x0E
COMMAND_SUGGESTIONS, // 0x0F
COMMANDS, // 0x10
CONTAINER_CLOSE, // 0x11
CONTAINER_SET_CONTENT, // 0x12
CONTAINER_SET_DATA, // 0x13
CONTAINER_SET_SLOT, // 0x14
COOKIE_REQUEST, // 0x15
COOLDOWN, // 0x16
CUSTOM_CHAT_COMPLETIONS, // 0x17
CUSTOM_PAYLOAD, // 0x18
DAMAGE_EVENT, // 0x19
DEBUG_BLOCK_VALUE, // 0x1A
DEBUG_CHUNK_VALUE, // 0x1B
DEBUG_ENTITY_VALUE, // 0x1C
DEBUG_EVENT, // 0x1D
DEBUG_SAMPLE, // 0x1E
DELETE_CHAT, // 0x1F
DISCONNECT, // 0x20
DISGUISED_CHAT, // 0x21
ENTITY_EVENT, // 0x22
ENTITY_POSITION_SYNC, // 0x23
EXPLODE, // 0x24
FORGET_LEVEL_CHUNK, // 0x25
GAME_EVENT, // 0x26
GAME_EVENT_TEST_HIGHLIGHT_POS, // 0x27
HORSE_SCREEN_OPEN, // 0x28
HURT_ANIMATION, // 0x29
INITIALIZE_BORDER, // 0x2A
KEEP_ALIVE, // 0x2B
LEVEL_CHUNK_WITH_LIGHT, // 0x2C
LEVEL_EVENT, // 0x2D
LEVEL_PARTICLES, // 0x2E
LIGHT_UPDATE, // 0x2F
LOGIN, // 0x30
MAP_ITEM_DATA, // 0x31
MERCHANT_OFFERS, // 0x32
MOVE_ENTITY_POS, // 0x33
MOVE_ENTITY_POS_ROT, // 0x34
MOVE_MINECART_ALONG_TRACK, // 0x35
MOVE_ENTITY_ROT, // 0x36
MOVE_VEHICLE, // 0x37
OPEN_BOOK, // 0x38
OPEN_SCREEN, // 0x39
OPEN_SIGN_EDITOR, // 0x3A
PING, // 0x3B
PONG_RESPONSE, // 0x3C
PLACE_GHOST_RECIPE, // 0x3D
PLAYER_ABILITIES, // 0x3E
PLAYER_CHAT, // 0x3F
PLAYER_COMBAT_END, // 0x40
PLAYER_COMBAT_ENTER, // 0x41
PLAYER_COMBAT_KILL, // 0x42
PLAYER_INFO_REMOVE, // 0x43
PLAYER_INFO_UPDATE, // 0x44
PLAYER_LOOK_AT, // 0x45
PLAYER_POSITION, // 0x46
PLAYER_ROTATION, // 0x47
RECIPE_BOOK_ADD, // 0x48
RECIPE_BOOK_REMOVE, // 0x49
RECIPE_BOOK_SETTINGS, // 0x4A
REMOVE_ENTITIES, // 0x4B
REMOVE_MOB_EFFECT, // 0x4C
RESET_SCORE, // 0x4D
RESOURCE_PACK_POP, // 0x4E
RESOURCE_PACK_PUSH, // 0x4F
RESPAWN, // 0x50
ROTATE_HEAD, // 0x51
SECTION_BLOCKS_UPDATE, // 0x52
SELECT_ADVANCEMENTS_TAB, // 0x53
SERVER_DATA, // 0x54
SET_ACTION_BAR_TEXT, // 0x55
SET_BORDER_CENTER, // 0x56
SET_BORDER_LERP_SIZE, // 0x57
SET_BORDER_SIZE, // 0x58
SET_BORDER_WARNING_DELAY, // 0x59
SET_BORDER_WARNING_DISTANCE, // 0x5A
SET_CAMERA, // 0x5B
SET_CHUNK_CACHE_CENTER, // 0x5C
SET_CHUNK_CACHE_RADIUS, // 0x5D
SET_CURSOR_ITEM, // 0x5E
SET_DEFAULT_SPAWN_POSITION, // 0x5F
SET_DISPLAY_OBJECTIVE, // 0x60
SET_ENTITY_DATA, // 0x61
SET_ENTITY_LINK, // 0x62
SET_ENTITY_MOTION, // 0x63
SET_EQUIPMENT, // 0x64
SET_EXPERIENCE, // 0x65
SET_HEALTH, // 0x66
SET_HELD_SLOT, // 0x67
SET_OBJECTIVE, // 0x68
SET_PASSENGERS, // 0x69
SET_PLAYER_INVENTORY, // 0x6A
SET_PLAYER_TEAM, // 0x6B
SET_SCORE, // 0x6C
SET_SIMULATION_DISTANCE, // 0x6D
SET_SUBTITLE_TEXT, // 0x6E
SET_TIME, // 0x6F
SET_TITLE_TEXT, // 0x70
SET_TITLES_ANIMATION, // 0x71
SOUND_ENTITY, // 0x72
SOUND, // 0x73
START_CONFIGURATION, // 0x74
STOP_SOUND, // 0x75
STORE_COOKIE, // 0x76
SYSTEM_CHAT, // 0x77
TAB_LIST, // 0x78
TAG_QUERY, // 0x79
TAKE_ITEM_ENTITY, // 0x7A
TELEPORT_ENTITY, // 0x7B
TEST_INSTANCE_BLOCK_STATUS, // 0x7C
TICKING_STATE, // 0x7D
TICKING_STEP, // 0x7E
TRANSFER, // 0x7F
UPDATE_ADVANCEMENTS, // 0x80
UPDATE_ATTRIBUTES, // 0x81
UPDATE_MOB_EFFECT, // 0x82
UPDATE_RECIPES, // 0x83
UPDATE_TAGS, // 0x84
PROJECTILE_POWER, // 0x85
CUSTOM_REPORT_DETAILS, // 0x86
SERVER_LINKS, // 0x87
TRACKED_WAYPOINT, // 0x88
CLEAR_DIALOG, // 0x89
SHOW_DIALOG; // 0x8A
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
@@ -0,0 +1,49 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet;
import com.viaversion.viaversion.api.protocol.packet.State;
public enum ServerboundConfigurationPackets1_21_9 implements ServerboundPacket1_21_9 {
CLIENT_INFORMATION, // 0x00
COOKIE_RESPONSE, // 0x01
CUSTOM_PAYLOAD, // 0x02
FINISH_CONFIGURATION, // 0x03
KEEP_ALIVE, // 0x04
PONG, // 0x05
RESOURCE_PACK, // 0x06
SELECT_KNOWN_PACKS, // 0x07
CUSTOM_CLICK_ACTION, // 0x08
ACCEPT_CODE_OF_CONDUCT; // 0x09
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
@Override
public State state() {
return State.CONFIGURATION;
}
}
@@ -0,0 +1,23 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
public interface ServerboundPacket1_21_9 extends ServerboundPacketType {
}
@@ -0,0 +1,119 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ResolvableProfile;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_9;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.Bee;
import com.viaversion.viaversion.api.minecraft.item.data.BlockEntityData;
import com.viaversion.viaversion.api.minecraft.item.data.EntityData;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.RecipeDisplayRewriter1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.Protocol1_21_7To1_21_9;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.packet.ServerboundPacket1_21_9;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
public final class BlockItemPacketRewriter1_21_9 extends StructuredItemRewriter<ClientboundPacket1_21_6, ServerboundPacket1_21_9, Protocol1_21_7To1_21_9> {
public BlockItemPacketRewriter1_21_9(final Protocol1_21_7To1_21_9 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPacket1_21_6> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21_6.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21_6.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_6.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_6.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_6.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_21_5::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21_6.BLOCK_ENTITY_DATA);
registerSetCursorItem(ClientboundPackets1_21_6.SET_CURSOR_ITEM);
registerSetPlayerInventory(ClientboundPackets1_21_6.SET_PLAYER_INVENTORY);
registerCooldown1_21_2(ClientboundPackets1_21_6.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21_6.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21_6.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21_6.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21_6.SET_EQUIPMENT);
registerMerchantOffers1_20_5(ClientboundPackets1_21_6.MERCHANT_OFFERS);
registerContainerClick1_21_5(ServerboundPackets1_21_6.CONTAINER_CLICK);
registerSetCreativeModeSlot1_21_5(ServerboundPackets1_21_6.SET_CREATIVE_MODE_SLOT);
final RecipeDisplayRewriter<ClientboundPacket1_21_6> recipeRewriter = new RecipeDisplayRewriter1_21_5<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_6.UPDATE_RECIPES);
recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_6.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_6.PLACE_GHOST_RECIPE);
}
@Override
protected void handleItemDataComponentsToClient(final UserConnection connection, final Item item, final StructuredDataContainer container) {
upgradeData(item, container);
super.handleItemDataComponentsToClient(connection, item, container);
}
public static void upgradeData(final Item item, final StructuredDataContainer container) {
container.replace(StructuredDataKey.BEES1_20_5, StructuredDataKey.BEES1_21_9, bees -> {
for (int i = 0; i < bees.length; i++) {
final Bee bee = bees[i];
bees[i] = new Bee(new EntityData(EntityTypes1_21_9.BEE.getId(), bee.entityData().tag()), bee.ticksInHive(), bee.minTicksInHive());
}
return bees;
});
// The actual type shouldn't matter for the display of items
container.replace(StructuredDataKey.ENTITY_DATA1_20_5, StructuredDataKey.ENTITY_DATA1_21_9, tag -> {
final int id = Protocol1_21_7To1_21_9.MAPPINGS.getEntityMappings().mappedId(tag.getString("id", "pig"));
return new EntityData(id == -1 ? 0 : id, tag);
});
container.replace(StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, StructuredDataKey.BLOCK_ENTITY_DATA1_21_9, tag -> {
final int id = Protocol1_21_7To1_21_9.MAPPINGS.getBlockEntityMappings().mappedId(tag.getString("id", "furnace"));
return new BlockEntityData(id == -1 ? 0 : id, tag);
});
container.replace(StructuredDataKey.PROFILE1_20_5, StructuredDataKey.PROFILE1_21_9, ResolvableProfile::new);
}
@Override
protected void handleItemDataComponentsToServer(final UserConnection connection, final Item item, final StructuredDataContainer container) {
downgradeData(item, container);
super.handleItemDataComponentsToServer(connection, item, container);
}
public static void downgradeData(final Item item, final StructuredDataContainer container) {
container.replaceKey(StructuredDataKey.BEES1_21_9, StructuredDataKey.BEES1_20_5);
container.replace(StructuredDataKey.ENTITY_DATA1_21_9, StructuredDataKey.ENTITY_DATA1_20_5, entityData -> {
final String id = Protocol1_21_7To1_21_9.MAPPINGS.getEntityMappings().mappedIdentifier(entityData.type());
entityData.tag().putString("id", id);
return entityData.tag();
});
container.replace(StructuredDataKey.BLOCK_ENTITY_DATA1_21_9, StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, blockEntityData -> {
final String id = Protocol1_21_7To1_21_9.MAPPINGS.getBlockEntityMappings().mappedIdentifier(blockEntityData.type());
blockEntityData.tag().putString("id", id);
return blockEntityData.tag();
});
container.replace(StructuredDataKey.PROFILE1_21_9, StructuredDataKey.PROFILE1_20_5, ResolvableProfile::profile);
}
}
@@ -0,0 +1,43 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.Protocol1_21_7To1_21_9;
import com.viaversion.viaversion.rewriter.text.NBTComponentRewriter;
import com.viaversion.viaversion.util.TagUtil;
public final class ComponentRewriter1_21_9 extends NBTComponentRewriter<ClientboundPacket1_21_6> {
public ComponentRewriter1_21_9(final Protocol1_21_7To1_21_9 protocol) {
super(protocol);
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) {
super.handleShowItem(connection, itemTag, componentsTag);
if (componentsTag == null) {
return;
}
removeDataComponents(componentsTag, StructuredDataKey.ENTITY_DATA1_20_5, StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, StructuredDataKey.BEES1_20_5);
}
}
@@ -0,0 +1,183 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.GlobalBlockPosition;
import com.viaversion.viaversion.api.minecraft.Vector3d;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_9;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_9;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_7to1_21_9.Protocol1_21_7To1_21_9;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandler;
import com.viaversion.viaversion.util.Key;
public final class EntityPacketRewriter1_21_9 extends EntityRewriter<ClientboundPacket1_21_6, Protocol1_21_7To1_21_9> {
public EntityPacketRewriter1_21_9(final Protocol1_21_7To1_21_9 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
registerSetEntityData(ClientboundPackets1_21_6.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_6.REMOVE_ENTITIES);
registerPlayerAbilities(ClientboundPackets1_21_6.PLAYER_ABILITIES);
registerGameEvent(ClientboundPackets1_21_6.GAME_EVENT);
registerLogin1_20_5(ClientboundPackets1_21_6.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_6.RESPAWN);
protocol.registerClientbound(ClientboundPackets1_21_6.ADD_ENTITY, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.UUID); // Entity UUID
final int entityTypeId = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
wrapper.write(Types.MOVEMENT_VECTOR, Vector3d.ZERO); // Set at the end
wrapper.passthrough(Types.BYTE); // Pitch
wrapper.passthrough(Types.BYTE); // Yaw
wrapper.passthrough(Types.BYTE); // Head yaw
final int data = wrapper.passthrough(Types.VAR_INT);
final EntityType entityType = trackAndRewrite(wrapper, entityTypeId, entityId);
if (protocol.getMappingData() != null && entityType == EntityTypes1_21_9.FALLING_BLOCK) {
final int mappedBlockStateId = protocol.getMappingData().getNewBlockStateId(data);
wrapper.set(Types.VAR_INT, 2, mappedBlockStateId);
}
wrapper.set(Types.MOVEMENT_VECTOR, 0, readRelativeMovement(wrapper));
});
protocol.registerClientbound(ClientboundPackets1_21_6.SET_ENTITY_MOTION, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
wrapper.write(Types.MOVEMENT_VECTOR, readRelativeMovement(wrapper));
});
protocol.registerClientbound(ClientboundPackets1_21_6.PLAYER_ROTATION, wrapper -> {
wrapper.passthrough(Types.FLOAT); // Y rotation
wrapper.write(Types.BOOLEAN, false); // Relative Y rotation
wrapper.passthrough(Types.FLOAT); // X rotation
wrapper.write(Types.BOOLEAN, false); // Relative X rotation
});
protocol.registerClientbound(ClientboundPackets1_21_6.SET_DEFAULT_SPAWN_POSITION, wrapper -> {
final BlockPosition pos = wrapper.read(Types.BLOCK_POSITION1_14);
final String dimension = tracker(wrapper.user()).currentWorld();
wrapper.write(Types.GLOBAL_POSITION, new GlobalBlockPosition(dimension, pos.x(), pos.y(), pos.z()));
wrapper.passthrough(Types.FLOAT); // Yaw
wrapper.write(Types.FLOAT, 0F); // Pitch
});
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
registryDataRewriter.addHandler("dimension_type", (key, dimension) -> {
if (Key.equals(key, "minecraft:the_end")) {
dimension.putFloat("ambient_light", 0.25F); // End now has actual skylight
}
});
protocol.registerClientbound(ClientboundConfigurationPackets1_21_6.REGISTRY_DATA, registryDataRewriter::handle);
}
private Vector3d readRelativeMovement(final PacketWrapper wrapper) {
final double movementX = wrapper.read(Types.SHORT) / 8000D;
final double movementY = wrapper.read(Types.SHORT) / 8000D;
final double movementZ = wrapper.read(Types.SHORT) / 8000D;
return new Vector3d(movementX, movementY, movementZ);
}
@Override
protected void registerRewrites() {
final EntityDataTypes1_21_5 unmappedEntityDataTypes = protocol.types().entityDataTypes();
final EntityDataTypes1_21_9 entityDataTypes = protocol.mappedTypes().entityDataTypes();
filter().handler((event, data) -> {
int id = data.dataType().typeId();
if (id == unmappedEntityDataTypes.compoundTagType.typeId()) {
if (event.entityType() == null) {
// Remove unhandled data from bad packets here
event.cancel();
}
return; // Handled below
}
if (id > unmappedEntityDataTypes.compoundTagType.typeId()) {
id--;
}
if (id > entityDataTypes.armadilloState.typeId()) {
id += 2; // copper golem and weathering copper state
}
data.setDataType(entityDataTypes.byId(id));
});
registerEntityDataTypeHandler(
entityDataTypes.itemType,
entityDataTypes.blockStateType,
entityDataTypes.optionalBlockStateType,
entityDataTypes.particleType,
entityDataTypes.particlesType,
entityDataTypes.componentType,
entityDataTypes.optionalComponentType
);
final EntityDataHandler shoulderDataHandler = (event, data) -> {
final CompoundTag value = data.value();
if (value == null) {
data.setTypeAndValue(protocol.mappedTypes().entityDataTypes.optionalVarIntType, null);
return;
}
final int variant = value.getInt("Variant", -1);
if (variant != -1) {
data.setTypeAndValue(protocol.mappedTypes().entityDataTypes.optionalVarIntType, variant);
} else {
data.setTypeAndValue(protocol.mappedTypes().entityDataTypes.optionalVarIntType, null);
}
};
filter().type(EntityTypes1_21_9.PLAYER).index(19).handler(shoulderDataHandler);
filter().type(EntityTypes1_21_9.PLAYER).index(20).handler(shoulderDataHandler);
filter().type(EntityTypes1_21_9.PLAYER).handler((event, data) -> {
// Move model customization and main hand to avatar
// except they've been swapped
if (event.index() == 17) {
event.setIndex(16);
} else if (event.index() == 18) {
event.setIndex(15);
} else if (event.index() == 15 || event.index() == 16) {
event.setIndex(event.index() + 2); // Move hearts and score up
}
});
}
@Override
public void onMappingDataLoaded() {
mapTypes();
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_9.getTypeFromId(type);
}
}
@@ -0,0 +1,47 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_7to1_21_9.rewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
public final class ParticleRewriter1_21_9 extends ParticleRewriter<ClientboundPacket1_21_6> {
public ParticleRewriter1_21_9(final Protocol<ClientboundPacket1_21_6, ?, ?, ?> protocol) {
super(protocol);
}
@Override
public void rewriteParticle(final UserConnection connection, final Particle particle) {
super.rewriteParticle(connection, particle);
final String identifier = protocol.getMappingData().getParticleMappings().mappedIdentifier(particle.id());
if ("minecraft:dragon_breath".equals(identifier)) {
particle.add(Types.FLOAT, 1F); // Power
} else if ("minecraft:flash".equals(identifier)) {
particle.add(Types.INT, -1); // Color
} else if ("minecraft:effect".equals(identifier) || "minecraft:instant_effect".equals(identifier)) {
particle.add(Types.INT, -1); // Color
particle.add(Types.FLOAT, 1F); // Power
}
}
}
@@ -53,6 +53,7 @@ import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTrac
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ChunkLoadTracker;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.EntityTracker1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.GroundFlagTracker;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.LastExplosionPowerStorage;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.TeleportAckCancelStorage;
import com.viaversion.viaversion.rewriter.AttributeRewriter;
@@ -258,11 +259,11 @@ public final class Protocol1_21To1_21_2 extends AbstractProtocol<ClientboundPack
StructuredDataKey.INTANGIBLE_PROJECTILE, StructuredDataKey.STORED_ENCHANTMENTS1_20_5, StructuredDataKey.DYED_COLOR1_20_5,
StructuredDataKey.MAP_COLOR, StructuredDataKey.MAP_ID, StructuredDataKey.MAP_DECORATIONS, StructuredDataKey.MAP_POST_PROCESSING,
StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, StructuredDataKey.WRITABLE_BOOK_CONTENT,
StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_2, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA, StructuredDataKey.INSTRUMENT1_21_2,
StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_2, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA1_20_5,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA1_20_5, StructuredDataKey.INSTRUMENT1_21_2,
StructuredDataKey.RECIPES, StructuredDataKey.LODESTONE_TRACKER, StructuredDataKey.FIREWORK_EXPLOSION, StructuredDataKey.FIREWORKS,
StructuredDataKey.PROFILE, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR,
StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES, StructuredDataKey.LOCK,
StructuredDataKey.PROFILE1_20_5, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR,
StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES1_20_5, StructuredDataKey.LOCK,
StructuredDataKey.CONTAINER_LOOT, StructuredDataKey.TOOL1_20_5, StructuredDataKey.ITEM_NAME, StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER,
StructuredDataKey.FOOD1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE1_21, StructuredDataKey.ATTRIBUTE_MODIFIERS1_21,
StructuredDataKey.REPAIRABLE, StructuredDataKey.ENCHANTABLE, StructuredDataKey.CONSUMABLE1_21_2,
@@ -277,6 +278,9 @@ public final class Protocol1_21To1_21_2 extends AbstractProtocol<ClientboundPack
connection.put(new BundleStateTracker());
connection.put(new GroundFlagTracker());
connection.put(new TeleportAckCancelStorage());
if (connection.getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_21_9)) {
connection.put(new LastExplosionPowerStorage());
}
final ProtocolVersion protocolVersion = connection.getProtocolInfo().protocolVersion();
if (protocolVersion.olderThan(ProtocolVersion.v1_21_4)) { // Only needed for 1.21.2/1.21.3
@@ -58,6 +58,7 @@ import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPacke
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPackets1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ChunkLoadTracker;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.LastExplosionPowerStorage;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
import com.viaversion.viaversion.util.ComponentUtil;
@@ -207,6 +208,12 @@ public final class BlockItemPacketRewriter1_21_2 extends StructuredItemRewriter<
affectedBlocks.add(new BlockPosition(x, y, z));
}
final LastExplosionPowerStorage lastExplosionPowerStorage = wrapper.user().get(LastExplosionPowerStorage.class);
if (lastExplosionPowerStorage != null) {
lastExplosionPowerStorage.setPower(power);
lastExplosionPowerStorage.setAffectedBlocks(affectedBlocks.size());
}
final float knockbackX = wrapper.read(Types.FLOAT);
final float knockbackY = wrapper.read(Types.FLOAT);
final float knockbackZ = wrapper.read(Types.FLOAT);
@@ -585,12 +592,17 @@ public final class BlockItemPacketRewriter1_21_2 extends StructuredItemRewriter<
dataContainer.replace(StructuredDataKey.LOCK, StructuredDataKey.LOCK, lock -> {
final CompoundTag predicateTag = (CompoundTag) lock;
final CompoundTag itemComponentsTag = predicateTag.getCompoundTag("components");
if (itemComponentsTag != null) {
// Back from json in the string tag to plain text
final StringTag customName = TagUtil.getNamespacedStringTag(itemComponentsTag, "custom_name");
return new StringTag(SerializerVersion.V1_20_5.toComponent(customName.getValue()).asUnformattedString());
if (itemComponentsTag == null) {
return null;
}
return null;
// Back from json in the string tag to plain text
final StringTag customName = TagUtil.getNamespacedStringTag(itemComponentsTag, "custom_name");
if (customName == null) {
return null;
}
return new StringTag(SerializerVersion.V1_20_5.toComponent(customName.getValue()).asUnformattedString());
});
dataContainer.replace(StructuredDataKey.INSTRUMENT1_21_2, StructuredDataKey.INSTRUMENT1_20_5, instrument -> {
if (instrument.hasId()) {
@@ -0,0 +1,42 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public final class LastExplosionPowerStorage implements StorableObject {
private float power;
private int affectedBlocks;
public float power() {
return power;
}
public void setPower(final float power) {
this.power = power;
}
public int affectedBlocks() {
return affectedBlocks;
}
public void setAffectedBlocks(final int affectedBlocks) {
this.affectedBlocks = affectedBlocks;
}
}
@@ -31,19 +31,21 @@ import java.util.logging.Level;
public class MovementTransmitterProvider implements Provider {
public void sendPlayer(UserConnection userConnection) {
if (userConnection.getProtocolInfo().getClientState() != State.PLAY || !userConnection.getEntityTracker(Protocol1_8To1_9.class).hasClientEntityId()) {
return;
}
userConnection.getChannel().eventLoop().execute(() -> {
if (userConnection.getProtocolInfo().getClientState() != State.PLAY || !userConnection.getEntityTracker(Protocol1_8To1_9.class).hasClientEntityId()) {
return;
}
final MovementTracker movementTracker = userConnection.get(MovementTracker.class);
movementTracker.incrementIdlePacket();
final MovementTracker movementTracker = userConnection.get(MovementTracker.class);
movementTracker.incrementIdlePacket();
try {
final PacketWrapper playerMovement = PacketWrapper.create(ServerboundPackets1_8.MOVE_PLAYER_STATUS_ONLY, userConnection);
playerMovement.write(Types.BOOLEAN, movementTracker.isGround()); // on ground
playerMovement.scheduleSendToServer(Protocol1_8To1_9.class);
} catch (Throwable e) {
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to send player movement packet", e);
}
try {
final PacketWrapper playerMovement = PacketWrapper.create(ServerboundPackets1_8.MOVE_PLAYER_STATUS_ONLY, userConnection);
playerMovement.write(Types.BOOLEAN, movementTracker.isGround()); // on ground
playerMovement.sendToServer(Protocol1_8To1_9.class);
} catch (Throwable e) {
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to send player movement packet", e);
}
});
}
}
@@ -19,27 +19,27 @@ package com.viaversion.viaversion.protocols.v1_8to1_9.task;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocol.ProtocolRunnable;
import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9;
import com.viaversion.viaversion.protocols.v1_8to1_9.provider.MovementTransmitterProvider;
import com.viaversion.viaversion.protocols.v1_8to1_9.storage.MovementTracker;
public final class IdlePacketTask extends ProtocolRunnable {
public IdlePacketTask() {
super(Protocol1_8To1_9.class);
}
public final class IdlePacketTask implements Runnable {
@Override
public void run(final UserConnection connection) {
final MovementTracker movementTracker = connection.get(MovementTracker.class);
if (movementTracker == null) {
return;
}
public void run() {
for (final UserConnection connection : Via.getManager().getConnectionManager().getConnections()) {
if (!connection.isActive()) {
continue;
}
final long nextIdleUpdate = movementTracker.getNextIdlePacket();
if (nextIdleUpdate <= System.currentTimeMillis()) {
Via.getManager().getProviders().get(MovementTransmitterProvider.class).sendPlayer(connection);
final MovementTracker tracker = connection.get(MovementTracker.class);
if (tracker == null) {
continue;
}
final long nextIdleUpdate = tracker.getNextIdlePacket();
if (nextIdleUpdate <= System.currentTimeMillis()) {
Via.getManager().getProviders().get(MovementTransmitterProvider.class).sendPlayer(connection);
}
}
}
}
@@ -32,6 +32,7 @@ import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.minecraft.GameMode;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.Vector3d;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
@@ -313,6 +314,27 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
});
}
public void registerTrackerWithData1_21_9(C packetType, EntityType fallingBlockType) {
protocol.registerClientbound(packetType, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.UUID); // Entity UUID
final int entityTypeId = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
wrapper.passthrough(Types.MOVEMENT_VECTOR); // Movement
wrapper.passthrough(Types.BYTE); // Pitch
wrapper.passthrough(Types.BYTE); // Yaw
wrapper.passthrough(Types.BYTE); // Head yaw
final int data = wrapper.passthrough(Types.VAR_INT);
final EntityType entityType = trackAndRewrite(wrapper, entityTypeId, entityId);
if (protocol.getMappingData() != null && entityType == fallingBlockType) {
final int mappedBlockStateId = protocol.getMappingData().getNewBlockStateId(data);
wrapper.set(Types.VAR_INT, 2, mappedBlockStateId);
}
});
}
/**
* Registers an entity tracker for the extra spawn packets like player, painting, or xp orb spawns.
*
Loaded 100 of 140 files, more files were not shown because too many files have changed in this diff. Show more