Compare commits

...
20 Commits
Author SHA1 Message Date
Nassim Jahnke 351b42b5e5 5.4.1 Release 2025-06-30 09:56:25 +02:00
Nassim Jahnke 20e3c832fb 1.21.7-rc2 2025-06-30 09:49:48 +02:00
Nassim Jahnke ec9c121da2 1.21.7-rc1 2025-06-30 09:49:47 +02:00
FlorianMichael 12c773edea Add missing translatable mappings (#4542)
Fixes #3331
Fixes #4273
2025-06-30 09:47:33 +02:00
Nassim Jahnke 97b411aa6d Manually handle text component boolean entries
Fixes #4558
2025-06-29 16:36:12 +02:00
Nassim Jahnke 24f6c4f0fd Implement hashing for potion contents 2025-06-29 15:50:56 +02:00
FlorianMichael 9409c7d22a [ci skip] Add SECURITY.md (#4520) 2025-06-29 15:36:49 +02:00
FlorianMichael 17d94a17f0 Always write length in LengthPrefixedTagType 2025-06-29 11:51:38 +02:00
riku6460andFlorianMichael a1cb4d3691 Add Types#CUSTOM_CLICK_ACTION_TAG for VB (#4557)
* Add LengthPrefixedTagType for CUSTOM_CLICK_ACTION

* Move type into own class, add instance into Types

---------

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

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

No files matched your search

+10
View File
@@ -0,0 +1,10 @@
# Security Policy
## Reporting a Vulnerability
If you discover a **security vulnerability**, please **do not** open a public issue. Instead, use one of the following **confidential contact methods**:
* **Email:** [security@viaversion.com](mailto:security@viaversion.com)
* **Discord:** Join our [Discord server](https://discord.gg/viaversion) and visit the [#exploit-report](https://discord.com/channels/316206679014244363/1388847764137316485) channel for further instructions.
If your issue is **not security-related** (e.g., bug reports, feature requests, or usage questions), please use the [GitHub Issues page](https://github.com/ViaVersion/ViaVersion/issues) or contact us via the [Discord server](https://discord.gg/viaversion).
@@ -233,13 +233,6 @@ public interface ViaVersionConfig extends Config {
*/
boolean isChunkBorderFix();
/**
* Should we fix nbt array's in json chat messages for 1.12 clients
*
* @return true if enabled
*/
boolean is1_12NBTArrayFix();
/**
* Should we make team colours based on the last colour in team prefix
*
@@ -208,8 +208,8 @@ public class MappingDataBase implements MappingData {
}
@Override
public int getOldSoundId(final int i) {
return soundMappings.getNewIdOrDefault(i, 0);
public int getOldSoundId(final int id) {
return soundMappings.inverse().getNewIdOrDefault(id, 0);
}
@Override
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.function.Function;
import java.util.function.Supplier;
public interface Holder<T> {
@@ -89,7 +90,18 @@ public interface Holder<T> {
* @param rewriteFunction the function to rewrite the id
* @return a new holder with the id rewritten, or self
*/
Holder<T> updateId(final Int2IntFunction rewriteFunction);
default Holder<T> updateId(final Int2IntFunction rewriteFunction) {
return this.updateId(rewriteFunction, null);
}
/**
* Returns a new holder with the id rewritten using the given function, or self if this is a direct holder or the id did not change.
*
* @param rewriteFunction the function to rewrite the id
* @param ifMissing a supplier that provides a new holder if the id is missing (i.e. -1)
* @return a new holder with the id rewritten, or self
*/
Holder<T> updateId(Int2IntFunction rewriteFunction, Supplier<Holder<T>> ifMissing);
/**
* Returns a new holder with the value rewritten using the given function, or self if this is an id holder or the value did not change.
@@ -25,6 +25,7 @@ package com.viaversion.viaversion.api.minecraft;
import com.google.common.base.Preconditions;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.function.Function;
import java.util.function.Supplier;
record IdHolder<T>(int id) implements Holder<T> {
@@ -48,12 +49,15 @@ record IdHolder<T>(int id) implements Holder<T> {
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
public Holder<T> updateId(final Int2IntFunction rewriteFunction, final Supplier<Holder<T>> ifMissing) {
final int rewrittenId = rewriteFunction.applyAsInt(id);
if (rewrittenId == id) {
return this;
}
if (rewrittenId == -1) {
if (ifMissing != null) {
return ifMissing.get();
}
throw new IllegalArgumentException("Received invalid id in updateId");
}
return Holder.of(rewrittenId);
@@ -22,11 +22,21 @@
*/
package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import org.checkerframework.checker.nullness.qual.Nullable;
public record SoundEvent(String identifier, @Nullable Float fixedRange) {
private static final Holder<SoundEvent> UNKNOWN = Holder.of(new SoundEvent("viaversion:unknown", 0F));
public SoundEvent withIdentifier(final String identifier) {
return new SoundEvent(identifier, this.fixedRange);
}
public static @Nullable Holder<SoundEvent> rewriteHolder(@Nullable final Holder<SoundEvent> holder, final Int2IntFunction soundRewriteFunction) {
if (holder == null) {
return null;
}
return holder.updateId(soundRewriteFunction, () -> UNKNOWN);
}
}
@@ -24,6 +24,7 @@ package com.viaversion.viaversion.api.minecraft;
import it.unimi.dsi.fastutil.ints.Int2IntFunction;
import java.util.function.Function;
import java.util.function.Supplier;
record ValueHolder<T>(T value) implements Holder<T> {
@@ -43,7 +44,7 @@ record ValueHolder<T>(T value) implements Holder<T> {
}
@Override
public Holder<T> updateId(final Int2IntFunction rewriteFunction) {
public Holder<T> updateId(final Int2IntFunction rewriteFunction, final Supplier<Holder<T>> ifMissing) {
return this;
}
@@ -0,0 +1,110 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.codec;
import com.viaversion.viaversion.api.type.Type;
import java.util.function.Consumer;
public class DelegatingOps implements Ops {
private final Ops delegate;
public DelegatingOps(final Ops delegate) {
this.delegate = delegate;
}
@Override
public CodecContext context() {
return delegate.context();
}
@Override
public void writeByte(final byte b) {
delegate.writeByte(b);
}
@Override
public void writeBytes(final byte[] array) {
delegate.writeBytes(array);
}
@Override
public void writeBoolean(final boolean b) {
delegate.writeBoolean(b);
}
@Override
public void writeShort(final short s) {
delegate.writeShort(s);
}
@Override
public void writeString(final CharSequence sequence) {
delegate.writeString(sequence);
}
@Override
public void writeInt(final int i) {
delegate.writeInt(i);
}
@Override
public void writeLong(final long l) {
delegate.writeLong(l);
}
@Override
public void writeFloat(final float f) {
delegate.writeFloat(f);
}
@Override
public void writeDouble(final double d) {
delegate.writeDouble(d);
}
@Override
public void writeInts(final int[] array) {
delegate.writeInts(array);
}
@Override
public void writeLongs(final long[] array) {
delegate.writeLongs(array);
}
@Override
public void writeList(final Consumer<ListSerializer> consumer) {
delegate.writeList(consumer);
}
@Override
public void writeMap(final Consumer<MapSerializer> consumer) {
delegate.writeMap(consumer);
}
@Override
public <V> void write(final Type<V> type, final V value) {
delegate.write(type, value);
}
}
@@ -129,5 +129,7 @@ public interface Ops {
MapSerializer writeList(String key, Consumer<ListSerializer> consumer);
MapSerializer writeMap(String key, Consumer<MapSerializer> consumer);
<T> MapSerializer writeInlinedMap(Type<T> valueType, T value);
}
}
@@ -0,0 +1,104 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.minecraft.codec;
import com.viaversion.viaversion.api.type.Type;
import java.util.function.Consumer;
public class ThrowingOps implements Ops {
@Override
public CodecContext context() {
throw new UnsupportedOperationException();
}
@Override
public void writeByte(final byte b) {
throw new UnsupportedOperationException();
}
@Override
public void writeBytes(final byte[] array) {
throw new UnsupportedOperationException();
}
@Override
public void writeBoolean(final boolean b) {
throw new UnsupportedOperationException();
}
@Override
public void writeShort(final short s) {
throw new UnsupportedOperationException();
}
@Override
public void writeString(final CharSequence sequence) {
throw new UnsupportedOperationException();
}
@Override
public void writeInt(final int i) {
throw new UnsupportedOperationException();
}
@Override
public void writeLong(final long l) {
throw new UnsupportedOperationException();
}
@Override
public void writeFloat(final float f) {
throw new UnsupportedOperationException();
}
@Override
public void writeDouble(final double d) {
throw new UnsupportedOperationException();
}
@Override
public void writeInts(final int[] array) {
throw new UnsupportedOperationException();
}
@Override
public void writeLongs(final long[] array) {
throw new UnsupportedOperationException();
}
@Override
public void writeList(final Consumer<ListSerializer> consumer) {
throw new UnsupportedOperationException();
}
@Override
public void writeMap(final Consumer<MapSerializer> consumer) {
throw new UnsupportedOperationException();
}
@Override
public <V> void write(final Type<V> type, final V value) {
throw new UnsupportedOperationException();
}
}
@@ -241,7 +241,7 @@ public final class StructuredDataContainer implements Copyable {
/**
* Sets the lookup for serializer ids. Required to call most of the other methods.
*
* @param protocol protocol to retreive the id of the serializer from
* @param protocol protocol to retrieve the id of the serializer from
* @param mappedNames if the names are mapped (true if structures from the mapped version are added, false for the unmapped version)
*/
public void setIdLookup(final Protocol<?, ?, ?, ?> protocol, final boolean mappedNames) {
@@ -95,10 +95,10 @@ public record StructuredDataKey<T>(String identifier, Type<T> type) {
public static final StructuredDataKey<Integer> DAMAGE = new StructuredDataKey<>("damage", Types.VAR_INT);
public static final StructuredDataKey<Unbreakable> UNBREAKABLE1_20_5 = new StructuredDataKey<>("unbreakable", Unbreakable.TYPE);
public static final StructuredDataKey<Unit> UNBREAKABLE1_21_5 = new StructuredDataKey<>("unbreakable", Types.EMPTY);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TAG);
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Types.TAG);
public static final StructuredDataKey<Tag> CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TEXT_COMPONENT_TAG);
public static final StructuredDataKey<Tag> ITEM_NAME = new StructuredDataKey<>("item_name", Types.TEXT_COMPONENT_TAG);
public static final StructuredDataKey<Key> ITEM_MODEL = new StructuredDataKey<>("item_model", Types.RESOURCE_LOCATION);
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", new ArrayType<>(Types.TAG, 256));
public static final StructuredDataKey<Tag[]> LORE = new StructuredDataKey<>("lore", new ArrayType<>(Types.TEXT_COMPONENT_TAG, 256));
public static final StructuredDataKey<Integer> RARITY = new StructuredDataKey<>("rarity", EnumTypes.RARITY);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS1_20_5 = new StructuredDataKey<>("enchantments", Enchantments.TYPE1_20_5);
public static final StructuredDataKey<Enchantments> ENCHANTMENTS1_21_5 = new StructuredDataKey<>("enchantments", Enchantments.TYPE1_21_5);
@@ -173,7 +173,7 @@ public record AttributeModifiers1_21(AttributeModifier[] modifiers, boolean show
map.writeMap("display", display -> {
display.write("type", Types.STRING, Display.DISPLAY_TYPES[value.display.id()]);
if (value.display instanceof final OverrideText overrideText) {
display.write("value", Types.TAG, overrideText.component);
display.write("value", Types.TEXT_COMPONENT_TAG, overrideText.component);
}
});
});
@@ -22,12 +22,15 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Holder;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.SoundEvent;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
import com.viaversion.viaversion.util.Rewritable;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -39,7 +42,7 @@ public record BlocksAttacks(
@Nullable String bypassedByTag,
@Nullable Holder<SoundEvent> blockSound,
@Nullable Holder<SoundEvent> disableSound
) {
) implements Rewritable {
public static final Type<BlocksAttacks> TYPE = new Type<>(BlocksAttacks.class) {
@@ -67,6 +70,13 @@ public record BlocksAttacks(
}
};
@Override
public BlocksAttacks rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> blockSound = SoundEvent.rewriteHolder(this.blockSound, Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> disableSound = SoundEvent.rewriteHolder(this.disableSound, Rewritable.soundRewriteFunction(protocol, clientbound));
return new BlocksAttacks(this.blockDelaySeconds, this.disableCooldownScale, this.damageReductions, this.itemDamage, this.bypassedByTag, blockSound, disableSound);
}
public record DamageReduction(float horizontalBlockingAngle, @Nullable HolderSet type, float base, float factor) {
public static final Type<DamageReduction> TYPE = new Type<>(DamageReduction.class) {
@@ -116,7 +116,7 @@ public record Consumable1_21_2(float consumeSeconds, int animationType, Holder<S
@Override
public Consumable1_21_2 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundHolder = this.sound.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> soundHolder = SoundEvent.rewriteHolder(this.sound, Rewritable.soundRewriteFunction(protocol, clientbound));
return soundHolder == this.sound ? this : new Consumable1_21_2(consumeSeconds, animationType, soundHolder, hasConsumeParticles, consumeEffects);
}
@@ -48,4 +48,6 @@ public final class EnumTypes {
public static final FakeEnumType RABBIT_VARIANT = new FakeEnumType(List.of("brown", "white", "black", "white_splotched", "gold", "salt"), of(99, "evil"));
// Pretty much enums, but with a resource location
public static final RegistryValueType VILLAGER_TYPE = new RegistryValueType("desert", "jungle", "plains", "savanna", "snow", "swamp", "taiga");
public static final RegistryValueType POTION = new RegistryValueType("water", "mundane", "thick", "awkward", "night_vision", "long_night_vision", "invisibility", "long_invisibility", "leaping", "long_leaping", "strong_leaping", "fire_resistance", "long_fire_resistance", "swiftness", "long_swiftness", "strong_swiftness", "slowness", "long_slowness", "strong_slowness", "turtle_master", "long_turtle_master", "strong_turtle_master", "water_breathing", "long_water_breathing", "healing", "strong_healing", "harming", "strong_harming", "poison", "long_poison", "strong_poison", "regeneration", "long_regeneration", "strong_regeneration", "strength", "long_strength", "strong_strength", "weakness", "long_weakness", "luck", "slow_falling", "long_slow_falling", "wind_charged", "weaving", "oozing", "infested");
public static final RegistryValueType MOB_EFFECT = new RegistryValueType("speed", "slowness", "haste", "mining_fatigue", "strength", "instant_health", "instant_damage", "jump_boost", "nausea", "regeneration", "resistance", "fire_resistance", "water_breathing", "invisibility", "blindness", "night_vision", "hunger", "weakness", "poison", "wither", "health_boost", "absorption", "saturation", "glowing", "levitation", "luck", "unluck", "slow_falling", "conduit_power", "dolphins_grace", "bad_omen", "hero_of_the_village", "darkness", "trial_omen", "raid_omen", "wind_charged", "weaving", "oozing", "infested");
}
@@ -137,8 +137,8 @@ public record Equippable(int equipmentSlot, Holder<SoundEvent> soundEvent, @Null
@Override
public Equippable rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> shearingSound = this.shearingSound.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> soundEvent = SoundEvent.rewriteHolder(this.soundEvent, Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> shearingSound = SoundEvent.rewriteHolder(this.shearingSound, Rewritable.soundRewriteFunction(protocol, clientbound));
return soundEvent == this.soundEvent && shearingSound == this.shearingSound ? this : new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt, equipOnInteract, canBeSheared, shearingSound);
}
}
@@ -52,7 +52,7 @@ public record Instrument1_20_5(Holder<SoundEvent> soundEvent, int useDuration, f
@Override
public Instrument1_20_5 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> soundEvent = SoundEvent.rewriteHolder(this.soundEvent, Rewritable.soundRewriteFunction(protocol, clientbound));
return soundEvent == this.soundEvent ? this : new Instrument1_20_5(soundEvent, useDuration, range);
}
}
@@ -59,7 +59,7 @@ public record Instrument1_21_2(Holder<SoundEvent> soundEvent, float useDuration,
@Override
public Instrument1_21_2 rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> soundEvent = SoundEvent.rewriteHolder(this.soundEvent, Rewritable.soundRewriteFunction(protocol, clientbound));
return soundEvent == this.soundEvent ? this : new Instrument1_21_2(soundEvent, useDuration, range, description);
}
@@ -111,7 +111,7 @@ public record JukeboxPlayable(EitherHolder<JukeboxSong> song, boolean showInTool
@Override
public JukeboxSong rewrite(final UserConnection connection, final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
final Holder<SoundEvent> soundEvent = this.soundEvent.updateId(Rewritable.soundRewriteFunction(protocol, clientbound));
final Holder<SoundEvent> soundEvent = SoundEvent.rewriteHolder(this.soundEvent, Rewritable.soundRewriteFunction(protocol, clientbound));
return soundEvent == this.soundEvent ? this : new JukeboxSong(soundEvent, description, lengthInSeconds, comparatorOutput);
}
}
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.util.Copyable;
@@ -85,6 +86,15 @@ public record PotionContents(@Nullable Integer potion, @Nullable Integer customC
PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects);
Types.OPTIONAL_STRING.write(buffer, value.customName);
}
@Override
public void write(final Ops ops, final PotionContents value) {
ops.writeMap(map -> map
.writeOptional("potion", EnumTypes.POTION, value.potion)
.writeOptional("custom_color", Types.INT, value.customColor)
.writeOptional("custom_effects", PotionEffect.ARRAY_TYPE, value.customEffects, new PotionEffect[0])
.writeOptional("custom_name", Types.STRING, value.customName));
}
};
@Override
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.ArrayType;
@@ -42,6 +43,13 @@ public record PotionEffect(int effect, PotionEffectData effectData) {
Types.VAR_INT.writePrimitive(buffer, value.effect);
PotionEffectData.TYPE.write(buffer, value.effectData);
}
@Override
public void write(final Ops ops, final PotionEffect value) {
ops.writeMap(map -> map
.write("id", EnumTypes.MOB_EFFECT, value.effect)
.writeInlinedMap(PotionEffectData.TYPE, value.effectData));
}
};
public static final Type<PotionEffect[]> ARRAY_TYPE = new ArrayType<>(TYPE);
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.minecraft.item.data;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
@@ -52,6 +53,17 @@ public record PotionEffectData(int amplifier, int duration, boolean ambient, boo
buffer.writeBoolean(value.showIcon);
OPTIONAL_TYPE.write(buffer, value.hiddenEffect);
}
@Override
public void write(final Ops ops, final PotionEffectData value) {
ops.writeMap(map -> map
.writeOptional("amplifier", Types.UNSIGNED_BYTE, (short) value.amplifier, (short) 0)
.writeOptional("duration", Types.INT, value.duration, 0)
.writeOptional("ambient", Types.BOOLEAN, value.ambient, false)
.writeOptional("show_particles", Types.BOOLEAN, value.showParticles, true)
.writeOptional("show_icon", Types.BOOLEAN, value.showIcon)
.writeOptional("hidden_effect", TYPE, value.hiddenEffect));
}
};
public static final Type<PotionEffectData> OPTIONAL_TYPE = new OptionalType<>(TYPE) {
};
@@ -90,6 +90,7 @@ public class ProtocolVersion implements Comparable<ProtocolVersion> {
public static final ProtocolVersion v1_21_4 = register(769, "1.21.4");
public static final ProtocolVersion v1_21_5 = register(770, "1.21.5");
public static final ProtocolVersion v1_21_6 = register(771, "1.21.6");
public static final ProtocolVersion v1_21_7 = register(772, "1.21.7");
public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null);
static {
@@ -108,6 +108,7 @@ import com.viaversion.viaversion.api.type.types.misc.GameProfileType;
import com.viaversion.viaversion.api.type.types.misc.HolderSetType;
import com.viaversion.viaversion.api.type.types.misc.HolderType;
import com.viaversion.viaversion.api.type.types.misc.KeyType;
import com.viaversion.viaversion.api.type.types.misc.LengthPrefixedTagType;
import com.viaversion.viaversion.api.type.types.misc.NamedCompoundTagType;
import com.viaversion.viaversion.api.type.types.misc.PlayerMessageSignatureType;
import com.viaversion.viaversion.api.type.types.misc.ProfileKeyType;
@@ -115,6 +116,7 @@ import com.viaversion.viaversion.api.type.types.misc.ProfilePropertyType;
import com.viaversion.viaversion.api.type.types.misc.SoundEventType;
import com.viaversion.viaversion.api.type.types.misc.TagKeyType;
import com.viaversion.viaversion.api.type.types.misc.TagType;
import com.viaversion.viaversion.api.type.types.misc.TextComponentTagType;
import com.viaversion.viaversion.api.type.types.misc.VillagerDataType;
import com.viaversion.viaversion.api.type.types.version.Types1_20_5;
import com.viaversion.viaversion.util.Key;
@@ -199,6 +201,8 @@ public final class Types {
public static final Type<Tag> TAG = new TagType();
public static final Type<Tag[]> TAG_ARRAY = new ArrayType<>(TAG);
public static final Type<Tag> OPTIONAL_TAG = new TagType.OptionalTagType();
public static final Type<Tag> TEXT_COMPONENT_TAG = new TextComponentTagType(); // only strictly needed for hashing
public static final Type<Tag> CUSTOM_CLICK_ACTION_TAG = new LengthPrefixedTagType(65536);
public static final Type<GlobalBlockPosition> GLOBAL_POSITION = new GlobalBlockPositionType();
public static final Type<GlobalBlockPosition> OPTIONAL_GLOBAL_POSITION = new GlobalBlockPositionType.OptionalGlobalPositionType();
@@ -41,4 +41,8 @@ public final class RegistryValueType extends VarIntType {
public void write(final Ops ops, final Integer value) {
Types.STRING.write(ops, names[value]);
}
public String[] names() {
return names;
}
}
@@ -0,0 +1,65 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.google.common.base.Preconditions;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import io.netty.buffer.ByteBuf;
public final class LengthPrefixedTagType extends Type<Tag> {
private final int maxLength;
public LengthPrefixedTagType(int maxLength) {
super(Tag.class);
this.maxLength = maxLength;
}
@Override
public Tag read(final ByteBuf buffer) {
final int length = Types.VAR_INT.readPrimitive(buffer);
Preconditions.checkArgument(length <= maxLength,
"Cannot receive tag longer than %s bytes (got %s bytes)", maxLength, length);
return Types.TAG.read(buffer.readSlice(length));
}
@Override
public void write(final ByteBuf buffer, final Tag tag) {
final ByteBuf tempBuf = buffer.alloc().buffer();
try {
Types.TAG.write(tempBuf, tag);
Preconditions.checkArgument(tempBuf.readableBytes() <= maxLength,
"Cannot send tag longer than %s bytes (got %s bytes)", maxLength, tempBuf.readableBytes());
Types.VAR_INT.writePrimitive(buffer, tempBuf.readableBytes());
buffer.writeBytes(tempBuf);
} finally {
tempBuf.release();
}
}
}
@@ -105,13 +105,13 @@ public class TagType extends Type<Tag> {
} else if (value instanceof CompoundTag compoundTag) {
ops.writeMap(map -> {
for (final Map.Entry<String, Tag> entry : compoundTag.entrySet()) {
map.write(entry.getKey(), Types.TAG, entry.getValue());
map.write(entry.getKey(), this, entry.getValue());
}
});
} else if (value instanceof ListTag<?> listTag) {
ops.writeList(list -> {
for (final Tag tag : listTag) {
list.write(Types.TAG, tag);
list.write(this, tag);
}
});
} else if (value instanceof IntArrayTag intArrayTag) {
@@ -0,0 +1,61 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.viaversion.viaversion.api.type.types.misc;
import com.viaversion.nbt.tag.ByteTag;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.minecraft.codec.Ops;
import com.viaversion.viaversion.api.type.Types;
import java.util.Map;
import java.util.Set;
/**
* Only strictly needed for hashing purposes for now.
*/
public class TextComponentTagType extends TagType {
private static final Set<String> BOOLEAN_KEYS = Set.of("bold", "italic", "underlined", "strikethrough", "obfuscated", "interpret");
@Override
public void write(final Ops ops, final Tag value) {
if (value instanceof final CompoundTag compoundTag) {
ops.writeMap(map -> {
for (final Map.Entry<String, Tag> entry : compoundTag.entrySet()) {
write(map, entry.getKey(), entry.getValue());
}
});
} else {
super.write(ops, value);
}
}
private void write(final Ops.MapSerializer map, final String key, final Tag value) {
// Better than fully parsing and re-serializing the component
if (value instanceof final ByteTag byteTag && BOOLEAN_KEYS.contains(key)) {
map.write(key, Types.BOOLEAN, byteTag.asBoolean());
} else {
map.write(key, this, value);
}
}
}
@@ -25,8 +25,8 @@ package com.viaversion.viaversion.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.libs.mcstructs.text.utils.JsonUtils;
import java.util.Comparator;
import net.lenni0451.mcstructs.text.utils.JsonUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class GsonUtil {
@@ -24,6 +24,17 @@ package com.viaversion.viaversion.util;
public final class MathUtil {
/**
* Returns the ceiled integer value of the given float.
*
* @param value float value to ceil
* @return ceiled integer value
*/
public static int ceil(final float value) {
final int intValue = (int) value;
return value > intValue ? intValue + 1 : intValue;
}
/**
* Returns the ceiled log to the base of 2 for the given number.
*
@@ -67,7 +67,7 @@ public interface Rewritable {
static Int2IntFunction soundRewriteFunction(final Protocol<?, ?, ?, ?> protocol, final boolean clientbound) {
return protocol.getMappingData().getSoundMappings() == null ? Int2IntFunction.identity()
: (clientbound ? protocol.getMappingData()::getNewSoundId : protocol.getMappingData()::getOldSoundId);
: (clientbound ? protocol.getMappingData().getSoundMappings()::getNewId : protocol.getMappingData()::getOldSoundId);
}
static @Nullable String mappedIdentifier(final FullMappings mappings, final String identifier) {
@@ -44,7 +44,6 @@ publishing {
fun ShadowJar.configureRelocations() {
relocate("com.google.gson", "com.viaversion.viaversion.libs.gson")
relocate("it.unimi.dsi.fastutil", "com.viaversion.viaversion.libs.fastutil")
relocate("net.lenni0451.mcstructs", "com.viaversion.viaversion.libs.mcstructs")
relocate("org.yaml.snakeyaml", "com.viaversion.viaversion.libs.snakeyaml")
}
@@ -18,8 +18,10 @@
package com.viaversion.viaversion.bukkit.providers;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockPosition;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.bukkit.platform.PaperViaInjector;
import com.viaversion.viaversion.bukkit.util.LegacyBlockToItem;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.provider.PickItemProvider;
@@ -187,14 +189,25 @@ public class BukkitPickItemProvider extends PickItemProvider {
}
return item;
};
} else if (PaperViaInjector.hasMethod(Material.class, "isItem")) {
return (block, includeData) -> new ItemStack(block.getType(), 1);
} else {
LegacyBlockToItem legacy = LegacyBlockToItem.getInstance();
}
final ProtocolVersion version = Via.getAPI().getServerVersion().lowestSupportedProtocolVersion();
if (version.equalTo(ProtocolVersion.v1_8)) {
final LegacyBlockToItem legacy = LegacyBlockToItem.getInstance();
return legacy != null ? (block, includeData) -> legacy.blockToItem(block) : (b, i) -> null;
} else if (PaperViaInjector.hasMethod(Material.class, "isItem")) {
return (block, includeData) -> {
if (!block.getType().isItem()) {
return null;
}
return version.newerThanOrEqualTo(ProtocolVersion.v1_13)
? new ItemStack(block.getType())
: new ItemStack(block.getType(), 1, (short) 0, block.getData());
};
} else {
return (block, includeData) -> null;
}
}
}
@FunctionalInterface
@@ -35,7 +35,7 @@ public record CodecRegistryContext(Protocol<?, ?, ?, ?> protocol, SerializerVers
StructuredDataKey.TRIM1_21_5, StructuredDataKey.TOOL1_21_5, StructuredDataKey.PROVIDES_TRIM_MATERIAL,
StructuredDataKey.CONSUMABLE1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE1_21_5, StructuredDataKey.INSTRUMENT1_21_5,
StructuredDataKey.EQUIPPABLE1_21_5, StructuredDataKey.REPAIRABLE, StructuredDataKey.DEATH_PROTECTION,
StructuredDataKey.BLOCKS_ATTACKS, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, StructuredDataKey.POTION_CONTENTS1_21_2,
StructuredDataKey.BLOCKS_ATTACKS, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS,
StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BREAK_SOUND,
StructuredDataKey.WOLF_VARIANT, StructuredDataKey.WOLF_SOUND_VARIANT, StructuredDataKey.PIG_VARIANT,
StructuredDataKey.COW_VARIANT, StructuredDataKey.CHICKEN_VARIANT, StructuredDataKey.FROG_VARIANT,
@@ -18,6 +18,7 @@
package com.viaversion.viaversion.codec.hash;
import com.viaversion.viaversion.api.minecraft.codec.CodecContext;
import com.viaversion.viaversion.api.minecraft.codec.ThrowingOps;
import com.viaversion.viaversion.api.minecraft.codec.hash.Hasher;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
@@ -221,6 +222,18 @@ public class HashOps extends OpsBase implements Hasher {
return this;
}
@Override
public <T> MapSerializer writeInlinedMap(final Type<T> valueType, final T value) {
// Only allow writeMap calls here
valueType.write(new ThrowingOps() {
@Override
public void writeMap(final Consumer<MapSerializer> consumer) {
consumer.accept(MapHashBuilder.this);
}
}, value);
return this;
}
public void applyHashToParent() {
if (entries.isEmpty()) {
hashBuilder.writeBytesDirect(EMPTY_MAP);
@@ -66,7 +66,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
private int pistonReplacementId;
private boolean chunkBorderFix;
private boolean autoTeam;
private boolean nbtArrayFix;
private BlockedProtocolVersions blockedProtocolVersions;
private String blockedDisconnectMessage;
private String reloadDisconnectMessage;
@@ -133,7 +132,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
pistonReplacementId = getInt("replacement-piston-id", 0);
chunkBorderFix = getBoolean("chunk-border-fix", false);
autoTeam = getBoolean("auto-team", true);
nbtArrayFix = getBoolean("chat-nbt-fix", true);
blockedProtocolVersions = loadBlockedProtocolVersions();
blockedDisconnectMessage = getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
reloadDisconnectMessage = getString("reload-disconnect-msg", "Server reload, please rejoin!");
@@ -379,11 +377,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf
return preventCollision && autoTeam;
}
@Override
public boolean is1_12NBTArrayFix() {
return nbtArrayFix;
}
@Override
public boolean shouldRegisterUserConnectionOnJoin() {
return false;
@@ -80,6 +80,7 @@ import com.viaversion.viaversion.protocols.v1_20to1_20_2.Protocol1_20To1_20_2;
import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_4;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.Protocol1_21_5To1_21_6;
import com.viaversion.viaversion.protocols.v1_21_6to1_21_7.Protocol1_21_6To1_21_7;
import com.viaversion.viaversion.protocols.v1_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;
@@ -203,6 +204,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
registerProtocol(new Protocol1_21_4To1_21_5(), ProtocolVersion.v1_21_5, ProtocolVersion.v1_21_4);
registerProtocol(new Protocol1_21_5To1_21_6(), ProtocolVersion.v1_21_6, ProtocolVersion.v1_21_5);
registerProtocol(new Protocol1_21_6To1_21_7(), ProtocolVersion.v1_21_7, ProtocolVersion.v1_21_6);
}
@Override
@@ -144,7 +144,7 @@ final class Protocol1_98To1_99 extends AbstractProtocol<ClientboundPacket1_21_2,
public void init(final UserConnection connection) {
// Register the entity tracker - used for entity id/entity data rewriting AND for tracking world data sent to the client (then used for chunk data rewriting)
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_4.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_5, SerializerVersion.V1_21_5));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_6, SerializerVersion.V1_21_6));
}
// Overriding these methods is important as they are relied on various rewriter classes
@@ -21,7 +21,6 @@ import com.google.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.ClientWorld;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
@@ -32,7 +31,6 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_12;
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_9_3;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
@@ -43,8 +41,6 @@ import com.viaversion.viaversion.protocols.v1_11_1to1_12.packet.ServerboundPacke
import com.viaversion.viaversion.protocols.v1_11_1to1_12.provider.InventoryQuickMoveProvider;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.rewriter.EntityPacketRewriter1_12;
import com.viaversion.viaversion.protocols.v1_11_1to1_12.rewriter.ItemPacketRewriter1_12;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.Protocol1_12_2To1_13;
import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPackets1_9_3;
import com.viaversion.viaversion.rewriter.SoundRewriter;
@@ -63,7 +59,6 @@ public class Protocol1_11_1To1_12 extends AbstractProtocol<ClientboundPackets1_9
super.registerPackets();
registerClientbound(ClientboundPackets1_9_3.CHAT, wrapper -> {
if (!Via.getConfig().is1_12NBTArrayFix()) return;
final JsonElement element = wrapper.passthrough(Types.COMPONENT);
TranslateRewriter.toClient(wrapper.user(), element);
ChatItemRewriter.toClient(element);
@@ -177,6 +177,14 @@ public class AchievementTranslations1_12 {
add("achievement.overkill.desc", "Deal nine hearts of damage in a single hit");
add("achievement.bookcase", "Librarian");
add("achievement.bookcase.desc", "Build some bookshelves to improve your enchantment table");
add("commands.achievement.usage", "/achievement <give|take> <name|*> [player]");
add("commands.achievement.give.success.all", "Successfully given all achievements to %s");
add("commands.achievement.take.success.all", "Successfully taken all achievements from %s");
add("commands.achievement.unknownAchievement", "Unknown achievement '%s'");
add("commands.achievement.take.success.one", "Successfully taken the achievement %s from %s");
add("commands.achievement.dontHave", "Player %s doesn't have achievement %s");
add("commands.achievement.alreadyHave", "Player %s already has achievement %s");
add("commands.achievement.give.success.one", "Successfully given %s the achievement %s");
}
private static void add(String key, String value) {
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.protocols.v1_12_2to1_13;
import com.google.common.collect.Sets;
import com.google.common.primitives.Ints;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.viaversion.viaversion.api.Via;
@@ -483,6 +484,31 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol<ClientboundPackets1_1
displayName = rewriteTeamMemberName(displayName);
wrapper.write(Types.STRING, displayName);
});
registerClientbound(ClientboundPackets1_12_1.PLAYER_INFO, wrapper -> {
final int action = wrapper.passthrough(Types.VAR_INT);
final int count = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < count; i++) {
wrapper.passthrough(Types.UUID); // Player UUID
if (action == 0) { // Add player
final String playerName = wrapper.read(Types.STRING);
wrapper.write(Types.STRING, rewriteTeamMemberName(playerName));
wrapper.passthrough(Types.PROFILE_PROPERTY_ARRAY); // Profile properties
wrapper.passthrough(Types.VAR_INT); // gamemode
wrapper.passthrough(Types.VAR_INT); // ping
final JsonElement displayName = wrapper.passthrough(Types.OPTIONAL_COMPONENT);
if (displayName != null) {
componentRewriter.processText(wrapper.user(), displayName);
}
} else if (action == 1 || action == 2) { // Update Gamemode/Latency
wrapper.passthrough(Types.VAR_INT);
} else if (action == 3) { // Update display name
final JsonElement displayName = wrapper.passthrough(Types.OPTIONAL_COMPONENT);
if (displayName != null) {
componentRewriter.processText(wrapper.user(), displayName);
}
}
}
});
componentRewriter.registerTitle(ClientboundPackets1_12_1.SET_TITLES);
@@ -65,6 +65,8 @@ public class ComponentRewriter1_16 extends JsonNBTComponentRewriter<ClientboundP
mappings.put("advancements.husbandry.break_diamond_hoe.description", "Completely use up a diamond hoe, and then reevaluate your life choices");
mappings.put("biome.minecraft.nether", "Nether");
mappings.put("key.swapHands", "key.swapOffhand");
mappings.put("commands.datapack.enable.success", "commands.datapack.modify.enable");
mappings.put("commands.datapack.disable.success", "commands.datapack.modify.disable");
}
@Override
@@ -34,6 +34,7 @@ import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ClientboundPac
import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ServerboundPackets1_16_2;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ClientboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.ComponentRewriter1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.EntityPacketRewriter1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.ItemPacketRewriter1_17;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter.WorldPacketRewriter1_17;
@@ -41,6 +42,7 @@ import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class Protocol1_16_4To1_17 extends AbstractProtocol<ClientboundPackets1_16_2, ClientboundPackets1_17, ServerboundPackets1_16_2, ServerboundPackets1_17> {
@@ -48,6 +50,7 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol<ClientboundPack
private final EntityPacketRewriter1_17 entityRewriter = new EntityPacketRewriter1_17(this);
private final ItemPacketRewriter1_17 itemRewriter = new ItemPacketRewriter1_17(this);
private final ParticleRewriter<ClientboundPackets1_16_2> particleRewriter = new ParticleRewriter<>(this);
private final ComponentRewriter1_17 componentRewriter = new ComponentRewriter1_17(this);
private final TagRewriter<ClientboundPackets1_16_2> tagRewriter = new TagRewriter<>(this);
public Protocol1_16_4To1_17() {
@@ -84,6 +87,13 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol<ClientboundPack
new StatisticsRewriter<>(this).register(ClientboundPackets1_16_2.AWARD_STATS);
componentRewriter.registerComponentPacket(ClientboundPackets1_16_2.CHAT);
componentRewriter.registerBossEvent(ClientboundPackets1_16_2.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_16_2.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_16_2.TAB_LIST);
componentRewriter.registerOpenScreen1_14(ClientboundPackets1_16_2.OPEN_SCREEN);
componentRewriter.registerPing();
SoundRewriter<ClientboundPackets1_16_2> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound(ClientboundPackets1_16_2.SOUND);
soundRewriter.registerSound(ClientboundPackets1_16_2.SOUND_ENTITY);
@@ -133,6 +143,9 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol<ClientboundPack
default -> throw new IllegalArgumentException("Invalid title type received: " + type);
}
if (type < 3) {
componentRewriter.processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT));
}
wrapper.setPacketType(packetType);
});
@@ -217,6 +230,11 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol<ClientboundPack
return particleRewriter;
}
@Override
public @Nullable ComponentRewriter1_17 getComponentRewriter() {
return componentRewriter;
}
@Override
public TagRewriter<ClientboundPackets1_16_2> getTagRewriter() {
return tagRewriter;
@@ -0,0 +1,50 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_16_4to1_17.rewriter;
import com.google.gson.JsonObject;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ClientboundPackets1_16_2;
import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter;
import java.util.HashMap;
import java.util.Map;
public final class ComponentRewriter1_17 extends JsonNBTComponentRewriter<ClientboundPackets1_16_2> {
private final Map<String, String> mappings = new HashMap<>();
public ComponentRewriter1_17(final Protocol<ClientboundPackets1_16_2, ?, ?, ?> protocol) {
super(protocol, ReadType.JSON);
mappings.put("commands.worldborder.set.failed.small.", "commands.worldborder.set.failed.small");
mappings.put("commands.worldborder.set.failed.big.", "commands.worldborder.set.failed.big");
mappings.put("commands.replaceitem.slot.inapplicable", "commands.item.target.no_such_slot");
mappings.put("commands.replaceitem.block.failed", "The target block is not a container");
mappings.put("commands.replaceitem.entity.success.single", "commands.item.entity.set.success.single");
mappings.put("commands.replaceitem.block.success", "commands.item.block.set.success");
mappings.put("commands.debug.reportSaved", "Created debug report in %s");
mappings.put("commands.debug.reportFailed", "Failed to create debug report");
}
@Override
protected void handleTranslate(final JsonObject object, final String translate) {
String mappedTranslation = mappings.get(translate);
if (mappedTranslation != null) {
object.addProperty("translate", mappedTranslation);
}
}
}
@@ -157,6 +157,11 @@ public final class EntityPacketRewriter1_17 extends EntityRewriter<ClientboundPa
default -> throw new IllegalArgumentException("Invalid combat type received: " + type);
};
if (type == 2) {
wrapper.passthrough(Types.VAR_INT); // Duration/Player id
wrapper.passthrough(Types.INT); // Killer id
protocol.getComponentRewriter().processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT));
}
wrapper.setPacketType(packetType);
});
@@ -30,6 +30,7 @@ import com.viaversion.viaversion.api.type.types.version.Types1_18;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPackets1_17;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.packet.ClientboundPackets1_18;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.rewriter.ComponentRewriter1_18;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.rewriter.EntityPacketRewriter1_18;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.rewriter.ItemPacketRewriter1_18;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.rewriter.WorldPacketRewriter1_18;
@@ -48,6 +49,7 @@ public final class Protocol1_17_1To1_18 extends AbstractProtocol<ClientboundPack
private final EntityPacketRewriter1_18 entityRewriter = new EntityPacketRewriter1_18(this);
private final ItemPacketRewriter1_18 itemRewriter = new ItemPacketRewriter1_18(this);
private final ParticleRewriter<ClientboundPackets1_17_1> particleRewriter = new ParticleRewriter<>(this);
private final ComponentRewriter1_18 componentRewriter = new ComponentRewriter1_18(this);
private final TagRewriter<ClientboundPackets1_17_1> tagRewriter = new TagRewriter<>(this);
public Protocol1_17_1To1_18() {
@@ -68,6 +70,17 @@ public final class Protocol1_17_1To1_18 extends AbstractProtocol<ClientboundPack
new StatisticsRewriter<>(this).register(ClientboundPackets1_17_1.AWARD_STATS);
componentRewriter.registerComponentPacket(ClientboundPackets1_17_1.CHAT);
componentRewriter.registerComponentPacket(ClientboundPackets1_17_1.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_17_1.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_17_1.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_17_1.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_17_1.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_17_1.TAB_LIST);
componentRewriter.registerOpenScreen1_14(ClientboundPackets1_17_1.OPEN_SCREEN);
componentRewriter.registerPlayerCombatKill(ClientboundPackets1_17_1.PLAYER_COMBAT_KILL);
componentRewriter.registerPing();
registerServerbound(ServerboundPackets1_17.CLIENT_INFORMATION, new PacketHandlers() {
@Override
public void register() {
@@ -130,6 +143,11 @@ public final class Protocol1_17_1To1_18 extends AbstractProtocol<ClientboundPack
return particleRewriter;
}
@Override
public ComponentRewriter1_18 getComponentRewriter() {
return componentRewriter;
}
@Override
public TagRewriter<ClientboundPackets1_17_1> getTagRewriter() {
return tagRewriter;
@@ -0,0 +1,39 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_17_1to1_18.rewriter;
import com.google.gson.JsonObject;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.protocols.v1_17to1_17_1.packet.ClientboundPackets1_17_1;
import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter;
public final class ComponentRewriter1_18 extends JsonNBTComponentRewriter<ClientboundPackets1_17_1> {
public ComponentRewriter1_18(final Protocol<ClientboundPackets1_17_1, ?, ?, ?> protocol) {
super(protocol, ReadType.JSON);
}
@Override
protected void handleTranslate(final JsonObject object, final String translate) {
if (translate.equals("commands.scoreboard.objectives.add.longName")) {
object.addProperty("translate", "Objective names cannot be longer than %s characters");
} else if (translate.equals("commands.team.add.longName")) {
object.addProperty("translate", "Team names cannot be longer than %s characters");
}
}
}
@@ -39,6 +39,7 @@ import com.viaversion.viaversion.protocols.v1_18_2to1_19.data.MappingData1_19;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.packet.ClientboundPackets1_19;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.packet.ServerboundPackets1_19;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.provider.AckSequenceProvider;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.rewriter.ComponentRewriter1_19;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.rewriter.EntityPacketRewriter1_19;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.rewriter.ItemPacketRewriter1_19;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.rewriter.WorldPacketRewriter1_19;
@@ -60,24 +61,13 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
private final EntityPacketRewriter1_19 entityRewriter = new EntityPacketRewriter1_19(this);
private final ItemPacketRewriter1_19 itemRewriter = new ItemPacketRewriter1_19(this);
private final ParticleRewriter<ClientboundPackets1_18> particleRewriter = new ParticleRewriter<>(this);
private final ComponentRewriter1_19 componentRewriter = new ComponentRewriter1_19(this);
private final TagRewriter<ClientboundPackets1_18> tagRewriter = new TagRewriter<>(this);
public Protocol1_18_2To1_19() {
super(ClientboundPackets1_18.class, ClientboundPackets1_19.class, ServerboundPackets1_17.class, ServerboundPackets1_19.class);
}
public static boolean isTextComponentNull(final JsonElement element) {
return element == null || element.isJsonNull() || (element.isJsonArray() && element.getAsJsonArray().isEmpty());
}
public static JsonElement mapTextComponentIfNull(JsonElement component) {
if (!isTextComponentNull(component)) {
return component;
} else {
return ComponentUtil.emptyJsonComponent();
}
}
@Override
protected void registerPackets() {
tagRewriter.registerGeneric(ClientboundPackets1_18.UPDATE_TAGS);
@@ -131,7 +121,7 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
new StatisticsRewriter<>(this).register(ClientboundPackets1_18.AWARD_STATS);
final PacketHandler singleNullTextComponentMapper = wrapper -> wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.read(Types.COMPONENT)));
final PacketHandler singleNullTextComponentMapper = wrapper -> wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.user(), wrapper.read(Types.COMPONENT)));
registerClientbound(ClientboundPackets1_18.SET_TITLE_TEXT, singleNullTextComponentMapper);
registerClientbound(ClientboundPackets1_18.SET_SUBTITLE_TEXT, singleNullTextComponentMapper);
registerClientbound(ClientboundPackets1_18.SET_ACTION_BAR_TEXT, singleNullTextComponentMapper);
@@ -139,20 +129,59 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
wrapper.passthrough(Types.STRING); // Objective Name
byte action = wrapper.passthrough(Types.BYTE); // Mode
if (action == 0 || action == 2) {
wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.read(Types.COMPONENT))); // Display Name
wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.user(), wrapper.read(Types.COMPONENT))); // Display Name
}
});
registerClientbound(ClientboundPackets1_18.SET_PLAYER_TEAM, wrapper -> {
wrapper.passthrough(Types.STRING); // Team Name
byte action = wrapper.passthrough(Types.BYTE); // Mode
if (action == 0 || action == 2) {
wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.read(Types.COMPONENT))); // Display Name
wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.user(), wrapper.read(Types.COMPONENT))); // Display Name
wrapper.passthrough(Types.BYTE); // Flags
wrapper.passthrough(Types.STRING); // Name Tag Visibility
wrapper.passthrough(Types.STRING); // Collision rule
wrapper.passthrough(Types.VAR_INT); // Color
wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.read(Types.COMPONENT))); // Prefix
wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.read(Types.COMPONENT))); // Suffix
wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.user(), wrapper.read(Types.COMPONENT))); // Prefix
wrapper.write(Types.COMPONENT, mapTextComponentIfNull(wrapper.user(), wrapper.read(Types.COMPONENT))); // Suffix
}
});
componentRewriter.registerBossEvent(ClientboundPackets1_18.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_18.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_18.TAB_LIST);
componentRewriter.registerOpenScreen1_14(ClientboundPackets1_18.OPEN_SCREEN);
componentRewriter.registerPlayerCombatKill(ClientboundPackets1_18.PLAYER_COMBAT_KILL);
componentRewriter.registerPing();
registerClientbound(ClientboundPackets1_18.PLAYER_INFO, wrapper -> {
final int action = wrapper.passthrough(Types.VAR_INT);
final int entries = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Types.UUID); // UUID
if (action == 0) { // Add player
wrapper.passthrough(Types.STRING); // Player Name
wrapper.passthrough(Types.PROFILE_PROPERTY_ARRAY);
wrapper.passthrough(Types.VAR_INT); // Gamemode
wrapper.passthrough(Types.VAR_INT); // Ping
final JsonElement displayName = wrapper.read(Types.OPTIONAL_COMPONENT); // Display name
if (isJsonNotNull(displayName)) {
wrapper.write(Types.OPTIONAL_COMPONENT, displayName);
} else {
wrapper.write(Types.OPTIONAL_COMPONENT, null);
}
// No public profile signature
wrapper.write(Types.OPTIONAL_PROFILE_KEY, null);
} else if (action == 1 || action == 2) { // Update gamemode/update latency
wrapper.passthrough(Types.VAR_INT);
} else if (action == 3) { // Update display name
final JsonElement displayName = wrapper.read(Types.OPTIONAL_COMPONENT); // Display name
if (isJsonNotNull(displayName)) {
wrapper.write(Types.OPTIONAL_COMPONENT, displayName);
} else {
wrapper.write(Types.OPTIONAL_COMPONENT, null);
}
}
}
});
@@ -288,10 +317,23 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol<ClientboundPack
});
}
private static long randomLong() {
private long randomLong() {
return ThreadLocalRandom.current().nextLong();
}
public boolean isJsonNotNull(final JsonElement element) {
return element != null && !element.isJsonNull() && (!element.isJsonArray() || !element.getAsJsonArray().isEmpty());
}
public JsonElement mapTextComponentIfNull(final UserConnection connection, final JsonElement component) {
if (isJsonNotNull(component)) {
componentRewriter.processText(connection, component);
return component;
} else {
return ComponentUtil.emptyJsonComponent();
}
}
@Override
protected void onMappingDataLoaded() {
Types1_19.PARTICLE.filler(this)
@@ -0,0 +1,53 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_18_2to1_19.rewriter;
import com.google.gson.JsonObject;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.protocols.v1_17_1to1_18.packet.ClientboundPackets1_18;
import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter;
import java.util.HashMap;
import java.util.Map;
public final class ComponentRewriter1_19 extends JsonNBTComponentRewriter<ClientboundPackets1_18> {
private final Map<String, String> mappings = new HashMap<>();
public ComponentRewriter1_19(final Protocol<ClientboundPackets1_18, ?, ?, ?> protocol) {
super(protocol, ReadType.JSON);
mappings.put("commands.locate.invalid", "commands.locate.structure.invalid");
mappings.put("commands.locatebiome.success", "commands.locate.biome.success");
mappings.put("command.placefeature.invalid", "commands.place.feature.failed");
mappings.put("commands.locatebiome.invalid", "commands.locate.biome.invalid");
mappings.put("commands.placefeature.invalid", "commands.place.feature.invalid");
mappings.put("commands.locatebiome.notFound", "commands.locate.biome.not_found");
mappings.put("commands.placefeature.success", "commands.place.feature.success");
mappings.put("commands.locate.failed", "commands.locate.structure.not_found");
mappings.put("commands.locate.success", "commands.locate.structure.success");
}
@Override
protected void handleTranslate(final JsonObject object, final String translate) {
String mappedTranslation = mappings.get(translate);
if (mappedTranslation != null) {
object.addProperty("translate", mappedTranslation);
}
}
}
@@ -18,7 +18,6 @@
package com.viaversion.viaversion.protocols.v1_18_2to1_19.rewriter;
import com.google.common.collect.Maps;
import com.google.gson.JsonElement;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.IntTag;
import com.viaversion.nbt.tag.ListTag;
@@ -232,38 +231,6 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter<ClientboundPa
handler(worldDataTrackerHandlerByKey());
}
});
protocol.registerClientbound(ClientboundPackets1_18.PLAYER_INFO, wrapper -> {
final int action = wrapper.passthrough(Types.VAR_INT);
final int entries = wrapper.passthrough(Types.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Types.UUID); // UUID
if (action == 0) { // Add player
wrapper.passthrough(Types.STRING); // Player Name
wrapper.passthrough(Types.PROFILE_PROPERTY_ARRAY);
wrapper.passthrough(Types.VAR_INT); // Gamemode
wrapper.passthrough(Types.VAR_INT); // Ping
final JsonElement displayName = wrapper.read(Types.OPTIONAL_COMPONENT); // Display name
if (!Protocol1_18_2To1_19.isTextComponentNull(displayName)) {
wrapper.write(Types.OPTIONAL_COMPONENT, displayName);
} else {
wrapper.write(Types.OPTIONAL_COMPONENT, null);
}
// No public profile signature
wrapper.write(Types.OPTIONAL_PROFILE_KEY, null);
} else if (action == 1 || action == 2) { // Update gamemode/update latency
wrapper.passthrough(Types.VAR_INT);
} else if (action == 3) { // Update display name
final JsonElement displayName = wrapper.read(Types.OPTIONAL_COMPONENT); // Display name
if (!Protocol1_18_2To1_19.isTextComponentNull(displayName)) {
wrapper.write(Types.OPTIONAL_COMPONENT, displayName);
} else {
wrapper.write(Types.OPTIONAL_COMPONENT, null);
}
}
}
});
}
private void writeDimensionKey(final PacketWrapper wrapper, final DimensionRegistryStorage registryStorage) {
@@ -45,6 +45,7 @@ import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ServerboundPackets1_19_3;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.rewriter.ComponentRewriter1_19_3;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.rewriter.EntityPacketRewriter1_19_3;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.rewriter.ItemPacketRewriter1_19_3;
import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.storage.NonceStorage1_19_3;
@@ -70,6 +71,7 @@ public final class Protocol1_19_1To1_19_3 extends AbstractProtocol<ClientboundPa
private final EntityPacketRewriter1_19_3 entityRewriter = new EntityPacketRewriter1_19_3(this);
private final ItemPacketRewriter1_19_3 itemRewriter = new ItemPacketRewriter1_19_3(this);
private final ParticleRewriter<ClientboundPackets1_19_1> particleRewriter = new ParticleRewriter<>(this);
private final ComponentRewriter1_19_3 componentRewriter = new ComponentRewriter1_19_3(this);
private final TagRewriter<ClientboundPackets1_19_1> tagRewriter = new TagRewriter<>(this);
public Protocol1_19_1To1_19_3() {
@@ -105,6 +107,17 @@ public final class Protocol1_19_1To1_19_3 extends AbstractProtocol<ClientboundPa
new StatisticsRewriter<>(this).register(ClientboundPackets1_19_1.AWARD_STATS);
componentRewriter.registerComponentPacket(ClientboundPackets1_19_1.SYSTEM_CHAT);
componentRewriter.registerComponentPacket(ClientboundPackets1_19_1.SET_ACTION_BAR_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_19_1.SET_TITLE_TEXT);
componentRewriter.registerComponentPacket(ClientboundPackets1_19_1.SET_SUBTITLE_TEXT);
componentRewriter.registerBossEvent(ClientboundPackets1_19_1.BOSS_EVENT);
componentRewriter.registerComponentPacket(ClientboundPackets1_19_1.DISCONNECT);
componentRewriter.registerTabList(ClientboundPackets1_19_1.TAB_LIST);
componentRewriter.registerOpenScreen1_14(ClientboundPackets1_19_1.OPEN_SCREEN);
componentRewriter.registerPlayerCombatKill(ClientboundPackets1_19_1.PLAYER_COMBAT_KILL);
componentRewriter.registerPing();
final CommandRewriter<ClientboundPackets1_19_1> commandRewriter = new CommandRewriter<>(this) {
@Override
public void handleArgument(final PacketWrapper wrapper, final String argumentType) {
@@ -389,6 +402,11 @@ public final class Protocol1_19_1To1_19_3 extends AbstractProtocol<ClientboundPa
return particleRewriter;
}
@Override
public ComponentRewriter1_19_3 getComponentRewriter() {
return componentRewriter;
}
@Override
public TagRewriter<ClientboundPackets1_19_1> getTagRewriter() {
return tagRewriter;
@@ -0,0 +1,40 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_19_1to1_19_3.rewriter;
import com.google.gson.JsonObject;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.protocols.v1_19to1_19_1.packet.ClientboundPackets1_19_1;
import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter;
public final class ComponentRewriter1_19_3 extends JsonNBTComponentRewriter<ClientboundPackets1_19_1> {
public ComponentRewriter1_19_3(final Protocol<ClientboundPackets1_19_1, ?, ?, ?> protocol) {
super(protocol, ReadType.JSON);
}
@Override
protected void handleTranslate(final JsonObject object, final String translate) {
switch (translate) {
case "commands.locate.poi.invalid" -> object.addProperty("translate", "There is no point of interest with type \"%s\"");
case "commands.locate.biome.invalid" -> object.addProperty("translate", "There is no biome with type \"%s\"");
case "multiplayer.disconnect.missing_public_key" -> object.addProperty("translate", "Missing profile public key.\nThis server requires secure profiles.");
case "multiplayer.disconnect.invalid_public_key" -> object.addProperty("translate", "Invalid signature for profile public key.\nTry restarting your game.");
}
}
}
@@ -133,6 +133,10 @@ public final class EntityPacketRewriter1_19_3 extends EntityRewriter<Clientbound
final int gamemode = wrapper.read(Types.VAR_INT);
final int ping = wrapper.read(Types.VAR_INT);
final JsonElement displayName = wrapper.read(Types.OPTIONAL_COMPONENT);
if (displayName != null) {
protocol.getComponentRewriter().processText(wrapper.user(), displayName);
}
wrapper.read(Types.OPTIONAL_PROFILE_KEY);
wrapper.write(Types.BOOLEAN, false); // No chat session data
@@ -143,7 +147,10 @@ public final class EntityPacketRewriter1_19_3 extends EntityRewriter<Clientbound
} else if (action == 1 || action == 2) { // Update gamemode/update latency
wrapper.passthrough(Types.VAR_INT);
} else if (action == 3) { // Update display name
wrapper.passthrough(Types.OPTIONAL_COMPONENT);
final JsonElement displayName = wrapper.passthrough(Types.OPTIONAL_COMPONENT);
if (displayName != null) {
protocol.getComponentRewriter().processText(wrapper.user(), displayName);
}
}
}
});
@@ -35,6 +35,10 @@ import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.libs.mcstructs.text.Style;
import com.viaversion.viaversion.libs.mcstructs.text.TextComponent;
import com.viaversion.viaversion.libs.mcstructs.text.TextFormatting;
import com.viaversion.viaversion.libs.mcstructs.text.components.TranslationComponent;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.v1_18_2to1_19.packet.ClientboundPackets1_19;
@@ -55,10 +59,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import net.lenni0451.mcstructs.text.Style;
import net.lenni0451.mcstructs.text.TextComponent;
import net.lenni0451.mcstructs.text.TextFormatting;
import net.lenni0451.mcstructs.text.components.TranslationComponent;
import org.checkerframework.checker.nullness.qual.Nullable;
public final class Protocol1_19To1_19_1 extends AbstractProtocol<ClientboundPackets1_19, ClientboundPackets1_19_1, ServerboundPackets1_19, ServerboundPackets1_19_1> {
@@ -19,8 +19,6 @@ package com.viaversion.viaversion.protocols.v1_21_2to1_21_4.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4;
import com.viaversion.viaversion.api.type.Types;
@@ -32,7 +30,6 @@ import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacke
import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.util.Key;
public final class EntityPacketRewriter1_21_4 extends EntityRewriter<ClientboundPacket1_21_2, Protocol1_21_2To1_21_4> {
@@ -46,34 +43,22 @@ public final class EntityPacketRewriter1_21_4 extends EntityRewriter<Clientbound
registerSetEntityData(ClientboundPackets1_21_2.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_2.REMOVE_ENTITIES);
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol) {
@Override
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
if (Key.stripMinecraftNamespace(key).equals("worldgen/biome")) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag effectsTag = ((CompoundTag) entry.tag()).getCompoundTag("effects");
final CompoundTag musicTag = effectsTag.getCompoundTag("music");
if (musicTag == null) {
continue;
}
// Wrap music
final ListTag<CompoundTag> weightedMusicTags = new ListTag<>(CompoundTag.class);
final CompoundTag weightedMusicTag = new CompoundTag();
weightedMusicTag.put("data", musicTag);
weightedMusicTag.putInt("weight", 1);
weightedMusicTags.add(weightedMusicTag);
effectsTag.put("music", weightedMusicTags);
}
}
return super.handle(connection, key, entries);
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
registryDataRewriter.addHandler("worldgen/biome", (key, biome) -> {
final CompoundTag effectsTag = biome.getCompoundTag("effects");
final CompoundTag musicTag = effectsTag.getCompoundTag("music");
if (musicTag == null) {
return;
}
};
// Wrap music
final ListTag<CompoundTag> weightedMusicTags = new ListTag<>(CompoundTag.class);
final CompoundTag weightedMusicTag = new CompoundTag();
weightedMusicTag.put("data", musicTag);
weightedMusicTag.putInt("weight", 1);
weightedMusicTags.add(weightedMusicTag);
effectsTag.put("music", weightedMusicTags);
});
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
registerLogin1_20_5(ClientboundPackets1_21_2.LOGIN);
@@ -75,29 +75,15 @@ public final class EntityPacketRewriter1_21_5 extends EntityRewriter<Clientbound
wrapper.write(Types.SHORT, (short) 0);
});
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol) {
@Override
public RegistryEntry[] handle(final UserConnection connection, final String key, final RegistryEntry[] entries) {
if (!key.equals("wolf_variant")) {
return super.handle(connection, key, entries);
}
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag variant = (CompoundTag) entry.tag();
final CompoundTag assets = new CompoundTag();
variant.put("assets", assets);
assets.put("wild", variant.remove("wild_texture"));
assets.put("tame", variant.remove("tame_texture"));
assets.put("angry", variant.remove("angry_texture"));
variant.remove("biomes");
}
return entries;
}
};
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
registryDataRewriter.addHandler("wolf_variant", (key, variant) -> {
final CompoundTag assets = new CompoundTag();
variant.put("assets", assets);
assets.put("wild", variant.remove("wild_texture"));
assets.put("tame", variant.remove("tame_texture"));
assets.put("angry", variant.remove("angry_texture"));
variant.remove("biomes");
});
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
protocol.registerFinishConfiguration(ClientboundConfigurationPackets1_21.FINISH_CONFIGURATION, wrapper -> {
@@ -17,6 +17,7 @@
*/
package com.viaversion.viaversion.protocols.v1_21_4to1_21_5.storage;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.viaversion.viaversion.api.minecraft.codec.CodecContext;
import com.viaversion.viaversion.api.minecraft.codec.CodecContext.RegistryAccess;
@@ -31,11 +32,11 @@ import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.Protocol1_21_4To1_21_
import com.viaversion.viaversion.util.SerializerVersion;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
public class ItemHashStorage1_21_5 implements ItemHasher {
private final Map<Long, StructuredData<?>> hashToStructuredData = CacheBuilder.newBuilder().concurrencyLevel(1).maximumSize(512).<Long, StructuredData<?>>build().asMap();
private final Cache<Long, StructuredData<?>> hashToStructuredData = CacheBuilder.newBuilder().concurrencyLevel(1).maximumSize(512).build();
private final List<String> enchantmentRegistry = new ArrayList<>();
private boolean processingClientboundInventoryPacket;
private final CodecContext context;
@@ -63,12 +64,16 @@ public class ItemHashStorage1_21_5 implements ItemHasher {
}
final long key = (long) structuredData.id() << 32 | hash;
this.hashToStructuredData.computeIfAbsent(key, $ -> structuredData.copy());
try {
this.hashToStructuredData.get(key, structuredData::copy);
} catch (final ExecutionException e) {
throw new RuntimeException(e);
}
}
public StructuredData<?> dataFromHash(final int dataComponentId, final int hash) {
final long key = (long) dataComponentId << 32 | hash;
final StructuredData<?> data = this.hashToStructuredData.get(key);
final StructuredData<?> data = this.hashToStructuredData.getIfPresent(key);
return data != null ? data.copy() : null;
}
@@ -173,7 +173,7 @@ public final class Protocol1_21_5To1_21_6 extends AbstractProtocol<ClientboundPa
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_6.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_5, SerializerVersion.V1_21_5));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_5, SerializerVersion.V1_21_6));
connection.put(new SneakStorage());
}
@@ -17,6 +17,8 @@
*/
package com.viaversion.viaversion.protocols.v1_21_5to1_21_6.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_6;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
@@ -32,6 +34,7 @@ import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPac
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.storage.SneakStorage;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.util.Key;
public final class EntityPacketRewriter1_21_6 extends EntityRewriter<ClientboundPacket1_21_5, Protocol1_21_5To1_21_6> {
@@ -50,8 +53,29 @@ public final class EntityPacketRewriter1_21_6 extends EntityRewriter<Clientbound
registerRespawn1_20_5(ClientboundPackets1_21_5.RESPAWN);
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
registryDataRewriter.addHandler("dimension_type", (key, dimension) -> {
// the client will render clouds if effects aren't set to either the_nether or the_end
String effects = dimension.getString("effects");
if (effects != null) {
effects = Key.stripMinecraftNamespace(effects);
if ("the_nether".equals(effects) || "the_end".equals(effects)) {
return; // don't show clouds
}
}
if (!dimension.contains("cloud_height")) {
dimension.putInt("cloud_height", 192);
}
});
protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle);
protocol.registerFinishConfiguration(ClientboundConfigurationPackets1_21.FINISH_CONFIGURATION, wrapper -> {
// send server links dialog as vanilla doesn't show server links by default otherwise
final PacketWrapper dialogsPacket = PacketWrapper.create(ClientboundConfigurationPackets1_21.REGISTRY_DATA, wrapper.user());
dialogsPacket.write(Types.STRING, "minecraft:dialog");
dialogsPacket.write(Types.REGISTRY_ENTRY_ARRAY, new RegistryEntry[]{serverLinksDialog()});
dialogsPacket.send(Protocol1_21_5To1_21_6.class);
});
protocol.appendClientbound(ClientboundPackets1_21_5.RESPAWN, wrapper -> {
wrapper.user().get(SneakStorage.class).setSneaking(false);
});
@@ -76,6 +100,30 @@ public final class EntityPacketRewriter1_21_6 extends EntityRewriter<Clientbound
});
}
private RegistryEntry serverLinksDialog() {
final CompoundTag serverLinksDialog = new CompoundTag();
serverLinksDialog.putString("type", "minecraft:server_links");
final CompoundTag title = new CompoundTag();
title.putString("translate", "menu.server_links.title");
serverLinksDialog.put("title", title);
final CompoundTag externalTitle = new CompoundTag();
externalTitle.putString("translate", "menu.server_links");
serverLinksDialog.put("external_title", externalTitle);
final CompoundTag exitAction = new CompoundTag();
exitAction.putInt("width", 200);
final CompoundTag exitActionLabel = new CompoundTag();
exitActionLabel.putString("translate", "gui.back");
exitAction.put("label", exitActionLabel);
serverLinksDialog.put("exit_action", exitAction);
serverLinksDialog.putInt("columns", 1);
serverLinksDialog.putInt("button_width", 310);
return new RegistryEntry("server_links", serverLinksDialog);
}
@Override
protected void registerRewrites() {
final EntityDataTypes1_21_5 entityDataTypes = VersionedTypes.V1_21_6.entityDataTypes;
@@ -0,0 +1,128 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_6to1_21_7;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys1_21_5;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_6;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_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.type.types.version.Types1_20_5;
import com.viaversion.viaversion.api.type.types.version.VersionedTypes;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.data.item.ItemHasherBase;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_6to1_21_7.rewriter.BlockItemPacketRewriter1_21_7;
import com.viaversion.viaversion.protocols.v1_21_6to1_21_7.rewriter.EntityPacketRewriter1_21_7;
import com.viaversion.viaversion.rewriter.ParticleRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.util.SerializerVersion;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
public final class Protocol1_21_6To1_21_7 extends AbstractProtocol<ClientboundPacket1_21_6, ClientboundPacket1_21_6, ServerboundPacket1_21_6, ServerboundPacket1_21_6> {
public static final MappingData MAPPINGS = new MappingDataBase("1.21.6", "1.21.7");
private final EntityPacketRewriter1_21_7 entityRewriter = new EntityPacketRewriter1_21_7(this);
private final BlockItemPacketRewriter1_21_7 itemRewriter = new BlockItemPacketRewriter1_21_7(this);
private final ParticleRewriter<ClientboundPacket1_21_6> particleRewriter = new ParticleRewriter<>(this);
private final TagRewriter<ClientboundPacket1_21_6> tagRewriter = new TagRewriter<>(this);
public Protocol1_21_6To1_21_7() {
super(ClientboundPacket1_21_6.class, ClientboundPacket1_21_6.class, ServerboundPacket1_21_6.class, ServerboundPacket1_21_6.class);
}
@Override
protected void registerPackets() {
super.registerPackets();
tagRewriter.registerGeneric(ClientboundPackets1_21_6.UPDATE_TAGS);
tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21_6.UPDATE_TAGS);
particleRewriter.registerLevelParticles1_21_4(ClientboundPackets1_21_6.LEVEL_PARTICLES);
particleRewriter.registerExplode1_21_2(ClientboundPackets1_21_6.EXPLODE); // Rewrites the included sound and particles
final SoundRewriter<ClientboundPacket1_21_6> soundRewriter = new SoundRewriter<>(this);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND);
soundRewriter.registerSound1_19_3(ClientboundPackets1_21_6.SOUND_ENTITY);
new StatisticsRewriter<>(this).register(ClientboundPackets1_21_6.AWARD_STATS);
}
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_6.PLAYER));
addItemHasher(connection, new ItemHasherBase(this, connection, SerializerVersion.V1_21_6, SerializerVersion.V1_21_6));
}
@Override
public MappingData getMappingData() {
return MAPPINGS;
}
@Override
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> types() {
return VersionedTypes.V1_21_6;
}
@Override
public Types1_20_5<StructuredDataKeys1_21_5, EntityDataTypes1_21_5> mappedTypes() {
return VersionedTypes.V1_21_6;
}
@Override
public TagRewriter<ClientboundPacket1_21_6> getTagRewriter() {
return tagRewriter;
}
@Override
public EntityPacketRewriter1_21_7 getEntityRewriter() {
return entityRewriter;
}
@Override
public BlockItemPacketRewriter1_21_7 getItemRewriter() {
return itemRewriter;
}
@Override
public ParticleRewriter<ClientboundPacket1_21_6> getParticleRewriter() {
return particleRewriter;
}
@Override
protected PacketTypesProvider<ClientboundPacket1_21_6, ClientboundPacket1_21_6, ServerboundPacket1_21_6, ServerboundPacket1_21_6> createPacketTypesProvider() {
return new SimplePacketTypesProvider<>(
packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_6.class, ClientboundConfigurationPackets1_21_6.class),
packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_6.class, ClientboundConfigurationPackets1_21_6.class),
packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_6.class),
packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_6.class, ServerboundConfigurationPackets1_21_6.class)
);
}
}
@@ -0,0 +1,63 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_6to1_21_7.rewriter;
import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_21_5;
import com.viaversion.viaversion.protocols.v1_21_4to1_21_5.rewriter.RecipeDisplayRewriter1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ServerboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_6to1_21_7.Protocol1_21_6To1_21_7;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.StructuredItemRewriter;
public final class BlockItemPacketRewriter1_21_7 extends StructuredItemRewriter<ClientboundPacket1_21_6, ServerboundPacket1_21_6, Protocol1_21_6To1_21_7> {
public BlockItemPacketRewriter1_21_7(final Protocol1_21_6To1_21_7 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
final BlockRewriter<ClientboundPacket1_21_6> blockRewriter = BlockRewriter.for1_20_2(protocol);
blockRewriter.registerBlockEvent(ClientboundPackets1_21_6.BLOCK_EVENT);
blockRewriter.registerBlockUpdate(ClientboundPackets1_21_6.BLOCK_UPDATE);
blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_6.SECTION_BLOCKS_UPDATE);
blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_6.LEVEL_EVENT, 2001);
blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_6.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_21_5::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_21_6.BLOCK_ENTITY_DATA);
registerSetCursorItem(ClientboundPackets1_21_6.SET_CURSOR_ITEM);
registerSetPlayerInventory(ClientboundPackets1_21_6.SET_PLAYER_INVENTORY);
registerCooldown1_21_2(ClientboundPackets1_21_6.COOLDOWN);
registerSetContent1_21_2(ClientboundPackets1_21_6.CONTAINER_SET_CONTENT);
registerSetSlot1_21_2(ClientboundPackets1_21_6.CONTAINER_SET_SLOT);
registerAdvancements1_20_3(ClientboundPackets1_21_6.UPDATE_ADVANCEMENTS);
registerSetEquipment(ClientboundPackets1_21_6.SET_EQUIPMENT);
registerMerchantOffers1_20_5(ClientboundPackets1_21_6.MERCHANT_OFFERS);
registerContainerClick1_21_5(ServerboundPackets1_21_6.CONTAINER_CLICK);
registerSetCreativeModeSlot1_21_5(ServerboundPackets1_21_6.SET_CREATIVE_MODE_SLOT);
final RecipeDisplayRewriter<ClientboundPacket1_21_6> recipeRewriter = new RecipeDisplayRewriter1_21_5<>(protocol);
recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_6.UPDATE_RECIPES);
recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_6.RECIPE_BOOK_ADD);
recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_6.PLACE_GHOST_RECIPE);
}
}
@@ -0,0 +1,68 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2025 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21_6to1_21_7.rewriter;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_6;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_5;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundConfigurationPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPacket1_21_6;
import com.viaversion.viaversion.protocols.v1_21_5to1_21_6.packet.ClientboundPackets1_21_6;
import com.viaversion.viaversion.protocols.v1_21_6to1_21_7.Protocol1_21_6To1_21_7;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
public final class EntityPacketRewriter1_21_7 extends EntityRewriter<ClientboundPacket1_21_6, Protocol1_21_6To1_21_7> {
public EntityPacketRewriter1_21_7(final Protocol1_21_6To1_21_7 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
registerTrackerWithData1_19(ClientboundPackets1_21_6.ADD_ENTITY, EntityTypes1_21_6.FALLING_BLOCK);
registerSetEntityData(ClientboundPackets1_21_6.SET_ENTITY_DATA);
registerRemoveEntities(ClientboundPackets1_21_6.REMOVE_ENTITIES);
registerPlayerAbilities(ClientboundPackets1_21_6.PLAYER_ABILITIES);
registerGameEvent(ClientboundPackets1_21_6.GAME_EVENT);
registerLogin1_20_5(ClientboundPackets1_21_6.LOGIN);
registerRespawn1_20_5(ClientboundPackets1_21_6.RESPAWN);
final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol);
protocol.registerClientbound(ClientboundConfigurationPackets1_21_6.REGISTRY_DATA, registryDataRewriter::handle);
}
@Override
protected void registerRewrites() {
final EntityDataTypes1_21_5 entityDataTypes = protocol.types().entityDataTypes();
registerEntityDataTypeHandler(
entityDataTypes.itemType,
entityDataTypes.blockStateType,
entityDataTypes.optionalBlockStateType,
entityDataTypes.particleType,
entityDataTypes.particlesType,
entityDataTypes.componentType,
entityDataTypes.optionalComponentType
);
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_6.getTypeFromId(type);
}
}
@@ -94,6 +94,20 @@ public final class ComponentRewriter1_21_2 extends JsonNBTComponentRewriter<Clie
}
}
@Override
protected void handleTranslate(final UserConnection connection, final CompoundTag parentTag, final StringTag translateTag) {
switch (translateTag.getValue()) {
case "commands.drop.no_loot_table" -> translateTag.setValue("Entity %s has no loot table");
case "commands.advancement.advancementNotFound" -> translateTag.setValue("No advancement was found by the name '%1$s'");
case "commands.function.success.single" -> translateTag.setValue("Test Executed %s command(s) from function '%s'");
case "commands.function.success.single.result" -> translateTag.setValue("Function '%2$s' returned %1$s");
case "commands.function.success.multiple" -> translateTag.setValue("Test Executed %s command(s) from %s functions");
case "commands.function.success.multiple.result" -> translateTag.setValue("Executed %s functions");
case "commands.fillbiome.success" -> translateTag.setValue("%s biome entry/entries set between %s, %s, %s and %s, %s, %s");
case "commands.publish.success" -> translateTag.setValue("Multiplayer game is now hosted on port %s");
}
}
public static void convertAttributes(final CompoundTag componentsTag, final FullMappings mappings) {
final CompoundTag attributeModifiers = TagUtil.getNamespacedCompoundTag(componentsTag, "attribute_modifiers");
if (attributeModifiers == null) {
@@ -40,10 +40,12 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class RegistryDataRewriter {
private final Map<String, Consumer<CompoundTag>> enchantmentEffectRewriters = new Object2ObjectArrayMap<>();
private final Map<String, BiConsumer<String, CompoundTag>> registryEntryHandlers = new Object2ObjectArrayMap<>();
private final Map<String, Consumer<CompoundTag>> enchantmentEffectHandlers = new Object2ObjectArrayMap<>(); // for nested enchantment data
private final Map<String, List<RegistryEntry>> toAdd = new Object2ObjectArrayMap<>();
private final Set<String> toRemove = new HashSet<>();
protected final Protocol<?, ?, ?, ?> protocol;
@@ -73,6 +75,18 @@ public class RegistryDataRewriter {
updateJukeboxSongs(entries);
}
final BiConsumer<String, CompoundTag> registryEntryHandler = this.registryEntryHandlers.get(key);
if (registryEntryHandler != null) {
for (final RegistryEntry entry : entries) {
if (entry.tag() == null) {
continue;
}
final CompoundTag tag = (CompoundTag) entry.tag();
registryEntryHandler.accept(entry.key(), tag);
}
}
final List<RegistryEntry> toAdd = this.toAdd.get(key);
if (toAdd != null) {
final Set<String> existingKeys = new HashSet<>();
@@ -106,14 +120,18 @@ public class RegistryDataRewriter {
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 remove(final String registryKey) {
toRemove.add(Key.stripMinecraftNamespace(registryKey));
}
public void addHandler(String registryKey, final BiConsumer<String, CompoundTag> handler) {
registryEntryHandlers.put(Key.stripMinecraftNamespace(registryKey), handler);
}
public void addEnchantmentEffectRewriter(final String key, final Consumer<CompoundTag> rewriter) {
enchantmentEffectHandlers.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);
@@ -227,15 +245,14 @@ public class RegistryDataRewriter {
}
private void runEffectRewriters(final CompoundTag effectTag) {
String effect = effectTag.getString("type");
final String effect = effectTag.getString("type");
if (effect == null) {
return;
}
effect = Key.stripMinecraftNamespace(effect);
updateAttributeField(effectTag);
final Consumer<CompoundTag> rewriter = enchantmentEffectRewriters.get(effect);
final Consumer<CompoundTag> rewriter = enchantmentEffectHandlers.get(Key.stripMinecraftNamespace(effect));
if (rewriter != null) {
rewriter.accept(effectTag);
}
@@ -23,20 +23,20 @@ import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.libs.mcstructs.text.Style;
import com.viaversion.viaversion.libs.mcstructs.text.TextComponent;
import com.viaversion.viaversion.libs.mcstructs.text.components.StringComponent;
import com.viaversion.viaversion.libs.mcstructs.text.components.TranslationComponent;
import com.viaversion.viaversion.libs.mcstructs.text.events.hover.HoverEvent;
import com.viaversion.viaversion.libs.mcstructs.text.events.hover.impl.EntityHoverEvent;
import com.viaversion.viaversion.libs.mcstructs.text.events.hover.impl.ItemHoverEvent;
import com.viaversion.viaversion.libs.mcstructs.text.serializer.TextComponentSerializer;
import com.viaversion.viaversion.libs.mcstructs.text.stringformat.StringFormat;
import com.viaversion.viaversion.libs.mcstructs.text.stringformat.handling.ColorHandling;
import com.viaversion.viaversion.libs.mcstructs.text.stringformat.handling.DeserializerUnknownHandling;
import com.viaversion.viaversion.libs.mcstructs.text.utils.TextUtils;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import net.lenni0451.mcstructs.text.Style;
import net.lenni0451.mcstructs.text.TextComponent;
import net.lenni0451.mcstructs.text.components.StringComponent;
import net.lenni0451.mcstructs.text.components.TranslationComponent;
import net.lenni0451.mcstructs.text.events.hover.HoverEvent;
import net.lenni0451.mcstructs.text.events.hover.impl.EntityHoverEvent;
import net.lenni0451.mcstructs.text.events.hover.impl.ItemHoverEvent;
import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer;
import net.lenni0451.mcstructs.text.stringformat.StringFormat;
import net.lenni0451.mcstructs.text.stringformat.handling.ColorHandling;
import net.lenni0451.mcstructs.text.stringformat.handling.DeserializerUnknownHandling;
import net.lenni0451.mcstructs.text.utils.TextUtils;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
@@ -19,13 +19,13 @@ package com.viaversion.viaversion.util;
import com.google.gson.JsonElement;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viaversion.libs.mcstructs.snbt.SNbt;
import com.viaversion.viaversion.libs.mcstructs.snbt.exceptions.SNbtDeserializeException;
import com.viaversion.viaversion.libs.mcstructs.snbt.exceptions.SNbtSerializeException;
import com.viaversion.viaversion.libs.mcstructs.text.TextComponent;
import com.viaversion.viaversion.libs.mcstructs.text.serializer.TextComponentCodec;
import com.viaversion.viaversion.libs.mcstructs.text.serializer.TextComponentSerializer;
import com.viaversion.viaversion.rewriter.text.JsonNBTComponentRewriter;
import net.lenni0451.mcstructs.snbt.SNbt;
import net.lenni0451.mcstructs.snbt.exceptions.SNbtDeserializeException;
import net.lenni0451.mcstructs.snbt.exceptions.SNbtSerializeException;
import net.lenni0451.mcstructs.text.TextComponent;
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.
@@ -50,7 +50,8 @@ public enum SerializerVersion {
V1_20_3(TextComponentCodec.V1_20_3, SNbt.V1_14),
V1_20_5(TextComponentCodec.V1_20_5, SNbt.V1_14),
V1_21_4(TextComponentCodec.V1_21_4, SNbt.V1_14),
V1_21_5(TextComponentCodec.V1_21_5, null/*Currently not needed and also not implemented 100% in MCStructs*/);
V1_21_5(TextComponentCodec.V1_21_5, null/*Currently not needed and also not implemented 100% in MCStructs*/),
V1_21_6(TextComponentCodec.V1_21_6, null);
final TextComponentSerializer jsonSerializer;
final SNbt<? extends Tag> sNbt;
@@ -93,8 +93,6 @@ hologram-y: -0.96
# Should we disable piston animation for 1.11/1.11.1 clients?
# In some cases, when firing lots of pistons, it crashes them.
piston-animation-patch: false
# Should we fix nbt for 1.12 and above clients in chat messages (causes invalid item)
chat-nbt-fix: true
# Experimental - Should we fix shift quick move action for 1.12 clients (causes shift + double click not to work when moving items) (only works on 1.8-1.11.2 bukkit based servers)
quick-move-action-fix: false
# Should we use prefix for team color on 1.13 and above clients?
+2 -2
View File
@@ -1,8 +1,8 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=5.4.0
projectVersion=5.4.1
# Smile emoji
mcVersions=1.21.6, 1.21.5, 1.21.4, 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
mcVersions=1.21.7, 1.21.6, 1.21.5, 1.21.4, 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.6
velocityVersion=3.4
+2 -2
View File
@@ -5,7 +5,7 @@ metadata.format.version = "1.1"
gson = "2.12.1"
fastutil = "8.5.15"
vianbt = "5.1.0"
mcstructs = "5-3.1.0-SNAPSHOT"
mcstructs = "5-3.1.1-SNAPSHOT"
# Common provided
netty = "4.0.20.Final"
@@ -20,7 +20,7 @@ checkerQual = "3.49.1"
paper = "1.20.4-R0.1-SNAPSHOT"
legacyBukkit = "1.8.8-R0.1-SNAPSHOT"
velocity = "3.1.1"
viaProxy = "3.4.2-SNAPSHOT"
viaProxy = "3.4.3-SNAPSHOT"
[libraries]