Compare commits

...
68 Commits
Author SHA1 Message Date
Nassim Jahnke f880adced2 5.1.0 Release 2024-10-25 09:24:29 +02:00
Nassim Jahnke fc07601f24 Fix glow squid index shift 2024-10-24 16:55:24 +02:00
Nassim Jahnke ecb241c187 Exclude error prone annotations
Recently added to gson, can be safely excluded
2024-10-24 12:50:36 +02:00
Nassim Jahnke 46040b1f5d Mark fallback return value in getProtocol as unknown 2024-10-23 17:04:54 +02:00
FlorianMichael 54daa11ce4 Fix ProtocolVersion#isKnown javadoc to make difference with isRegistered more clear 2024-10-23 17:02:45 +02:00
RaphiMC c556420870 Add option to construct ChunkSectionLightImpl without block light 2024-10-23 16:42:21 +02:00
FlorianMichael 84d928ebe7 Update version ranges in gradle.properties 2024-10-23 16:25:52 +02:00
FlorianMichael fa6eab5cc3 1.21.3 2024-10-23 15:42:16 +02:00
FlorianMichael 94b26a903c Check for suppress conversion warnings option in ComponentUtil functions 2024-10-22 22:31:17 +02:00
Nassim Jahnke c242456c30 Remove snapshot version 2024-10-22 17:02:14 +02:00
Nassim Jahnke 8391e9d924 Fix consumable writing 2024-10-22 13:23:06 +02:00
RK_01 f5aac9b1ab Convert all data from food component (#13) 2024-10-22 13:21:44 +02:00
RK_01 a6850392e1 Add failsafe handling to ACCEPT_TELEPORTATION packet order fix (#12) 2024-10-22 13:03:43 +02:00
RK_01 2b37178482 Fix ACCEPT_TELEPORTATION packet order (#11) 2024-10-22 11:13:45 +02:00
Nassim Jahnke 82199d9f39 1.21.2-rc2 2024-10-21 18:36:50 +02:00
FlorianMichael c2d2c6d067 Explain SerializerVersion terminology 2024-10-19 14:50:09 +02:00
FlorianMichael 4066a7b5b6 Mark serializer versions in ComponentRewriter as nullable 2024-10-19 14:43:43 +02:00
Nassim Jahnke 4a7624fef4 Update profile actions enum type 2024-10-19 13:18:14 +02:00
EnZaXD e38b3f3824 Add new PROFILE_ACTIONS_ENUM type in Types for 1.21.2+ 2024-10-19 11:45:51 +02:00
Nassim Jahnke 4573035aab 1.21.2-rc1 2024-10-17 15:28:15 +02:00
Nassim Jahnke 393a5ee973 1.21.2-pre5 2024-10-16 16:06:39 +02:00
Nassim Jahnke 080dc18165 1.21.2-pre4 2024-10-15 15:08:36 +02:00
Nassim Jahnke 6fd421d36e Fix finish configuration state change 2024-10-15 15:08:36 +02:00
Nassim Jahnke 84bd1d0782 Use recipe inputs from old recipe packet 2024-10-15 15:08:36 +02:00
Nassim Jahnke cff2303c62 1.21.2-pre3 2024-10-15 15:08:36 +02:00
Nassim Jahnke f5733c2cb8 They fixed the typo 2024-10-15 15:08:36 +02:00
Nassim Jahnke 21fec0e263 1.21.2-pre2 2024-10-15 15:08:36 +02:00
RK_01 093acc519e Fix CONTAINER_SET_SLOT translation (#9) 2024-10-15 15:08:35 +02:00
RK_01 886be3161e Fix EXPLODE knockback check and affected blocks (#8) 2024-10-15 15:08:35 +02:00
RK_01 dc7b708556 Fix PLAYER_POSITION delta movement (#7) 2024-10-15 15:08:35 +02:00
Nassim Jahnke e82f28c1ac Rewrite particles 2024-10-15 15:08:35 +02:00
Nassim Jahnke 7c7239a70d 1.21.2-pre1 2024-10-15 15:08:35 +02:00
Nassim Jahnke 3e3dad9e33 Show notification on recipe add 2024-10-15 15:08:35 +02:00
Nassim Jahnke 4871977681 Fix recipe removal array index 2024-10-15 15:08:34 +02:00
Nassim Jahnke 0a56e57aec Send stonecutter recipes 2024-10-15 15:08:34 +02:00
Nassim Jahnke a6ff477b8a Implement clientbound ghost recipe, fix null recipe groups 2024-10-15 15:08:34 +02:00
Nassim Jahnke ddad0384f3 Make recipes mostly work again 2024-10-15 15:08:34 +02:00
Nassim Jahnke aabe47f8bc Start working on recipe rewriting 2024-10-15 15:08:34 +02:00
Nassim Jahnke 354a5f1b75 Update packet id comments 2024-10-15 15:08:34 +02:00
Nassim Jahnke f58afd434d WIP 24w40a 2024-10-15 15:08:34 +02:00
Nassim Jahnke 57d5652cd5 Remove SetWrapper, moved to addon 2024-10-15 15:08:33 +02:00
Nassim Jahnke 25b521dfcf Rewrite lock nbt 2024-10-15 15:08:33 +02:00
Nassim Jahnke ce655d0679 Use absolute day time value 2024-10-15 15:08:33 +02:00
Nassim Jahnke e4e8297a82 24w39a 2024-10-15 15:08:33 +02:00
Nassim Jahnke 8357fd01aa Update attributes in item hover events 2024-10-15 15:08:33 +02:00
Nassim Jahnke 12b420d3e7 Send instrument registry, handle duration change from ticks to seconds 2024-10-15 15:08:33 +02:00
Nassim Jahnke db20bc0ae4 24w38a 2024-10-15 15:08:33 +02:00
Nassim Jahnke 2a2afa3821 Register component rewriter 2024-10-15 15:08:32 +02:00
Nassim Jahnke f0b2d9aafe 24w37a 2024-10-15 15:08:32 +02:00
Nassim Jahnke cd427a2a39 Don't use -1 to indicate no vehicle 2024-10-15 15:08:32 +02:00
Nassim Jahnke 75537d3f85 Cancel player input if not in a vehicle, fix shift/sprint input 2024-10-15 15:08:32 +02:00
Nassim Jahnke a88e2f3fb5 Set impulse to 0.98 instead of 1 as per vanilla value 2024-10-15 15:08:32 +02:00
Nassim Jahnke 8a41e7add6 Remove new item data from serverbound items 2024-10-15 15:08:32 +02:00
Nassim Jahnke 9c35228287 24w36a 2024-10-15 15:08:32 +02:00
Nassim Jahnke f9ec6b9d03 Split holder implementation 2024-10-15 15:08:31 +02:00
Nassim Jahnke 22d396d909 Add item hover event handling 2024-10-15 15:08:31 +02:00
Nassim Jahnke 39b28e21ca 24w35a, including missed change from 33a 2024-10-15 15:08:31 +02:00
Nassim Jahnke 0488cb7fbe Fix item type in 1.21.2 entity data 2024-10-15 15:08:31 +02:00
Nassim Jahnke ec4aa0637e 24w34a 2024-10-15 15:08:31 +02:00
Nassim Jahnke ffc5584b1c Null check component rewriter 2024-10-15 15:08:31 +02:00
Nassim Jahnke 45c6cfedb0 Update mappings 2024-10-15 15:08:30 +02:00
Nassim Jahnke c150e50636 Store attribute mappings in full 2024-10-15 15:08:30 +02:00
Nassim Jahnke 16e32a62e5 Bump version to 5.1.0-SNAPSHOT 2024-10-15 15:08:27 +02:00
Nassim Jahnke 1d18f2e45e Fix container id conversion and itemrewriter explosion method 2024-10-15 15:08:20 +02:00
Nassim Jahnke e46b38e58a Remove outdated todos 2024-10-15 15:08:20 +02:00
Nassim Jahnke 033741d292 WIP 24w33a 2024-10-15 15:08:20 +02:00
Nassim Jahnke 7a3ef1e0b7 5.0.5 Release 2024-10-15 10:44:03 +02:00
Nassim Jahnke 5be41ed3e9 Use stripped key in tag getting
Fixes #4182
2024-10-14 21:35:10 +02:00
94 changed files with 3880 additions and 373 deletions

No files matched your search

+3 -1
View File
@@ -19,7 +19,9 @@ dependencies {
api(libs.vianbt) {
exclude("it.unimi.dsi", "fastutil")
}
api(libs.gson)
api(libs.gson) {
exclude("com.google.errorprone", "error_prone_annotations")
}
implementation(rootProject.libs.text) {
exclude("com.google.code.gson", "gson")
exclude("com.viaversion", "nbt")
@@ -53,6 +53,14 @@ public interface FullMappings extends BiMappings {
*/
@Nullable String identifier(int id);
/**
* Returns the unmapped string identifier for the given mapped identifier.
*
* @param mappedIdentifier mapped identifier
* @return unmapped string identifier, or null if not found
*/
@Nullable String identifier(String mappedIdentifier);
/**
* Returns the mapped string identifier for the given mapped id.
*
@@ -83,6 +83,17 @@ public class FullMappingsBase implements FullMappings {
return Key.namespaced(identifier);
}
@Override
public @Nullable String identifier(final String mappedIdentifier) {
final int mappedId = mappedId(mappedIdentifier);
if (mappedId == -1) {
return null;
}
final int id = mappings.inverse().getNewId(mappedId);
return id != -1 ? identifier(id) : null;
}
@Override
public String mappedIdentifier(final int mappedId) {
if (mappedId < 0 || mappedId >= mappedIdToString.length) {
@@ -126,10 +126,10 @@ public interface MappingData {
@Nullable Mappings getEnchantmentMappings();
@Nullable Mappings getAttributeMappings();
@Nullable Mappings getPaintingMappings();
@Nullable FullMappings getAttributeMappings();
@Nullable FullMappings getEntityMappings();
@Nullable FullMappings getArgumentTypeMappings();
@@ -43,10 +43,10 @@ public class MappingDataBase implements MappingData {
protected FullMappings entityMappings;
protected FullMappings recipeSerializerMappings;
protected FullMappings itemDataSerializerMappings;
protected FullMappings attributeMappings;
protected ParticleMappings particleMappings;
protected BiMappings itemMappings;
protected BiMappings blockMappings;
protected BiMappings attributeMappings;
protected Mappings blockStateMappings;
protected Mappings blockEntityMappings;
protected Mappings soundMappings;
@@ -76,8 +76,6 @@ public class MappingDataBase implements MappingData {
menuMappings = loadMappings(data, "menus");
enchantmentMappings = loadMappings(data, "enchantments");
paintingMappings = loadMappings(data, "paintings");
attributeMappings = loadBiMappings(data, "attributes");
final CompoundTag unmappedIdentifierData = readUnmappedIdentifiersFile("identifiers-" + unmappedVersion + ".nbt");
final CompoundTag mappedIdentifierData = readMappedIdentifiersFile("identifiers-" + mappedVersion + ".nbt");
@@ -87,6 +85,7 @@ public class MappingDataBase implements MappingData {
argumentTypeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "argumenttypes");
recipeSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "recipe_serializers");
itemDataSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "data_component_type");
attributeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "attributes");
final List<String> unmappedParticles = identifiersFromGlobalIds(unmappedIdentifierData, "particles");
final List<String> mappedParticles = identifiersFromGlobalIds(mappedIdentifierData, "particles");
@@ -272,7 +271,7 @@ public class MappingDataBase implements MappingData {
}
@Override
public @Nullable Mappings getAttributeMappings() {
public @Nullable FullMappings getAttributeMappings() {
return attributeMappings;
}
@@ -78,7 +78,7 @@ public interface DebugHandler {
/**
* Returns whether packets should be logged after being transformed.
* Set to true by default.
* Set to false by default.
*
* @return whether packets should be logged after being transformed
*/
@@ -35,7 +35,7 @@ public interface Holder<T> {
* @throws IllegalArgumentException if the id is negative
*/
static <T> Holder<T> of(final int id) {
return new HolderImpl<>(id);
return new IdHolder<>(id);
}
/**
@@ -46,7 +46,7 @@ public interface Holder<T> {
* @return a new direct holder
*/
static <T> Holder<T> of(final T value) {
return new HolderImpl<>(value);
return new ValueHolder<>(value);
}
/**
@@ -36,7 +36,7 @@ public interface HolderSet {
* @return a new holder set
*/
static HolderSet of(final String tagKey) {
return new HolderSetImpl(tagKey);
return new HolderSetImpl.Tag(tagKey);
}
/**
@@ -46,7 +46,7 @@ public interface HolderSet {
* @return a new holder set
*/
static HolderSet of(final int[] ids) {
return new HolderSetImpl(ids);
return new HolderSetImpl.Ids(ids);
}
/**
@@ -22,50 +22,63 @@
*/
package com.viaversion.viaversion.api.minecraft;
import com.viaversion.viaversion.util.EitherImpl;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.Arrays;
final class HolderSetImpl extends EitherImpl<String, int[]> implements HolderSet {
final class HolderSetImpl {
HolderSetImpl(final String tagKey) {
super(tagKey, null);
}
record Tag(String tagKey) implements HolderSet {
@Override
public boolean hasTagKey() {
return true;
}
HolderSetImpl(final int[] ids) {
super(null, ids);
}
@Override
public int[] ids() {
throw new IllegalArgumentException("This holder set has a tag key");
}
@Override
public String tagKey() {
return left();
}
@Override
public boolean hasIds() {
return false;
}
@Override
public boolean hasTagKey() {
return isLeft();
}
@Override
public int[] ids() {
return right();
}
@Override
public boolean hasIds() {
return isRight();
}
@Override
public HolderSet rewrite(final Int2IntFunction idRewriter) {
if (hasTagKey()) {
@Override
public HolderSet rewrite(final Int2IntFunction idRewriter) {
return this;
}
}
final int[] ids = ids();
final int[] mappedIds = new int[ids.length];
for (int i = 0; i < mappedIds.length; i++) {
mappedIds[i] = idRewriter.applyAsInt(ids[i]);
record Ids(int[] ids) implements HolderSet {
@Override
public boolean hasTagKey() {
return false;
}
@Override
public String tagKey() {
throw new IllegalArgumentException("This holder set has direct ids");
}
@Override
public boolean hasIds() {
return true;
}
@Override
public HolderSet rewrite(final Int2IntFunction idRewriter) {
final int[] mappedIds = new int[ids.length];
for (int i = 0; i < mappedIds.length; i++) {
mappedIds[i] = idRewriter.applyAsInt(ids[i]);
}
return new Ids(mappedIds);
}
@Override
public String toString() {
return "Ids{" +
"ids=" + Arrays.toString(ids) +
'}';
}
return new HolderSetImpl(mappedIds);
}
}
@@ -25,49 +25,29 @@ package com.viaversion.viaversion.api.minecraft;
import com.google.common.base.Preconditions;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
final class HolderImpl<T> implements Holder<T> {
record IdHolder<T>(int id) implements Holder<T> {
private final T value;
private final int id;
HolderImpl(final int id) {
IdHolder {
Preconditions.checkArgument(id >= 0, "id cannot be negative");
this.value = null;
this.id = id;
}
HolderImpl(final T value) {
this.value = value;
this.id = -1;
}
@Override
public boolean isDirect() {
return id == -1;
return false;
}
@Override
public boolean hasId() {
return id != -1;
return true;
}
@Override
public T value() {
Preconditions.checkArgument(isDirect(), "Holder is not direct");
return value;
}
@Override
public int id() {
return id;
throw new IllegalArgumentException("Holder is not direct");
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
if (isDirect()) {
return this;
}
final int rewrittenId = rewriteFunction.applyAsInt(id);
if (rewrittenId == id) {
return this;
@@ -77,12 +57,4 @@ final class HolderImpl<T> implements Holder<T> {
}
return Holder.of(rewrittenId);
}
@Override
public String toString() {
return "HolderImpl{" +
"value=" + value +
", id=" + id +
'}';
}
}
@@ -36,4 +36,8 @@ public record RegistryEntry(String key, @Nullable Tag tag) {
public RegistryEntry withKey(final String key) {
return new RegistryEntry(key, tag != null ? tag.copy() : null);
}
public RegistryEntry copy() {
return new RegistryEntry(key, tag != null ? tag.copy() : null);
}
}
@@ -0,0 +1,48 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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 it.unimi.dsi.fastutil.ints.Int2IntFunction;
record ValueHolder<T>(T value) implements Holder<T> {
@Override
public boolean isDirect() {
return true;
}
@Override
public boolean hasId() {
return false;
}
@Override
public int id() {
return -1;
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
return this;
}
}
@@ -37,14 +37,14 @@ public class ChunkSectionImpl implements ChunkSection {
public ChunkSectionImpl(final boolean holdsLight) {
addPalette(PaletteType.BLOCKS, new DataPaletteImpl(ChunkSection.SIZE));
if (holdsLight) {
this.light = new ChunkSectionLightImpl();
this.light = ChunkSectionLightImpl.createWithBlockLight();
}
}
public ChunkSectionImpl(final boolean holdsLight, final int expectedPaletteLength) {
addPalette(PaletteType.BLOCKS, new DataPaletteImpl(ChunkSection.SIZE, expectedPaletteLength));
if (holdsLight) {
this.light = new ChunkSectionLightImpl();
this.light = ChunkSectionLightImpl.createWithBlockLight();
}
}
@@ -35,7 +35,7 @@ public interface ChunkSectionLight {
/**
* Returns whether the section has sky light.
*
* @return true if skylight is present
* @return true if sky light is present
*/
boolean hasSkyLight();
@@ -43,7 +43,7 @@ public interface ChunkSectionLight {
* Returns whether the section has block light.
* This returns true unless specifically set to null.
*
* @return true if skylight is present
* @return true if block light is present
*/
boolean hasBlockLight();
@@ -30,9 +30,17 @@ public class ChunkSectionLightImpl implements ChunkSectionLight {
private NibbleArray blockLight;
private NibbleArray skyLight;
public ChunkSectionLightImpl() {
// Block light is always written
this.blockLight = new NibbleArray(ChunkSection.SIZE);
protected ChunkSectionLightImpl() {
}
public static ChunkSectionLight createWithBlockLight() {
final ChunkSectionLightImpl light = new ChunkSectionLightImpl();
light.blockLight = new NibbleArray(ChunkSection.SIZE);
return light;
}
public static ChunkSectionLight createEmpty() {
return new ChunkSectionLightImpl();
}
@Override
@@ -26,6 +26,7 @@ import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
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.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate;
import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrim;
@@ -34,13 +35,19 @@ 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.BlockStateProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant;
import com.viaversion.viaversion.api.minecraft.item.data.DeathProtection;
import com.viaversion.viaversion.api.minecraft.item.data.DyedColor;
import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.minecraft.item.data.Equippable;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableString;
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
import com.viaversion.viaversion.api.minecraft.item.data.Fireworks;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument;
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.JukeboxPlayable;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
@@ -48,11 +55,13 @@ import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
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.Unbreakable;
import com.viaversion.viaversion.api.minecraft.item.data.UseCooldown;
import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.api.type.types.version.Types1_21_2;
import com.viaversion.viaversion.util.Unit;
public record StructuredDataKey<T>(String identifier, Type<T> type) {
@@ -64,6 +73,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Unbreakable> UNBREAKABLE = new StructuredDataKey<>("unbreakable", Unbreakable.TYPE);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TAG);
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Types.TAG);
public static final StructuredDataKey<String> ITEM_MODEL = new StructuredDataKey<>("item_model", Types.STRING);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", Types.TAG_ARRAY);
public static final StructuredDataKey<Integer> RARITY = new StructuredDataKey<>("rarity", Types.VAR_INT);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS = new StructuredDataKey<>("enchantments", Enchantments.TYPE);
@@ -78,10 +88,21 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Unit> CREATIVE_SLOT_LOCK = new StructuredDataKey<>("creative_slot_lock", Types.EMPTY);
public static final StructuredDataKey<Boolean> ENCHANTMENT_GLINT_OVERRIDE = new StructuredDataKey<>("enchantment_glint_override", Types.BOOLEAN);
public static final StructuredDataKey<Tag> INTANGIBLE_PROJECTILE = new StructuredDataKey<>("intangible_projectile", Types.TAG); // Doesn't actually hold data
public static final StructuredDataKey<FoodProperties> FOOD1_20_5 = new StructuredDataKey<>("food", FoodProperties.TYPE1_20_5);
public static final StructuredDataKey<FoodProperties> FOOD1_21 = new StructuredDataKey<>("food", FoodProperties.TYPE1_21);
public static final StructuredDataKey<FoodProperties1_20_5> FOOD1_20_5 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_20_5);
public static final StructuredDataKey<FoodProperties1_20_5> FOOD1_21 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_21);
public static final StructuredDataKey<FoodProperties1_21_2> FOOD1_21_2 = new StructuredDataKey<>("food", FoodProperties1_21_2.TYPE);
public static final StructuredDataKey<Consumable1_21_2> CONSUMABLE1_21_2 = new StructuredDataKey<>("consumable", Consumable1_21_2.TYPE);
public static final StructuredDataKey<Item> USE_REMAINDER = new StructuredDataKey<>("use_remainder", Types1_21_2.ITEM);
public static final StructuredDataKey<UseCooldown> USE_COOLDOWN = new StructuredDataKey<>("use_cooldown", UseCooldown.TYPE);
public static final StructuredDataKey<Unit> FIRE_RESISTANT = new StructuredDataKey<>("fire_resistant", Types.EMPTY);
public static final StructuredDataKey<DamageResistant> DAMAGE_RESISTANT = new StructuredDataKey<>("damage_resistant", DamageResistant.TYPE);
public static final StructuredDataKey<ToolProperties> TOOL = new StructuredDataKey<>("tool", ToolProperties.TYPE);
public static final StructuredDataKey<Integer> ENCHANTABLE = new StructuredDataKey<>("enchantable", Types.VAR_INT);
public static final StructuredDataKey<Equippable> EQUIPPABLE = new StructuredDataKey<>("equippable", Equippable.TYPE);
public static final StructuredDataKey<HolderSet> REPAIRABLE = new StructuredDataKey<>("repairable", Types.HOLDER_SET);
public static final StructuredDataKey<Unit> GLIDER = new StructuredDataKey<>("glider", Types.EMPTY);
public static final StructuredDataKey<String> TOOLTIP_STYLE = new StructuredDataKey<>("tooltip_style", Types.STRING);
public static final StructuredDataKey<DeathProtection> DEATH_PROTECTION = new StructuredDataKey<>("death_protection", DeathProtection.TYPE);
public static final StructuredDataKey<Enchantments> STORED_ENCHANTMENTS = new StructuredDataKey<>("stored_enchantments", Enchantments.TYPE);
public static final StructuredDataKey<DyedColor> DYED_COLOR = new StructuredDataKey<>("dyed_color", DyedColor.TYPE);
public static final StructuredDataKey<Integer> MAP_COLOR = new StructuredDataKey<>("map_color", Types.INT);
@@ -90,9 +111,12 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Integer> MAP_POST_PROCESSING = new StructuredDataKey<>("map_post_processing", Types.VAR_INT);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_20_5 = new StructuredDataKey<>("charged_projectiles", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_21 = new StructuredDataKey<>("charged_projectiles", Types1_21.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CHARGED_PROJECTILES1_21_2 = new StructuredDataKey<>("charged_projectiles", Types1_21_2.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_20_5 = new StructuredDataKey<>("bundle_contents", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_21 = new StructuredDataKey<>("bundle_contents", Types1_21.ITEM_ARRAY);
public static final StructuredDataKey<PotionContents> POTION_CONTENTS = new StructuredDataKey<>("potion_contents", PotionContents.TYPE);
public static final StructuredDataKey<Item[]> BUNDLE_CONTENTS1_21_2 = new StructuredDataKey<>("bundle_contents", Types1_21_2.ITEM_ARRAY);
public static final StructuredDataKey<PotionContents> POTION_CONTENTS1_20_5 = new StructuredDataKey<>("potion_contents", PotionContents.TYPE1_20_5);
public static final StructuredDataKey<PotionContents> POTION_CONTENTS1_21_2 = new StructuredDataKey<>("potion_contents", PotionContents.TYPE1_21_2);
public static final StructuredDataKey<SuspiciousStewEffect[]> SUSPICIOUS_STEW_EFFECTS = new StructuredDataKey<>("suspicious_stew_effects", SuspiciousStewEffect.ARRAY_TYPE);
public static final StructuredDataKey<FilterableString[]> WRITABLE_BOOK_CONTENT = new StructuredDataKey<>("writable_book_content", FilterableString.ARRAY_TYPE);
public static final StructuredDataKey<WrittenBook> WRITTEN_BOOK_CONTENT = new StructuredDataKey<>("written_book_content", WrittenBook.TYPE);
@@ -101,7 +125,8 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<CompoundTag> ENTITY_DATA = new StructuredDataKey<>("entity_data", Types.COMPOUND_TAG);
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<Holder<Instrument>> INSTRUMENT = new StructuredDataKey<>("instrument", Instrument.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<Integer> OMINOUS_BOTTLE_AMPLIFIER = new StructuredDataKey<>("ominous_bottle_amplifier", Types.VAR_INT);
public static final StructuredDataKey<JukeboxPlayable> JUKEBOX_PLAYABLE = new StructuredDataKey<>("jukebox_playable", JukeboxPlayable.TYPE);
public static final StructuredDataKey<Tag> RECIPES = new StructuredDataKey<>("recipes", Types.TAG);
@@ -115,6 +140,7 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<PotDecorations> POT_DECORATIONS = new StructuredDataKey<>("pot_decorations", PotDecorations.TYPE);
public static final StructuredDataKey<Item[]> CONTAINER1_20_5 = new StructuredDataKey<>("container", Types1_20_5.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CONTAINER1_21 = new StructuredDataKey<>("container", Types1_21.ITEM_ARRAY);
public static final StructuredDataKey<Item[]> CONTAINER1_21_2 = new StructuredDataKey<>("container", Types1_21_2.ITEM_ARRAY);
public static final StructuredDataKey<BlockStateProperties> BLOCK_STATE = new StructuredDataKey<>("block_state", BlockStateProperties.TYPE);
public static final StructuredDataKey<Bee[]> BEES = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE);
public static final StructuredDataKey<Tag> LOCK = new StructuredDataKey<>("lock", Types.TAG);
@@ -0,0 +1,314 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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_2 implements EntityType {
ENTITY(null, null),
AREA_EFFECT_CLOUD(ENTITY),
END_CRYSTAL(ENTITY),
EVOKER_FANGS(ENTITY),
EXPERIENCE_ORB(ENTITY),
EYE_OF_ENDER(ENTITY),
FALLING_BLOCK(ENTITY),
ITEM(ENTITY),
TNT(ENTITY),
OMINOUS_ITEM_SPAWNER(ENTITY),
MARKER(ENTITY),
LIGHTNING_BOLT(ENTITY),
INTERACTION(ENTITY),
DISPLAY(ENTITY, null),
BLOCK_DISPLAY(DISPLAY),
ITEM_DISPLAY(DISPLAY),
TEXT_DISPLAY(DISPLAY),
// Hanging entities
HANGING_ENTITY(ENTITY, null),
LEASH_KNOT(HANGING_ENTITY),
PAINTING(HANGING_ENTITY),
ITEM_FRAME(HANGING_ENTITY),
GLOW_ITEM_FRAME(ITEM_FRAME),
// Projectiles
PROJECTILE(ENTITY, null),
ITEM_PROJECTILE(PROJECTILE, null),
SNOWBALL(ITEM_PROJECTILE),
ENDER_PEARL(ITEM_PROJECTILE),
EGG(ITEM_PROJECTILE),
POTION(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_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),
PLAYER(LIVING_ENTITY),
// 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),
// 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),
COW(ABSTRACT_ANIMAL),
MOOSHROOM(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),
CREAKING_TRANSIENT(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_2(final EntityType parent) {
this.parent = parent;
this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT));
}
EntityTypes1_21_2(final EntityType parent, @Nullable final String identifier) {
this.parent = parent;
this.identifier = identifier;
}
@Override
public int getId() {
if (id == -1) {
throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")");
}
return id;
}
@Override
public String identifier() {
Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type");
return identifier;
}
@Override
public @Nullable EntityType getParent() {
return parent;
}
@Override
public boolean isAbstractType() {
return identifier == null;
}
public static EntityType getTypeFromId(final int typeId) {
return EntityTypeUtil.getTypeFromId(TYPES, typeId, ENTITY);
}
public static void initialize(final Protocol<?, ?, ?, ?> protocol) {
EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id);
}
}
@@ -26,10 +26,11 @@ import com.viaversion.viaversion.api.minecraft.PaintingVariant;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.WolfVariant;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
@@ -40,7 +41,7 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
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 = add(7, Types1_21.ITEM);
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);
@@ -65,8 +66,9 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes {
public final EntityDataType vector3FType = add(29, Types.VECTOR3F);
public final EntityDataType quaternionType = add(30, Types.QUATERNION);
public EntityDataTypes1_21(final ParticleType particleType, final ArrayType<Particle> particlesType) {
public EntityDataTypes1_21(final Type<Item> itemType, final ParticleType particleType, final ArrayType<Particle> particlesType) {
super(31);
this.itemType = add(7, itemType);
this.particleType = add(17, particleType);
this.particlesType = add(18, particlesType);
}
@@ -0,0 +1,111 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import io.netty.buffer.ByteBuf;
public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<SoundEvent> sound,
boolean hasConsumeParticles, ConsumeEffect<?>[] consumeEffects) {
public static final Type<?>[] EFFECT_TYPES = {
ApplyStatusEffects.TYPE,
Types.HOLDER_SET, // remove effects
Types.EMPTY, // clear all effects
Types.FLOAT, // teleport randomly
Types.SOUND_EVENT // play sound
};
public static final Type<Consumable1_21_2> TYPE = new Type<>(Consumable1_21_2.class) {
@Override
public Consumable1_21_2 read(final ByteBuf buffer) {
final float consumeSeconds = buffer.readFloat();
final int animationType = Types.VAR_INT.readPrimitive(buffer);
final Holder<SoundEvent> sound = Types.SOUND_EVENT.read(buffer);
final boolean hasConsumeParticles = buffer.readBoolean();
final ConsumeEffect<?>[] consumeEffects = ConsumeEffect.ARRAY_TYPE.read(buffer);
return new Consumable1_21_2(consumeSeconds, animationType, sound, hasConsumeParticles, consumeEffects);
}
@Override
public void write(final ByteBuf buffer, final Consumable1_21_2 value) {
buffer.writeFloat(value.consumeSeconds);
Types.VAR_INT.writePrimitive(buffer, value.animationType);
Types.SOUND_EVENT.write(buffer, value.sound);
buffer.writeBoolean(value.hasConsumeParticles);
ConsumeEffect.ARRAY_TYPE.write(buffer, value.consumeEffects);
}
};
public record ConsumeEffect<T>(int id, Type<T> type, T value) {
public static final Type<ConsumeEffect<?>> TYPE = new Type<>(ConsumeEffect.class) {
@Override
public ConsumeEffect<?> read(final ByteBuf buffer) {
// Oh no...
final int effectType = Types.VAR_INT.readPrimitive(buffer);
final Type<?> type = EFFECT_TYPES[effectType];
final Object value = type.read(buffer);
return ConsumeEffect.of(effectType, type, value);
}
@Override
public void write(final ByteBuf buffer, final ConsumeEffect<?> value) {
Types.VAR_INT.writePrimitive(buffer, value.id);
value.writeValue(buffer);
}
};
public static final Type<ConsumeEffect<?>[]> ARRAY_TYPE = new ArrayType<>(TYPE);
static <T> ConsumeEffect<T> of(final int id, final Type<T> type, final Object value) {
//noinspection unchecked
return new ConsumeEffect<>(id, type, (T) value);
}
void writeValue(final ByteBuf buf) {
this.type.write(buf, this.value);
}
}
public record ApplyStatusEffects(PotionEffect[] effects, float probability) {
public static final Type<ApplyStatusEffects> TYPE = new Type<>(ApplyStatusEffects.class) {
@Override
public ApplyStatusEffects read(final ByteBuf buffer) {
final PotionEffect[] effects = PotionEffect.ARRAY_TYPE.read(buffer);
final float probability = buffer.readFloat();
return new ApplyStatusEffects(effects, probability);
}
@Override
public void write(final ByteBuf buffer, final ApplyStatusEffects value) {
PotionEffect.ARRAY_TYPE.write(buffer, value.effects);
buffer.writeFloat(value.probability);
}
};
}
}
@@ -0,0 +1,43 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record DamageResistant(String typesTagKey) {
public static final Type<DamageResistant> TYPE = new Type<>(DamageResistant.class) {
@Override
public DamageResistant read(final ByteBuf buffer) {
final String typesTagKey = Types.STRING.read(buffer);
return new DamageResistant(typesTagKey);
}
@Override
public void write(final ByteBuf buffer, final DamageResistant value) {
Types.STRING.write(buffer, value.typesTagKey());
}
};
}
@@ -22,26 +22,23 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2.ConsumeEffect;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record FoodEffect(PotionEffect effect, float probability) {
public record DeathProtection(ConsumeEffect<?>[] deathEffects) {
public static final Type<FoodEffect> TYPE = new Type<>(FoodEffect.class) {
public static final Type<DeathProtection> TYPE = new Type<>(DeathProtection.class) {
@Override
public FoodEffect read(final ByteBuf buffer) {
final PotionEffect effect = PotionEffect.TYPE.read(buffer);
final float probability = buffer.readFloat();
return new FoodEffect(effect, probability);
public DeathProtection read(final ByteBuf buffer) {
final ConsumeEffect<?>[] deathEffects = ConsumeEffect.ARRAY_TYPE.read(buffer);
return new DeathProtection(deathEffects);
}
@Override
public void write(final ByteBuf buffer, final FoodEffect value) {
PotionEffect.TYPE.write(buffer, value.effect);
buffer.writeFloat(value.probability);
public void write(final ByteBuf buffer, final DeathProtection value) {
ConsumeEffect.ARRAY_TYPE.write(buffer, value.deathEffects);
}
};
public static final Type<FoodEffect[]> ARRAY_TYPE = new ArrayType<>(TYPE);
}
@@ -0,0 +1,69 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import org.checkerframework.checker.nullness.qual.Nullable;
public record Equippable(int equipmentSlot, Holder<SoundEvent> soundEvent, @Nullable String model,
@Nullable String cameraOverlay, @Nullable HolderSet allowedEntities, boolean dispensable,
boolean swappable, boolean damageOnHurt) {
public static final Type<Equippable> TYPE = new Type<>(Equippable.class) {
@Override
public Equippable read(final ByteBuf buffer) {
final int equipmentSlot = Types.VAR_INT.readPrimitive(buffer);
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final String model = Types.OPTIONAL_STRING.read(buffer);
final String cameraOverlay = Types.OPTIONAL_STRING.read(buffer);
final HolderSet allowedEntities = Types.HOLDER_SET.read(buffer);
final boolean dispensable = buffer.readBoolean();
final boolean swappable = buffer.readBoolean();
final boolean damageOnHurt = buffer.readBoolean();
return new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt);
}
@Override
public void write(final ByteBuf buffer, final Equippable value) {
Types.VAR_INT.writePrimitive(buffer, value.equipmentSlot());
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.OPTIONAL_STRING.write(buffer, value.model());
Types.OPTIONAL_STRING.write(buffer, value.cameraOverlay());
Types.HOLDER_SET.write(buffer, value.allowedEntities());
buffer.writeBoolean(value.dispensable());
buffer.writeBoolean(value.swappable());
buffer.writeBoolean(value.damageOnHurt());
}
};
public Equippable rewrite(final Int2IntFunction soundIdRewriter) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriter);
return soundEvent == this.soundEvent ? this : new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt);
}
}
@@ -25,25 +25,26 @@ package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import io.netty.buffer.ByteBuf;
public record FoodProperties(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds,
Item usingConvertsTo, FoodEffect[] possibleEffects) {
public record FoodProperties1_20_5(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds,
Item usingConvertsTo, FoodEffect[] possibleEffects) {
public static final Type<FoodProperties> TYPE1_20_5 = new Type<>(FoodProperties.class) {
public static final Type<FoodProperties1_20_5> TYPE1_20_5 = new Type<>(FoodProperties1_20_5.class) {
@Override
public FoodProperties read(final ByteBuf buffer) {
public FoodProperties1_20_5 read(final ByteBuf buffer) {
final int nutrition = Types.VAR_INT.readPrimitive(buffer);
final float saturationModifier = buffer.readFloat();
final boolean canAlwaysEat = buffer.readBoolean();
final float eatSeconds = buffer.readFloat();
final FoodEffect[] possibleEffects = FoodEffect.ARRAY_TYPE.read(buffer);
return new FoodProperties(nutrition, saturationModifier, canAlwaysEat, eatSeconds, null, possibleEffects);
return new FoodProperties1_20_5(nutrition, saturationModifier, canAlwaysEat, eatSeconds, null, possibleEffects);
}
@Override
public void write(final ByteBuf buffer, final FoodProperties value) {
public void write(final ByteBuf buffer, final FoodProperties1_20_5 value) {
Types.VAR_INT.writePrimitive(buffer, value.nutrition);
buffer.writeFloat(value.saturationModifier);
buffer.writeBoolean(value.canAlwaysEat);
@@ -51,20 +52,20 @@ public record FoodProperties(int nutrition, float saturationModifier, boolean ca
FoodEffect.ARRAY_TYPE.write(buffer, value.possibleEffects);
}
};
public static final Type<FoodProperties> TYPE1_21 = new Type<FoodProperties>(FoodProperties.class) {
public static final Type<FoodProperties1_20_5> TYPE1_21 = new Type<>(FoodProperties1_20_5.class) {
@Override
public FoodProperties read(final ByteBuf buffer) {
public FoodProperties1_20_5 read(final ByteBuf buffer) {
final int nutrition = Types.VAR_INT.readPrimitive(buffer);
final float saturationModifier = buffer.readFloat();
final boolean canAlwaysEat = buffer.readBoolean();
final float eatSeconds = buffer.readFloat();
final Item usingConvertsTo = Types1_21.OPTIONAL_ITEM.read(buffer);
final FoodEffect[] possibleEffects = FoodEffect.ARRAY_TYPE.read(buffer);
return new FoodProperties(nutrition, saturationModifier, canAlwaysEat, eatSeconds, usingConvertsTo, possibleEffects);
return new FoodProperties1_20_5(nutrition, saturationModifier, canAlwaysEat, eatSeconds, usingConvertsTo, possibleEffects);
}
@Override
public void write(final ByteBuf buffer, final FoodProperties value) {
public void write(final ByteBuf buffer, final FoodProperties1_20_5 value) {
Types.VAR_INT.writePrimitive(buffer, value.nutrition);
buffer.writeFloat(value.saturationModifier);
buffer.writeBoolean(value.canAlwaysEat);
@@ -73,4 +74,23 @@ public record FoodProperties(int nutrition, float saturationModifier, boolean ca
FoodEffect.ARRAY_TYPE.write(buffer, value.possibleEffects);
}
};
public record FoodEffect(PotionEffect effect, float probability) {
public static final Type<FoodEffect> TYPE = new Type<>(FoodEffect.class) {
@Override
public FoodEffect read(final ByteBuf buffer) {
final PotionEffect effect = PotionEffect.TYPE.read(buffer);
final float probability = buffer.readFloat();
return new FoodEffect(effect, probability);
}
@Override
public void write(final ByteBuf buffer, final FoodEffect value) {
PotionEffect.TYPE.write(buffer, value.effect);
buffer.writeFloat(value.probability);
}
};
public static final Type<FoodEffect[]> ARRAY_TYPE = new ArrayType<>(TYPE);
}
}
@@ -0,0 +1,47 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public record FoodProperties1_21_2(int nutrition, float saturationModifier, boolean canAlwaysEat) {
public static final Type<FoodProperties1_21_2> TYPE = new Type<>(FoodProperties1_21_2.class) {
@Override
public FoodProperties1_21_2 read(final ByteBuf buffer) {
final int nutrition = Types.VAR_INT.readPrimitive(buffer);
final float saturationModifier = buffer.readFloat();
final boolean canAlwaysEat = buffer.readBoolean();
return new FoodProperties1_21_2(nutrition, saturationModifier, canAlwaysEat);
}
@Override
public void write(final ByteBuf buffer, final FoodProperties1_21_2 value) {
Types.VAR_INT.writePrimitive(buffer, value.nutrition);
buffer.writeFloat(value.saturationModifier);
buffer.writeBoolean(value.canAlwaysEat);
}
};
}
@@ -29,27 +29,27 @@ import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record Instrument(Holder<SoundEvent> soundEvent, int useDuration, float range) {
public record Instrument1_20_5(Holder<SoundEvent> soundEvent, int useDuration, float range) {
public static final HolderType<Instrument> TYPE = new HolderType<>() {
public static final HolderType<Instrument1_20_5> TYPE = new HolderType<>() {
@Override
public Instrument readDirect(final ByteBuf buffer) {
public Instrument1_20_5 readDirect(final ByteBuf buffer) {
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final int useDuration = Types.VAR_INT.readPrimitive(buffer);
final float range = buffer.readFloat();
return new Instrument(soundEvent, useDuration, range);
final float range = Types.FLOAT.readPrimitive(buffer);
return new Instrument1_20_5(soundEvent, useDuration, range);
}
@Override
public void writeDirect(final ByteBuf buffer, final Instrument value) {
public void writeDirect(final ByteBuf buffer, final Instrument1_20_5 value) {
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.VAR_INT.writePrimitive(buffer, value.useDuration());
buffer.writeFloat(value.range());
Types.FLOAT.writePrimitive(buffer, value.range());
}
};
public Instrument rewrite(final Int2IntFunction soundIdRewriteFunction) {
public Instrument1_20_5 rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new Instrument(soundEvent, useDuration, range);
return soundEvent == this.soundEvent ? this : new Instrument1_20_5(soundEvent, useDuration, range);
}
}
@@ -0,0 +1,58 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import io.netty.buffer.ByteBuf;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
public record Instrument1_21_2(Holder<SoundEvent> soundEvent, float useDuration, float range, Tag description) {
public static final HolderType<Instrument1_21_2> TYPE = new HolderType<>() {
@Override
public Instrument1_21_2 readDirect(final ByteBuf buffer) {
final Holder<SoundEvent> soundEvent = Types.SOUND_EVENT.read(buffer);
final float useDuration = Types.FLOAT.readPrimitive(buffer);
final float range = Types.FLOAT.readPrimitive(buffer);
final Tag description = Types.TAG.read(buffer);
return new Instrument1_21_2(soundEvent, useDuration, range, description);
}
@Override
public void writeDirect(final ByteBuf buffer, final Instrument1_21_2 value) {
Types.SOUND_EVENT.write(buffer, value.soundEvent());
Types.FLOAT.writePrimitive(buffer, value.useDuration());
Types.FLOAT.writePrimitive(buffer, value.range());
Types.TAG.write(buffer, value.description());
}
};
public Instrument1_21_2 rewrite(final Int2IntFunction soundIdRewriteFunction) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(soundIdRewriteFunction);
return soundEvent == this.soundEvent ? this : new Instrument1_21_2(soundEvent, useDuration, range, description);
}
}
@@ -27,15 +27,20 @@ import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
public record PotionContents(@Nullable Integer potion, @Nullable Integer customColor, PotionEffect[] customEffects) {
public record PotionContents(@Nullable Integer potion, @Nullable Integer customColor, PotionEffect[] customEffects,
@Nullable String customName) {
public static final Type<PotionContents> TYPE = new Type<>(PotionContents.class) {
public PotionContents(final @Nullable Integer potion, final @Nullable Integer customColor, final PotionEffect[] customEffects) {
this(potion, customColor, customEffects, null);
}
public static final Type<PotionContents> TYPE1_20_5 = new Type<>(PotionContents.class) {
@Override
public PotionContents read(final ByteBuf buffer) {
final Integer potion = buffer.readBoolean() ? Types.VAR_INT.readPrimitive(buffer) : null;
final Integer customColor = buffer.readBoolean() ? buffer.readInt() : null;
final PotionEffect[] customEffects = PotionEffect.ARRAY_TYPE.read(buffer);
return new PotionContents(potion, customColor, customEffects);
return new PotionContents(potion, customColor, customEffects, null);
}
@Override
@@ -53,4 +58,31 @@ public record PotionContents(@Nullable Integer potion, @Nullable Integer customC
PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects);
}
};
public static final Type<PotionContents> TYPE1_21_2 = new Type<>(PotionContents.class) {
@Override
public PotionContents read(final ByteBuf buffer) {
final Integer potion = buffer.readBoolean() ? Types.VAR_INT.readPrimitive(buffer) : null;
final Integer customColor = buffer.readBoolean() ? buffer.readInt() : null;
final PotionEffect[] customEffects = PotionEffect.ARRAY_TYPE.read(buffer);
final String customName = Types.OPTIONAL_STRING.read(buffer);
return new PotionContents(potion, customColor, customEffects, customName);
}
@Override
public void write(final ByteBuf buffer, final PotionContents value) {
buffer.writeBoolean(value.potion != null);
if (value.potion != null) {
Types.VAR_INT.writePrimitive(buffer, value.potion);
}
buffer.writeBoolean(value.customColor != null);
if (value.customColor != null) {
buffer.writeInt(value.customColor);
}
PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects);
Types.OPTIONAL_STRING.write(buffer, value.customName);
}
};
}
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
public record UseCooldown(float seconds, @Nullable String cooldownGroup) {
public static final Type<UseCooldown> TYPE = new Type<>(UseCooldown.class) {
@Override
public UseCooldown read(final ByteBuf buffer) {
final float seconds = buffer.readFloat();
final String cooldownGroup = Types.OPTIONAL_STRING.read(buffer);
return new UseCooldown(seconds, cooldownGroup);
}
@Override
public void write(final ByteBuf buffer, final UseCooldown value) {
buffer.writeFloat(value.seconds());
Types.OPTIONAL_STRING.write(buffer, value.cooldownGroup());
}
};
public UseCooldown rewrite(final Function<String, String> idRewriter) {
if (cooldownGroup == null) {
return this;
}
final String mappedCooldownGroup = idRewriter.apply(cooldownGroup);
return new UseCooldown(seconds, mappedCooldownGroup);
}
}
@@ -198,6 +198,14 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
}
}
public void registerFinishConfiguration(final CU packetType, final PacketHandler handler) {
registerClientbound(packetType, wrapper -> {
// TODO Temporary solution to handle the finish configuration packet already having changed our tracked protocol state in a previous handler
wrapper.user().getProtocolInfo().setServerState(State.CONFIGURATION);
handler.handle(wrapper);
});
}
@Override
public final void loadMappingData() {
getMappingData().load();
@@ -43,7 +43,8 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
private static final List<ProtocolVersion> VERSION_LIST = new ArrayList<>();
public static final ProtocolVersion v1_7_2 = register(4, "1.7.2-1.7.5", new SubVersionRange("1.7", 2, 5));
@Deprecated(forRemoval=true) public static final ProtocolVersion v1_7_1 = v1_7_2;
@Deprecated(forRemoval = true)
public static final ProtocolVersion v1_7_1 = v1_7_2;
public static final ProtocolVersion v1_7_6 = register(5, "1.7.6-1.7.10", new SubVersionRange("1.7", 6, 10));
public static final ProtocolVersion v1_8 = register(47, "1.8.x", new SubVersionRange("1.8", 0, 9));
public static final ProtocolVersion v1_9 = register(107, "1.9");
@@ -85,8 +86,13 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_20_3 = register(765, "1.20.3-1.20.4", new SubVersionRange("1.20", 3, 4));
public static final ProtocolVersion v1_20_5 = register(766, "1.20.5-1.20.6", new SubVersionRange("1.20", 5, 6));
public static final ProtocolVersion v1_21 = register(767, "1.21-1.21.1", new SubVersionRange("1.21", 0, 1));
public static final ProtocolVersion v1_21_2 = register(768, "1.21.2-1.21.3", new SubVersionRange("1.21", 2, 3));
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
static {
unknown.known = false;
}
public static ProtocolVersion register(int version, String name) {
return register(version, -1, name);
}
@@ -150,7 +156,11 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
return protocolVersion;
}
}
return new ProtocolVersion(VersionType.SPECIAL, version, -1, "Unknown (" + version + ")", null);
// Will be made nullable instead in the future...
final ProtocolVersion unknown = new ProtocolVersion(versionType, version, -1, "Unknown (" + version + ")", null);
unknown.known = false;
return unknown;
}
public static @NonNull ProtocolVersion getProtocol(final int version) {
@@ -201,6 +211,8 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
private final int snapshotVersion;
private final String name;
private final Set<String> includedVersions;
@Deprecated // Remove when getProtocol is made nullable
private boolean known = true;
/**
* Constructs a new ProtocolVersion instance.
@@ -285,12 +297,12 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
}
/**
* Returns whether the protocol is set. Should only be unknown for unregistered protocols returned by {@link #getProtocol(int)}.
* Returns whether the protocol version is {@link #unknown}. For checking if the protocol version is registered, use {@link #isRegistered(VersionType, int)}
*
* @return true if the protocol is set
* @return true if the protocol version is unknown
*/
public boolean isKnown() {
return version != -1;
return known;
}
/**
@@ -23,6 +23,7 @@
package com.viaversion.viaversion.api.rewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
@@ -50,6 +51,8 @@ public interface ItemRewriter<T extends Protocol<?, ?, ?, ?>> extends Rewriter<T
@Nullable
Item handleItemToServer(UserConnection connection, @Nullable Item item);
void rewriteParticle(UserConnection connection, Particle particle);
/**
* Returns the item type of the current protocol.
*
@@ -189,7 +189,9 @@ public final class Types {
public static final Type<PlayerMessageSignature> OPTIONAL_PLAYER_MESSAGE_SIGNATURE = new PlayerMessageSignatureType.OptionalPlayerMessageSignatureType();
public static final Type<PlayerMessageSignature[]> PLAYER_MESSAGE_SIGNATURE_ARRAY = new ArrayType<>(PLAYER_MESSAGE_SIGNATURE);
public static final BitSetType PROFILE_ACTIONS_ENUM = new BitSetType(6);
public static final BitSetType PROFILE_ACTIONS_ENUM1_19_3 = new BitSetType(6);
public static final BitSetType PROFILE_ACTIONS_ENUM1_21_2 = new BitSetType(7);
public static final ByteArrayType SIGNATURE_BYTES = new ByteArrayType(256);
public static final BitSetType ACKNOWLEDGED_BIT_SET = new BitSetType(20);
public static final ByteArrayType.OptionalByteArrayType OPTIONAL_SIGNATURE_BYTES = new ByteArrayType.OptionalByteArrayType(256);
@@ -36,11 +36,19 @@ public class IntType extends Type<Integer> implements TypeConverter<Integer> {
return buffer.readInt();
}
public int readPrimitive(ByteBuf buffer) {
return buffer.readInt();
}
@Override
public void write(ByteBuf buffer, Integer object) {
buffer.writeInt(object);
}
public void writePrimitive(ByteBuf buffer, int object) {
buffer.writeInt(object);
}
@Override
public Integer from(Object o) {
if (o instanceof Number number) {
@@ -87,5 +87,12 @@ public class StructuredDataType extends Type<StructuredData<?>> {
types[id] = key;
return this;
}
public DataFiller add(final StructuredDataKey<?>... keys) {
for (final StructuredDataKey<?> key : keys) {
add(key);
}
return this;
}
}
}
@@ -77,6 +77,10 @@ public class ParticleType extends DynamicType<Particle> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Blue 0-1
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4
};
public static final DataReader<Particle> DUST1_21_2 = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // RGB
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4
};
public static final DataReader<Particle> DUST_TRANSITION = (buf, particle) -> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Red 0-1
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Green 0-1
@@ -86,6 +90,11 @@ public class ParticleType extends DynamicType<Particle> {
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Green
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Blue
};
public static final DataReader<Particle> DUST_TRANSITION1_21_2 = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // From RGB
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // To RGB
particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4
};
public static final DataReader<Particle> VIBRATION = (buf, particle) -> {
particle.add(Types.BLOCK_POSITION1_14, Types.BLOCK_POSITION1_14.read(buf)); // From block pos
@@ -136,7 +145,15 @@ public class ParticleType extends DynamicType<Particle> {
public static final DataReader<Particle> SHRIEK = (buf, particle) -> {
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Delay
};
public static final DataReader<Particle> COLOR = (buf, particle) -> particle.add(Types.INT, buf.readInt());
public static final DataReader<Particle> COLOR = (buf, particle) -> {
particle.add(Types.INT, Types.INT.readPrimitive(buf));
};
public static final DataReader<Particle> TRAIL = (buf, particle) -> {
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Target X
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Target Y
particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Target Z
particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color
};
public static DataReader<Particle> item(Type<Item> item) {
return (buf, particle) -> particle.add(item, item.read(buf));
@@ -50,7 +50,7 @@ public final class Types1_21 {
public static final ParticleType PARTICLE = new ParticleType();
public static final ArrayType<Particle> PARTICLES = new ArrayType<>(PARTICLE);
public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(PARTICLE, PARTICLES);
public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(ITEM, PARTICLE, PARTICLES);
public static final Type<EntityData> ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES);
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.data.StructuredData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataListType;
import com.viaversion.viaversion.api.type.types.entitydata.EntityDataType;
import com.viaversion.viaversion.api.type.types.item.ItemCostType1_20_5;
import com.viaversion.viaversion.api.type.types.item.ItemType1_20_5;
import com.viaversion.viaversion.api.type.types.item.StructuredDataType;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import java.util.List;
// Most of these are only safe to use after protocol loading
public final class Types1_21_2 {
public static final StructuredDataType STRUCTURED_DATA = new StructuredDataType();
public static final Type<StructuredData<?>[]> STRUCTURED_DATA_ARRAY = new ArrayType<>(STRUCTURED_DATA);
public static final ItemType1_20_5 ITEM = new ItemType1_20_5(STRUCTURED_DATA);
public static final Type<Item> OPTIONAL_ITEM = ITEM.new OptionalItemType(); // Optional as in boolean prefixed, not via the amount
public static final Type<Item[]> ITEM_ARRAY = new ArrayType<>(ITEM);
public static final Type<Item> ITEM_COST = new ItemCostType1_20_5(STRUCTURED_DATA_ARRAY);
public static final Type<Item> OPTIONAL_ITEM_COST = new ItemCostType1_20_5.OptionalItemCostType(ITEM_COST);
public static final ParticleType PARTICLE = new ParticleType();
public static final ArrayType<Particle> PARTICLES = new ArrayType<>(PARTICLE);
public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(ITEM, PARTICLE, PARTICLES);
public static final Type<EntityData> ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES);
public static final Type<List<EntityData>> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA);
}
@@ -76,6 +76,7 @@ import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.Protocol1_20_3To1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21;
import com.viaversion.viaversion.protocols.v1_20to1_20_2.Protocol1_20To1_20_2;
import com.viaversion.viaversion.protocols.v1_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;
import com.viaversion.viaversion.protocols.v1_9_3to1_10.Protocol1_9_3To1_10;
@@ -192,6 +193,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
registerProtocol(new Protocol1_20_3To1_20_5(), ProtocolVersion.v1_20_5, ProtocolVersion.v1_20_3);
registerProtocol(new Protocol1_20_5To1_21(), ProtocolVersion.v1_21, ProtocolVersion.v1_20_5);
registerProtocol(new Protocol1_21To1_21_2(), ProtocolVersion.v1_21_2, ProtocolVersion.v1_21);
}
@Override
@@ -23,11 +23,14 @@ import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket;
public enum ClientboundLoginPackets implements BaseClientboundPacket {
LOGIN_DISCONNECT, // 0x00
HELLO, // 0x01
GAME_PROFILE, // 0x02
LOGIN_FINISHED, // 0x02
LOGIN_COMPRESSION, // 0x03
CUSTOM_QUERY, // 0x04
COOKIE_REQUEST; // 0x05
@Deprecated(forRemoval = true)
public static final ClientboundLoginPackets GAME_PROFILE = LOGIN_FINISHED;
@Override
public final int getId() {
return ordinal();
@@ -128,7 +128,7 @@ public class ClientboundBaseProtocol1_7 extends AbstractProtocol<BaseClientbound
});
// Track player name/uuid and setup connection + track state
registerClientbound(ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
registerClientbound(ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> {
final ProtocolInfo info = wrapper.user().getProtocolInfo();
if (info.serverProtocolVersion().olderThan(ProtocolVersion.v1_16)) {
@@ -19,11 +19,11 @@ package com.viaversion.viaversion.protocols.template;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter.RecipeRewriter1_20_3;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
@@ -57,21 +57,24 @@ final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter<Clientbou
// Registers item id changes
// Other places using item ids are: Entity data, tags, statistics, effect
// registerOpenWindow(ClientboundPackets1_21.OPEN_WINDOW); - If a new container type was added
registerCooldown(ClientboundPackets1_21.COOLDOWN);
registerSetContent1_17_1(ClientboundPackets1_21.CONTAINER_SET_CONTENT);
registerSetSlot1_17_1(ClientboundPackets1_21.CONTAINER_SET_SLOT);
// registerOpenScreen(ClientboundPackets1_21.OPEN_SCREEN); If a new container type was added; also remove from the component rewriter registration
//protocol.registerClientbound(ClientboundPackets1_21_2.SET_CURSOR_ITEM, this::passthroughClientboundItem);
registerCooldown1_21_2(ClientboundPackets1_21.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21.SET_EQUIPMENT);
registerContainerClick1_17_1(ServerboundPackets1_20_5.CONTAINER_CLICK);
registerContainerClick1_21_2(ServerboundPackets1_20_5.CONTAINER_CLICK);
registerMerchantOffers1_20_5(ClientboundPackets1_21.MERCHANT_OFFERS);
registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT);
registerLevelParticles1_20_5(ClientboundPackets1_21.LEVEL_PARTICLES);
registerExplosion(ClientboundPackets1_21.EXPLODE); // Rewrites the included sound and particles
registerExplosion1_21_2(ClientboundPackets1_21.EXPLODE); // Rewrites the included sound and particles
new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_21.UPDATE_RECIPES);
final RecipeDisplayRewriter<ClientboundPacket1_21> recipeRewriter = new RecipeDisplayRewriter<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21.UPDATE_RECIPES);
//recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21.PLACE_GHOST_RECIPE);
// OR do this if serialization of recipes changed and override the relevant method
// Add new serializers to RecipeRewriter, or extend the last one for changes
// new RecipeRewriter1_20_3<ClientboundPacket1_21>(this) {}.register1_20_5(ClientboundPackets1_21.DECLARE_RECIPES);
// Add new serializers to RecipeDisplayRewriter, or extend the last one for changes
}
}
@@ -0,0 +1,46 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.template;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
public final class ComponentRewriter1_99 extends ComponentRewriter<ClientboundPacket1_21> {
public ComponentRewriter1_99(final Protocol1_99To_98 protocol) {
super(protocol, ReadType.NBT);
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) {
super.handleShowItem(connection, itemTag, componentsTag);
if (componentsTag == null) {
return;
}
// Remove or update data from componentsTag
}
@Override
protected SerializerVersion inputSerializerVersion() {
return SerializerVersion.V1_20_5;
}
}
@@ -24,6 +24,7 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
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.rewriter.ComponentRewriter;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5;
@@ -50,6 +51,7 @@ final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, Cl
private final EntityPacketRewriter1_99 entityRewriter = new EntityPacketRewriter1_99(this);
private final BlockItemPacketRewriter1_99 itemRewriter = new BlockItemPacketRewriter1_99(this);
private final TagRewriter<ClientboundPacket1_21> tagRewriter = new TagRewriter<>(this);
private final ComponentRewriter1_99 componentRewriter = new ComponentRewriter1_99(this);
public Protocol1_99To_98() {
// Passing the class types into the super constructor is needed for automatic packet type id remapping, but can otherwise be omitted
@@ -63,6 +65,20 @@ final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, Cl
tagRewriter.registerGeneric(ClientboundPackets1_21.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS);
// If needed for item or component changes
componentRewriter.registerOpenScreen(ClientboundPackets1_21.OPEN_SCREEN);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_21.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_21.TAB_LIST);
componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21.PLAYER_COMBAT_KILL);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SYSTEM_CHAT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.DISGUISED_CHAT);
componentRewriter.registerPlayerInfoUpdate1_21_2(ClientboundPackets1_21.PLAYER_INFO_UPDATE);
componentRewriter.registerPing();
final SoundRewriter<ClientboundPacket1_21> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND_ENTITY);
@@ -90,16 +106,19 @@ final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, Cl
// EntityTypes1_20_5.initialize(this);
// Uncomment if a new particle was added = ids shifted; requires a new Types_ class copied from the last
/*Types1_21.PARTICLE.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST)
.reader("falling_dust", ParticleType.Readers.BLOCK)
.reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION)
.reader("item", ParticleType.Readers.ITEM1_20_2)
.reader("vibration", ParticleType.Readers.VIBRATION1_20_3)
.reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE)
.reader("shriek", ParticleType.Readers.SHRIEK);*/
/*Types1_21_2.PARTICLE.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST1_21_2)
.reader("dust_pillar", ParticleType.Readers.BLOCK)
.reader("falling_dust", ParticleType.Readers.BLOCK)
.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("trail", ParticleType.Readers.TRAIL)
.reader("item", ParticleType.Readers.item(itemRewriter.mappedItemType()));*/
super.onMappingDataLoaded(); // Calls load methods on rewriters. Last in case the rewriters access the above filled data
}
@@ -132,6 +151,11 @@ final class Protocol1_99To_98 extends AbstractProtocol<ClientboundPacket1_21, Cl
return tagRewriter;
}
@Override
public ComponentRewriter getComponentRewriter() {
return componentRewriter;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21, ClientboundPacket1_21, ServerboundPacket1_20_5, ServerboundPacket1_20_5> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
@@ -353,7 +353,7 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
registerClientbound(ClientboundPackets1_12_1.PLACE_GHOST_RECIPE, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE);
map(Types.UNSIGNED_BYTE);
handler(wrapper -> wrapper.write(Types.STRING, "viaversion:legacy/" + wrapper.read(Types.VAR_INT)));
}
});
@@ -594,7 +594,7 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
registerServerbound(ServerboundPackets1_13.PLACE_RECIPE, new PacketHandlers() {
@Override
public void register() {
map(Types.BYTE); // Window id
map(Types.UNSIGNED_BYTE); // Window id
handler(wrapper -> {
String s = wrapper.read(Types.STRING);
@@ -81,7 +81,7 @@ public class Protocol1_15_2To1_16 extends AbstractProtocol<ClientboundPackets1_1
new StatisticsRewriter<>(this).register(ClientboundPackets1_15.AWARD_STATS);
// Login Success
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> {
// Transform string to a uuid
UUID uuid = UUID.fromString(wrapper.read(Types.STRING));
wrapper.write(Types.UUID, uuid);
@@ -232,7 +232,7 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
cancelServerbound(ServerboundPackets1_19.CHAT_PREVIEW);
// Login changes
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE, new PacketHandlers() {
registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, new PacketHandlers() {
@Override
public void register() {
map(Types.UUID); // UUID
@@ -116,7 +116,7 @@ public final class EntityPacketRewriter1_19_3 extends EntityRewriter<Clientbound
set.set(action == 1 ? action + 1 : action + 2);
}
wrapper.write(Types.PROFILE_ACTIONS_ENUM, set);
wrapper.write(Types.PROFILE_ACTIONS_ENUM1_19_3, set);
final int entries = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Types.UUID); // UUID
@@ -50,8 +50,7 @@ public class RecipeRewriter1_19_3<C extends ClientboundPacketType> extends Recip
wrapper.passthrough(Types.STRING); // Group
wrapper.passthrough(Types.VAR_INT); // Crafting book category
handleIngredients(wrapper);
final Item result = rewrite(wrapper.user(), wrapper.read(itemType()));
wrapper.write(mappedItemType(), result);
wrapper.write(mappedItemType(), rewrite(wrapper.user(), wrapper.read(itemType())));
}
@Override
@@ -268,7 +268,7 @@ public final class Protocol1_20_2To1_20_3 extends AbstractProtocol<ClientboundPa
}
});
registerClientbound(ClientboundPackets1_20_2.PLAYER_INFO_UPDATE, wrapper -> {
final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM);
final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM1_19_3);
final int entries = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Types.UUID);
@@ -64,4 +64,4 @@ public class RecipeRewriter1_20_3<C extends ClientboundPacketType> extends Recip
protected Type<Item[]> mappedItemArrayType() {
return protocol.getItemRewriter().mappedItemArrayType();
}
}
}
@@ -211,7 +211,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
new CommandRewriter1_19_4<>(this).registerDeclareCommands1_19(ClientboundPackets1_20_3.COMMANDS);
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> {
wrapper.passthrough(Types.UUID); // UUID
wrapper.passthrough(Types.STRING); // Name
@@ -272,10 +272,10 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol<ClientboundPa
.add(StructuredDataKey.CREATIVE_SLOT_LOCK).add(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE).add(StructuredDataKey.INTANGIBLE_PROJECTILE)
.add(StructuredDataKey.STORED_ENCHANTMENTS).add(StructuredDataKey.DYED_COLOR).add(StructuredDataKey.MAP_COLOR)
.add(StructuredDataKey.MAP_ID).add(StructuredDataKey.MAP_DECORATIONS).add(StructuredDataKey.MAP_POST_PROCESSING)
.add(StructuredDataKey.CHARGED_PROJECTILES1_20_5).add(StructuredDataKey.BUNDLE_CONTENTS1_20_5).add(StructuredDataKey.POTION_CONTENTS)
.add(StructuredDataKey.CHARGED_PROJECTILES1_20_5).add(StructuredDataKey.BUNDLE_CONTENTS1_20_5).add(StructuredDataKey.POTION_CONTENTS1_20_5)
.add(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS).add(StructuredDataKey.WRITABLE_BOOK_CONTENT).add(StructuredDataKey.WRITTEN_BOOK_CONTENT)
.add(StructuredDataKey.TRIM).add(StructuredDataKey.DEBUG_STICK_STATE).add(StructuredDataKey.ENTITY_DATA)
.add(StructuredDataKey.BUCKET_ENTITY_DATA).add(StructuredDataKey.BLOCK_ENTITY_DATA).add(StructuredDataKey.INSTRUMENT)
.add(StructuredDataKey.BUCKET_ENTITY_DATA).add(StructuredDataKey.BLOCK_ENTITY_DATA).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.BANNER_PATTERNS).add(StructuredDataKey.BASE_COLOR).add(StructuredDataKey.POT_DECORATIONS)
@@ -18,8 +18,9 @@
package com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPacket1_21_2;
public enum ServerboundConfigurationPackets1_20_5 implements ServerboundPacket1_20_5 {
public enum ServerboundConfigurationPackets1_20_5 implements ServerboundPacket1_20_5, ServerboundPacket1_21_2 {
CLIENT_INFORMATION, // 0x00
COOKIE_RESPONSE, // 0x01
@@ -60,9 +60,9 @@ import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableString;
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
import com.viaversion.viaversion.api.minecraft.item.data.Fireworks;
import com.viaversion.viaversion.api.minecraft.item.data.FoodEffect;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5.FoodEffect;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
@@ -536,7 +536,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
if (instrument != null) {
final int id = Instruments1_20_3.keyToId(instrument);
if (id != -1) {
data.set(StructuredDataKey.INSTRUMENT, Holder.of(id));
data.set(StructuredDataKey.INSTRUMENT1_20_5, Holder.of(id));
}
}
@@ -628,7 +628,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
if (serverVersion.olderThanOrEqualTo(ProtocolVersion.v1_8)) {
if (item.identifier() == 814 || item.identifier() == 819 || item.identifier() == 824 || item.identifier() == 829 || item.identifier() == 834) { // swords
// Make sword "eatable" to enable clientside instant blocking on 1.8. Consume time is set really high, so the eating animation doesn't play
item.dataContainer().set(StructuredDataKey.FOOD1_20_5, new FoodProperties(0, 0F, true, 3600, null, new FoodEffect[0]));
item.dataContainer().set(StructuredDataKey.FOOD1_20_5, new FoodProperties1_20_5(0, 0F, true, 3600, null, new FoodEffect[0]));
}
}
}
@@ -727,7 +727,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
soundEvent = Holder.of(instrument.getInt("sound_event"));
}
data.set(StructuredDataKey.INSTRUMENT, Holder.of(new Instrument(soundEvent, useDuration, range)));
data.set(StructuredDataKey.INSTRUMENT1_20_5, Holder.of(new Instrument1_20_5(soundEvent, useDuration, range)));
}
private void restoreFoodFromBackup(final CompoundTag food, final StructuredDataContainer data) {
@@ -756,7 +756,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
effect.getFloat("probability")
));
}
data.set(StructuredDataKey.FOOD1_20_5, new FoodProperties(nutrition, saturation, canAlwaysEat, eatSeconds, null, possibleEffects.toArray(new FoodEffect[0])));
data.set(StructuredDataKey.FOOD1_20_5, new FoodProperties1_20_5(nutrition, saturation, canAlwaysEat, eatSeconds, null, possibleEffects.toArray(new FoodEffect[0])));
}
private void restoreToolFromBackup(final CompoundTag tool, final StructuredDataContainer data) {
@@ -965,7 +965,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter<Clientboun
}
if (potionId != null || customPotionColorTag != null || potionEffects != null) {
data.set(StructuredDataKey.POTION_CONTENTS, new PotionContents(
data.set(StructuredDataKey.POTION_CONTENTS1_20_5, new PotionContents(
potionId,
customPotionColorTag != null ? customPotionColorTag.asInt() : null,
potionEffects != null ? potionEffects : new PotionEffect[0]
@@ -55,9 +55,9 @@ import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableString;
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
import com.viaversion.viaversion.api.minecraft.item.data.Fireworks;
import com.viaversion.viaversion.api.minecraft.item.data.FoodEffect;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5.FoodEffect;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker;
import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations;
import com.viaversion.viaversion.api.minecraft.item.data.PotionContents;
@@ -144,7 +144,7 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
registerEmpty(StructuredDataKey.MAP_POST_PROCESSING);
register(StructuredDataKey.CHARGED_PROJECTILES1_20_5, this::convertChargedProjectiles);
register(StructuredDataKey.BUNDLE_CONTENTS1_20_5, this::convertBundleContents);
register(StructuredDataKey.POTION_CONTENTS, this::convertPotionContents);
register(StructuredDataKey.POTION_CONTENTS1_20_5, this::convertPotionContents);
register(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, this::convertSuspiciousStewEffects);
register(StructuredDataKey.WRITABLE_BOOK_CONTENT, this::convertWritableBookContent);
register(StructuredDataKey.WRITTEN_BOOK_CONTENT, this::convertWrittenBookContent);
@@ -153,7 +153,7 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
register(StructuredDataKey.ENTITY_DATA, this::convertEntityData);
register(StructuredDataKey.BUCKET_ENTITY_DATA, this::convertBucketEntityData);
register(StructuredDataKey.BLOCK_ENTITY_DATA, this::convertBlockEntityData);
register(StructuredDataKey.INSTRUMENT, this::convertInstrument);
register(StructuredDataKey.INSTRUMENT1_20_5, this::convertInstrument);
register(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, this::convertOminousBottleAmplifier);
register(StructuredDataKey.RECIPES, this::convertRecipes);
register(StructuredDataKey.LODESTONE_TRACKER, this::convertLodestoneTracker);
@@ -502,7 +502,7 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
return convertUnit();
}
protected CompoundTag convertFood(final FoodProperties value) {
protected CompoundTag convertFood(final FoodProperties1_20_5 value) {
final CompoundTag tag = new CompoundTag();
tag.put("nutrition", convertNonNegativeInt(value.nutrition()));
tag.putFloat("saturation", value.saturationModifier());
@@ -745,12 +745,12 @@ public class ComponentRewriter1_20_5<C extends ClientboundPacketType> extends Co
return convertNbtWithId(value);
}
protected Tag convertInstrument(final Holder<Instrument> value) {
protected Tag convertInstrument(final Holder<Instrument1_20_5> value) {
if (value.hasId()) {
return new StringTag(Instruments1_20_3.idToKey(value.id()));
}
final Instrument instrument = value.value();
final Instrument1_20_5 instrument = value.value();
final CompoundTag tag = new CompoundTag();
final Holder<SoundEvent> sound = instrument.soundEvent();
if (sound.hasId()) {
@@ -44,8 +44,8 @@ import com.viaversion.viaversion.api.minecraft.item.data.Enchantments;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent;
import com.viaversion.viaversion.api.minecraft.item.data.FilterableString;
import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion;
import com.viaversion.viaversion.api.minecraft.item.data.FoodEffect;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument;
import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5.FoodEffect;
import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.PotionEffect;
import com.viaversion.viaversion.api.minecraft.item.data.PotionEffectData;
import com.viaversion.viaversion.api.minecraft.item.data.StatePropertyMatcher;
@@ -278,12 +278,12 @@ public final class StructuredDataConverter {
}
profileTag.put("Properties", propertiesTag);
});
register(StructuredDataKey.INSTRUMENT, (data, tag) -> {
register(StructuredDataKey.INSTRUMENT1_20_5, (data, tag) -> {
// Can't do anything with direct values
if (!data.hasId()) {
if (backupInconvertibleData) {
final CompoundTag backupTag = new CompoundTag();
final Instrument instrument = data.value();
final Instrument1_20_5 instrument = data.value();
if (instrument.soundEvent().hasId()) {
backupTag.putInt("sound_event", instrument.soundEvent().id());
} else {
@@ -398,7 +398,7 @@ public final class StructuredDataConverter {
enchantmentsTag.add(invalidEnchantment);
});
register(StructuredDataKey.POTION_CONTENTS, (data, tag) -> {
register(StructuredDataKey.POTION_CONTENTS1_20_5, (data, tag) -> {
if (data.potion() != null) {
final String potion = Potions1_20_5.idToKey(data.potion()); // Include 1.20.5 names
if (potion != null) {
@@ -201,10 +201,10 @@ public final class Protocol1_20_5To1_21 extends AbstractProtocol<ClientboundPack
.add(StructuredDataKey.CREATIVE_SLOT_LOCK).add(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE).add(StructuredDataKey.INTANGIBLE_PROJECTILE)
.add(StructuredDataKey.STORED_ENCHANTMENTS).add(StructuredDataKey.DYED_COLOR).add(StructuredDataKey.MAP_COLOR)
.add(StructuredDataKey.MAP_ID).add(StructuredDataKey.MAP_DECORATIONS).add(StructuredDataKey.MAP_POST_PROCESSING)
.add(StructuredDataKey.CHARGED_PROJECTILES1_21).add(StructuredDataKey.BUNDLE_CONTENTS1_21).add(StructuredDataKey.POTION_CONTENTS)
.add(StructuredDataKey.CHARGED_PROJECTILES1_21).add(StructuredDataKey.BUNDLE_CONTENTS1_21).add(StructuredDataKey.POTION_CONTENTS1_20_5)
.add(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS).add(StructuredDataKey.WRITABLE_BOOK_CONTENT).add(StructuredDataKey.WRITTEN_BOOK_CONTENT)
.add(StructuredDataKey.TRIM).add(StructuredDataKey.DEBUG_STICK_STATE).add(StructuredDataKey.ENTITY_DATA)
.add(StructuredDataKey.BUCKET_ENTITY_DATA).add(StructuredDataKey.BLOCK_ENTITY_DATA).add(StructuredDataKey.INSTRUMENT)
.add(StructuredDataKey.BUCKET_ENTITY_DATA).add(StructuredDataKey.BLOCK_ENTITY_DATA).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.BANNER_PATTERNS).add(StructuredDataKey.BASE_COLOR).add(StructuredDataKey.POT_DECORATIONS)
@@ -18,8 +18,9 @@
package com.viaversion.viaversion.protocols.v1_20_5to1_21.packet;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2;
public enum ClientboundConfigurationPackets1_21 implements ClientboundPacket1_21 {
public enum ClientboundConfigurationPackets1_21 implements ClientboundPacket1_21, ClientboundPacket1_21_2 {
COOKIE_REQUEST, // 0x00
CUSTOM_PAYLOAD, // 0x01
@@ -60,9 +60,4 @@ public final class ComponentRewriter1_21 extends ComponentRewriter<ClientboundPa
protected SerializerVersion inputSerializerVersion() {
return SerializerVersion.V1_20_5;
}
@Override
protected SerializerVersion outputSerializerVersion() {
return SerializerVersion.V1_20_5;
}
}
@@ -70,7 +70,7 @@ public final class EntityPacketRewriter1_21 extends EntityRewriter<ClientboundPa
}
});
protocol.registerClientbound(ClientboundConfigurationPackets1_20_5.FINISH_CONFIGURATION, wrapper -> {
protocol.registerFinishConfiguration(ClientboundConfigurationPackets1_20_5.FINISH_CONFIGURATION, wrapper -> {
// Add new registries
final PacketWrapper paintingRegistryPacket = wrapper.create(ClientboundConfigurationPackets1_20_5.REGISTRY_DATA);
paintingRegistryPacket.write(Types.STRING, "minecraft:painting_variant");
@@ -144,7 +144,7 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol<ClientboundPack
// We need to wait for it send the login ack before actually sending the play login,
// hence packets are added to a queue. With the data from the login packet, we sent what is needed
// during the configuration phase before finally transitioning to the play state with the client as well.
registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> {
wrapper.user().get(ConfigurationState.class).setBridgePhase(BridgePhase.PROFILE_SENT);
wrapper.user().getProtocolInfo().setServerState(State.PLAY);
});
@@ -0,0 +1,266 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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;
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.entities.EntityTypes1_21_2;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
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_21_2;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_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.protocols.v1_21to1_21_2.packet.ServerboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPackets1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.BlockItemPacketRewriter1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.ComponentRewriter1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.EntityPacketRewriter1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage;
import com.viaversion.viaversion.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import java.util.BitSet;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
public final class Protocol1_21To1_21_2 extends AbstractProtocol<ClientboundPacket1_21, ClientboundPacket1_21_2, ServerboundPacket1_20_5, ServerboundPacket1_21_2> {
public static final MappingData MAPPINGS = new MappingDataBase("1.21", "1.21.2");
private final EntityPacketRewriter1_21_2 entityRewriter = new EntityPacketRewriter1_21_2(this);
private final BlockItemPacketRewriter1_21_2 itemRewriter = new BlockItemPacketRewriter1_21_2(this);
private final TagRewriter<ClientboundPacket1_21> tagRewriter = new TagRewriter<>(this);
private final ComponentRewriter1_21_2 componentRewriter = new ComponentRewriter1_21_2(this);
public Protocol1_21To1_21_2() {
super(ClientboundPacket1_21.class, ClientboundPacket1_21_2.class, ServerboundPacket1_20_5.class, ServerboundPacket1_21_2.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
tagRewriter.registerGeneric(ClientboundPackets1_21.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS);
componentRewriter.registerOpenScreen(ClientboundPackets1_21.OPEN_SCREEN);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_21.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_21.TAB_LIST);
componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21.PLAYER_COMBAT_KILL);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.SYSTEM_CHAT);
componentRewriter.registerComponentPacket(ClientboundPackets1_21.DISGUISED_CHAT);
componentRewriter.registerPing();
final SoundRewriter<ClientboundPacket1_21> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND_ENTITY);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21.AWARD_STATS);
new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21.UPDATE_ATTRIBUTES);
registerServerbound(ServerboundPackets1_21_2.CLIENT_INFORMATION, this::clientInformation);
registerServerbound(ServerboundConfigurationPackets1_20_5.CLIENT_INFORMATION, this::clientInformation);
cancelServerbound(ServerboundPackets1_21_2.BUNDLE_ITEM_SELECTED);
cancelServerbound(ServerboundPackets1_21_2.CLIENT_TICK_END);
registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> {
wrapper.passthrough(Types.UUID); // UUID
wrapper.passthrough(Types.STRING); // Name
final int properties = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < properties; i++) {
wrapper.passthrough(Types.STRING); // Name
wrapper.passthrough(Types.STRING); // Value
wrapper.passthrough(Types.OPTIONAL_STRING); // Signature
}
wrapper.read(Types.BOOLEAN); // Strict error handling
});
registerClientbound(ClientboundPackets1_21.SET_TIME, wrapper -> {
wrapper.passthrough(Types.LONG); // Game time
long dayTime = wrapper.read(Types.LONG);
boolean doDaylightCycle = true;
if (dayTime < 0) {
dayTime = -dayTime;
doDaylightCycle = false;
}
wrapper.write(Types.LONG, dayTime);
wrapper.write(Types.BOOLEAN, doDaylightCycle);
});
registerClientbound(ClientboundPackets1_21.PLAYER_INFO_UPDATE, wrapper -> {
final BitSet actions = wrapper.passthroughAndMap(Types.PROFILE_ACTIONS_ENUM1_19_3, Types.PROFILE_ACTIONS_ENUM1_21_2);
if (!actions.get(5)) { // Update display name
return;
}
final int entries = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Types.UUID);
if (actions.get(0)) {
wrapper.passthrough(Types.STRING); // Player Name
final int properties = wrapper.passthrough(Types.VAR_INT);
for (int j = 0; j < properties; j++) {
wrapper.passthrough(Types.STRING); // Name
wrapper.passthrough(Types.STRING); // Value
wrapper.passthrough(Types.OPTIONAL_STRING); // Signature
}
}
if (actions.get(1) && wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.UUID); // Session UUID
wrapper.passthrough(Types.PROFILE_KEY);
}
if (actions.get(2)) {
wrapper.passthrough(Types.VAR_INT); // Gamemode
}
if (actions.get(3)) {
wrapper.passthrough(Types.BOOLEAN); // Listed
}
if (actions.get(4)) {
wrapper.passthrough(Types.VAR_INT); // Latency
}
componentRewriter.processTag(wrapper.user(), wrapper.passthrough(Types.OPTIONAL_TAG));
}
});
registerClientbound(ClientboundPackets1_21.BUNDLE_DELIMITER, wrapper -> wrapper.user().get(BundleStateTracker.class).toggleBundling());
registerServerbound(ServerboundPackets1_21_2.PONG, wrapper -> {
final int id = wrapper.passthrough(Types.INT); // id
if (wrapper.user().get(PlayerPositionStorage.class).checkPong(id)) {
wrapper.cancel();
}
});
}
private void clientInformation(final PacketWrapper wrapper) {
wrapper.passthrough(Types.STRING); // Locale
wrapper.passthrough(Types.BYTE); // View distance
wrapper.passthrough(Types.VAR_INT); // Chat visibility
wrapper.passthrough(Types.BOOLEAN); // Chat colors
wrapper.passthrough(Types.UNSIGNED_BYTE); // Skin parts
wrapper.passthrough(Types.VAR_INT); // Main hand
wrapper.passthrough(Types.BOOLEAN); // Text filtering enabled
wrapper.passthrough(Types.BOOLEAN); // Allow listing
wrapper.read(Types.VAR_INT); // Particle status
}
@Override
protected void onMappingDataLoaded() {
EntityTypes1_21_2.initialize(this);
Types1_21_2.PARTICLE.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST1_21_2)
.reader("dust_pillar", ParticleType.Readers.BLOCK)
.reader("falling_dust", ParticleType.Readers.BLOCK)
.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("trail", ParticleType.Readers.TRAIL)
.reader("item", ParticleType.Readers.item(Types1_21_2.ITEM));
Types1_21_2.STRUCTURED_DATA.filler(this).add(StructuredDataKey.CUSTOM_DATA, StructuredDataKey.MAX_STACK_SIZE, StructuredDataKey.MAX_DAMAGE,
StructuredDataKey.UNBREAKABLE, StructuredDataKey.RARITY, StructuredDataKey.HIDE_TOOLTIP, StructuredDataKey.DAMAGE_RESISTANT,
StructuredDataKey.CUSTOM_NAME, StructuredDataKey.LORE, StructuredDataKey.ENCHANTMENTS, StructuredDataKey.CAN_PLACE_ON,
StructuredDataKey.CAN_BREAK, StructuredDataKey.CUSTOM_MODEL_DATA, StructuredDataKey.HIDE_ADDITIONAL_TOOLTIP,
StructuredDataKey.REPAIR_COST, StructuredDataKey.CREATIVE_SLOT_LOCK, StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE,
StructuredDataKey.INTANGIBLE_PROJECTILE, StructuredDataKey.STORED_ENCHANTMENTS, StructuredDataKey.DYED_COLOR,
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.TRIM, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA,
StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA, 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.CONTAINER_LOOT, StructuredDataKey.TOOL, StructuredDataKey.ITEM_NAME, StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER,
StructuredDataKey.FOOD1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE, StructuredDataKey.ATTRIBUTE_MODIFIERS1_21,
StructuredDataKey.REPAIRABLE, StructuredDataKey.ENCHANTABLE, StructuredDataKey.CONSUMABLE1_21_2,
StructuredDataKey.USE_COOLDOWN, StructuredDataKey.DAMAGE, StructuredDataKey.EQUIPPABLE, StructuredDataKey.ITEM_MODEL,
StructuredDataKey.GLIDER, StructuredDataKey.TOOLTIP_STYLE, StructuredDataKey.DEATH_PROTECTION,
// Volatile thanks to containing item
StructuredDataKey.CHARGED_PROJECTILES1_21_2, StructuredDataKey.BUNDLE_CONTENTS1_21_2, StructuredDataKey.CONTAINER1_21_2, StructuredDataKey.USE_REMAINDER);
super.onMappingDataLoaded();
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_2.PLAYER));
connection.put(new BundleStateTracker());
connection.put(new PlayerPositionStorage());
}
@Override
public MappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityPacketRewriter1_21_2 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter1_21_2 getItemRewriter() {
return itemRewriter;
}
@Override
public TagRewriter<ClientboundPacket1_21> getTagRewriter() {
return tagRewriter;
}
@Override
public ComponentRewriter getComponentRewriter() {
return componentRewriter;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21, ClientboundPacket1_21_2, ServerboundPacket1_20_5, ServerboundPacket1_21_2> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_2.class, ServerboundConfigurationPackets1_20_5.class)
);
}
}
@@ -0,0 +1,23 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.packet;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
public interface ClientboundPacket1_21_2 extends ClientboundPacketType {
}
@@ -0,0 +1,163 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.packet;
public enum ClientboundPackets1_21_2 implements ClientboundPacket1_21_2 {
BUNDLE_DELIMITER, // 0x00
ADD_ENTITY, // 0x01
ADD_EXPERIENCE_ORB, // 0x02
ANIMATE, // 0x03
AWARD_STATS, // 0x04
BLOCK_CHANGED_ACK, // 0x05
BLOCK_DESTRUCTION, // 0x06
BLOCK_ENTITY_DATA, // 0x07
BLOCK_EVENT, // 0x08
BLOCK_UPDATE, // 0x09
BOSS_EVENT, // 0x0A
CHANGE_DIFFICULTY, // 0x0B
CHUNK_BATCH_FINISHED, // 0x0C
CHUNK_BATCH_START, // 0x0D
CHUNKS_BIOMES, // 0x0E
CLEAR_TITLES, // 0x0F
COMMAND_SUGGESTIONS, // 0x10
COMMANDS, // 0x11
CONTAINER_CLOSE, // 0x12
CONTAINER_SET_CONTENT, // 0x13
CONTAINER_SET_DATA, // 0x14
CONTAINER_SET_SLOT, // 0x15
COOKIE_REQUEST, // 0x16
COOLDOWN, // 0x17
CUSTOM_CHAT_COMPLETIONS, // 0x18
CUSTOM_PAYLOAD, // 0x19
DAMAGE_EVENT, // 0x1A
DEBUG_SAMPLE, // 0x1B
DELETE_CHAT, // 0x1C
DISCONNECT, // 0x1D
DISGUISED_CHAT, // 0x1E
ENTITY_EVENT, // 0x1F
ENTITY_POSITION_SYNC, // 0x20
EXPLODE, // 0x21
FORGET_LEVEL_CHUNK, // 0x22
GAME_EVENT, // 0x23
HORSE_SCREEN_OPEN, // 0x24
HURT_ANIMATION, // 0x25
INITIALIZE_BORDER, // 0x26
KEEP_ALIVE, // 0x27
LEVEL_CHUNK_WITH_LIGHT, // 0x28
LEVEL_EVENT, // 0x29
LEVEL_PARTICLES, // 0x2A
LIGHT_UPDATE, // 0x2B
LOGIN, // 0x2C
MAP_ITEM_DATA, // 0x2D
MERCHANT_OFFERS, // 0x2E
MOVE_ENTITY_POS, // 0x2F
MOVE_ENTITY_POS_ROT, // 0x30
MOVE_MINECART_ALONG_TRACK, // 0x31
MOVE_ENTITY_ROT, // 0x32
MOVE_VEHICLE, // 0x33
OPEN_BOOK, // 0x34
OPEN_SCREEN, // 0x35
OPEN_SIGN_EDITOR, // 0x36
PING, // 0x37
PONG_RESPONSE, // 0x38
PLACE_GHOST_RECIPE, // 0x39
PLAYER_ABILITIES, // 0x3A
PLAYER_CHAT, // 0x3B
PLAYER_COMBAT_END, // 0x3C
PLAYER_COMBAT_ENTER, // 0x3D
PLAYER_COMBAT_KILL, // 0x3E
PLAYER_INFO_REMOVE, // 0x3F
PLAYER_INFO_UPDATE, // 0x40
PLAYER_LOOK_AT, // 0x41
PLAYER_POSITION, // 0x42
PLAYER_ROTATION, // 0x43
RECIPE_BOOK_ADD, // 0x44
RECIPE_BOOK_REMOVE, // 0x45
RECIPE_BOOK_SETTINGS, // 0x46
REMOVE_ENTITIES, // 0x47
REMOVE_MOB_EFFECT, // 0x48
RESET_SCORE, // 0x49
RESOURCE_PACK_POP, // 0x4A
RESOURCE_PACK_PUSH, // 0x4B
RESPAWN, // 0x4C
ROTATE_HEAD, // 0x4D
SECTION_BLOCKS_UPDATE, // 0x4E
SELECT_ADVANCEMENTS_TAB, // 0x4F
SERVER_DATA, // 0x50
SET_ACTION_BAR_TEXT, // 0x51
SET_BORDER_CENTER, // 0x52
SET_BORDER_LERP_SIZE, // 0x53
SET_BORDER_SIZE, // 0x54
SET_BORDER_WARNING_DELAY, // 0x55
SET_BORDER_WARNING_DISTANCE, // 0x56
SET_CAMERA, // 0x57
SET_CHUNK_CACHE_CENTER, // 0x58
SET_CHUNK_CACHE_RADIUS, // 0x59
SET_CURSOR_ITEM, // 0x5A
SET_DEFAULT_SPAWN_POSITION, // 0x5B
SET_DISPLAY_OBJECTIVE, // 0x5C
SET_ENTITY_DATA, // 0x5D
SET_ENTITY_LINK, // 0x5E
SET_ENTITY_MOTION, // 0x5F
SET_EQUIPMENT, // 0x60
SET_EXPERIENCE, // 0x61
SET_HEALTH, // 0x62
SET_HELD_SLOT, // 0x63
SET_OBJECTIVE, // 0x64
SET_PASSENGERS, // 0x65
SET_PLAYER_INVENTORY, // 0x66
SET_PLAYER_TEAM, // 0x67
SET_SCORE, // 0x68
SET_SIMULATION_DISTANCE, // 0x69
SET_SUBTITLE_TEXT, // 0x6A
SET_TIME, // 0x6B
SET_TITLE_TEXT, // 0x6C
SET_TITLES_ANIMATION, // 0x6D
SOUND_ENTITY, // 0x6E
SOUND, // 0x6F
START_CONFIGURATION, // 0x70
STOP_SOUND, // 0x71
STORE_COOKIE, // 0x72
SYSTEM_CHAT, // 0x73
TAB_LIST, // 0x74
TAG_QUERY, // 0x75
TAKE_ITEM_ENTITY, // 0x76
TELEPORT_ENTITY, // 0x77
TICKING_STATE, // 0x78
TICKING_STEP, // 0x79
TRANSFER, // 0x7A
UPDATE_ADVANCEMENTS, // 0x7B
UPDATE_ATTRIBUTES, // 0x7C
UPDATE_MOB_EFFECT, // 0x7D
UPDATE_RECIPES, // 0x7E
UPDATE_TAGS, // 0x7F
PROJECTILE_POWER, // 0x80
CUSTOM_REPORT_DETAILS, // 0x81
SERVER_LINKS; // 0x82
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
@@ -0,0 +1,23 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.packet;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
public interface ServerboundPacket1_21_2 extends ServerboundPacketType {
}
@@ -0,0 +1,92 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.packet;
public enum ServerboundPackets1_21_2 implements ServerboundPacket1_21_2 {
ACCEPT_TELEPORTATION, // 0x00
BLOCK_ENTITY_TAG_QUERY, // 0x01
BUNDLE_ITEM_SELECTED, // 0x02
CHANGE_DIFFICULTY, // 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, // 0x22
PING_REQUEST, // 0x23
PLACE_RECIPE, // 0x24
PLAYER_ABILITIES, // 0x25
PLAYER_ACTION, // 0x26
PLAYER_COMMAND, // 0x27
PLAYER_INPUT, // 0x28
PONG, // 0x29
RECIPE_BOOK_CHANGE_SETTINGS, // 0x2A
RECIPE_BOOK_SEEN_RECIPE, // 0x2B
RENAME_ITEM, // 0x2C
RESOURCE_PACK, // 0x2D
SEEN_ADVANCEMENTS, // 0x2E
SELECT_TRADE, // 0x2F
SET_BEACON, // 0x30
SET_CARRIED_ITEM, // 0x31
SET_COMMAND_BLOCK, // 0x32
SET_COMMAND_MINECART, // 0x33
SET_CREATIVE_MODE_SLOT, // 0x34
SET_JIGSAW_BLOCK, // 0x35
SET_STRUCTURE_BLOCK, // 0x36
SIGN_UPDATE, // 0x37
SWING, // 0x38
TELEPORT_TO_ENTITY, // 0x39
USE_ITEM_ON, // 0x3A
USE_ITEM; // 0x3B
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
@@ -0,0 +1,500 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.Particle;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2;
import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant;
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.PotionEffect;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.api.type.types.version.Types1_21_2;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPacket1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.TagUtil;
import com.viaversion.viaversion.util.Unit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
public final class BlockItemPacketRewriter1_21_2 extends StructuredItemRewriter<ClientboundPacket1_21, ServerboundPacket1_21_2, Protocol1_21To1_21_2> {
private static final int RECIPE_NOTIFICATION_FLAG = 1 << 0;
private static final int RECIPE_HIGHLIGHT_FLAG = 1 << 1;
private static final int RECIPE_INIT = 0;
private static final int RECIPE_ADD = 1;
private static final int RECIPE_REMOVE = 2;
public BlockItemPacketRewriter1_21_2(final Protocol1_21To1_21_2 protocol) {
super(protocol,
Types1_21.ITEM, Types1_21.ITEM_ARRAY, Types1_21_2.ITEM, Types1_21_2.ITEM_ARRAY,
Types1_21.ITEM_COST, Types1_21.OPTIONAL_ITEM_COST, Types1_21_2.ITEM_COST, Types1_21_2.OPTIONAL_ITEM_COST,
Types1_21.PARTICLE, Types1_21_2.PARTICLE
);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPacket1_21> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21.BLOCK_ENTITY_DATA);
registerAdvancements1_20_3(ClientboundPackets1_21.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21.SET_EQUIPMENT);
registerMerchantOffers1_20_5(ClientboundPackets1_21.MERCHANT_OFFERS);
registerSetCreativeModeSlot(ServerboundPackets1_21_2.SET_CREATIVE_MODE_SLOT);
registerLevelParticles1_20_5(ClientboundPackets1_21.LEVEL_PARTICLES);
protocol.registerClientbound(ClientboundPackets1_21.COOLDOWN, wrapper -> {
final MappingData mappingData = protocol.getMappingData();
final int itemId = wrapper.read(Types.VAR_INT);
final int mappedItemId = mappingData.getNewItemId(itemId);
wrapper.write(Types.STRING, mappingData.getFullItemMappings().mappedIdentifier(mappedItemId));
});
protocol.registerClientbound(ClientboundPackets1_21.CONTAINER_SET_CONTENT, wrapper -> {
updateContainerId(wrapper);
wrapper.passthrough(Types.VAR_INT); // State id
final Item[] items = wrapper.read(itemArrayType());
wrapper.write(mappedItemArrayType(), items);
for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(wrapper.user(), items[i]);
}
passthroughClientboundItem(wrapper);
});
protocol.registerClientbound(ClientboundPackets1_21.CONTAINER_SET_SLOT, wrapper -> {
updateContainerId(wrapper);
final int containerId = wrapper.get(Types.VAR_INT, 0);
if (containerId == -1) { // cursor item
wrapper.setPacketType(ClientboundPackets1_21_2.SET_CURSOR_ITEM);
wrapper.resetReader();
wrapper.read(Types.VAR_INT); // container id
wrapper.read(Types.VAR_INT); // State id
wrapper.read(Types.SHORT); // Slot id
} else if (containerId == -2) { // cursor item
wrapper.setPacketType(ClientboundPackets1_21_2.SET_PLAYER_INVENTORY);
wrapper.resetReader();
wrapper.read(Types.VAR_INT); // container id
wrapper.read(Types.VAR_INT); // State id
wrapper.write(Types.VAR_INT, (int) wrapper.read(Types.SHORT)); // Slot id
} else {
wrapper.passthrough(Types.VAR_INT); // State id
wrapper.passthrough(Types.SHORT); // Slot id
}
passthroughClientboundItem(wrapper);
});
protocol.registerClientbound(ClientboundPackets1_21.CONTAINER_CLOSE, this::updateContainerId);
protocol.registerClientbound(ClientboundPackets1_21.CONTAINER_SET_DATA, this::updateContainerId);
protocol.registerClientbound(ClientboundPackets1_21.HORSE_SCREEN_OPEN, this::updateContainerId);
protocol.registerClientbound(ClientboundPackets1_21.SET_CARRIED_ITEM, ClientboundPackets1_21_2.SET_HELD_SLOT);
protocol.registerServerbound(ServerboundPackets1_21_2.CONTAINER_CLOSE, this::updateContainerIdServerbound);
protocol.registerServerbound(ServerboundPackets1_21_2.CONTAINER_CLICK, wrapper -> {
updateContainerIdServerbound(wrapper);
wrapper.passthrough(Types.VAR_INT); // State id
wrapper.passthrough(Types.SHORT); // Slot
wrapper.passthrough(Types.BYTE); // Button
wrapper.passthrough(Types.VAR_INT); // Mode
final int length = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < length; i++) {
wrapper.passthrough(Types.SHORT); // Slot
passthroughServerboundItem(wrapper);
}
passthroughServerboundItem(wrapper);
});
protocol.registerClientbound(ClientboundPackets1_21.PLACE_GHOST_RECIPE, wrapper -> {
this.updateContainerId(wrapper);
final String recipeKey = wrapper.read(Types.STRING);
final RecipeRewriter1_21_2.Recipe recipe = wrapper.user().get(RecipeRewriter1_21_2.class).recipe(recipeKey);
if (recipe == null) {
wrapper.cancel();
return;
}
wrapper.write(Types.VAR_INT, recipe.recipeDisplayId());
recipe.writeRecipeDisplay(wrapper);
});
protocol.registerServerbound(ServerboundPackets1_21_2.PLACE_RECIPE, wrapper -> {
this.updateContainerIdServerbound(wrapper);
convertServerboundRecipeDisplayId(wrapper);
});
protocol.registerServerbound(ServerboundPackets1_21_2.RECIPE_BOOK_SEEN_RECIPE, this::convertServerboundRecipeDisplayId);
protocol.registerServerbound(ServerboundPackets1_21_2.USE_ITEM_ON, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Hand
wrapper.passthrough(Types.BLOCK_POSITION1_14); // Block position
wrapper.passthrough(Types.VAR_INT); // Direction
wrapper.passthrough(Types.FLOAT); // X
wrapper.passthrough(Types.FLOAT); // Y
wrapper.passthrough(Types.FLOAT); // Z
wrapper.passthrough(Types.BOOLEAN); // Inside
wrapper.read(Types.BOOLEAN); // World border hit
});
protocol.registerClientbound(ClientboundPackets1_21.EXPLODE, wrapper -> {
final int centerX = (int) Math.floor(wrapper.passthrough(Types.DOUBLE)); // Center X
final int centerY = (int) Math.floor(wrapper.passthrough(Types.DOUBLE)); // Center Y
final int centerZ = (int) Math.floor(wrapper.passthrough(Types.DOUBLE)); // Center Z
final float power = wrapper.read(Types.FLOAT); // Power
final List<BlockPosition> affectedBlocks = new ArrayList<>();
final int blocks = wrapper.read(Types.VAR_INT);
for (int i = 0; i < blocks; i++) {
final int x = centerX + wrapper.read(Types.BYTE); // Relative X
final int y = centerY + wrapper.read(Types.BYTE); // Relative Y
final int z = centerZ + wrapper.read(Types.BYTE); // Relative Z
affectedBlocks.add(new BlockPosition(x, y, z));
}
final float knockbackX = wrapper.read(Types.FLOAT);
final float knockbackY = wrapper.read(Types.FLOAT);
final float knockbackZ = wrapper.read(Types.FLOAT);
if (knockbackX != 0 || knockbackY != 0 || knockbackZ != 0) {
wrapper.write(Types.BOOLEAN, true);
wrapper.write(Types.DOUBLE, (double) knockbackX);
wrapper.write(Types.DOUBLE, (double) knockbackY);
wrapper.write(Types.DOUBLE, (double) knockbackZ);
} else {
wrapper.write(Types.BOOLEAN, false);
}
final int blockInteractionMode = wrapper.read(Types.VAR_INT);
if (blockInteractionMode == 1 || blockInteractionMode == 2) {
for (final BlockPosition affectedBlock : affectedBlocks) {
final PacketWrapper blockUpdate = PacketWrapper.create(ClientboundPackets1_21_2.BLOCK_UPDATE, wrapper.user());
blockUpdate.write(Types.BLOCK_POSITION1_14, affectedBlock); // position
blockUpdate.write(Types.VAR_INT, 0); // block state
blockUpdate.send(Protocol1_21To1_21_2.class);
}
}
final Particle smallExplosionParticle = wrapper.read(Types1_21.PARTICLE);
final Particle largeExplosionParticle = wrapper.read(Types1_21.PARTICLE);
if (power >= 2.0F && blockInteractionMode != 0) {
rewriteParticle(wrapper.user(), largeExplosionParticle);
wrapper.write(Types1_21_2.PARTICLE, largeExplosionParticle);
} else {
rewriteParticle(wrapper.user(), smallExplosionParticle);
wrapper.write(Types1_21_2.PARTICLE, smallExplosionParticle);
}
new SoundRewriter<>(protocol).soundHolderHandler().handle(wrapper);
});
protocol.registerClientbound(ClientboundPackets1_21.UPDATE_RECIPES, wrapper -> {
final FullMappings recipeSerializerMappings = protocol.getMappingData().getRecipeSerializerMappings();
final RecipeRewriter1_21_2 rewriter = new RecipeRewriter1_21_2(protocol);
wrapper.user().put(rewriter);
final int size = wrapper.read(Types.VAR_INT);
for (int i = 0; i < size; i++) {
final String recipeIdentifier = wrapper.read(Types.STRING);
final int serializerTypeId = wrapper.read(Types.VAR_INT);
final String serializerTypeIdentifier = recipeSerializerMappings.identifier(serializerTypeId);
rewriter.setCurrentRecipeIdentifier(recipeIdentifier);
rewriter.handleRecipeType(wrapper, serializerTypeIdentifier);
}
rewriter.finalizeRecipes();
// These are used for client predictions, such smithing or furnace inputs.
// Other recipes will be written in RECIPE/RECIPE_BOOK_ADD
rewriter.writeUpdateRecipeInputs(wrapper);
});
protocol.registerClientbound(ClientboundPackets1_21.RECIPE, ClientboundPackets1_21_2.RECIPE_BOOK_ADD, wrapper -> {
final int state = wrapper.passthrough(Types.VAR_INT);
// Pairs of open + filtering for: Crafting, furnace, blast furnace, smoker
final PacketWrapper settingsPacket = wrapper.create(ClientboundPackets1_21_2.RECIPE_BOOK_SETTINGS);
for (int i = 0; i < 4 * 2; i++) {
settingsPacket.write(Types.BOOLEAN, wrapper.read(Types.BOOLEAN));
}
settingsPacket.send(Protocol1_21To1_21_2.class);
// Read recipe keys from the packet
final String[] recipes = wrapper.read(Types.STRING_ARRAY);
Set<String> toHighlight = Set.of();
if (state == RECIPE_INIT) {
final String[] highlightRecipes = wrapper.read(Types.STRING_ARRAY);
toHighlight = Set.of(highlightRecipes);
}
final RecipeRewriter1_21_2 recipeRewriter = wrapper.user().get(RecipeRewriter1_21_2.class);
if (recipeRewriter == null) {
protocol.getLogger().severe("Recipes not yet sent for recipe add packet");
wrapper.cancel();
return;
}
wrapper.clearPacket();
if (state == RECIPE_REMOVE) {
wrapper.setPacketType(ClientboundPackets1_21_2.RECIPE_BOOK_REMOVE);
final int[] ids = new int[recipes.length];
for (int i = 0; i < recipes.length; i++) {
final String recipeKey = recipes[i];
final RecipeRewriter1_21_2.Recipe recipe = recipeRewriter.recipe(recipeKey);
if (recipe == null) {
protocol.getLogger().severe("Recipe not found for key " + recipeKey);
wrapper.cancel();
return;
}
ids[i] = recipe.index();
}
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, ids);
return;
}
// Add or init recipes
int size = recipes.length;
wrapper.write(Types.VAR_INT, size);
for (final String recipeKey : recipes) {
final RecipeRewriter1_21_2.Recipe recipe = recipeRewriter.recipe(recipeKey);
if (recipe == null) {
// Stonecutting and smithing recipes, or bad data
size--;
continue;
}
wrapper.write(Types.VAR_INT, recipe.index()); // Display ID, just an arbitrary index as determined by the server
wrapper.write(Types.VAR_INT, recipe.recipeDisplayId());
recipe.writeRecipeDisplay(wrapper);
wrapper.write(Types.OPTIONAL_VAR_INT, recipe.group() != -1 ? recipe.group() : null);
wrapper.write(Types.VAR_INT, recipe.category());
final Item[][] ingredients = recipe.ingredients();
if (ingredients != null) {
wrapper.write(Types.BOOLEAN, true);
// Why are some of these empty? Who knows, but they can't be
final List<HolderSet> filteredIngredients = Arrays.stream(ingredients).filter(ingredient -> ingredient.length > 0).map(recipeRewriter::toHolderSet).toList();
wrapper.write(Types.VAR_INT, filteredIngredients.size());
for (final HolderSet ingredient : filteredIngredients) {
wrapper.write(Types.HOLDER_SET, ingredient);
}
} else {
wrapper.write(Types.BOOLEAN, false);
}
byte flags = 0;
if (state == RECIPE_ADD) {
if (recipe.showNotification()) {
flags |= RECIPE_NOTIFICATION_FLAG;
}
flags |= RECIPE_HIGHLIGHT_FLAG;
} else if (toHighlight.contains(recipeKey)) {
flags |= RECIPE_HIGHLIGHT_FLAG;
}
wrapper.write(Types.BYTE, flags);
}
// Update final size
wrapper.set(Types.VAR_INT, 0, size);
wrapper.write(Types.BOOLEAN, state == RECIPE_INIT); // Replace
});
}
private void convertServerboundRecipeDisplayId(final PacketWrapper wrapper) {
final int recipeDisplayId = wrapper.read(Types.VAR_INT);
final RecipeRewriter1_21_2.Recipe recipe = wrapper.user().get(RecipeRewriter1_21_2.class).recipe(recipeDisplayId);
if (recipe == null) {
wrapper.cancel();
return;
}
wrapper.write(Types.STRING, recipe.identifier());
}
@Override
public void rewriteParticle(final UserConnection connection, final Particle particle) {
super.rewriteParticle(connection, particle);
final String identifier = protocol.getMappingData().getParticleMappings().mappedIdentifier(particle.id());
if (identifier.equals("minecraft:dust_color_transition")) {
floatsToARGB(particle, 0);
floatsToARGB(particle, 1);
} else if (identifier.equals("minecraft:dust")) {
floatsToARGB(particle, 0);
}
}
private void floatsToARGB(final Particle particle, final int fromIndex) {
final Particle.ParticleData<Float> r = particle.removeArgument(fromIndex);
final Particle.ParticleData<Float> g = particle.removeArgument(fromIndex);
final Particle.ParticleData<Float> b = particle.removeArgument(fromIndex);
final int rgb = 255 << 24 | (int) (r.getValue() * 255) << 16 | (int) (g.getValue() * 255) << 8 | (int) (b.getValue() * 255);
particle.add(fromIndex, Types.INT, rgb);
}
@Override
public Item handleItemToClient(final UserConnection connection, final Item item) {
super.handleItemToClient(connection, item);
updateItemData(item);
return item;
}
@Override
public Item handleItemToServer(final UserConnection connection, final Item item) {
super.handleItemToServer(connection, item);
downgradeItemData(item);
return item;
}
private void updateContainerId(final PacketWrapper wrapper) {
// Container id handling was always a bit whack with most reading them as unsigned bytes, some as bytes, some already as var ints.
// In VV they're generally read as unsigned bytes to not have to look the type up every time, but we need to make sure they're
// properly converted to ints when used
final short containerId = wrapper.read(Types.UNSIGNED_BYTE);
final int intId = (byte) containerId;
wrapper.write(Types.VAR_INT, intId);
}
private void updateContainerIdServerbound(final PacketWrapper wrapper) {
final int containerId = wrapper.read(Types.VAR_INT);
wrapper.write(Types.UNSIGNED_BYTE, (short) containerId);
}
public static void updateItemData(final Item item) {
final StructuredDataContainer dataContainer = item.dataContainer();
dataContainer.replace(StructuredDataKey.INSTRUMENT1_20_5, StructuredDataKey.INSTRUMENT1_21_2, instrument -> {
if (instrument.hasId()) {
return Holder.of(instrument.id());
}
final Instrument1_20_5 value = instrument.value();
return Holder.of(new Instrument1_21_2(value.soundEvent(), value.useDuration() / 20F, value.range(), new StringTag("")));
});
dataContainer.replace(StructuredDataKey.FOOD1_21, StructuredDataKey.FOOD1_21_2, food -> {
final Holder<SoundEvent> sound = Holder.of(new SoundEvent("minecraft:entity.generic.eat", null));
final Consumable1_21_2.ConsumeEffect<?>[] consumeEffects = new Consumable1_21_2.ConsumeEffect[food.possibleEffects().length];
for (int i = 0; i < consumeEffects.length; i++) {
final FoodProperties1_20_5.FoodEffect effect = food.possibleEffects()[i];
final Consumable1_21_2.ApplyStatusEffects applyStatusEffects = new Consumable1_21_2.ApplyStatusEffects(new PotionEffect[]{effect.effect()}, effect.probability());
consumeEffects[i] = new Consumable1_21_2.ConsumeEffect<>(0 /* add status effect */, Consumable1_21_2.ApplyStatusEffects.TYPE, applyStatusEffects);
}
dataContainer.set(StructuredDataKey.CONSUMABLE1_21_2, new Consumable1_21_2(food.eatSeconds(), 1 /* eat */, sound, true, consumeEffects));
if (food.usingConvertsTo() != null) {
dataContainer.set(StructuredDataKey.USE_REMAINDER, food.usingConvertsTo());
}
return new FoodProperties1_21_2(food.nutrition(), food.saturationModifier(), food.canAlwaysEat());
});
dataContainer.replaceKey(StructuredDataKey.CONTAINER1_21, StructuredDataKey.CONTAINER1_21_2);
dataContainer.replaceKey(StructuredDataKey.CHARGED_PROJECTILES1_21, StructuredDataKey.CHARGED_PROJECTILES1_21_2);
dataContainer.replaceKey(StructuredDataKey.BUNDLE_CONTENTS1_21, StructuredDataKey.BUNDLE_CONTENTS1_21_2);
dataContainer.replaceKey(StructuredDataKey.POTION_CONTENTS1_20_5, StructuredDataKey.POTION_CONTENTS1_21_2);
dataContainer.replace(StructuredDataKey.FIRE_RESISTANT, StructuredDataKey.DAMAGE_RESISTANT, fireResistant -> new DamageResistant("minecraft:is_fire"));
dataContainer.replace(StructuredDataKey.LOCK, lock -> {
final CompoundTag predicateTag = new CompoundTag();
final CompoundTag itemComponentsTag = new CompoundTag();
predicateTag.put("components", itemComponentsTag);
itemComponentsTag.put("custom_name", lock);
return predicateTag;
});
}
public static void downgradeItemData(final Item item) {
final StructuredDataContainer dataContainer = item.dataContainer();
dataContainer.replace(StructuredDataKey.LOCK, StructuredDataKey.LOCK, lock -> {
final CompoundTag predicateTag = (CompoundTag) lock;
final CompoundTag itemComponentsTag = predicateTag.getCompoundTag("components");
if (itemComponentsTag != null) {
return TagUtil.getNamespacedStringTag(itemComponentsTag, "custom_name");
}
return null;
});
dataContainer.replace(StructuredDataKey.INSTRUMENT1_21_2, StructuredDataKey.INSTRUMENT1_20_5, instrument -> {
if (instrument.hasId()) {
return Holder.of(instrument.id());
}
final Instrument1_21_2 value = instrument.value();
return Holder.of(new Instrument1_20_5(value.soundEvent(), (int) (value.useDuration() * 20), value.range()));
});
dataContainer.replace(StructuredDataKey.FOOD1_21_2, StructuredDataKey.FOOD1_21, food -> {
final Consumable1_21_2 consumableData = dataContainer.get(StructuredDataKey.CONSUMABLE1_21_2);
final Item useRemainderData = dataContainer.get(StructuredDataKey.USE_REMAINDER);
final float eatSeconds = consumableData != null ? consumableData.consumeSeconds() : 1.6F;
final List<FoodProperties1_20_5.FoodEffect> foodEffects = new ArrayList<>();
if (consumableData != null) {
for (Consumable1_21_2.ConsumeEffect<?> consumeEffect : consumableData.consumeEffects()) {
if (consumeEffect.value() instanceof Consumable1_21_2.ApplyStatusEffects applyStatusEffects) {
for (PotionEffect effect : applyStatusEffects.effects()) {
foodEffects.add(new FoodProperties1_20_5.FoodEffect(effect, applyStatusEffects.probability()));
}
}
}
}
return new FoodProperties1_20_5(food.nutrition(), food.saturationModifier(), food.canAlwaysEat(), eatSeconds, useRemainderData, foodEffects.toArray(new FoodProperties1_20_5.FoodEffect[0]));
});
dataContainer.replaceKey(StructuredDataKey.CONTAINER1_21_2, StructuredDataKey.CONTAINER1_21);
dataContainer.replaceKey(StructuredDataKey.CHARGED_PROJECTILES1_21_2, StructuredDataKey.CHARGED_PROJECTILES1_21);
dataContainer.replaceKey(StructuredDataKey.BUNDLE_CONTENTS1_21_2, StructuredDataKey.BUNDLE_CONTENTS1_21);
dataContainer.replaceKey(StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.POTION_CONTENTS1_20_5);
dataContainer.replace(StructuredDataKey.DAMAGE_RESISTANT, StructuredDataKey.FIRE_RESISTANT, damageResistant -> {
if (Key.stripMinecraftNamespace(damageResistant.typesTagKey()).equals("is_fire")) {
return Unit.INSTANCE;
}
return null;
});
dataContainer.remove(StructuredDataKey.REPAIRABLE);
dataContainer.remove(StructuredDataKey.ENCHANTABLE);
dataContainer.remove(StructuredDataKey.CONSUMABLE1_21_2);
dataContainer.remove(StructuredDataKey.USE_REMAINDER);
dataContainer.remove(StructuredDataKey.USE_COOLDOWN);
dataContainer.remove(StructuredDataKey.ITEM_MODEL);
dataContainer.remove(StructuredDataKey.EQUIPPABLE);
dataContainer.remove(StructuredDataKey.GLIDER);
dataContainer.remove(StructuredDataKey.TOOLTIP_STYLE);
dataContainer.remove(StructuredDataKey.DEATH_PROTECTION);
}
}
@@ -0,0 +1,93 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
import com.viaversion.viaversion.util.TagUtil;
import java.util.Iterator;
public final class ComponentRewriter1_21_2 extends ComponentRewriter<ClientboundPacket1_21> {
public ComponentRewriter1_21_2(final Protocol1_21To1_21_2 protocol) {
super(protocol, ReadType.NBT);
}
@Override
protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) {
super.handleShowItem(connection, itemTag, componentsTag);
if (componentsTag == null) {
return;
}
convertAttributes(componentsTag, protocol.getMappingData().getAttributeMappings());
final CompoundTag instrument = TagUtil.getNamespacedCompoundTag(componentsTag, "instrument");
if (instrument != null) {
instrument.putString("description", "");
}
final CompoundTag food = TagUtil.getNamespacedCompoundTag(componentsTag, "food");
if (food != null) {
final CompoundTag convertsTo = food.getCompoundTag("using_converts_to");
if (convertsTo != null) {
food.remove("using_converts_to");
componentsTag.put("minecraft:use_remainder", convertsTo);
}
food.remove("eat_seconds");
food.remove("effects");
}
TagUtil.removeNamespaced(componentsTag, "fire_resistant");
TagUtil.removeNamespaced(componentsTag, "lock");
}
public static void convertAttributes(final CompoundTag componentsTag, final FullMappings mappings) {
final CompoundTag attributeModifiers = TagUtil.getNamespacedCompoundTag(componentsTag, "attribute_modifiers");
if (attributeModifiers == null) {
return;
}
final ListTag<CompoundTag> modifiers = attributeModifiers.getListTag("modifiers", CompoundTag.class);
final Iterator<CompoundTag> iterator = modifiers.iterator();
while (iterator.hasNext()) {
final CompoundTag modifier = iterator.next();
final StringTag attribute = modifier.getStringTag("type");
final String mappedAttribute = mappings.mappedIdentifier(attribute.getValue());
if (mappedAttribute != null) {
attribute.setValue(mappedAttribute);
} else {
iterator.remove();
}
}
}
@Override
protected SerializerVersion inputSerializerVersion() {
return SerializerVersion.V1_20_5;
}
// Only cosmetic changes in the 1.21.2 serializer
}
@@ -0,0 +1,353 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_2;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_21;
import com.viaversion.viaversion.api.type.types.version.Types1_21_2;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
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.ClientVehicleStorage;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import java.util.concurrent.ThreadLocalRandom;
public final class EntityPacketRewriter1_21_2 extends EntityRewriter<ClientboundPacket1_21, Protocol1_21To1_21_2> {
private static final String[] GOAT_HORN_INSTRUMENTS = {
"ponder_goat_horn",
"sing_goat_horn",
"seek_goat_horn",
"feel_goat_horn",
"admire_goat_horn",
"call_goat_horn",
"yearn_goat_horn",
"dream_goat_horn"
};
private static final float IMPULSE = 0.98F;
public EntityPacketRewriter1_21_2(final Protocol1_21To1_21_2 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
registerTrackerWithData1_19(ClientboundPackets1_21.ADD_ENTITY, EntityTypes1_21_2.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21.SET_ENTITY_DATA, Types1_21.ENTITY_DATA_LIST, Types1_21_2.ENTITY_DATA_LIST);
registerRemoveEntities(ClientboundPackets1_21.REMOVE_ENTITIES);
protocol.registerFinishConfiguration(ClientboundConfigurationPackets1_21.FINISH_CONFIGURATION, wrapper -> {
final PacketWrapper instrumentsPacket = wrapper.create(ClientboundConfigurationPackets1_21.REGISTRY_DATA);
instrumentsPacket.write(Types.STRING, "minecraft:instrument");
final RegistryEntry[] entries = new RegistryEntry[GOAT_HORN_INSTRUMENTS.length];
for (int i = 0; i < GOAT_HORN_INSTRUMENTS.length; i++) {
final CompoundTag tag = new CompoundTag();
tag.putString("sound_event", "item.goat_horn.sound." + i);
tag.putFloat("use_duration", 7);
tag.putInt("range", 256);
tag.putString("description", "");
entries[i] = new RegistryEntry(GOAT_HORN_INSTRUMENTS[i], tag);
}
instrumentsPacket.write(Types.REGISTRY_ENTRY_ARRAY, entries);
instrumentsPacket.send(Protocol1_21To1_21_2.class);
});
final RegistryDataRewriter registryDataRewriter = registryDataRewriter();
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
protocol.registerClientbound(ClientboundPackets1_21.LOGIN, new PacketHandlers() {
@Override
public void register() {
map(Types.INT); // Entity id
map(Types.BOOLEAN); // Hardcore
map(Types.STRING_ARRAY); // World List
map(Types.VAR_INT); // Max players
map(Types.VAR_INT); // View distance
map(Types.VAR_INT); // Simulation distance
map(Types.BOOLEAN); // Reduced debug info
map(Types.BOOLEAN); // Show death screen
map(Types.BOOLEAN); // Limited crafting
map(Types.VAR_INT); // Dimension id
map(Types.STRING); // World
map(Types.LONG); // Seed
map(Types.BYTE); // Gamemode
map(Types.BYTE); // Previous gamemode
map(Types.BOOLEAN); // Debug
map(Types.BOOLEAN); // Flat
map(Types.OPTIONAL_GLOBAL_POSITION); // Last death location
map(Types.VAR_INT); // Portal cooldown
handler(worldDataTrackerHandlerByKey1_20_5(3));
handler(playerTrackerHandler());
create(Types.VAR_INT, 64); // Sea level, was hardcoded at 64 before
}
});
protocol.registerClientbound(ClientboundPackets1_21.RESPAWN, wrapper -> {
final int dimensionId = wrapper.passthrough(Types.VAR_INT);
final String world = wrapper.passthrough(Types.STRING);
wrapper.passthrough(Types.LONG); // Seed
wrapper.passthrough(Types.BYTE); // Gamemode
wrapper.passthrough(Types.BYTE); // Previous gamemode
wrapper.passthrough(Types.BOOLEAN); // Debug
wrapper.passthrough(Types.BOOLEAN); // Flat
wrapper.passthrough(Types.OPTIONAL_GLOBAL_POSITION); // Last death location
wrapper.passthrough(Types.VAR_INT); // Portal cooldown
wrapper.write(Types.VAR_INT, 64); // Sea level
trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world);
wrapper.user().remove(ClientVehicleStorage.class);
});
protocol.registerClientbound(ClientboundPackets1_21.PLAYER_POSITION, wrapper -> {
wrapper.write(Types.VAR_INT, 0); // Teleport id, set at the end
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
wrapper.write(Types.DOUBLE, 0D); // Delta movement X
wrapper.write(Types.DOUBLE, 0D); // Delta movement Y
wrapper.write(Types.DOUBLE, 0D); // Delta movement Z
wrapper.passthrough(Types.FLOAT); // Y rot
wrapper.passthrough(Types.FLOAT); // X rot
int relativeArguments = wrapper.read(Types.BYTE) & 0b00011111;
if ((relativeArguments & (1 << 0)) != 0) { // relative X
relativeArguments |= 1 << 5; // relative delta movement X
}
if ((relativeArguments & (1 << 1)) != 0) { // relative Y
relativeArguments |= 1 << 6; // relative delta movement Y
}
if ((relativeArguments & (1 << 2)) != 0) { // relative Z
relativeArguments |= 1 << 7; // relative delta movement Z
}
wrapper.write(Types.INT, relativeArguments);
final int teleportId = wrapper.read(Types.VAR_INT);
wrapper.set(Types.VAR_INT, 0, teleportId);
// Accept teleportation and player position were swapped.
// Send a ping first to then capture and send the player position the accept teleportation
final boolean isBundling = wrapper.user().get(BundleStateTracker.class).isBundling();
if (!isBundling) {
final PacketWrapper bundleStart = wrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER);
bundleStart.send(Protocol1_21To1_21_2.class);
}
final int pingId = ThreadLocalRandom.current().nextInt();
wrapper.user().get(PlayerPositionStorage.class).addPendingPong(pingId);
final PacketWrapper ping = wrapper.create(ClientboundPackets1_21_2.PING);
ping.write(Types.INT, pingId); // id
ping.send(Protocol1_21To1_21_2.class);
wrapper.send(Protocol1_21To1_21_2.class);
wrapper.cancel();
if (!isBundling) {
final PacketWrapper bundleEnd = wrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER);
bundleEnd.send(Protocol1_21To1_21_2.class);
}
});
protocol.registerClientbound(ClientboundPackets1_21.SET_PASSENGERS, wrapper -> {
final int vehicleId = wrapper.passthrough(Types.VAR_INT);
final int[] passengerIds = wrapper.passthrough(Types.VAR_INT_ARRAY_PRIMITIVE);
final ClientVehicleStorage storage = wrapper.user().get(ClientVehicleStorage.class);
if (storage != null && vehicleId == storage.vehicleId()) {
wrapper.user().remove(ClientVehicleStorage.class);
}
final int clientEntityId = tracker(wrapper.user()).clientEntityId();
for (final int passenger : passengerIds) {
if (passenger == clientEntityId) {
wrapper.user().put(new ClientVehicleStorage(vehicleId));
break;
}
}
});
protocol.appendClientbound(ClientboundPackets1_21.REMOVE_ENTITIES, wrapper -> {
final ClientVehicleStorage vehicleStorage = wrapper.user().get(ClientVehicleStorage.class);
if (vehicleStorage == null) {
return;
}
final int[] entityIds = wrapper.get(Types.VAR_INT_ARRAY_PRIMITIVE, 0);
for (final int entityId : entityIds) {
if (entityId == vehicleStorage.vehicleId()) {
wrapper.user().remove(ClientVehicleStorage.class);
break;
}
}
});
protocol.registerServerbound(ServerboundPackets1_21_2.PLAYER_INPUT, wrapper -> {
// Previously only used while in a vehicle, now always sent
// Filter them appropriately
if (!wrapper.user().has(ClientVehicleStorage.class)) {
wrapper.cancel();
return;
}
final byte flags = wrapper.read(Types.BYTE);
final boolean left = (flags & 1 << 2) != 0;
final boolean right = (flags & 1 << 3) != 0;
wrapper.write(Types.FLOAT, left ? IMPULSE : (right ? -IMPULSE : 0F));
final boolean forward = (flags & 1 << 0) != 0;
final boolean backward = (flags & 1 << 1) != 0;
wrapper.write(Types.FLOAT, forward ? IMPULSE : (backward ? -IMPULSE : 0F));
byte updatedFlags = 0;
if ((flags & 1 << 4) != 0) {
updatedFlags |= 1;
}
if ((flags & 1 << 5) != 0) {
updatedFlags |= 2;
}
wrapper.write(Types.BYTE, updatedFlags);
});
protocol.registerClientbound(ClientboundPackets1_21.TELEPORT_ENTITY, ClientboundPackets1_21_2.ENTITY_POSITION_SYNC, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
// Unused...
wrapper.write(Types.DOUBLE, 0D); // Delta movement X
wrapper.write(Types.DOUBLE, 0D); // Delta movement Y
wrapper.write(Types.DOUBLE, 0D); // Delta movement Z
// Unpack y and x rot
final byte yaw = wrapper.read(Types.BYTE);
final byte pitch = wrapper.read(Types.BYTE);
wrapper.write(Types.FLOAT, yaw * 360F / 256F);
wrapper.write(Types.FLOAT, pitch * 360F / 256F);
});
protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_POS, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
readOnGround(wrapper);
});
protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_POS_ROT, wrapper -> {
final double x = wrapper.passthrough(Types.DOUBLE); // X
final double y = wrapper.passthrough(Types.DOUBLE); // Y
final double z = wrapper.passthrough(Types.DOUBLE); // Z
final float yaw = wrapper.passthrough(Types.FLOAT); // Yaw
final float pitch = wrapper.passthrough(Types.FLOAT); // Pitch
readOnGround(wrapper);
final PlayerPositionStorage playerPositionStorage = wrapper.user().get(PlayerPositionStorage.class);
if (playerPositionStorage.checkCaptureNextPlayerPositionPacket()) {
// Capture this packet and send it after accept teleportation
final boolean onGround = wrapper.get(Types.BOOLEAN, 0);
playerPositionStorage.setPlayerPosition(new PlayerPositionStorage.PlayerPosition(x, y, z, yaw, pitch, onGround));
wrapper.cancel();
}
});
protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_ROT, wrapper -> {
wrapper.passthrough(Types.FLOAT); // Yaw
wrapper.passthrough(Types.FLOAT); // Pitch
readOnGround(wrapper);
});
protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_STATUS_ONLY, this::readOnGround);
protocol.registerServerbound(ServerboundPackets1_21_2.ACCEPT_TELEPORTATION, wrapper -> {
final PlayerPositionStorage playerPositionStorage = wrapper.user().get(PlayerPositionStorage.class);
if (playerPositionStorage.checkHasPlayerPosition()) {
// Send move player after accept teleportation
wrapper.sendToServer(Protocol1_21To1_21_2.class);
wrapper.cancel();
playerPositionStorage.sendMovePlayerPosRot(wrapper.user());
}
});
}
private RegistryDataRewriter registryDataRewriter() {
final CompoundTag enderpearlData = new CompoundTag();
enderpearlData.putString("scaling", "when_caused_by_living_non_player");
enderpearlData.putString("message_id", "fall");
enderpearlData.putFloat("exhaustion", 0.0F);
final CompoundTag maceSmashData = new CompoundTag();
maceSmashData.putString("scaling", "when_caused_by_living_non_player");
maceSmashData.putString("message_id", "mace_smash");
maceSmashData.putFloat("exhaustion", 0.1F);
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
registryDataRewriter.addEntries(
"damage_type",
new RegistryEntry("minecraft:ender_pearl", enderpearlData),
new RegistryEntry("minecraft:mace_smash", maceSmashData)
);
registryDataRewriter.addEnchantmentEffectRewriter("damage_item", tag -> tag.putString("type", "change_item_damage"));
return registryDataRewriter;
}
private void readOnGround(final PacketWrapper wrapper) {
final short data = wrapper.read(Types.UNSIGNED_BYTE);
wrapper.write(Types.BOOLEAN, (data & 1) != 0); // On ground, ignoring horizontal collision data
}
@Override
protected void registerRewrites() {
filter().mapDataType(Types1_21_2.ENTITY_DATA_TYPES::byId);
registerEntityDataTypeHandler(
Types1_21_2.ENTITY_DATA_TYPES.itemType,
Types1_21_2.ENTITY_DATA_TYPES.blockStateType,
Types1_21_2.ENTITY_DATA_TYPES.optionalBlockStateType,
Types1_21_2.ENTITY_DATA_TYPES.particleType,
Types1_21_2.ENTITY_DATA_TYPES.particlesType,
Types1_21_2.ENTITY_DATA_TYPES.componentType,
Types1_21_2.ENTITY_DATA_TYPES.optionalComponentType
);
registerBlockStateHandler(EntityTypes1_21_2.ABSTRACT_MINECART, 11);
filter().type(EntityTypes1_21_2.ABSTRACT_BOAT).removeIndex(11); // Goodbye boat type
filter().type(EntityTypes1_21_2.SALMON).addIndex(17); // Data type
filter().type(EntityTypes1_21_2.AGEABLE_WATER_CREATURE).addIndex(16); // Baby
filter().type(EntityTypes1_21_2.ABSTRACT_ARROW).addIndex(10); // In ground
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_2.getTypeFromId(type);
}
@Override
public void onMappingDataLoaded() {
mapTypes();
}
}
@@ -0,0 +1,346 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.rewriter;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.version.Types1_21_2;
import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter.RecipeRewriter1_20_3;
import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21;
import com.viaversion.viaversion.util.Key;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
// Use directly as a connection storage. Slightly weird, but easiest and closed off from other packages
final class RecipeRewriter1_21_2 extends RecipeRewriter1_20_3<ClientboundPacket1_21> implements StorableObject {
private static final int[] EMPTY_ARRAY = new int[0];
private final List<StoneCutterRecipe> stoneCutterRecipes = new ArrayList<>();
private final Object2IntMap<String> recipeGroups = new Object2IntOpenHashMap<>();
private final Map<String, Recipe> recipesByKey = new HashMap<>();
private final Map<String, IntSet> recipeInputs = new Object2ObjectArrayMap<>();
private final List<Recipe> recipes = new ArrayList<>();
private String currentRecipeIdentifier;
public void setCurrentRecipeIdentifier(final String recipeIdentifier) {
this.currentRecipeIdentifier = Key.stripMinecraftNamespace(recipeIdentifier);
}
RecipeRewriter1_21_2(final Protocol<ClientboundPacket1_21, ?, ?, ?> protocol) {
super(protocol);
recipeGroups.defaultReturnValue(-1);
recipeHandlers.put("smelting", wrapper -> handleSmelting("furnace_input", wrapper));
recipeHandlers.put("blasting", wrapper -> handleSmelting("blast_furnace_input", wrapper));
recipeHandlers.put("smoking", wrapper -> handleSmelting("smoker_input", wrapper));
recipeHandlers.put("campfire_cooking", wrapper -> handleSmelting("campfire_input", wrapper));
}
@Override
public void handleSimpleRecipe(final PacketWrapper wrapper) {
final int category = wrapper.read(Types.VAR_INT);
// Special recipes aren't sent to the client
}
@Override
public void handleStonecutting(final PacketWrapper wrapper) {
final int group = readRecipeGroup(wrapper);
final Item[] ingredient = readIngredient(wrapper);
final Item result = rewrite(wrapper.user(), wrapper.read(itemType()));
final StoneCutterRecipe recipe = new StoneCutterRecipe(currentRecipeIdentifier, group, ingredient, result);
stoneCutterRecipes.add(recipe); // Sent separately in update_recipes
}
private void addRecipe(final Recipe recipe) {
recipes.add(recipe);
recipesByKey.put(currentRecipeIdentifier, recipe);
}
@Override
public void handleSmithingTransform(final PacketWrapper wrapper) {
readRecipeInputs("smithing_template", wrapper);
readRecipeInputs("smithing_base", wrapper);
readRecipeInputs("smithing_addition", wrapper);
wrapper.read(itemType()); // Result
}
@Override
public void handleSmithingTrim(final PacketWrapper wrapper) {
readRecipeInputs("smithing_template", wrapper);
readRecipeInputs("smithing_base", wrapper);
readRecipeInputs("smithing_addition", wrapper);
}
@Override
public void handleCraftingShaped(final PacketWrapper wrapper) {
final int group = readRecipeGroup(wrapper);
final int category = wrapper.read(Types.VAR_INT);
final int width = wrapper.read(Types.VAR_INT);
final int height = wrapper.read(Types.VAR_INT);
final int ingredientsSize = width * height;
final Item[][] ingredients = new Item[ingredientsSize][];
for (int i = 0; i < ingredientsSize; i++) {
ingredients[i] = readIngredient(wrapper);
}
final Item result = rewrite(wrapper.user(), wrapper.read(itemType()));
final boolean showNotification = wrapper.read(Types.BOOLEAN);
final ShapedRecipe recipe = new ShapedRecipe(recipesByKey.size(), currentRecipeIdentifier, group, category, width, height, ingredients, result, showNotification);
addRecipe(recipe);
}
@Override
public void handleCraftingShapeless(final PacketWrapper wrapper) {
final int group = readRecipeGroup(wrapper);
final int category = wrapper.read(Types.VAR_INT);
final int ingredientsSize = wrapper.read(Types.VAR_INT);
final Item[][] ingredients = new Item[ingredientsSize][];
for (int i = 0; i < ingredientsSize; i++) {
ingredients[i] = readIngredient(wrapper);
}
final Item result = rewrite(wrapper.user(), wrapper.read(itemType()));
final ShapelessRecipe recipe = new ShapelessRecipe(recipesByKey.size(), currentRecipeIdentifier, group, category, ingredients, result);
addRecipe(recipe);
}
public void handleSmelting(final String key, final PacketWrapper wrapper) {
final int group = readRecipeGroup(wrapper);
final int category = wrapper.read(Types.VAR_INT);
final Item[] ingredient = readRecipeInputs(key, wrapper);
final Item result = rewrite(wrapper.user(), wrapper.read(itemType()));
final float experience = wrapper.read(Types.FLOAT);
final int cookingTime = wrapper.read(Types.VAR_INT);
final FurnaceRecipe recipe = new FurnaceRecipe(recipesByKey.size(), currentRecipeIdentifier, group, category, ingredient, result, cookingTime, experience);
addRecipe(recipe);
}
private int readRecipeGroup(final PacketWrapper wrapper) {
final String recipeGroup = Key.stripMinecraftNamespace(wrapper.read(Types.STRING));
if (recipeGroup.isEmpty()) {
return -1;
}
if (recipeGroups.containsKey(recipeGroup)) {
return recipeGroups.getInt(recipeGroup);
}
final int size = recipeGroups.size();
recipeGroups.put(recipeGroup, size);
return size;
}
private Item[] readIngredient(final PacketWrapper wrapper) {
final Item[] items = wrapper.read(itemArrayType());
for (int i = 0; i < items.length; i++) {
final Item item = items[i];
items[i] = rewrite(wrapper.user(), item);
}
return items;
}
public HolderSet toHolderSet(final Item[] ingredient) {
// Ingredients are no longer full items, already store them as just holder sets
final int[] ids = new int[ingredient.length];
for (int i = 0; i < ingredient.length; i++) {
ids[i] = ingredient[i].identifier();
}
return HolderSet.of(ids);
}
public @Nullable Recipe recipe(final String key) {
return recipesByKey.get(Key.stripMinecraftNamespace(key));
}
public @Nullable Recipe recipe(final int displayId) {
return displayId >= 0 && displayId < recipes.size() ? recipes.get(displayId) : null;
}
public void finalizeRecipes() {
// Need to be sorted alphabetically
stoneCutterRecipes.sort(Comparator.comparing(recipe -> recipe.identifier));
}
public void writeUpdateRecipeInputs(final PacketWrapper wrapper) {
// Smithing and smelting inputs
wrapper.write(Types.VAR_INT, recipeInputs.size());
for (final Map.Entry<String, IntSet> entry : recipeInputs.entrySet()) {
wrapper.write(Types.STRING, entry.getKey());
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, entry.getValue().toArray(EMPTY_ARRAY));
}
// Stonecutter recipes
wrapper.write(Types.VAR_INT, stoneCutterRecipes.size());
for (final StoneCutterRecipe recipe : stoneCutterRecipes) {
final HolderSet ingredient = toHolderSet(recipe.ingredient());
wrapper.write(Types.HOLDER_SET, ingredient);
writeItemDisplay(wrapper, recipe.result());
}
}
private Item[] readRecipeInputs(final String key, final PacketWrapper wrapper) {
// Collect inputs for new UPDATE_RECIPE
final Item[] ingredient = readIngredient(wrapper);
final IntSet ids = recipeInputs.computeIfAbsent(key, $ -> new IntOpenHashSet(ingredient.length));
for (final Item item : ingredient) {
ids.add(item.identifier());
}
return ingredient;
}
interface Recipe {
int SLOT_DISPLAY_EMPTY = 0;
int SLOT_DISPLAY_ANY_FUEL = 1;
int SLOT_DISPLAY_ITEM = 3;
int SLOT_DISPLAY_COMPOSITE = 7;
int index();
String identifier();
int recipeDisplayId();
default Item @Nullable [][] ingredients() {
final Item[] ingredient = ingredient();
return ingredient == null ? null : new Item[][]{ingredient};
}
default Item @Nullable [] ingredient() {
return null;
}
default int group() {
return -1;
}
default boolean showNotification() {
return true;
}
int category();
void writeRecipeDisplay(PacketWrapper wrapper);
}
record ShapelessRecipe(int index, String identifier, int group, int category, Item[][] ingredients,
Item result) implements Recipe {
@Override
public int recipeDisplayId() {
return 0;
}
@Override
public void writeRecipeDisplay(final PacketWrapper wrapper) {
writeIngredientsDisplay(wrapper, ingredients);
writeItemDisplay(wrapper, result);
writeCraftingStationDisplay(wrapper);
}
}
record ShapedRecipe(int index, String identifier, int group, int category, int width, int height,
Item[][] ingredients, Item result, boolean showNotification) implements Recipe {
@Override
public int recipeDisplayId() {
return 1;
}
@Override
public void writeRecipeDisplay(final PacketWrapper wrapper) {
wrapper.write(Types.VAR_INT, width);
wrapper.write(Types.VAR_INT, height);
writeIngredientsDisplay(wrapper, ingredients);
writeItemDisplay(wrapper, result);
writeCraftingStationDisplay(wrapper);
}
}
record FurnaceRecipe(int index, String identifier, int group, int category, Item[] ingredient,
Item result, int duration, float experience) implements Recipe {
@Override
public int recipeDisplayId() {
return 2;
}
@Override
public void writeRecipeDisplay(final PacketWrapper wrapper) {
writeIngredientDisplay(wrapper, ingredient);
wrapper.write(Types.VAR_INT, SLOT_DISPLAY_ANY_FUEL); // Fuel
writeItemDisplay(wrapper, result);
writeCraftingStationDisplay(wrapper);
wrapper.write(Types.VAR_INT, duration);
wrapper.write(Types.FLOAT, experience);
}
}
record StoneCutterRecipe(String identifier, int group, Item[] ingredient, Item result) {
public int recipeDisplayId() {
return 3;
}
public void writeRecipeDisplay(final PacketWrapper wrapper) {
writeIngredientDisplay(wrapper, ingredient);
writeItemDisplay(wrapper, result);
writeCraftingStationDisplay(wrapper);
}
}
private static void writeIngredientsDisplay(final PacketWrapper wrapper, final Item[][] ingredients) {
wrapper.write(Types.VAR_INT, ingredients.length);
for (final Item[] ingredient : ingredients) {
writeIngredientDisplay(wrapper, ingredient);
}
}
private static void writeIngredientDisplay(final PacketWrapper wrapper, final Item[] ingredient) {
if (ingredient.length == 0) {
wrapper.write(Types.VAR_INT, Recipe.SLOT_DISPLAY_EMPTY);
return;
}
wrapper.write(Types.VAR_INT, Recipe.SLOT_DISPLAY_COMPOSITE);
wrapper.write(Types.VAR_INT, ingredient.length);
for (final Item item : ingredient) {
writeItemDisplay(wrapper, item);
}
}
private static void writeItemDisplay(final PacketWrapper wrapper, final Item item) {
wrapper.write(Types.VAR_INT, Recipe.SLOT_DISPLAY_ITEM);
wrapper.write(Types1_21_2.ITEM, item.copy());
}
private static void writeCraftingStationDisplay(final PacketWrapper wrapper) {
wrapper.write(Types.VAR_INT, Recipe.SLOT_DISPLAY_EMPTY);
}
}
@@ -0,0 +1,34 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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 class BundleStateTracker implements StorableObject {
private boolean bundling;
public boolean isBundling() {
return this.bundling;
}
public void toggleBundling() {
this.bundling = !this.bundling;
}
}
@@ -0,0 +1,23 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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 record ClientVehicleStorage(int vehicleId) implements StorableObject {
}
@@ -0,0 +1,94 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
public class PlayerPositionStorage implements StorableObject {
private final IntSet pendingPongs = new IntOpenHashSet();
private boolean captureNextPlayerPositionPacket;
private PlayerPosition playerPosition;
public void addPendingPong(final int id) {
if (!this.pendingPongs.add(id)) {
throw new IllegalStateException("Pong already pending for id " + id);
}
}
public boolean checkPong(final int id) {
if (this.pendingPongs.remove(id)) {
this.reset(); // Ensure we don't have any leftover state
this.captureNextPlayerPositionPacket = true;
return true;
} else {
return false;
}
}
public boolean checkCaptureNextPlayerPositionPacket() {
if (this.captureNextPlayerPositionPacket) {
this.captureNextPlayerPositionPacket = false;
return true;
} else { // Packet order was wrong
this.reset();
return false;
}
}
public void setPlayerPosition(final PlayerPosition playerPosition) {
this.playerPosition = playerPosition;
}
public boolean checkHasPlayerPosition() {
if (this.playerPosition != null) {
return true;
} else { // Packet order was wrong (ACCEPT_TELEPORTATION before MOVE_PLAYER_POS_ROT packet)
this.reset();
return false;
}
}
public void sendMovePlayerPosRot(final UserConnection user) {
final PacketWrapper movePlayerPosRot = PacketWrapper.create(ServerboundPackets1_20_5.MOVE_PLAYER_POS_ROT, user);
movePlayerPosRot.write(Types.DOUBLE, this.playerPosition.x); // X
movePlayerPosRot.write(Types.DOUBLE, this.playerPosition.y); // Y
movePlayerPosRot.write(Types.DOUBLE, this.playerPosition.z); // Z
movePlayerPosRot.write(Types.FLOAT, this.playerPosition.yaw); // Yaw
movePlayerPosRot.write(Types.FLOAT, this.playerPosition.pitch); // Pitch
movePlayerPosRot.write(Types.BOOLEAN, this.playerPosition.onGround); // On Ground
movePlayerPosRot.sendToServer(Protocol1_21To1_21_2.class);
this.reset();
}
private void reset() {
this.captureNextPlayerPositionPacket = false;
this.playerPosition = null;
}
public record PlayerPosition(double x, double y, double z, float yaw, float pitch, boolean onGround) {
}
}
@@ -36,7 +36,6 @@ import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPacke
import com.viaversion.viaversion.protocols.v1_9_3to1_10.rewriter.ItemPacketRewriter1_10;
import com.viaversion.viaversion.protocols.v1_9_3to1_10.storage.ResourcePackTracker;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_3, ClientboundPackets1_9_3, ServerboundPackets1_9_3, ServerboundPackets1_9_3> {
@@ -49,12 +48,12 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol<ClientboundPackets1_9_
public static final ValueTransformer<List<EntityData>, List<EntityData>> TRANSFORM_ENTITY_DATA = new ValueTransformer<>(Types1_9.ENTITY_DATA_LIST) {
@Override
public List<EntityData> transform(PacketWrapper wrapper, List<EntityData> inputValue) {
List<EntityData> dataList = new CopyOnWriteArrayList<>(inputValue);
for (EntityData data : dataList) {
if (data.id() >= 5)
for (EntityData data : inputValue) {
if (data.id() >= 5) {
data.setId(data.id() + 1);
}
}
return dataList;
return inputValue;
}
};
private final ItemPacketRewriter1_10 itemRewriter = new ItemPacketRewriter1_10(this);
@@ -142,10 +142,11 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
public void registerPlayerInfoUpdate1_20_3(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM);
final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM1_19_3);
if (!actions.get(5)) { // Update display name
return;
}
final int entries = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Types.UUID);
@@ -177,6 +178,49 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
});
}
public void registerPlayerInfoUpdate1_21_2(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM1_21_2);
if (!actions.get(5)) { // Update display name
return;
}
final int entries = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Types.UUID);
if (actions.get(0)) {
wrapper.passthrough(Types.STRING); // Player Name
final int properties = wrapper.passthrough(Types.VAR_INT);
for (int j = 0; j < properties; j++) {
wrapper.passthrough(Types.STRING); // Name
wrapper.passthrough(Types.STRING); // Value
wrapper.passthrough(Types.OPTIONAL_STRING); // Signature
}
}
if (actions.get(1) && wrapper.passthrough(Types.BOOLEAN)) {
wrapper.passthrough(Types.UUID); // Session UUID
wrapper.passthrough(Types.PROFILE_KEY);
}
if (actions.get(2)) {
wrapper.passthrough(Types.VAR_INT); // Gamemode
}
if (actions.get(3)) {
wrapper.passthrough(Types.BOOLEAN); // Listed
}
if (actions.get(4)) {
wrapper.passthrough(Types.VAR_INT); // Latency
}
processTag(wrapper.user(), wrapper.passthrough(Types.OPTIONAL_TAG));
if (actions.get(6)) {
wrapper.passthrough(Types.VAR_INT); // List order
}
}
});
}
public void registerPlayerCombatKill(final C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
@@ -359,6 +403,10 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
final CompoundTag componentsTag = contentsTag.getCompoundTag("components");
handleShowItem(connection, contentsTag, componentsTag);
if (componentsTag != null) {
final CompoundTag useRemainder = TagUtil.getNamespacedCompoundTag(componentsTag, "use_remainder");
if (useRemainder != null) {
handleShowItem(connection, useRemainder);
}
handleContainerContents(connection, componentsTag);
if (inputSerializerVersion() != null) {
handleWrittenBookContents(connection, componentsTag);
@@ -370,6 +418,10 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
}
}
protected final void handleShowItem(final UserConnection connection, final CompoundTag itemTag) {
handleShowItem(connection, itemTag, itemTag.getCompoundTag("components"));
}
protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, @Nullable final CompoundTag componentsTag) {
final StringTag idTag = itemTag.getStringTag("id");
final String mappedId = protocol.getMappingData().getFullItemMappings().mappedIdentifier(idTag.getValue());
@@ -385,8 +437,7 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
}
for (final CompoundTag entryTag : container) {
final CompoundTag itemTag = entryTag.getCompoundTag("item");
handleShowItem(connection, itemTag, itemTag.getCompoundTag("components"));
handleShowItem(connection, entryTag.getCompoundTag("item"));
}
}
@@ -435,16 +486,16 @@ public class ComponentRewriter<C extends ClientboundPacketType> implements com.v
}
}
protected SerializerVersion inputSerializerVersion() {
protected @Nullable SerializerVersion inputSerializerVersion() {
return null;
}
protected SerializerVersion outputSerializerVersion() {
return null;
protected @Nullable SerializerVersion outputSerializerVersion() {
return inputSerializerVersion(); // Only matters if the nbt serializer changed
}
private void convertLegacyContents(final CompoundTag hoverEvent) {
if (inputSerializerVersion() == null || outputSerializerVersion() == null) {
if (inputSerializerVersion() == null) {
return;
}
@@ -35,12 +35,10 @@ import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
@@ -235,8 +233,10 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
rewriteParticle(event.user(), particle);
}
} else if (type == componentType || type == optionalComponentType) {
final Tag component = data.value();
protocol.getComponentRewriter().processTag(event.user(), component);
if (protocol.getComponentRewriter() != null) {
final Tag component = data.value();
protocol.getComponentRewriter().processTag(event.user(), component);
}
}
});
}
@@ -589,21 +589,17 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
}
public void rewriteParticle(UserConnection connection, Particle particle) {
if (protocol.getItemRewriter() != null) {
protocol.getItemRewriter().rewriteParticle(connection, particle);
return;
}
// Dupe parts of the logic if no item rewriter is available
ParticleMappings mappings = protocol.getMappingData().getParticleMappings();
int id = particle.id();
if (mappings.isBlockParticle(id)) {
Particle.ParticleData<Integer> data = particle.getArgument(0);
data.setValue(protocol.getMappingData().getNewBlockStateId(data.getValue()));
} else if (mappings.isItemParticle(id) && protocol.getItemRewriter() != null) {
Particle.ParticleData<Item> data = particle.getArgument(0);
ItemRewriter<?> itemRewriter = protocol.getItemRewriter();
Item item = itemRewriter.handleItemToClient(connection, data.getValue());
if (itemRewriter.mappedItemType() != null && itemRewriter.itemType() != itemRewriter.mappedItemType()) {
// Replace the type
particle.set(0, itemRewriter.mappedItemType(), item);
} else {
data.setValue(item);
}
}
particle.setId(protocol.getMappingData().getNewParticleId(id));
@@ -20,6 +20,7 @@ package com.viaversion.viaversion.rewriter;
import com.google.gson.JsonElement;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.data.Mappings;
import com.viaversion.viaversion.api.data.ParticleMappings;
import com.viaversion.viaversion.api.minecraft.Particle;
@@ -105,30 +106,30 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
}
public void registerSetContent1_17_1(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // Window id
map(Types.VAR_INT); // State id
handler(wrapper -> {
Item[] items = wrapper.passthroughAndMap(itemArrayType, mappedItemArrayType);
for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(wrapper.user(), items[i]);
}
registerSetContent1_17_1(packetType, Types.UNSIGNED_BYTE);
}
handleClientboundItem(wrapper);
});
public void registerSetContent1_21_2(C packetType) {
registerSetContent1_17_1(packetType, Types.VAR_INT);
}
private void registerSetContent1_17_1(C packetType, Type<? extends Number> containerIdType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(containerIdType); // Container id
wrapper.passthrough(Types.VAR_INT); // State id
Item[] items = wrapper.passthroughAndMap(itemArrayType, mappedItemArrayType);
for (int i = 0; i < items.length; i++) {
items[i] = handleItemToClient(wrapper.user(), items[i]);
}
passthroughClientboundItem(wrapper);
});
}
public void registerOpenScreen(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.VAR_INT); // Container id
handler(wrapper -> handleMenuType(wrapper));
}
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Container id
handleMenuType(wrapper);
});
}
@@ -147,22 +148,27 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // Window id
map(Types.UNSIGNED_BYTE); // Container id
map(Types.SHORT); // Slot id
handler(wrapper -> handleClientboundItem(wrapper));
handler(wrapper -> passthroughClientboundItem(wrapper));
}
});
}
public void registerSetSlot1_17_1(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // Window id
map(Types.VAR_INT); // State id
map(Types.SHORT); // Slot id
handler(wrapper -> handleClientboundItem(wrapper));
}
registerSetSlot1_17_1(packetType, Types.UNSIGNED_BYTE);
}
public void registerSetSlot1_21_2(C packetType) {
registerSetSlot1_17_1(packetType, Types.VAR_INT);
}
private void registerSetSlot1_17_1(C packetType, Type<? extends Number> containerIdType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(containerIdType); // Container id
wrapper.passthrough(Types.VAR_INT); // State id
wrapper.passthrough(Types.SHORT); // Slot id
passthroughClientboundItem(wrapper);
});
}
@@ -173,7 +179,7 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
public void register() {
map(Types.VAR_INT); // Entity ID
map(Types.VAR_INT); // Slot ID
handler(wrapper -> handleClientboundItem(wrapper));
handler(wrapper -> passthroughClientboundItem(wrapper));
}
});
}
@@ -190,7 +196,7 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
do {
slot = wrapper.passthrough(Types.BYTE);
// & 0x7F into an extra variable if slot is needed
handleClientboundItem(wrapper);
passthroughClientboundItem(wrapper);
} while (slot < 0);
});
}
@@ -202,7 +208,7 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
@Override
public void register() {
map(Types.SHORT); // 0 - Slot
handler(wrapper -> handleServerboundItem(wrapper));
handler(wrapper -> passthroughServerboundItem(wrapper));
}
});
}
@@ -211,38 +217,41 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
protocol.registerServerbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // 0 - Window ID
map(Types.UNSIGNED_BYTE); // 0 - Container ID
map(Types.SHORT); // 1 - Slot
map(Types.BYTE); // 2 - Button
map(Types.SHORT); // 3 - Action number
map(Types.VAR_INT); // 4 - Mode
handler(wrapper -> handleServerboundItem(wrapper));
handler(wrapper -> passthroughServerboundItem(wrapper));
}
});
}
public void registerContainerClick1_17_1(S packetType) {
protocol.registerServerbound(packetType, new PacketHandlers() {
@Override
public void register() {
map(Types.UNSIGNED_BYTE); // Window Id
map(Types.VAR_INT); // State id
map(Types.SHORT); // Slot
map(Types.BYTE); // Button
map(Types.VAR_INT); // Mode
registerContainerClick1_17_1(packetType, Types.UNSIGNED_BYTE);
}
handler(wrapper -> {
// Affected items
int length = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < length; i++) {
wrapper.passthrough(Types.SHORT); // Slot
handleServerboundItem(wrapper);
}
public void registerContainerClick1_21_2(S packetType) {
registerContainerClick1_17_1(packetType, Types.VAR_INT);
}
// Carried item
handleServerboundItem(wrapper);
});
public void registerContainerClick1_17_1(S packetType, Type<? extends Number> containerIdType) {
protocol.registerServerbound(packetType, wrapper -> {
wrapper.passthrough(containerIdType); // Container id
wrapper.passthrough(Types.VAR_INT); // State id
wrapper.passthrough(Types.SHORT); // Slot
wrapper.passthrough(Types.BYTE); // Button
wrapper.passthrough(Types.VAR_INT); // Mode
// Affected items
final int length = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < length; i++) {
wrapper.passthrough(Types.SHORT); // Slot
passthroughServerboundItem(wrapper);
}
// Carried item
passthroughServerboundItem(wrapper);
});
}
@@ -253,6 +262,15 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
});
}
public void registerCooldown1_21_2(C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
String itemIdentifier = wrapper.read(Types.OPTIONAL_STRING);
if (itemIdentifier != null) {
itemIdentifier = mappedIdentifier(protocol.getMappingData().getFullItemMappings(), itemIdentifier);
}
wrapper.write(Types.OPTIONAL_STRING, itemIdentifier);
});
}
public void registerCustomPayloadTradeList(C packetType) {
protocol.registerClientbound(packetType, new PacketHandlers() {
@@ -274,11 +292,11 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
final int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
handleClientboundItem(wrapper); // Input Item
handleClientboundItem(wrapper); // Output Item
passthroughClientboundItem(wrapper); // Input Item
passthroughClientboundItem(wrapper); // Output Item
if (wrapper.passthrough(Types.BOOLEAN)) {
handleClientboundItem(wrapper); // Second Item
passthroughClientboundItem(wrapper); // Second Item
}
wrapper.passthrough(Types.BOOLEAN); // Trade disabled
@@ -294,11 +312,11 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
wrapper.passthrough(Types.VAR_INT);
int size = wrapper.passthrough(Types.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
handleClientboundItem(wrapper); // Input
handleClientboundItem(wrapper); // Output
passthroughClientboundItem(wrapper); // Input
passthroughClientboundItem(wrapper); // Output
if (wrapper.passthrough(Types.BOOLEAN)) { // Has second item
handleClientboundItem(wrapper); // Second item
passthroughClientboundItem(wrapper); // Second item
}
wrapper.passthrough(Types.BOOLEAN); // Trade disabled
@@ -319,9 +337,9 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
wrapper.passthrough(Types.VAR_INT); // Container id
int size = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < size; i++) {
handleClientboundItem(wrapper); // Input
handleClientboundItem(wrapper); // Output
handleClientboundItem(wrapper); // Second item
passthroughClientboundItem(wrapper); // Input
passthroughClientboundItem(wrapper); // Output
passthroughClientboundItem(wrapper); // Second item
wrapper.passthrough(Types.BOOLEAN); // Trade disabled
wrapper.passthrough(Types.INT); // Number of tools uses
@@ -344,7 +362,7 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
final Item input = wrapper.read(itemCostType);
wrapper.write(mappedItemCostType, handleItemToClient(wrapper.user(), input));
handleClientboundItem(wrapper); // Result
passthroughClientboundItem(wrapper); // Result
Item secondInput = wrapper.read(optionalItemCostType);
if (secondInput != null) {
@@ -382,7 +400,7 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
componentRewriter.processText(wrapper.user(), description);
}
handleClientboundItem(wrapper); // Icon
passthroughClientboundItem(wrapper); // Icon
wrapper.passthrough(Types.VAR_INT); // Frame type
int flags = wrapper.passthrough(Types.INT); // Flags
if ((flags & 1) != 0) {
@@ -420,7 +438,7 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
componentRewriter.processTag(wrapper.user(), description);
}
handleClientboundItem(wrapper); // Icon
passthroughClientboundItem(wrapper); // Icon
wrapper.passthrough(Types.VAR_INT); // Frame type
int flags = wrapper.passthrough(Types.INT); // Flags
if ((flags & 1) != 0) {
@@ -549,6 +567,24 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
});
}
public void registerExplosion1_21_2(C packetType) {
final SoundRewriter<C> soundRewriter = new SoundRewriter<>(protocol);
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
wrapper.passthrough(Types.DOUBLE); // Knockback X
wrapper.passthrough(Types.DOUBLE); // Knockback Y
wrapper.passthrough(Types.DOUBLE); // Knockback Z
final Particle explosionParticle = wrapper.read(particleType);
wrapper.write(mappedParticleType, explosionParticle);
rewriteParticle(wrapper.user(), explosionParticle);
soundRewriter.soundHolderHandler().handle(wrapper);
});
}
public PacketHandler levelParticlesHandler() {
return levelParticlesHandler(Types.INT);
}
@@ -565,7 +601,7 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
int data = wrapper.read(Types.VAR_INT);
wrapper.write(Types.VAR_INT, protocol.getMappingData().getNewBlockStateId(data));
} else if (mappings.isItemParticle(id)) {
handleClientboundItem(wrapper);
passthroughClientboundItem(wrapper);
}
int mappedId = protocol.getMappingData().getNewParticleId(id);
@@ -575,17 +611,18 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
};
}
private void handleClientboundItem(final PacketWrapper wrapper) {
protected void passthroughClientboundItem(final PacketWrapper wrapper) {
final Item item = handleItemToClient(wrapper.user(), wrapper.read(itemType));
wrapper.write(mappedItemType, item);
}
private void handleServerboundItem(final PacketWrapper wrapper) {
protected void passthroughServerboundItem(final PacketWrapper wrapper) {
final Item item = handleItemToServer(wrapper.user(), wrapper.read(mappedItemType));
wrapper.write(itemType, item);
}
protected void rewriteParticle(UserConnection connection, Particle particle) {
@Override
public void rewriteParticle(UserConnection connection, Particle particle) {
ParticleMappings mappings = protocol.getMappingData().getParticleMappings();
int id = particle.id();
if (mappings.isBlockParticle(id)) {
@@ -605,6 +642,21 @@ public class ItemRewriter<C extends ClientboundPacketType, S extends Serverbound
particle.setId(protocol.getMappingData().getNewParticleId(id));
}
protected @Nullable String mappedIdentifier(final FullMappings mappings, final String identifier) {
// Check if the original exists before mapping
if (mappings.id(identifier) == -1) {
return identifier;
}
return mappings.mappedIdentifier(identifier);
}
protected @Nullable String unmappedIdentifier(final FullMappings mappings, final String mappedIdentifier) {
if (mappings.mappedId(mappedIdentifier) == -1) {
return mappedIdentifier;
}
return mappings.identifier(mappedIdentifier);
}
@Override
public Type<Item> itemType() {
return itemType;
@@ -0,0 +1,192 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.rewriter;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
import com.viaversion.viaversion.api.type.Types;
// Base for 1.21.2 and onwards
public class RecipeDisplayRewriter<C extends ClientboundPacketType> {
protected final Protocol<C, ?, ?, ?> protocol;
public RecipeDisplayRewriter(final Protocol<C, ?, ?, ?> protocol) {
this.protocol = protocol;
}
public void registerUpdateRecipes(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
final int size = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < size; i++) {
wrapper.passthrough(Types.STRING); // Recipe group
rewriteItemIds(wrapper.passthrough(Types.VAR_INT_ARRAY_PRIMITIVE));
}
final int stonecutterRecipesSize = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < stonecutterRecipesSize; i++) {
handleIngredient(wrapper);
handleSlotDisplay(wrapper);
}
});
}
public void registerRecipeBookAdd(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
final int size = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < size; i++) {
wrapper.passthrough(Types.VAR_INT); // Display ID
handleRecipeDisplay(wrapper);
wrapper.passthrough(Types.OPTIONAL_VAR_INT); // Group
wrapper.passthrough(Types.VAR_INT); // Category
if (wrapper.passthrough(Types.BOOLEAN)) {
final int ingredientsSize = wrapper.passthrough(Types.VAR_INT);
for (int j = 0; j < ingredientsSize; j++) {
handleIngredient(wrapper); // Items
}
}
wrapper.passthrough(Types.BYTE); // Flags
}
});
}
public void registerPlaceGhostRecipe(final C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Container ID
handleRecipeDisplay(wrapper);
});
}
protected void handleShapeless(final PacketWrapper wrapper) {
handleSlotDisplayList(wrapper); // Ingredients
handleSlotDisplay(wrapper); // Result
handleSlotDisplay(wrapper); // Crafting station
}
protected void handleShaped(final PacketWrapper wrapper) {
wrapper.passthrough(Types.VAR_INT); // Width
wrapper.passthrough(Types.VAR_INT); // Height
handleSlotDisplayList(wrapper); // Ingredients
handleSlotDisplay(wrapper); // Result
handleSlotDisplay(wrapper); // Crafting station
}
protected void handleFurnace(final PacketWrapper wrapper) {
handleSlotDisplay(wrapper); // Ingredient
handleSlotDisplay(wrapper); // Fuel
handleSlotDisplay(wrapper); // Result
handleSlotDisplay(wrapper); // Crafting station
}
protected void handleStoneCutter(final PacketWrapper wrapper) {
handleSlotDisplay(wrapper); // Input
handleSlotDisplay(wrapper); // Result
handleSlotDisplay(wrapper); // Crafting station
}
protected void handleSmithing(final PacketWrapper wrapper) {
handleSlotDisplay(wrapper); // Template
handleSlotDisplay(wrapper); // Base
handleSlotDisplay(wrapper); // Addition
handleSlotDisplay(wrapper); // Result
handleSlotDisplay(wrapper); // Crafting station
}
protected void handleRecipeDisplay(final PacketWrapper wrapper) {
final int type = wrapper.passthrough(Types.VAR_INT);
switch (type) {
case 0 -> handleShapeless(wrapper);
case 1 -> handleShaped(wrapper);
case 2 -> handleFurnace(wrapper);
case 3 -> handleStoneCutter(wrapper);
case 4 -> handleSmithing(wrapper);
}
}
protected void handleSlotDisplay(final PacketWrapper wrapper) {
// empty and any_fuel are empty
final int type = wrapper.passthrough(Types.VAR_INT);
switch (type) {
case 2 -> handleItemId(wrapper); // Item type
case 3 -> handleItem(wrapper); // Item
case 4 -> wrapper.passthrough(Types.STRING); // Tag key
case 5 -> handleSmithingTrimSlotDisplay(wrapper); // Smithing trim
case 6 -> handleWithRemainderSlotDisplay(wrapper); // With remainder
case 7 -> handleSlotDisplayList(wrapper); // Composite
}
}
protected void handleSlotDisplayList(final PacketWrapper wrapper) {
final int size = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < size; i++) {
handleSlotDisplay(wrapper);
}
}
protected void handleSmithingTrimSlotDisplay(final PacketWrapper wrapper) {
handleSlotDisplay(wrapper); // Base
handleSlotDisplay(wrapper); // Material
handleSlotDisplay(wrapper); // Pattern
}
protected void handleWithRemainderSlotDisplay(final PacketWrapper wrapper) {
handleSlotDisplay(wrapper); // Input
handleSlotDisplay(wrapper); // Remainder
}
protected void handleIngredient(final PacketWrapper wrapper) {
final HolderSet items = wrapper.passthrough(Types.HOLDER_SET);
if (items.hasTagKey()) {
return;
}
final int[] ids = items.ids();
for (int i = 0; i < ids.length; i++) {
ids[i] = rewriteItemId(ids[i]);
}
}
protected void handleItemId(final PacketWrapper wrapper) {
final int id = wrapper.passthrough(Types.VAR_INT);
wrapper.write(Types.VAR_INT, rewriteItemId(id));
}
protected void handleItem(final PacketWrapper wrapper) {
final ItemRewriter<?> itemRewriter = protocol.getItemRewriter();
final Item item = wrapper.read(itemRewriter.itemType());
itemRewriter.handleItemToClient(wrapper.user(), item);
wrapper.write(itemRewriter.mappedItemType(), item);
}
protected int rewriteItemId(final int id) {
if (protocol.getMappingData() != null && protocol.getMappingData().getItemMappings() != null) {
return protocol.getMappingData().getItemMappings().getNewIdOrDefault(id, id);
}
return id;
}
protected void rewriteItemIds(final int[] ids) {
for (int i = 0; i < ids.length; i++) {
final int id = ids[i];
ids[i] = rewriteItemId(id);
}
}
}
@@ -18,6 +18,7 @@
package com.viaversion.viaversion.rewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
@@ -29,6 +30,7 @@ import java.util.HashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
// Base up to and including 1.21.1
public class RecipeRewriter<C extends ClientboundPacketType> {
protected final Protocol<C, ?, ?, ?> protocol;
@@ -80,13 +82,22 @@ public class RecipeRewriter<C extends ClientboundPacketType> {
public void register1_20_5(C packetType) {
protocol.registerClientbound(packetType, wrapper -> {
int size = wrapper.passthrough(Types.VAR_INT);
final int size = wrapper.passthrough(Types.VAR_INT);
int newSize = size;
for (int i = 0; i < size; i++) {
wrapper.passthrough(Types.STRING); // Recipe Identifier
final String recipeIdentifier = wrapper.read(Types.STRING);
final int typeId = wrapper.passthrough(Types.VAR_INT);
final String type = protocol.getMappingData().getRecipeSerializerMappings().identifier(typeId);
handleRecipeType(wrapper, type);
final FullMappings recipeSerializerMappings = protocol.getMappingData().getRecipeSerializerMappings();
final int typeId = wrapper.read(Types.VAR_INT);
final int mappedId = recipeSerializerMappings.getNewId(typeId);
if (mappedId != -1) {
wrapper.write(Types.STRING, recipeIdentifier);
wrapper.write(Types.VAR_INT, mappedId);
} else {
wrapper.set(Types.VAR_INT, 0, --newSize);
}
handleRecipeType(wrapper, Key.stripMinecraftNamespace(recipeSerializerMappings.identifier(typeId))); // Use the original
}
});
}
@@ -150,6 +161,13 @@ public class RecipeRewriter<C extends ClientboundPacketType> {
handleIngredient(wrapper); // Additions
}
protected int rewrite(final int itemId) {
if (protocol.getMappingData() != null && protocol.getItemRewriter() != null) {
return protocol.getMappingData().getNewItemId(itemId);
}
return itemId;
}
protected @Nullable Item rewrite(UserConnection connection, @Nullable Item item) {
if (protocol.getItemRewriter() != null) {
return protocol.getItemRewriter().handleItemToClient(connection, item);
@@ -0,0 +1,195 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.data.entity.DimensionData;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.data.entity.DimensionDataImpl;
import com.viaversion.viaversion.util.Key;
import com.viaversion.viaversion.util.TagUtil;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public class RegistryDataRewriter {
private final Map<String, Consumer<CompoundTag>> enchantmentEffectRewriters = new Object2ObjectArrayMap<>();
private final Map<String, List<RegistryEntry>> toAdd = new Object2ObjectArrayMap<>();
private final Protocol<?, ?, ?, ?> protocol;
public RegistryDataRewriter(Protocol<?, ?, ?, ?> protocol) {
this.protocol = protocol;
}
public void handle(final PacketWrapper wrapper) {
final String registryKey = wrapper.passthrough(Types.STRING);
RegistryEntry[] entries = wrapper.read(Types.REGISTRY_ENTRY_ARRAY);
entries = handle(wrapper.user(), registryKey, entries);
wrapper.write(Types.REGISTRY_ENTRY_ARRAY, entries);
}
public RegistryEntry[] handle(final UserConnection connection, String key, RegistryEntry[] entries) {
key = Key.stripMinecraftNamespace(key);
if (key.equals("enchantment")) {
updateEnchantments(entries);
}
final List<RegistryEntry> toAdd = this.toAdd.get(key);
if (toAdd != null) {
final int length = entries.length;
final int toAddLength = toAdd.size();
entries = Arrays.copyOf(entries, length + toAddLength);
for (int i = 0; i < toAddLength; i++) {
entries[length + i] = toAdd.get(i).copy();
}
}
trackDimensionAndBiomes(connection, key, entries);
return entries;
}
public void addEntries(final String registryKey, final RegistryEntry... entries) {
toAdd.computeIfAbsent(Key.stripMinecraftNamespace(registryKey), $ -> new ArrayList<>()).addAll(List.of(entries));
}
public void addEnchantmentEffectRewriter(final String key, final Consumer<CompoundTag> rewriter) {
enchantmentEffectRewriters.put(Key.stripMinecraftNamespace(key), rewriter);
}
public void trackDimensionAndBiomes(final UserConnection connection, final String registryKey, final RegistryEntry[] entries) {
if (registryKey.equals("worldgen/biome")) {
protocol.getEntityRewriter().tracker(connection).setBiomesSent(entries.length);
} else if (registryKey.equals("dimension_type")) {
final Map<String, DimensionData> dimensionDataMap = new HashMap<>(entries.length);
for (int i = 0; i < entries.length; i++) {
final RegistryEntry entry = entries[i];
final String key = Key.stripMinecraftNamespace(entry.key());
final DimensionData dimensionData = entry.tag() != null
? new DimensionDataImpl(i, (CompoundTag) entry.tag())
: DimensionDataImpl.withDefaultsFor(key, i);
dimensionDataMap.put(key, dimensionData);
}
protocol.getEntityRewriter().tracker(connection).setDimensions(dimensionDataMap);
}
}
public void updateEnchantments(final RegistryEntry[] entries) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag effects = ((CompoundTag) entry.tag()).getCompoundTag("effects");
if (effects == null) {
continue;
}
// Go through all effects, almost all of them may contain an "effect" element
for (final Map.Entry<String, Tag> effectEntry : effects.entrySet()) {
if (effectEntry.getValue() instanceof final CompoundTag compoundTag) {
updateNestedEffect(compoundTag);
} else if (effectEntry.getValue() instanceof final ListTag<?> listTag && listTag.getElementType() == CompoundTag.class) {
for (final Tag tag : listTag) {
updateNestedEffect((CompoundTag) tag);
}
}
}
updateAttributesFields(effects);
}
}
private void updateNestedEffect(final CompoundTag effectsTag) {
final CompoundTag effect = effectsTag.getCompoundTag("effect");
if (effect == null) {
return;
}
runEffectRewriters(effect);
final ListTag<CompoundTag> innerEffects = effect.getListTag("effects", CompoundTag.class);
if (innerEffects == null) {
return;
}
for (final CompoundTag innerEffect : innerEffects) {
runEffectRewriters(innerEffect);
}
}
private void updateAttributesFields(final CompoundTag effects) {
if (!hasAttributeMappings()) {
return;
}
final ListTag<CompoundTag> attributesList = TagUtil.getNamespacedCompoundTagList(effects, "attributes");
if (attributesList == null) {
return;
}
for (final CompoundTag attributeData : attributesList) {
updateAttributeField(attributeData);
}
}
private void runEffectRewriters(final CompoundTag effectTag) {
String effect = effectTag.getString("type");
if (effect == null) {
return;
}
effect = Key.stripMinecraftNamespace(effect);
updateAttributeField(effectTag);
final Consumer<CompoundTag> rewriter = enchantmentEffectRewriters.get(effect);
if (rewriter != null) {
rewriter.accept(effectTag);
}
}
private void updateAttributeField(final CompoundTag attributeData) {
final StringTag attributeTag = attributeData.getStringTag("attribute");
if (attributeTag == null) {
return;
}
final FullMappings mappings = protocol.getMappingData().getAttributeMappings();
final String attribute = Key.stripMinecraftNamespace(attributeTag.getValue());
String mappedAttribute = mappings.mappedIdentifier(attribute);
if (mappedAttribute == null) {
mappedAttribute = mappings.mappedIdentifier(0); // Dummy
}
attributeTag.setValue(mappedAttribute);
}
private boolean hasAttributeMappings() {
return protocol.getMappingData() != null && protocol.getMappingData().getAttributeMappings() != null;
}
}
@@ -36,6 +36,7 @@ import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.type.Type;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.Map;
import java.util.function.Function;
import org.checkerframework.checker.nullness.qual.Nullable;
public class StructuredItemRewriter<C extends ClientboundPacketType, S extends ServerboundPacketType,
@@ -118,6 +119,11 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
final Int2IntFunction itemIdRewriter = clientbound ? mappingData::getNewItemId : mappingData::getOldItemId;
container.replace(StructuredDataKey.TRIM, value -> value.rewrite(itemIdRewriter));
container.replace(StructuredDataKey.POT_DECORATIONS, value -> value.rewrite(itemIdRewriter));
container.replace(StructuredDataKey.REPAIRABLE, value -> value.rewrite(itemIdRewriter));
}
if (mappingData.getFullItemMappings() != null) {
final Function<String, String> itemIdRewriter = clientbound ? id -> mappedIdentifier(mappingData.getFullItemMappings(), id) : id -> unmappedIdentifier(mappingData.getFullItemMappings(), id);
container.replace(StructuredDataKey.USE_COOLDOWN, value -> value.rewrite(itemIdRewriter));
}
if (mappingData.getBlockMappings() != null) {
final Int2IntFunction blockIdRewriter = clientbound ? mappingData::getNewBlockId : mappingData::getOldBlockId;
@@ -127,7 +133,8 @@ public class StructuredItemRewriter<C extends ClientboundPacketType, S extends S
}
if (mappingData.getSoundMappings() != null) {
final Int2IntFunction soundIdRewriter = clientbound ? mappingData::getNewSoundId : mappingData::getOldSoundId;
container.replace(StructuredDataKey.INSTRUMENT, value -> value.isDirect() ? Holder.of(value.value().rewrite(soundIdRewriter)) : value);
container.replace(StructuredDataKey.INSTRUMENT1_20_5, value -> value.isDirect() ? Holder.of(value.value().rewrite(soundIdRewriter)) : value);
container.replace(StructuredDataKey.INSTRUMENT1_21_2, value -> value.isDirect() ? Holder.of(value.value().rewrite(soundIdRewriter)) : value);
container.replace(StructuredDataKey.JUKEBOX_PLAYABLE, value -> value.rewrite(soundIdRewriter));
}
if (clientbound && protocol.getComponentRewriter() != null) {
@@ -162,7 +162,7 @@ public class TagRewriter<C extends ClientboundPacketType> implements com.viavers
wrapper.write(Types.STRING, registryKey);
final RegistryType type = RegistryType.getByKey(registryKey);
final RegistryType type = RegistryType.getByKey(strippedKey);
if (type != null) {
handle(wrapper, type);
readTypes.add(type);
@@ -60,7 +60,9 @@ public final class ComponentUtil {
final ATextComponent component = SerializerVersion.V1_20_3.toComponent(tag);
return component != null ? SerializerVersion.V1_19_4.toJson(component) : null;
} catch (final Exception e) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting tag: " + tag, e);
if (!Via.getConfig().isSuppressConversionWarnings()) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting tag: " + tag, e);
}
return plainToJson("<error>");
}
}
@@ -74,7 +76,9 @@ public final class ComponentUtil {
final ATextComponent component = SerializerVersion.V1_19_4.toComponent(element);
return trimStrings(SerializerVersion.V1_20_3.toTag(component));
} catch (final Exception e) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + element, e);
if (!Via.getConfig().isSuppressConversionWarnings()) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + element, e);
}
return new StringTag("<error>");
}
}
@@ -101,7 +105,9 @@ public final class ComponentUtil {
final ATextComponent component = SerializerVersion.V1_20_5.toComponent(tag);
return component != null ? SerializerVersion.V1_20_3.toString(component) : null;
} catch (final Exception e) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting tag: " + tag, e);
if (!Via.getConfig().isSuppressConversionWarnings()) {
Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting tag: " + tag, e);
}
return plainToJson("<error>").toString();
}
}
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.util;
import com.google.gson.JsonElement;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.rewriter.ComponentRewriter;
import net.lenni0451.mcstructs.snbt.SNbtSerializer;
import net.lenni0451.mcstructs.snbt.exceptions.SNbtDeserializeException;
import net.lenni0451.mcstructs.snbt.exceptions.SNbtSerializeException;
@@ -26,6 +27,13 @@ import net.lenni0451.mcstructs.text.ATextComponent;
import net.lenni0451.mcstructs.text.serializer.TextComponentCodec;
import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer;
/**
* Wrapper enum to unify text component and string nbt serialization functions across different versions.
* Only contains versions which have actual changes we handle.
*
* @see ComponentUtil
* @see ComponentRewriter
*/
public enum SerializerVersion {
V1_6(TextComponentSerializer.V1_6, null),
V1_7(TextComponentSerializer.V1_7, SNbtSerializer.V1_7),
@@ -115,4 +123,4 @@ public enum SerializerVersion {
throw new RuntimeException(e);
}
}
}
}
@@ -1,60 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 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.util;
import com.google.common.collect.ForwardingSet;
import java.util.Collection;
import java.util.Set;
import java.util.function.Consumer;
import org.checkerframework.checker.nullness.qual.NonNull;
public class SetWrapper<E> extends ForwardingSet<E> {
private final Set<E> set;
private final Consumer<E> addListener;
public SetWrapper(Set<E> set, Consumer<E> addListener) {
this.set = set;
this.addListener = addListener;
}
@Override
public boolean add(@NonNull E element) {
addListener.accept(element);
return super.add(element);
}
@Override
public boolean addAll(Collection<? extends E> collection) {
for (E element : collection) {
addListener.accept(element);
}
return super.addAll(collection);
}
@Override
protected Set<E> delegate() {
return originalSet();
}
public Set<E> originalSet() {
return this.set;
}
}
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.util;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -69,6 +70,11 @@ public final class TagUtil {
return listTag != null ? listTag : tag.getListTag(Key.stripMinecraftNamespace(key), CompoundTag.class);
}
public static @Nullable StringTag getNamespacedStringTag(final CompoundTag tag, final String key) {
final StringTag stringTag = tag.getStringTag(Key.namespaced(key));
return stringTag != null ? stringTag : tag.getStringTag(Key.stripMinecraftNamespace(key));
}
public static Tag handleDeep(final Tag tag, final TagUpdater consumer) {
return handleDeep(null, tag, consumer);
}
@@ -25,7 +25,7 @@ block-disconnect-msg: "You are using an unsupported Minecraft version!"
# (We don't suggest using reload either, use a plugin manager)
# You can customize the message we kick people with if you use ProtocolLib here.
reload-disconnect-msg: "Server reload, please rejoin!"
# We warn when there's an error converting item and block data over versions, should we suppress these? (Only suggested if spamming)
# We warn when there's an error converting item/block or component/nbt data over versions, should we suppress these? (Only suggested if spamming)
suppress-conversion-warnings: false
#
#----------------------------------------------------------#
+3 -3
View File
@@ -1,9 +1,9 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=5.0.4
projectVersion=5.1.0
# Smile emoji
mcVersions=1.21.1,1.21,1.20.6,1.20.5,1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9
mcVersionRange=1.8-1.21.1
mcVersions=1.21.3,1.21.2,1.21.1,1.21,1.20.6,1.20.5,1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9
mcVersionRange=1.8-1.21.3
velocityVersion=3.3
# Gradle properties
+1 -1
View File
@@ -4,7 +4,7 @@ metadata.format.version = "1.1"
gson = "2.11.0"
fastutil = "8.5.14"
vianbt = "5.0.0"
vianbt = "5.0.1"
mcstructs = "5-2.5.4-SNAPSHOT"
# Common provided