diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index b1361d123..fa5194a1f 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,3 @@ github: kennytv patreon: kennytv +custom: ['https://florianmichael.de/donate'] diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index fd389ec4b..2395d98ca 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -21,10 +21,11 @@ body: - type: textarea attributes: - label: Console Error + label: Server/Client Error description: | If you encounter warnings/errors in your console, **paste them with https://mclo.gs/ and put the paste link here**. If the error is small/less than 10 lines, you may put it directly into this field. + **Important**: If you are kicked for `Network Protocol Error` or an encoder/decoder exception, please click the `Open Report Directory` button on your client and paste the newest disconnect file contents. value: | ``` Put the mclo.gs link or text here. @@ -51,7 +52,7 @@ body: List the steps on how we can reproduce the issue. Make sure we can easily understand what you mean with each step. placeholder: | Example: - 1. Login with a 1.13.2 client + 1. Login with a 1.21.3 client 2. Place a sign 3. The sign text is displayed wrong validations: diff --git a/.gitignore b/.gitignore index a638baf11..15b6889e0 100644 --- a/.gitignore +++ b/.gitignore @@ -109,4 +109,7 @@ nb-configuration.xml .nb-gradle/ ### MacOS ### -.DS_Store \ No newline at end of file +.DS_Store + +### Run Folder (ViaProxy) ### +common/run/ diff --git a/README.md b/README.md index ed691448a..1712c8bd2 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,13 @@ Supported Versions: **User Docs:** https://docs.viaversion.com/display/VIAVERSION/ +Snapshot support +-------- +**ViaVersion will only be released a few days *after* a Minecraft update** unless the protocol changes of the update were trivial. If you want early-access, usually days or even weeks before the final release, you can subscribe to either: +- [GitHub Sponsors](https://github.com/sponsors/kennytv/sponsorships?sponsor=kennytv&tier_id=385613&preview=false) (preferred option. Use the `/verify` command on this Discord after), or alternatively +- [Patreon](https://www.patreon.com/kennytv/membership) (see the highest tier and make sure to link Patreon to your Discord account under Settings->Connections) + This also includes access to a private repository with the code, which will be pushed to the public repository after the given delay on a Minecraft update. + Releases/Dev Builds -------- You can find official releases in the following places: @@ -91,8 +98,7 @@ Resources - **[Via Mappings Generator](https://github.com/ViaVersion/Mappings)** - **[Mojang mappings](https://minecraft.wiki/w/Obfuscation_map)** (Thank you, Mojang, very cool) -- **[wiki.vg](https://wiki.vg)** (Used for historic information regarding packet structure, we also contribute back) -- **[Burger](https://github.com/Pokechu22/Burger)** (See [PAaaS](https://github.com/Matsv/Paaas)) +- Previously: **[Burger](https://github.com/Pokechu22/Burger)** (see [PAaaS](https://github.com/Matsv/Paaas)) and **wiki.vg** License -------- diff --git a/api/build.gradle.kts b/api/build.gradle.kts index ee08a31c3..e3387e596 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -19,7 +19,9 @@ dependencies { api(libs.vianbt) { exclude("it.unimi.dsi", "fastutil") } - api(libs.gson) + api(libs.gson) { + exclude("com.google.errorprone", "error_prone_annotations") + } implementation(rootProject.libs.text) { exclude("com.google.code.gson", "gson") exclude("com.viaversion", "nbt") diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/FullMappings.java b/api/src/main/java/com/viaversion/viaversion/api/data/FullMappings.java index e9081ef20..be319a37a 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/FullMappings.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/FullMappings.java @@ -53,6 +53,14 @@ public interface FullMappings extends BiMappings { */ @Nullable String identifier(int id); + /** + * Returns the unmapped string identifier for the given mapped identifier. + * + * @param mappedIdentifier mapped identifier + * @return unmapped string identifier, or null if not found + */ + @Nullable String identifier(String mappedIdentifier); + /** * Returns the mapped string identifier for the given mapped id. * diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/FullMappingsBase.java b/api/src/main/java/com/viaversion/viaversion/api/data/FullMappingsBase.java index 9c4e7fccb..cd108b3e7 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/FullMappingsBase.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/FullMappingsBase.java @@ -84,7 +84,18 @@ public class FullMappingsBase implements FullMappings { } @Override - public String mappedIdentifier(final int mappedId) { + public @Nullable String identifier(final String mappedIdentifier) { + final int mappedId = mappedId(mappedIdentifier); + if (mappedId == -1) { + return null; + } + + final int id = mappings.inverse().getNewId(mappedId); + return id != -1 ? identifier(id) : null; + } + + @Override + public @Nullable String mappedIdentifier(final int mappedId) { if (mappedId < 0 || mappedId >= mappedIdToString.length) { return null; } diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/MappingData.java b/api/src/main/java/com/viaversion/viaversion/api/data/MappingData.java index b46fa9524..e9ed08785 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/MappingData.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/MappingData.java @@ -35,56 +35,82 @@ public interface MappingData { void load(); /** - * Returns the mapped block state id, or -1 if unmapped. + * Returns the mapped block state id, or 0 if unmapped. * * @param id unmapped block state id - * @return mapped block state id, or -1 if unmapped + * @return mapped block state id, or 0 if unmapped * @throws NullPointerException if this mappingdata does not hold block state mappings */ int getNewBlockStateId(int id); /** - * Returns the mapped block id, or -1 if unmapped. + * Returns the mapped block id, or 0 if unmapped. * * @param id unmapped block id - * @return mapped block id, or -1 if unmapped + * @return mapped block id, or 0 if unmapped * @throws NullPointerException if this mappingdata does not hold block mappings */ int getNewBlockId(int id); + /** + * Returns the backwards mapped block id, or 1 if unmapped. + * + * @param id mapped block id + * @return backwards mapped block id, or 1 if unmapped + */ int getOldBlockId(int id); /** - * Returns the mapped item id, or -1 if unmapped. + * Returns the mapped item id, or 0 if unmapped. * * @param id unmapped item id - * @return mapped item id, or -1 if unmapped + * @return mapped item id, or 0 if unmapped * @throws NullPointerException if this mappingdata does not hold item mappings */ int getNewItemId(int id); /** - * Returns the backwards mapped item id, or -1 if unmapped. + * Returns the backwards mapped item id, or 1 if unmapped. * * @param id mapped item id - * @return backwards mapped item id, or -1 if unmapped + * @return backwards mapped item id, or 1 if unmapped * @throws NullPointerException if this mappingdata does not hold item mappings */ int getOldItemId(int id); /** - * Returns the mapped particle id, or -1 if unmapped. + * Returns the mapped particle id, or 0 if unmapped. * * @param id unmapped particle id - * @return mapped particle id, or -1 if unmapped + * @return mapped particle id, or 0 if unmapped * @throws NullPointerException if this mappingdata does not hold particle mappings */ int getNewParticleId(int id); + /** + * Returns the mapped attribute id, or 0 if unmapped. + * + * @param id unmapped attribute id + * @return mapped attribute id, or 0 if unmapped + * @throws NullPointerException if this mappingdata does not hold attribute mappings + */ int getNewAttributeId(int id); + /** + * Returns the mapped sound id, or 0 if unmapped. + * + * @param id unmapped sound id + * @return mapped sound id, or 0 if unmapped + * @throws NullPointerException if this mappingdata does not hold sound mappings + */ int getNewSoundId(int id); + /** + * Returns the backwards mapped sound id, or 1 if unmapped. + * + * @param i mapped sound id + * @return backwards mapped sound id, or 1 if unmapped + */ int getOldSoundId(int i); /** @@ -126,10 +152,10 @@ public interface MappingData { @Nullable Mappings getEnchantmentMappings(); - @Nullable Mappings getAttributeMappings(); - @Nullable Mappings getPaintingMappings(); + @Nullable FullMappings getAttributeMappings(); + @Nullable FullMappings getEntityMappings(); @Nullable FullMappings getArgumentTypeMappings(); diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/MappingDataBase.java b/api/src/main/java/com/viaversion/viaversion/api/data/MappingDataBase.java index 06283302e..01b8bda51 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/MappingDataBase.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/MappingDataBase.java @@ -43,10 +43,10 @@ public class MappingDataBase implements MappingData { protected FullMappings entityMappings; protected FullMappings recipeSerializerMappings; protected FullMappings itemDataSerializerMappings; + protected FullMappings attributeMappings; protected ParticleMappings particleMappings; protected BiMappings itemMappings; protected BiMappings blockMappings; - protected BiMappings attributeMappings; protected Mappings blockStateMappings; protected Mappings blockEntityMappings; protected Mappings soundMappings; @@ -76,8 +76,6 @@ public class MappingDataBase implements MappingData { menuMappings = loadMappings(data, "menus"); enchantmentMappings = loadMappings(data, "enchantments"); paintingMappings = loadMappings(data, "paintings"); - attributeMappings = loadBiMappings(data, "attributes"); - final CompoundTag unmappedIdentifierData = readUnmappedIdentifiersFile("identifiers-" + unmappedVersion + ".nbt"); final CompoundTag mappedIdentifierData = readMappedIdentifiersFile("identifiers-" + mappedVersion + ".nbt"); @@ -87,6 +85,7 @@ public class MappingDataBase implements MappingData { argumentTypeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "argumenttypes"); recipeSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "recipe_serializers"); itemDataSerializerMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "data_component_type"); + attributeMappings = loadFullMappings(data, unmappedIdentifierData, mappedIdentifierData, "attributes"); final List unmappedParticles = identifiersFromGlobalIds(unmappedIdentifierData, "particles"); final List mappedParticles = identifiersFromGlobalIds(mappedIdentifierData, "particles"); @@ -180,7 +179,7 @@ public class MappingDataBase implements MappingData { @Override public int getOldBlockId(final int id) { - return blockMappings.getNewIdOrDefault(id, 1); + return blockMappings.inverse().getNewIdOrDefault(id, 1); } @Override @@ -272,7 +271,7 @@ public class MappingDataBase implements MappingData { } @Override - public @Nullable Mappings getAttributeMappings() { + public @Nullable FullMappings getAttributeMappings() { return attributeMappings; } diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/ParticleMappings.java b/api/src/main/java/com/viaversion/viaversion/api/data/ParticleMappings.java index b15881411..468145907 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/ParticleMappings.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/ParticleMappings.java @@ -36,6 +36,7 @@ public class ParticleMappings extends FullMappingsBase { addBlockParticle("falling_dust"); addBlockParticle("block_marker"); addBlockParticle("dust_pillar"); + addBlockParticle("block_crumble"); addItemParticle("item"); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/debug/DebugHandler.java b/api/src/main/java/com/viaversion/viaversion/api/debug/DebugHandler.java index 84ad255a3..823653a65 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/debug/DebugHandler.java +++ b/api/src/main/java/com/viaversion/viaversion/api/debug/DebugHandler.java @@ -78,7 +78,7 @@ public interface DebugHandler { /** * Returns whether packets should be logged after being transformed. - * Set to true by default. + * Set to false by default. * * @return whether packets should be logged after being transformed */ diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/BlockPosition.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/BlockPosition.java index f8ab744d0..e723379cf 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/BlockPosition.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/BlockPosition.java @@ -37,6 +37,13 @@ public class BlockPosition { return new BlockPosition(x + face.modX(), y + face.modY(), z + face.modZ()); } + public double distanceFromCenterSquared(final double x, final double y, final double z) { + final double dx = this.x + 0.5 - x; + final double dy = this.y + 0.5 - y; + final double dz = this.z + 0.5 - z; + return dx * dx + dy * dy + dz * dz; + } + public int x() { return x; } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/ChunkPosition.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/ChunkPosition.java index 400dd6136..5ff063f15 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/ChunkPosition.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/ChunkPosition.java @@ -66,6 +66,17 @@ public final class ChunkPosition { return (long) chunkX & 0xffffffffL | ((long) chunkZ & 0xffffffffL) << 32; } + /** + * Returns a long key for the given block coordinates. + * + * @param x the block X coordinate + * @param z the block Z coordinate + * @return the chunk key + */ + public static long chunkKeyForBlock(final int x, final int z) { + return chunkKey(x >> 4, z >> 4); + } + @Override public boolean equals(final Object o) { if (this == o) return true; diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/Holder.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/Holder.java index d597ba9ca..b056fa2ed 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/Holder.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/Holder.java @@ -35,7 +35,7 @@ public interface Holder { * @throws IllegalArgumentException if the id is negative */ static Holder of(final int id) { - return new HolderImpl<>(id); + return new IdHolder<>(id); } /** @@ -46,7 +46,7 @@ public interface Holder { * @return a new direct holder */ static Holder of(final T value) { - return new HolderImpl<>(value); + return new ValueHolder<>(value); } /** diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderSet.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderSet.java index 087cdf07b..ccd0e1d2f 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderSet.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderSet.java @@ -36,7 +36,7 @@ public interface HolderSet { * @return a new holder set */ static HolderSet of(final String tagKey) { - return new HolderSetImpl(tagKey); + return new HolderSetImpl.Tag(tagKey); } /** @@ -46,7 +46,7 @@ public interface HolderSet { * @return a new holder set */ static HolderSet of(final int[] ids) { - return new HolderSetImpl(ids); + return new HolderSetImpl.Ids(ids); } /** diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderSetImpl.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderSetImpl.java index 5557da917..5c9c5d095 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderSetImpl.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderSetImpl.java @@ -22,50 +22,63 @@ */ package com.viaversion.viaversion.api.minecraft; -import com.viaversion.viaversion.util.EitherImpl; import it.unimi.dsi.fastutil.ints.Int2IntFunction; +import java.util.Arrays; -final class HolderSetImpl extends EitherImpl implements HolderSet { +final class HolderSetImpl { - HolderSetImpl(final String tagKey) { - super(tagKey, null); - } + record Tag(String tagKey) implements HolderSet { + @Override + public boolean hasTagKey() { + return true; + } - HolderSetImpl(final int[] ids) { - super(null, ids); - } + @Override + public int[] ids() { + throw new IllegalArgumentException("This holder set has a tag key"); + } - @Override - public String tagKey() { - return left(); - } + @Override + public boolean hasIds() { + return false; + } - @Override - public boolean hasTagKey() { - return isLeft(); - } - - @Override - public int[] ids() { - return right(); - } - - @Override - public boolean hasIds() { - return isRight(); - } - - @Override - public HolderSet rewrite(final Int2IntFunction idRewriter) { - if (hasTagKey()) { + @Override + public HolderSet rewrite(final Int2IntFunction idRewriter) { return this; } + } - final int[] ids = ids(); - final int[] mappedIds = new int[ids.length]; - for (int i = 0; i < mappedIds.length; i++) { - mappedIds[i] = idRewriter.applyAsInt(ids[i]); + record Ids(int[] ids) implements HolderSet { + @Override + public boolean hasTagKey() { + return false; + } + + @Override + public String tagKey() { + throw new IllegalArgumentException("This holder set has direct ids"); + } + + @Override + public boolean hasIds() { + return true; + } + + @Override + public HolderSet rewrite(final Int2IntFunction idRewriter) { + final int[] mappedIds = new int[ids.length]; + for (int i = 0; i < mappedIds.length; i++) { + mappedIds[i] = idRewriter.applyAsInt(ids[i]); + } + return new Ids(mappedIds); + } + + @Override + public String toString() { + return "Ids{" + + "ids=" + Arrays.toString(ids) + + '}'; } - return new HolderSetImpl(mappedIds); } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderImpl.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/IdHolder.java similarity index 73% rename from api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderImpl.java rename to api/src/main/java/com/viaversion/viaversion/api/minecraft/IdHolder.java index bcbaaf390..1386d50b3 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/HolderImpl.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/IdHolder.java @@ -25,49 +25,29 @@ package com.viaversion.viaversion.api.minecraft; import com.google.common.base.Preconditions; import it.unimi.dsi.fastutil.ints.Int2IntFunction; -final class HolderImpl implements Holder { +record IdHolder(int id) implements Holder { - private final T value; - private final int id; - - HolderImpl(final int id) { + IdHolder { Preconditions.checkArgument(id >= 0, "id cannot be negative"); - this.value = null; - this.id = id; - } - - HolderImpl(final T value) { - this.value = value; - this.id = -1; } @Override public boolean isDirect() { - return id == -1; + return false; } @Override public boolean hasId() { - return id != -1; + return true; } @Override public T value() { - Preconditions.checkArgument(isDirect(), "Holder is not direct"); - return value; - } - - @Override - public int id() { - return id; + throw new IllegalArgumentException("Holder is not direct"); } @Override public Holder updateId(final Int2IntFunction rewriteFunction) { - if (isDirect()) { - return this; - } - final int rewrittenId = rewriteFunction.applyAsInt(id); if (rewrittenId == id) { return this; @@ -77,12 +57,4 @@ final class HolderImpl implements Holder { } return Holder.of(rewrittenId); } - - @Override - public String toString() { - return "HolderImpl{" + - "value=" + value + - ", id=" + id + - '}'; - } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/PaintingVariant.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/PaintingVariant.java index 90073d972..d5fb1424d 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/PaintingVariant.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/PaintingVariant.java @@ -22,13 +22,19 @@ */ package com.viaversion.viaversion.api.minecraft; +import com.viaversion.nbt.tag.Tag; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.misc.HolderType; import io.netty.buffer.ByteBuf; +import org.checkerframework.checker.nullness.qual.Nullable; -public record PaintingVariant(int width, int height, String assetId) { +public record PaintingVariant(int width, int height, String assetId, @Nullable Tag title, @Nullable Tag author) { - public static HolderType TYPE = new HolderType<>() { + public PaintingVariant(final int width, final int height, final String assetId) { + this(width, height, assetId, null, null); + } + + public static HolderType TYPE1_21 = new HolderType<>() { @Override public PaintingVariant readDirect(final ByteBuf buffer) { final int width = Types.VAR_INT.readPrimitive(buffer); @@ -44,4 +50,24 @@ public record PaintingVariant(int width, int height, String assetId) { Types.STRING.write(buffer, variant.assetId()); } }; + public static HolderType TYPE1_21_2 = new HolderType<>() { + @Override + public PaintingVariant readDirect(final ByteBuf buffer) { + final int width = Types.VAR_INT.readPrimitive(buffer); + final int height = Types.VAR_INT.readPrimitive(buffer); + final String assetId = Types.STRING.read(buffer); + final Tag title = Types.OPTIONAL_TAG.read(buffer); + final Tag author = Types.OPTIONAL_TAG.read(buffer); + return new PaintingVariant(width, height, assetId, title, author); + } + + @Override + public void writeDirect(final ByteBuf buffer, final PaintingVariant variant) { + Types.VAR_INT.writePrimitive(buffer, variant.width()); + Types.VAR_INT.writePrimitive(buffer, variant.height()); + Types.STRING.write(buffer, variant.assetId()); + Types.OPTIONAL_TAG.write(buffer, variant.title()); + Types.OPTIONAL_TAG.write(buffer, variant.author()); + } + }; } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/RegistryEntry.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/RegistryEntry.java index 36ab302b0..c210fd82d 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/RegistryEntry.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/RegistryEntry.java @@ -36,4 +36,8 @@ public record RegistryEntry(String key, @Nullable Tag tag) { public RegistryEntry withKey(final String key) { return new RegistryEntry(key, tag != null ? tag.copy() : null); } + + public RegistryEntry copy() { + return new RegistryEntry(key, tag != null ? tag.copy() : null); + } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/ValueHolder.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/ValueHolder.java new file mode 100644 index 000000000..c34b07cd0 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/ValueHolder.java @@ -0,0 +1,48 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft; + +import it.unimi.dsi.fastutil.ints.Int2IntFunction; + +record ValueHolder(T value) implements Holder { + + @Override + public boolean isDirect() { + return true; + } + + @Override + public boolean hasId() { + return false; + } + + @Override + public int id() { + return -1; + } + + @Override + public Holder updateId(final Int2IntFunction rewriteFunction) { + return this; + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionImpl.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionImpl.java index c24fcaaf6..402fc0913 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionImpl.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionImpl.java @@ -37,14 +37,14 @@ public class ChunkSectionImpl implements ChunkSection { public ChunkSectionImpl(final boolean holdsLight) { addPalette(PaletteType.BLOCKS, new DataPaletteImpl(ChunkSection.SIZE)); if (holdsLight) { - this.light = new ChunkSectionLightImpl(); + this.light = ChunkSectionLightImpl.createWithBlockLight(); } } public ChunkSectionImpl(final boolean holdsLight, final int expectedPaletteLength) { addPalette(PaletteType.BLOCKS, new DataPaletteImpl(ChunkSection.SIZE, expectedPaletteLength)); if (holdsLight) { - this.light = new ChunkSectionLightImpl(); + this.light = ChunkSectionLightImpl.createWithBlockLight(); } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionLight.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionLight.java index 7badd3d5f..bb63a43c6 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionLight.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionLight.java @@ -35,7 +35,7 @@ public interface ChunkSectionLight { /** * Returns whether the section has sky light. * - * @return true if skylight is present + * @return true if sky light is present */ boolean hasSkyLight(); @@ -43,7 +43,7 @@ public interface ChunkSectionLight { * Returns whether the section has block light. * This returns true unless specifically set to null. * - * @return true if skylight is present + * @return true if block light is present */ boolean hasBlockLight(); diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionLightImpl.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionLightImpl.java index eb039d79f..61e49a76d 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionLightImpl.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/ChunkSectionLightImpl.java @@ -30,9 +30,17 @@ public class ChunkSectionLightImpl implements ChunkSectionLight { private NibbleArray blockLight; private NibbleArray skyLight; - public ChunkSectionLightImpl() { - // Block light is always written - this.blockLight = new NibbleArray(ChunkSection.SIZE); + protected ChunkSectionLightImpl() { + } + + public static ChunkSectionLight createWithBlockLight() { + final ChunkSectionLightImpl light = new ChunkSectionLightImpl(); + light.blockLight = new NibbleArray(ChunkSection.SIZE); + return light; + } + + public static ChunkSectionLight createEmpty() { + return new ChunkSectionLightImpl(); } @Override diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/data/StructuredDataKey.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/data/StructuredDataKey.java index 7f40096ce..3560ad31a 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/data/StructuredDataKey.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/data/StructuredDataKey.java @@ -26,6 +26,7 @@ import com.viaversion.nbt.tag.CompoundTag; import com.viaversion.nbt.tag.Tag; import com.viaversion.viaversion.api.minecraft.GameProfile; import com.viaversion.viaversion.api.minecraft.Holder; +import com.viaversion.viaversion.api.minecraft.HolderSet; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.item.data.AdventureModePredicate; import com.viaversion.viaversion.api.minecraft.item.data.ArmorTrim; @@ -34,13 +35,20 @@ import com.viaversion.viaversion.api.minecraft.item.data.AttributeModifiers1_21; import com.viaversion.viaversion.api.minecraft.item.data.BannerPatternLayer; import com.viaversion.viaversion.api.minecraft.item.data.Bee; import com.viaversion.viaversion.api.minecraft.item.data.BlockStateProperties; +import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2; +import com.viaversion.viaversion.api.minecraft.item.data.CustomModelData1_21_4; +import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant; +import com.viaversion.viaversion.api.minecraft.item.data.DeathProtection; import com.viaversion.viaversion.api.minecraft.item.data.DyedColor; import com.viaversion.viaversion.api.minecraft.item.data.Enchantments; +import com.viaversion.viaversion.api.minecraft.item.data.Equippable; import com.viaversion.viaversion.api.minecraft.item.data.FilterableString; import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion; import com.viaversion.viaversion.api.minecraft.item.data.Fireworks; -import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties; -import com.viaversion.viaversion.api.minecraft.item.data.Instrument; +import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5; +import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_21_2; +import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5; +import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2; import com.viaversion.viaversion.api.minecraft.item.data.JukeboxPlayable; import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker; import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations; @@ -48,11 +56,15 @@ import com.viaversion.viaversion.api.minecraft.item.data.PotionContents; import com.viaversion.viaversion.api.minecraft.item.data.SuspiciousStewEffect; import com.viaversion.viaversion.api.minecraft.item.data.ToolProperties; import com.viaversion.viaversion.api.minecraft.item.data.Unbreakable; +import com.viaversion.viaversion.api.minecraft.item.data.UseCooldown; import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.ArrayType; import com.viaversion.viaversion.api.type.types.version.Types1_20_5; import com.viaversion.viaversion.api.type.types.version.Types1_21; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.api.type.types.version.Types1_21_4; import com.viaversion.viaversion.util.Unit; public record StructuredDataKey(String identifier, Type type) { @@ -64,24 +76,38 @@ public record StructuredDataKey(String identifier, Type type) { public static final StructuredDataKey UNBREAKABLE = new StructuredDataKey<>("unbreakable", Unbreakable.TYPE); public static final StructuredDataKey CUSTOM_NAME = new StructuredDataKey<>("custom_name", Types.TAG); public static final StructuredDataKey ITEM_NAME = new StructuredDataKey<>("item_name", Types.TAG); - public static final StructuredDataKey LORE = new StructuredDataKey<>("lore", Types.TAG_ARRAY); + public static final StructuredDataKey ITEM_MODEL = new StructuredDataKey<>("item_model", Types.STRING); + public static final StructuredDataKey LORE = new StructuredDataKey<>("lore", new ArrayType<>(Types.TAG, 256)); public static final StructuredDataKey RARITY = new StructuredDataKey<>("rarity", Types.VAR_INT); public static final StructuredDataKey ENCHANTMENTS = new StructuredDataKey<>("enchantments", Enchantments.TYPE); public static final StructuredDataKey CAN_PLACE_ON = new StructuredDataKey<>("can_place_on", AdventureModePredicate.TYPE); public static final StructuredDataKey CAN_BREAK = new StructuredDataKey<>("can_break", AdventureModePredicate.TYPE); public static final StructuredDataKey ATTRIBUTE_MODIFIERS1_20_5 = new StructuredDataKey<>("attribute_modifiers", AttributeModifiers1_20_5.TYPE); public static final StructuredDataKey ATTRIBUTE_MODIFIERS1_21 = new StructuredDataKey<>("attribute_modifiers", AttributeModifiers1_21.TYPE); - public static final StructuredDataKey CUSTOM_MODEL_DATA = new StructuredDataKey<>("custom_model_data", Types.VAR_INT); + public static final StructuredDataKey CUSTOM_MODEL_DATA1_20_5 = new StructuredDataKey<>("custom_model_data", Types.VAR_INT); + public static final StructuredDataKey CUSTOM_MODEL_DATA1_21_4 = new StructuredDataKey<>("custom_model_data", CustomModelData1_21_4.TYPE); public static final StructuredDataKey HIDE_ADDITIONAL_TOOLTIP = new StructuredDataKey<>("hide_additional_tooltip", Types.EMPTY); public static final StructuredDataKey HIDE_TOOLTIP = new StructuredDataKey<>("hide_tooltip", Types.EMPTY); public static final StructuredDataKey REPAIR_COST = new StructuredDataKey<>("repair_cost", Types.VAR_INT); public static final StructuredDataKey CREATIVE_SLOT_LOCK = new StructuredDataKey<>("creative_slot_lock", Types.EMPTY); public static final StructuredDataKey ENCHANTMENT_GLINT_OVERRIDE = new StructuredDataKey<>("enchantment_glint_override", Types.BOOLEAN); public static final StructuredDataKey INTANGIBLE_PROJECTILE = new StructuredDataKey<>("intangible_projectile", Types.TAG); // Doesn't actually hold data - public static final StructuredDataKey FOOD1_20_5 = new StructuredDataKey<>("food", FoodProperties.TYPE1_20_5); - public static final StructuredDataKey FOOD1_21 = new StructuredDataKey<>("food", FoodProperties.TYPE1_21); + public static final StructuredDataKey FOOD1_20_5 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_20_5); + public static final StructuredDataKey FOOD1_21 = new StructuredDataKey<>("food", FoodProperties1_20_5.TYPE1_21); + public static final StructuredDataKey FOOD1_21_2 = new StructuredDataKey<>("food", FoodProperties1_21_2.TYPE); + public static final StructuredDataKey CONSUMABLE1_21_2 = new StructuredDataKey<>("consumable", Consumable1_21_2.TYPE); + public static final StructuredDataKey USE_REMAINDER1_21_2 = new StructuredDataKey<>("use_remainder", Types1_21_2.ITEM); + public static final StructuredDataKey USE_REMAINDER1_21_4 = new StructuredDataKey<>("use_remainder", Types1_21_4.ITEM); + public static final StructuredDataKey USE_COOLDOWN = new StructuredDataKey<>("use_cooldown", UseCooldown.TYPE); public static final StructuredDataKey FIRE_RESISTANT = new StructuredDataKey<>("fire_resistant", Types.EMPTY); + public static final StructuredDataKey DAMAGE_RESISTANT = new StructuredDataKey<>("damage_resistant", DamageResistant.TYPE); public static final StructuredDataKey TOOL = new StructuredDataKey<>("tool", ToolProperties.TYPE); + public static final StructuredDataKey ENCHANTABLE = new StructuredDataKey<>("enchantable", Types.VAR_INT); + public static final StructuredDataKey EQUIPPABLE = new StructuredDataKey<>("equippable", Equippable.TYPE); + public static final StructuredDataKey REPAIRABLE = new StructuredDataKey<>("repairable", Types.HOLDER_SET); + public static final StructuredDataKey GLIDER = new StructuredDataKey<>("glider", Types.EMPTY); + public static final StructuredDataKey TOOLTIP_STYLE = new StructuredDataKey<>("tooltip_style", Types.STRING); + public static final StructuredDataKey DEATH_PROTECTION = new StructuredDataKey<>("death_protection", DeathProtection.TYPE); public static final StructuredDataKey STORED_ENCHANTMENTS = new StructuredDataKey<>("stored_enchantments", Enchantments.TYPE); public static final StructuredDataKey DYED_COLOR = new StructuredDataKey<>("dyed_color", DyedColor.TYPE); public static final StructuredDataKey MAP_COLOR = new StructuredDataKey<>("map_color", Types.INT); @@ -90,18 +116,26 @@ public record StructuredDataKey(String identifier, Type type) { public static final StructuredDataKey MAP_POST_PROCESSING = new StructuredDataKey<>("map_post_processing", Types.VAR_INT); public static final StructuredDataKey CHARGED_PROJECTILES1_20_5 = new StructuredDataKey<>("charged_projectiles", Types1_20_5.ITEM_ARRAY); public static final StructuredDataKey CHARGED_PROJECTILES1_21 = new StructuredDataKey<>("charged_projectiles", Types1_21.ITEM_ARRAY); + public static final StructuredDataKey CHARGED_PROJECTILES1_21_2 = new StructuredDataKey<>("charged_projectiles", Types1_21_2.ITEM_ARRAY); + public static final StructuredDataKey CHARGED_PROJECTILES1_21_4 = new StructuredDataKey<>("charged_projectiles", Types1_21_4.ITEM_ARRAY); public static final StructuredDataKey BUNDLE_CONTENTS1_20_5 = new StructuredDataKey<>("bundle_contents", Types1_20_5.ITEM_ARRAY); public static final StructuredDataKey BUNDLE_CONTENTS1_21 = new StructuredDataKey<>("bundle_contents", Types1_21.ITEM_ARRAY); - public static final StructuredDataKey POTION_CONTENTS = new StructuredDataKey<>("potion_contents", PotionContents.TYPE); + public static final StructuredDataKey BUNDLE_CONTENTS1_21_2 = new StructuredDataKey<>("bundle_contents", Types1_21_2.ITEM_ARRAY); + public static final StructuredDataKey BUNDLE_CONTENTS1_21_4 = new StructuredDataKey<>("bundle_contents", Types1_21_4.ITEM_ARRAY); + public static final StructuredDataKey POTION_CONTENTS1_20_5 = new StructuredDataKey<>("potion_contents", PotionContents.TYPE1_20_5); + public static final StructuredDataKey POTION_CONTENTS1_21_2 = new StructuredDataKey<>("potion_contents", PotionContents.TYPE1_21_2); public static final StructuredDataKey SUSPICIOUS_STEW_EFFECTS = new StructuredDataKey<>("suspicious_stew_effects", SuspiciousStewEffect.ARRAY_TYPE); public static final StructuredDataKey WRITABLE_BOOK_CONTENT = new StructuredDataKey<>("writable_book_content", FilterableString.ARRAY_TYPE); public static final StructuredDataKey WRITTEN_BOOK_CONTENT = new StructuredDataKey<>("written_book_content", WrittenBook.TYPE); - public static final StructuredDataKey TRIM = new StructuredDataKey<>("trim", ArmorTrim.TYPE); + public static final StructuredDataKey TRIM1_20_5 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_20_5); + public static final StructuredDataKey TRIM1_21_2 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_21_2); + public static final StructuredDataKey TRIM1_21_4 = new StructuredDataKey<>("trim", ArmorTrim.TYPE1_21_4); public static final StructuredDataKey DEBUG_STICK_STATE = new StructuredDataKey<>("debug_stick_state", Types.COMPOUND_TAG); public static final StructuredDataKey ENTITY_DATA = new StructuredDataKey<>("entity_data", Types.COMPOUND_TAG); public static final StructuredDataKey BUCKET_ENTITY_DATA = new StructuredDataKey<>("bucket_entity_data", Types.COMPOUND_TAG); public static final StructuredDataKey BLOCK_ENTITY_DATA = new StructuredDataKey<>("block_entity_data", Types.COMPOUND_TAG); - public static final StructuredDataKey> INSTRUMENT = new StructuredDataKey<>("instrument", Instrument.TYPE); + public static final StructuredDataKey> INSTRUMENT1_20_5 = new StructuredDataKey<>("instrument", Instrument1_20_5.TYPE); + public static final StructuredDataKey> INSTRUMENT1_21_2 = new StructuredDataKey<>("instrument", Instrument1_21_2.TYPE); public static final StructuredDataKey OMINOUS_BOTTLE_AMPLIFIER = new StructuredDataKey<>("ominous_bottle_amplifier", Types.VAR_INT); public static final StructuredDataKey JUKEBOX_PLAYABLE = new StructuredDataKey<>("jukebox_playable", JukeboxPlayable.TYPE); public static final StructuredDataKey RECIPES = new StructuredDataKey<>("recipes", Types.TAG); @@ -115,6 +149,8 @@ public record StructuredDataKey(String identifier, Type type) { public static final StructuredDataKey POT_DECORATIONS = new StructuredDataKey<>("pot_decorations", PotDecorations.TYPE); public static final StructuredDataKey CONTAINER1_20_5 = new StructuredDataKey<>("container", Types1_20_5.ITEM_ARRAY); public static final StructuredDataKey CONTAINER1_21 = new StructuredDataKey<>("container", Types1_21.ITEM_ARRAY); + public static final StructuredDataKey CONTAINER1_21_2 = new StructuredDataKey<>("container", new ArrayType<>(Types1_21_2.ITEM, 256)); + public static final StructuredDataKey CONTAINER1_21_4 = new StructuredDataKey<>("container", Types1_21_4.ITEM_ARRAY); public static final StructuredDataKey BLOCK_STATE = new StructuredDataKey<>("block_state", BlockStateProperties.TYPE); public static final StructuredDataKey BEES = new StructuredDataKey<>("bees", Bee.ARRAY_TYPE); public static final StructuredDataKey LOCK = new StructuredDataKey<>("lock", Types.TAG); diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/entities/EntityTypes1_21_2.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/entities/EntityTypes1_21_2.java new file mode 100644 index 000000000..05a635439 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/entities/EntityTypes1_21_2.java @@ -0,0 +1,314 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.entities; + +import com.google.common.base.Preconditions; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.util.EntityTypeUtil; +import com.viaversion.viaversion.util.Key; +import java.util.Locale; +import org.checkerframework.checker.nullness.qual.Nullable; + +public enum EntityTypes1_21_2 implements EntityType { + + ENTITY(null, null), + + AREA_EFFECT_CLOUD(ENTITY), + END_CRYSTAL(ENTITY), + EVOKER_FANGS(ENTITY), + EXPERIENCE_ORB(ENTITY), + EYE_OF_ENDER(ENTITY), + FALLING_BLOCK(ENTITY), + ITEM(ENTITY), + TNT(ENTITY), + OMINOUS_ITEM_SPAWNER(ENTITY), + MARKER(ENTITY), + LIGHTNING_BOLT(ENTITY), + INTERACTION(ENTITY), + + DISPLAY(ENTITY, null), + BLOCK_DISPLAY(DISPLAY), + ITEM_DISPLAY(DISPLAY), + TEXT_DISPLAY(DISPLAY), + + // Hanging entities + HANGING_ENTITY(ENTITY, null), + LEASH_KNOT(HANGING_ENTITY), + PAINTING(HANGING_ENTITY), + ITEM_FRAME(HANGING_ENTITY), + GLOW_ITEM_FRAME(ITEM_FRAME), + + // Projectiles + PROJECTILE(ENTITY, null), + ITEM_PROJECTILE(PROJECTILE, null), + SNOWBALL(ITEM_PROJECTILE), + ENDER_PEARL(ITEM_PROJECTILE), + EGG(ITEM_PROJECTILE), + POTION(ITEM_PROJECTILE), + EXPERIENCE_BOTTLE(ITEM_PROJECTILE), + FIREWORK_ROCKET(PROJECTILE), + LLAMA_SPIT(PROJECTILE), + SHULKER_BULLET(PROJECTILE), + FISHING_BOBBER(PROJECTILE), + WITHER_SKULL(PROJECTILE), + DRAGON_FIREBALL(PROJECTILE), // Doesn't actually inherit fireball + + ABSTRACT_ARROW(PROJECTILE, null), + ARROW(ABSTRACT_ARROW), + SPECTRAL_ARROW(ABSTRACT_ARROW), + TRIDENT(ABSTRACT_ARROW), + + ABSTRACT_FIREBALL(ENTITY, null), + FIREBALL(ABSTRACT_FIREBALL), + SMALL_FIREBALL(ABSTRACT_FIREBALL), + + ABSTRACT_WIND_CHARGE(PROJECTILE, null), + WIND_CHARGE(ABSTRACT_WIND_CHARGE), + BREEZE_WIND_CHARGE(ABSTRACT_WIND_CHARGE), + + // Vehicles + VEHICLE(ENTITY, null), + + ABSTRACT_MINECART(VEHICLE, null), + MINECART(ABSTRACT_MINECART), + FURNACE_MINECART(ABSTRACT_MINECART), + COMMAND_BLOCK_MINECART(ABSTRACT_MINECART), + TNT_MINECART(ABSTRACT_MINECART), + SPAWNER_MINECART(ABSTRACT_MINECART), + + ABSTRACT_MINECART_CONTAINER(ABSTRACT_MINECART, null), + CHEST_MINECART(ABSTRACT_MINECART_CONTAINER), + HOPPER_MINECART(ABSTRACT_MINECART_CONTAINER), + + ABSTRACT_BOAT(VEHICLE, null), + ABSTRACT_CHEST_BOAT(ABSTRACT_BOAT, null), + ACACIA_BOAT(ABSTRACT_BOAT), + ACACIA_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + BAMBOO_CHEST_RAFT(ABSTRACT_CHEST_BOAT), + BAMBOO_RAFT(ABSTRACT_BOAT), + BIRCH_BOAT(ABSTRACT_BOAT), + BIRCH_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + CHERRY_BOAT(ABSTRACT_BOAT), + CHERRY_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + DARK_OAK_BOAT(ABSTRACT_BOAT), + DARK_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + JUNGLE_BOAT(ABSTRACT_BOAT), + JUNGLE_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + MANGROVE_BOAT(ABSTRACT_BOAT), + MANGROVE_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + OAK_BOAT(ABSTRACT_BOAT), + OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + PALE_OAK_BOAT(ABSTRACT_BOAT), + PALE_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + SPRUCE_BOAT(ABSTRACT_BOAT), + SPRUCE_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + + // Living entities as a larger subclass + LIVING_ENTITY(ENTITY, null), + ARMOR_STAND(LIVING_ENTITY), + PLAYER(LIVING_ENTITY), + + // Mobs as a larger subclass + MOB(LIVING_ENTITY, null), + ENDER_DRAGON(MOB), + + SLIME(MOB), + MAGMA_CUBE(SLIME), + + // Ambient mobs + AMBIENT_CREATURE(MOB, null), + BAT(AMBIENT_CREATURE), + + // Flying mobs + FLYING_MOB(MOB, null), + GHAST(FLYING_MOB), + PHANTOM(FLYING_MOB), + + // Pathfinder mobs and its subclasses + PATHFINDER_MOB(MOB, null), + ALLAY(PATHFINDER_MOB), + + ABSTRACT_GOLEM(PATHFINDER_MOB, null), + SNOW_GOLEM(ABSTRACT_GOLEM), + IRON_GOLEM(ABSTRACT_GOLEM), + SHULKER(ABSTRACT_GOLEM), + + // Ageable mobs and (tamable) animals + ABSTRACT_AGEABLE(PATHFINDER_MOB, null), + ABSTRACT_VILLAGER(ABSTRACT_AGEABLE, null), + VILLAGER(ABSTRACT_VILLAGER), + WANDERING_TRADER(ABSTRACT_VILLAGER), + + ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null), + AXOLOTL(ABSTRACT_ANIMAL), + CHICKEN(ABSTRACT_ANIMAL), + PANDA(ABSTRACT_ANIMAL), + PIG(ABSTRACT_ANIMAL), + POLAR_BEAR(ABSTRACT_ANIMAL), + RABBIT(ABSTRACT_ANIMAL), + SHEEP(ABSTRACT_ANIMAL), + BEE(ABSTRACT_ANIMAL), + TURTLE(ABSTRACT_ANIMAL), + FOX(ABSTRACT_ANIMAL), + FROG(ABSTRACT_ANIMAL), + GOAT(ABSTRACT_ANIMAL), + HOGLIN(ABSTRACT_ANIMAL), + STRIDER(ABSTRACT_ANIMAL), + SNIFFER(ABSTRACT_ANIMAL), + ARMADILLO(ABSTRACT_ANIMAL), + + COW(ABSTRACT_ANIMAL), + MOOSHROOM(COW), + + TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null), + CAT(TAMABLE_ANIMAL), + OCELOT(TAMABLE_ANIMAL), + WOLF(TAMABLE_ANIMAL), + PARROT(TAMABLE_ANIMAL), + + ABSTRACT_HORSE(ABSTRACT_ANIMAL, null), + HORSE(ABSTRACT_HORSE), + SKELETON_HORSE(ABSTRACT_HORSE), + ZOMBIE_HORSE(ABSTRACT_HORSE), + CAMEL(ABSTRACT_HORSE), + + ABSTRACT_CHESTED_HORSE(ABSTRACT_HORSE, null), + DONKEY(ABSTRACT_CHESTED_HORSE), + MULE(ABSTRACT_CHESTED_HORSE), + LLAMA(ABSTRACT_CHESTED_HORSE), + TRADER_LLAMA(LLAMA), + + // Monsters + ABSTRACT_MONSTER(PATHFINDER_MOB, null), + BLAZE(ABSTRACT_MONSTER), + CREEPER(ABSTRACT_MONSTER), + ENDERMITE(ABSTRACT_MONSTER), + ENDERMAN(ABSTRACT_MONSTER), + GIANT(ABSTRACT_MONSTER), + SILVERFISH(ABSTRACT_MONSTER), + VEX(ABSTRACT_MONSTER), + WITHER(ABSTRACT_MONSTER), + BREEZE(ABSTRACT_MONSTER), + ZOGLIN(ABSTRACT_MONSTER), + WARDEN(ABSTRACT_MONSTER), + CREAKING(ABSTRACT_MONSTER), + CREAKING_TRANSIENT(CREAKING), + + ABSTRACT_SKELETON(ABSTRACT_MONSTER, null), + SKELETON(ABSTRACT_SKELETON), + STRAY(ABSTRACT_SKELETON), + WITHER_SKELETON(ABSTRACT_SKELETON), + BOGGED(ABSTRACT_SKELETON), + + ZOMBIE(ABSTRACT_MONSTER), + DROWNED(ZOMBIE), + HUSK(ZOMBIE), + ZOMBIFIED_PIGLIN(ZOMBIE), + ZOMBIE_VILLAGER(ZOMBIE), + + GUARDIAN(ABSTRACT_MONSTER), + ELDER_GUARDIAN(GUARDIAN), + + SPIDER(ABSTRACT_MONSTER), + CAVE_SPIDER(SPIDER), + + ABSTRACT_PIGLIN(ABSTRACT_MONSTER, null), + PIGLIN(ABSTRACT_PIGLIN), + PIGLIN_BRUTE(ABSTRACT_PIGLIN), + + // Water mobs + AGEABLE_WATER_CREATURE(ABSTRACT_AGEABLE, null), + DOLPHIN(AGEABLE_WATER_CREATURE), + + SQUID(AGEABLE_WATER_CREATURE), + GLOW_SQUID(SQUID), + + WATER_ANIMAL(PATHFINDER_MOB, null), + ABSTRACT_FISH(WATER_ANIMAL, null), + PUFFERFISH(ABSTRACT_FISH), + TADPOLE(ABSTRACT_FISH), + + ABSTRACT_SCHOOLING_FISH(ABSTRACT_FISH, null), + COD(ABSTRACT_SCHOOLING_FISH), + SALMON(ABSTRACT_SCHOOLING_FISH), + TROPICAL_FISH(ABSTRACT_SCHOOLING_FISH), + + // Raiders + ABSTRACT_RAIDER(ABSTRACT_MONSTER, null), + WITCH(ABSTRACT_RAIDER), + RAVAGER(ABSTRACT_RAIDER), + + ABSTRACT_ILLAGER(ABSTRACT_RAIDER, null), + SPELLCASTER_ILLAGER(ABSTRACT_ILLAGER, null), + VINDICATOR(ABSTRACT_ILLAGER), + PILLAGER(ABSTRACT_ILLAGER), + EVOKER(SPELLCASTER_ILLAGER), + ILLUSIONER(SPELLCASTER_ILLAGER); + + private static final EntityType[] TYPES = EntityTypeUtil.createSizedArray(values()); + private final EntityType parent; + private final String identifier; + private int id = -1; + + EntityTypes1_21_2(final EntityType parent) { + this.parent = parent; + this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT)); + } + + EntityTypes1_21_2(final EntityType parent, @Nullable final String identifier) { + this.parent = parent; + this.identifier = identifier; + } + + @Override + public int getId() { + if (id == -1) { + throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")"); + } + return id; + } + + @Override + public String identifier() { + Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type"); + return identifier; + } + + @Override + public @Nullable EntityType getParent() { + return parent; + } + + @Override + public boolean isAbstractType() { + return identifier == null; + } + + public static EntityType getTypeFromId(final int typeId) { + return EntityTypeUtil.getTypeFromId(TYPES, typeId, ENTITY); + } + + public static void initialize(final Protocol protocol) { + EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id); + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/entities/EntityTypes1_21_4.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/entities/EntityTypes1_21_4.java new file mode 100644 index 000000000..c66581468 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/entities/EntityTypes1_21_4.java @@ -0,0 +1,313 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.entities; + +import com.google.common.base.Preconditions; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.util.EntityTypeUtil; +import com.viaversion.viaversion.util.Key; +import java.util.Locale; +import org.checkerframework.checker.nullness.qual.Nullable; + +public enum EntityTypes1_21_4 implements EntityType { + + ENTITY(null, null), + + AREA_EFFECT_CLOUD(ENTITY), + END_CRYSTAL(ENTITY), + EVOKER_FANGS(ENTITY), + EXPERIENCE_ORB(ENTITY), + EYE_OF_ENDER(ENTITY), + FALLING_BLOCK(ENTITY), + ITEM(ENTITY), + TNT(ENTITY), + OMINOUS_ITEM_SPAWNER(ENTITY), + MARKER(ENTITY), + LIGHTNING_BOLT(ENTITY), + INTERACTION(ENTITY), + + DISPLAY(ENTITY, null), + BLOCK_DISPLAY(DISPLAY), + ITEM_DISPLAY(DISPLAY), + TEXT_DISPLAY(DISPLAY), + + // Hanging entities + HANGING_ENTITY(ENTITY, null), + LEASH_KNOT(HANGING_ENTITY), + PAINTING(HANGING_ENTITY), + ITEM_FRAME(HANGING_ENTITY), + GLOW_ITEM_FRAME(ITEM_FRAME), + + // Projectiles + PROJECTILE(ENTITY, null), + ITEM_PROJECTILE(PROJECTILE, null), + SNOWBALL(ITEM_PROJECTILE), + ENDER_PEARL(ITEM_PROJECTILE), + EGG(ITEM_PROJECTILE), + POTION(ITEM_PROJECTILE), + EXPERIENCE_BOTTLE(ITEM_PROJECTILE), + FIREWORK_ROCKET(PROJECTILE), + LLAMA_SPIT(PROJECTILE), + SHULKER_BULLET(PROJECTILE), + FISHING_BOBBER(PROJECTILE), + WITHER_SKULL(PROJECTILE), + DRAGON_FIREBALL(PROJECTILE), // Doesn't actually inherit fireball + + ABSTRACT_ARROW(PROJECTILE, null), + ARROW(ABSTRACT_ARROW), + SPECTRAL_ARROW(ABSTRACT_ARROW), + TRIDENT(ABSTRACT_ARROW), + + ABSTRACT_FIREBALL(ENTITY, null), + FIREBALL(ABSTRACT_FIREBALL), + SMALL_FIREBALL(ABSTRACT_FIREBALL), + + ABSTRACT_WIND_CHARGE(PROJECTILE, null), + WIND_CHARGE(ABSTRACT_WIND_CHARGE), + BREEZE_WIND_CHARGE(ABSTRACT_WIND_CHARGE), + + // Vehicles + VEHICLE(ENTITY, null), + + ABSTRACT_MINECART(VEHICLE, null), + MINECART(ABSTRACT_MINECART), + FURNACE_MINECART(ABSTRACT_MINECART), + COMMAND_BLOCK_MINECART(ABSTRACT_MINECART), + TNT_MINECART(ABSTRACT_MINECART), + SPAWNER_MINECART(ABSTRACT_MINECART), + + ABSTRACT_MINECART_CONTAINER(ABSTRACT_MINECART, null), + CHEST_MINECART(ABSTRACT_MINECART_CONTAINER), + HOPPER_MINECART(ABSTRACT_MINECART_CONTAINER), + + ABSTRACT_BOAT(VEHICLE, null), + ABSTRACT_CHEST_BOAT(ABSTRACT_BOAT, null), + ACACIA_BOAT(ABSTRACT_BOAT), + ACACIA_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + BAMBOO_CHEST_RAFT(ABSTRACT_CHEST_BOAT), + BAMBOO_RAFT(ABSTRACT_BOAT), + BIRCH_BOAT(ABSTRACT_BOAT), + BIRCH_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + CHERRY_BOAT(ABSTRACT_BOAT), + CHERRY_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + DARK_OAK_BOAT(ABSTRACT_BOAT), + DARK_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + JUNGLE_BOAT(ABSTRACT_BOAT), + JUNGLE_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + MANGROVE_BOAT(ABSTRACT_BOAT), + MANGROVE_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + OAK_BOAT(ABSTRACT_BOAT), + OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + PALE_OAK_BOAT(ABSTRACT_BOAT), + PALE_OAK_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + SPRUCE_BOAT(ABSTRACT_BOAT), + SPRUCE_CHEST_BOAT(ABSTRACT_CHEST_BOAT), + + // Living entities as a larger subclass + LIVING_ENTITY(ENTITY, null), + ARMOR_STAND(LIVING_ENTITY), + PLAYER(LIVING_ENTITY), + + // Mobs as a larger subclass + MOB(LIVING_ENTITY, null), + ENDER_DRAGON(MOB), + + SLIME(MOB), + MAGMA_CUBE(SLIME), + + // Ambient mobs + AMBIENT_CREATURE(MOB, null), + BAT(AMBIENT_CREATURE), + + // Flying mobs + FLYING_MOB(MOB, null), + GHAST(FLYING_MOB), + PHANTOM(FLYING_MOB), + + // Pathfinder mobs and its subclasses + PATHFINDER_MOB(MOB, null), + ALLAY(PATHFINDER_MOB), + + ABSTRACT_GOLEM(PATHFINDER_MOB, null), + SNOW_GOLEM(ABSTRACT_GOLEM), + IRON_GOLEM(ABSTRACT_GOLEM), + SHULKER(ABSTRACT_GOLEM), + + // Ageable mobs and (tamable) animals + ABSTRACT_AGEABLE(PATHFINDER_MOB, null), + ABSTRACT_VILLAGER(ABSTRACT_AGEABLE, null), + VILLAGER(ABSTRACT_VILLAGER), + WANDERING_TRADER(ABSTRACT_VILLAGER), + + ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null), + AXOLOTL(ABSTRACT_ANIMAL), + CHICKEN(ABSTRACT_ANIMAL), + PANDA(ABSTRACT_ANIMAL), + PIG(ABSTRACT_ANIMAL), + POLAR_BEAR(ABSTRACT_ANIMAL), + RABBIT(ABSTRACT_ANIMAL), + SHEEP(ABSTRACT_ANIMAL), + BEE(ABSTRACT_ANIMAL), + TURTLE(ABSTRACT_ANIMAL), + FOX(ABSTRACT_ANIMAL), + FROG(ABSTRACT_ANIMAL), + GOAT(ABSTRACT_ANIMAL), + HOGLIN(ABSTRACT_ANIMAL), + STRIDER(ABSTRACT_ANIMAL), + SNIFFER(ABSTRACT_ANIMAL), + ARMADILLO(ABSTRACT_ANIMAL), + + COW(ABSTRACT_ANIMAL), + MOOSHROOM(COW), + + TAMABLE_ANIMAL(ABSTRACT_ANIMAL, null), + CAT(TAMABLE_ANIMAL), + OCELOT(TAMABLE_ANIMAL), + WOLF(TAMABLE_ANIMAL), + PARROT(TAMABLE_ANIMAL), + + ABSTRACT_HORSE(ABSTRACT_ANIMAL, null), + HORSE(ABSTRACT_HORSE), + SKELETON_HORSE(ABSTRACT_HORSE), + ZOMBIE_HORSE(ABSTRACT_HORSE), + CAMEL(ABSTRACT_HORSE), + + ABSTRACT_CHESTED_HORSE(ABSTRACT_HORSE, null), + DONKEY(ABSTRACT_CHESTED_HORSE), + MULE(ABSTRACT_CHESTED_HORSE), + LLAMA(ABSTRACT_CHESTED_HORSE), + TRADER_LLAMA(LLAMA), + + // Monsters + ABSTRACT_MONSTER(PATHFINDER_MOB, null), + BLAZE(ABSTRACT_MONSTER), + CREEPER(ABSTRACT_MONSTER), + ENDERMITE(ABSTRACT_MONSTER), + ENDERMAN(ABSTRACT_MONSTER), + GIANT(ABSTRACT_MONSTER), + SILVERFISH(ABSTRACT_MONSTER), + VEX(ABSTRACT_MONSTER), + WITHER(ABSTRACT_MONSTER), + BREEZE(ABSTRACT_MONSTER), + ZOGLIN(ABSTRACT_MONSTER), + WARDEN(ABSTRACT_MONSTER), + CREAKING(ABSTRACT_MONSTER), + + ABSTRACT_SKELETON(ABSTRACT_MONSTER, null), + SKELETON(ABSTRACT_SKELETON), + STRAY(ABSTRACT_SKELETON), + WITHER_SKELETON(ABSTRACT_SKELETON), + BOGGED(ABSTRACT_SKELETON), + + ZOMBIE(ABSTRACT_MONSTER), + DROWNED(ZOMBIE), + HUSK(ZOMBIE), + ZOMBIFIED_PIGLIN(ZOMBIE), + ZOMBIE_VILLAGER(ZOMBIE), + + GUARDIAN(ABSTRACT_MONSTER), + ELDER_GUARDIAN(GUARDIAN), + + SPIDER(ABSTRACT_MONSTER), + CAVE_SPIDER(SPIDER), + + ABSTRACT_PIGLIN(ABSTRACT_MONSTER, null), + PIGLIN(ABSTRACT_PIGLIN), + PIGLIN_BRUTE(ABSTRACT_PIGLIN), + + // Water mobs + AGEABLE_WATER_CREATURE(ABSTRACT_AGEABLE, null), + DOLPHIN(AGEABLE_WATER_CREATURE), + + SQUID(AGEABLE_WATER_CREATURE), + GLOW_SQUID(SQUID), + + WATER_ANIMAL(PATHFINDER_MOB, null), + ABSTRACT_FISH(WATER_ANIMAL, null), + PUFFERFISH(ABSTRACT_FISH), + TADPOLE(ABSTRACT_FISH), + + ABSTRACT_SCHOOLING_FISH(ABSTRACT_FISH, null), + COD(ABSTRACT_SCHOOLING_FISH), + SALMON(ABSTRACT_SCHOOLING_FISH), + TROPICAL_FISH(ABSTRACT_SCHOOLING_FISH), + + // Raiders + ABSTRACT_RAIDER(ABSTRACT_MONSTER, null), + WITCH(ABSTRACT_RAIDER), + RAVAGER(ABSTRACT_RAIDER), + + ABSTRACT_ILLAGER(ABSTRACT_RAIDER, null), + SPELLCASTER_ILLAGER(ABSTRACT_ILLAGER, null), + VINDICATOR(ABSTRACT_ILLAGER), + PILLAGER(ABSTRACT_ILLAGER), + EVOKER(SPELLCASTER_ILLAGER), + ILLUSIONER(SPELLCASTER_ILLAGER); + + private static final EntityType[] TYPES = EntityTypeUtil.createSizedArray(values()); + private final EntityType parent; + private final String identifier; + private int id = -1; + + EntityTypes1_21_4(final EntityType parent) { + this.parent = parent; + this.identifier = Key.namespaced(name().toLowerCase(Locale.ROOT)); + } + + EntityTypes1_21_4(final EntityType parent, @Nullable final String identifier) { + this.parent = parent; + this.identifier = identifier; + } + + @Override + public int getId() { + if (id == -1) { + throw new IllegalStateException("Ids have not been initialized yet (type " + name() + ")"); + } + return id; + } + + @Override + public String identifier() { + Preconditions.checkArgument(identifier != null, "Called identifier method on abstract type"); + return identifier; + } + + @Override + public @Nullable EntityType getParent() { + return parent; + } + + @Override + public boolean isAbstractType() { + return identifier == null; + } + + public static EntityType getTypeFromId(final int typeId) { + return EntityTypeUtil.getTypeFromId(TYPES, typeId, ENTITY); + } + + public static void initialize(final Protocol protocol) { + EntityTypeUtil.initialize(values(), TYPES, protocol, (type, id) -> type.id = id); + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/entitydata/types/EntityDataTypes1_21.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/entitydata/types/EntityDataTypes1_21.java index cd746d676..0498c5ae3 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/entitydata/types/EntityDataTypes1_21.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/entitydata/types/EntityDataTypes1_21.java @@ -26,10 +26,11 @@ import com.viaversion.viaversion.api.minecraft.PaintingVariant; import com.viaversion.viaversion.api.minecraft.Particle; import com.viaversion.viaversion.api.minecraft.WolfVariant; import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.ArrayType; import com.viaversion.viaversion.api.type.types.misc.ParticleType; -import com.viaversion.viaversion.api.type.types.version.Types1_21; public final class EntityDataTypes1_21 extends AbstractEntityDataTypes { @@ -40,7 +41,7 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes { public final EntityDataType stringType = add(4, Types.STRING); public final EntityDataType componentType = add(5, Types.TAG); public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG); - public final EntityDataType itemType = add(7, Types1_21.ITEM); + public final EntityDataType itemType; public final EntityDataType booleanType = add(8, Types.BOOLEAN); public final EntityDataType rotationsType = add(9, Types.ROTATIONS); public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14); @@ -59,14 +60,15 @@ public final class EntityDataTypes1_21 extends AbstractEntityDataTypes { public final EntityDataType wolfVariantType = add(23, WolfVariant.TYPE); public final EntityDataType frogVariantType = add(24, Types.VAR_INT); public final EntityDataType optionalGlobalPosition = add(25, Types.OPTIONAL_GLOBAL_POSITION); - public final EntityDataType paintingVariantType = add(26, PaintingVariant.TYPE); + public final EntityDataType paintingVariantType = add(26, PaintingVariant.TYPE1_21); public final EntityDataType snifferState = add(27, Types.VAR_INT); public final EntityDataType armadilloState = add(28, Types.VAR_INT); public final EntityDataType vector3FType = add(29, Types.VECTOR3F); public final EntityDataType quaternionType = add(30, Types.QUATERNION); - public EntityDataTypes1_21(final ParticleType particleType, final ArrayType particlesType) { + public EntityDataTypes1_21(final Type itemType, final ParticleType particleType, final ArrayType particlesType) { super(31); + this.itemType = add(7, itemType); this.particleType = add(17, particleType); this.particlesType = add(18, particlesType); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/entitydata/types/EntityDataTypes1_21_2.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/entitydata/types/EntityDataTypes1_21_2.java new file mode 100644 index 000000000..6e9d13080 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/entitydata/types/EntityDataTypes1_21_2.java @@ -0,0 +1,74 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.entitydata.types; + +import com.viaversion.viaversion.api.minecraft.PaintingVariant; +import com.viaversion.viaversion.api.minecraft.Particle; +import com.viaversion.viaversion.api.minecraft.WolfVariant; +import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.misc.ParticleType; + +public final class EntityDataTypes1_21_2 extends AbstractEntityDataTypes { + + public final EntityDataType byteType = add(0, Types.BYTE); + public final EntityDataType varIntType = add(1, Types.VAR_INT); + public final EntityDataType longType = add(2, Types.VAR_LONG); + public final EntityDataType floatType = add(3, Types.FLOAT); + public final EntityDataType stringType = add(4, Types.STRING); + public final EntityDataType componentType = add(5, Types.TAG); + public final EntityDataType optionalComponentType = add(6, Types.OPTIONAL_TAG); + public final EntityDataType itemType; + public final EntityDataType booleanType = add(8, Types.BOOLEAN); + public final EntityDataType rotationsType = add(9, Types.ROTATIONS); + public final EntityDataType blockPositionType = add(10, Types.BLOCK_POSITION1_14); + public final EntityDataType optionalBlockPositionType = add(11, Types.OPTIONAL_POSITION_1_14); + public final EntityDataType directionType = add(12, Types.VAR_INT); + public final EntityDataType optionalUUIDType = add(13, Types.OPTIONAL_UUID); + public final EntityDataType blockStateType = add(14, Types.VAR_INT); + public final EntityDataType optionalBlockStateType = add(15, Types.VAR_INT); + public final EntityDataType compoundTagType = add(16, Types.COMPOUND_TAG); + public final EntityDataType particleType; + public final EntityDataType particlesType; + public final EntityDataType villagerDatatType = add(19, Types.VILLAGER_DATA); + public final EntityDataType optionalVarIntType = add(20, Types.OPTIONAL_VAR_INT); + public final EntityDataType poseType = add(21, Types.VAR_INT); + public final EntityDataType catVariantType = add(22, Types.VAR_INT); + public final EntityDataType wolfVariantType = add(23, WolfVariant.TYPE); + public final EntityDataType frogVariantType = add(24, Types.VAR_INT); + public final EntityDataType optionalGlobalPosition = add(25, Types.OPTIONAL_GLOBAL_POSITION); + public final EntityDataType paintingVariantType = add(26, PaintingVariant.TYPE1_21_2); + public final EntityDataType snifferState = add(27, Types.VAR_INT); + public final EntityDataType armadilloState = add(28, Types.VAR_INT); + public final EntityDataType vector3FType = add(29, Types.VECTOR3F); + public final EntityDataType quaternionType = add(30, Types.QUATERNION); + + public EntityDataTypes1_21_2(final Type itemType, final ParticleType particleType, final Type particlesType) { + super(31); + this.itemType = add(7, itemType); + this.particleType = add(17, particleType); + this.particlesType = add(18, particlesType); + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/ArmorTrim.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/ArmorTrim.java index e06e414f7..e6c276d37 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/ArmorTrim.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/ArmorTrim.java @@ -29,10 +29,10 @@ import it.unimi.dsi.fastutil.ints.Int2IntFunction; public record ArmorTrim(Holder material, Holder pattern, boolean showInTooltip) { - public static final Type TYPE = new Type<>(ArmorTrim.class) { + public static final Type TYPE1_20_5 = new Type<>(ArmorTrim.class) { @Override public ArmorTrim read(final ByteBuf buffer) { - final Holder material = ArmorTrimMaterial.TYPE.read(buffer); + final Holder material = ArmorTrimMaterial.TYPE1_20_5.read(buffer); final Holder pattern = ArmorTrimPattern.TYPE.read(buffer); final boolean showInTooltip = buffer.readBoolean(); return new ArmorTrim(material, pattern, showInTooltip); @@ -40,7 +40,39 @@ public record ArmorTrim(Holder material, Holder TYPE1_21_2 = new Type<>(ArmorTrim.class) { + @Override + public ArmorTrim read(final ByteBuf buffer) { + final Holder material = ArmorTrimMaterial.TYPE1_21_2.read(buffer); + final Holder pattern = ArmorTrimPattern.TYPE.read(buffer); + final boolean showInTooltip = buffer.readBoolean(); + return new ArmorTrim(material, pattern, showInTooltip); + } + + @Override + public void write(final ByteBuf buffer, final ArmorTrim value) { + ArmorTrimMaterial.TYPE1_21_2.write(buffer, value.material); + ArmorTrimPattern.TYPE.write(buffer, value.pattern); + buffer.writeBoolean(value.showInTooltip); + } + }; + public static final Type TYPE1_21_4 = new Type<>(ArmorTrim.class) { + @Override + public ArmorTrim read(final ByteBuf buffer) { + final Holder material = ArmorTrimMaterial.TYPE1_21_4.read(buffer); + final Holder pattern = ArmorTrimPattern.TYPE.read(buffer); + final boolean showInTooltip = buffer.readBoolean(); + return new ArmorTrim(material, pattern, showInTooltip); + } + + @Override + public void write(final ByteBuf buffer, final ArmorTrim value) { + ArmorTrimMaterial.TYPE1_21_4.write(buffer, value.material); ArmorTrimPattern.TYPE.write(buffer, value.pattern); buffer.writeBoolean(value.showInTooltip); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/ArmorTrimMaterial.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/ArmorTrimMaterial.java index efed9bcff..2b9dde7e9 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/ArmorTrimMaterial.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/ArmorTrimMaterial.java @@ -27,13 +27,19 @@ import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.misc.HolderType; import io.netty.buffer.ByteBuf; import it.unimi.dsi.fastutil.ints.Int2IntFunction; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import java.util.Map; public record ArmorTrimMaterial(String assetName, int itemId, float itemModelIndex, - Int2ObjectMap overrideArmorMaterials, Tag description) { + Map overrideArmorMaterials, Tag description) { - public static final HolderType TYPE = new HolderType<>() { + public ArmorTrimMaterial(final String assetName, final int itemId, final Map overrideArmorMaterials, final Tag description) { + this(assetName, itemId, 0F, overrideArmorMaterials, description); + } + + public static final HolderType TYPE1_20_5 = new HolderType<>() { + // The override key is an int, but given we don't use it at all and that creating a new type is annoying, + // we'll just store it in the string map:tm: @Override public ArmorTrimMaterial readDirect(final ByteBuf buffer) { final String assetName = Types.STRING.read(buffer); @@ -41,10 +47,45 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd final float itemModelIndex = buffer.readFloat(); final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer); - final Int2ObjectMap overrideArmorMaterials = new Int2ObjectOpenHashMap<>(overrideArmorMaterialsSize); + final Map overrideArmorMaterials = new Object2ObjectArrayMap<>(overrideArmorMaterialsSize); for (int i = 0; i < overrideArmorMaterialsSize; i++) { final int key = Types.VAR_INT.readPrimitive(buffer); final String value = Types.STRING.read(buffer); + overrideArmorMaterials.put(Integer.toString(key), value); + } + + final Tag description = Types.TAG.read(buffer); + return new ArmorTrimMaterial(assetName, item, itemModelIndex, overrideArmorMaterials, description); + } + + @Override + public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial value) { + Types.STRING.write(buffer, value.assetName()); + Types.VAR_INT.writePrimitive(buffer, value.itemId()); + buffer.writeFloat(value.itemModelIndex()); + + Types.VAR_INT.writePrimitive(buffer, value.overrideArmorMaterials().size()); + for (final Map.Entry entry : value.overrideArmorMaterials().entrySet()) { + Types.VAR_INT.writePrimitive(buffer, Integer.parseInt(entry.getKey())); + Types.STRING.write(buffer, entry.getValue()); + } + + Types.TAG.write(buffer, value.description()); + } + }; + + public static final HolderType TYPE1_21_2 = new HolderType<>() { + @Override + public ArmorTrimMaterial readDirect(final ByteBuf buffer) { + final String assetName = Types.STRING.read(buffer); + final int item = Types.VAR_INT.readPrimitive(buffer); + final float itemModelIndex = buffer.readFloat(); + + final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer); + final Map overrideArmorMaterials = new Object2ObjectArrayMap<>(overrideArmorMaterialsSize); + for (int i = 0; i < overrideArmorMaterialsSize; i++) { + final String key = Types.STRING.read(buffer); + final String value = Types.STRING.read(buffer); overrideArmorMaterials.put(key, value); } @@ -59,8 +100,41 @@ public record ArmorTrimMaterial(String assetName, int itemId, float itemModelInd buffer.writeFloat(value.itemModelIndex()); Types.VAR_INT.writePrimitive(buffer, value.overrideArmorMaterials().size()); - for (final Int2ObjectMap.Entry entry : value.overrideArmorMaterials().int2ObjectEntrySet()) { - Types.VAR_INT.writePrimitive(buffer, entry.getIntKey()); + for (final Map.Entry entry : value.overrideArmorMaterials().entrySet()) { + Types.STRING.write(buffer, entry.getKey()); + Types.STRING.write(buffer, entry.getValue()); + } + + Types.TAG.write(buffer, value.description()); + } + }; + + public static final HolderType TYPE1_21_4 = new HolderType<>() { + @Override + public ArmorTrimMaterial readDirect(final ByteBuf buffer) { + final String assetName = Types.STRING.read(buffer); + final int item = Types.VAR_INT.readPrimitive(buffer); + + final int overrideArmorMaterialsSize = Types.VAR_INT.readPrimitive(buffer); + final Map overrideArmorMaterials = new Object2ObjectArrayMap<>(overrideArmorMaterialsSize); + for (int i = 0; i < overrideArmorMaterialsSize; i++) { + final String key = Types.STRING.read(buffer); + final String value = Types.STRING.read(buffer); + overrideArmorMaterials.put(key, value); + } + + final Tag description = Types.TAG.read(buffer); + return new ArmorTrimMaterial(assetName, item, overrideArmorMaterials, description); + } + + @Override + public void writeDirect(final ByteBuf buffer, final ArmorTrimMaterial value) { + Types.STRING.write(buffer, value.assetName()); + Types.VAR_INT.writePrimitive(buffer, value.itemId()); + + Types.VAR_INT.writePrimitive(buffer, value.overrideArmorMaterials().size()); + for (final Map.Entry entry : value.overrideArmorMaterials().entrySet()) { + Types.STRING.write(buffer, entry.getKey()); Types.STRING.write(buffer, entry.getValue()); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Consumable1_21_2.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Consumable1_21_2.java new file mode 100644 index 000000000..020026379 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Consumable1_21_2.java @@ -0,0 +1,111 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.item.data; + +import com.viaversion.viaversion.api.minecraft.Holder; +import com.viaversion.viaversion.api.minecraft.SoundEvent; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.ArrayType; +import io.netty.buffer.ByteBuf; + +public record Consumable1_21_2(float consumeSeconds, int animationType, Holder sound, + boolean hasConsumeParticles, ConsumeEffect[] consumeEffects) { + + public static final Type[] EFFECT_TYPES = { + ApplyStatusEffects.TYPE, + Types.HOLDER_SET, // remove effects + Types.EMPTY, // clear all effects + Types.FLOAT, // teleport randomly + Types.SOUND_EVENT // play sound + }; + + public static final Type TYPE = new Type<>(Consumable1_21_2.class) { + @Override + public Consumable1_21_2 read(final ByteBuf buffer) { + final float consumeSeconds = buffer.readFloat(); + final int animationType = Types.VAR_INT.readPrimitive(buffer); + final Holder sound = Types.SOUND_EVENT.read(buffer); + final boolean hasConsumeParticles = buffer.readBoolean(); + final ConsumeEffect[] consumeEffects = ConsumeEffect.ARRAY_TYPE.read(buffer); + return new Consumable1_21_2(consumeSeconds, animationType, sound, hasConsumeParticles, consumeEffects); + } + + @Override + public void write(final ByteBuf buffer, final Consumable1_21_2 value) { + buffer.writeFloat(value.consumeSeconds); + Types.VAR_INT.writePrimitive(buffer, value.animationType); + Types.SOUND_EVENT.write(buffer, value.sound); + buffer.writeBoolean(value.hasConsumeParticles); + ConsumeEffect.ARRAY_TYPE.write(buffer, value.consumeEffects); + } + }; + + public record ConsumeEffect(int id, Type type, T value) { + + public static final Type> TYPE = new Type<>(ConsumeEffect.class) { + @Override + public ConsumeEffect read(final ByteBuf buffer) { + // Oh no... + final int effectType = Types.VAR_INT.readPrimitive(buffer); + final Type type = EFFECT_TYPES[effectType]; + final Object value = type.read(buffer); + return ConsumeEffect.of(effectType, type, value); + } + + @Override + public void write(final ByteBuf buffer, final ConsumeEffect value) { + Types.VAR_INT.writePrimitive(buffer, value.id); + value.writeValue(buffer); + } + }; + public static final Type[]> ARRAY_TYPE = new ArrayType<>(TYPE); + + static ConsumeEffect of(final int id, final Type type, final Object value) { + //noinspection unchecked + return new ConsumeEffect<>(id, type, (T) value); + } + + void writeValue(final ByteBuf buf) { + this.type.write(buf, this.value); + } + } + + public record ApplyStatusEffects(PotionEffect[] effects, float probability) { + + public static final Type TYPE = new Type<>(ApplyStatusEffects.class) { + @Override + public ApplyStatusEffects read(final ByteBuf buffer) { + final PotionEffect[] effects = PotionEffect.ARRAY_TYPE.read(buffer); + final float probability = buffer.readFloat(); + return new ApplyStatusEffects(effects, probability); + } + + @Override + public void write(final ByteBuf buffer, final ApplyStatusEffects value) { + PotionEffect.ARRAY_TYPE.write(buffer, value.effects); + buffer.writeFloat(value.probability); + } + }; + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/CustomModelData1_21_4.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/CustomModelData1_21_4.java new file mode 100644 index 000000000..9aa29d140 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/CustomModelData1_21_4.java @@ -0,0 +1,49 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.item.data; + +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; +import io.netty.buffer.ByteBuf; + +public record CustomModelData1_21_4(float[] floats, boolean[] booleans, String[] strings, int[] colors) { + + public static final Type TYPE = new Type<>(CustomModelData1_21_4.class) { + @Override + public CustomModelData1_21_4 read(final ByteBuf buffer) { + final float[] floats = Types.FLOAT_ARRAY_PRIMITIVE.read(buffer); + final boolean[] booleans = Types.BOOLEAN_ARRAY_PRIMITIVE.read(buffer); + final String[] strings = Types.STRING_ARRAY.read(buffer); + final int[] colors = Types.INT_ARRAY_PRIMITIVE.read(buffer); + return new CustomModelData1_21_4(floats, booleans, strings, colors); + } + + @Override + public void write(final ByteBuf buffer, final CustomModelData1_21_4 value) { + Types.FLOAT_ARRAY_PRIMITIVE.write(buffer, value.floats()); + Types.BOOLEAN_ARRAY_PRIMITIVE.write(buffer, value.booleans()); + Types.STRING_ARRAY.write(buffer, value.strings()); + Types.INT_ARRAY_PRIMITIVE.write(buffer, value.colors()); + } + }; +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/DamageResistant.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/DamageResistant.java new file mode 100644 index 000000000..39ed94a57 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/DamageResistant.java @@ -0,0 +1,43 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.item.data; + +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; +import io.netty.buffer.ByteBuf; + +public record DamageResistant(String typesTagKey) { + + public static final Type TYPE = new Type<>(DamageResistant.class) { + @Override + public DamageResistant read(final ByteBuf buffer) { + final String typesTagKey = Types.STRING.read(buffer); + return new DamageResistant(typesTagKey); + } + + @Override + public void write(final ByteBuf buffer, final DamageResistant value) { + Types.STRING.write(buffer, value.typesTagKey()); + } + }; +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodEffect.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/DeathProtection.java similarity index 66% rename from api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodEffect.java rename to api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/DeathProtection.java index 3051ce390..3a5c784d1 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodEffect.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/DeathProtection.java @@ -22,26 +22,23 @@ */ package com.viaversion.viaversion.api.minecraft.item.data; +import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2.ConsumeEffect; import com.viaversion.viaversion.api.type.Type; -import com.viaversion.viaversion.api.type.types.ArrayType; +import com.viaversion.viaversion.api.type.Types; import io.netty.buffer.ByteBuf; -public record FoodEffect(PotionEffect effect, float probability) { +public record DeathProtection(ConsumeEffect[] deathEffects) { - public static final Type TYPE = new Type<>(FoodEffect.class) { + public static final Type TYPE = new Type<>(DeathProtection.class) { @Override - public FoodEffect read(final ByteBuf buffer) { - final PotionEffect effect = PotionEffect.TYPE.read(buffer); - final float probability = buffer.readFloat(); - return new FoodEffect(effect, probability); + public DeathProtection read(final ByteBuf buffer) { + final ConsumeEffect[] deathEffects = ConsumeEffect.ARRAY_TYPE.read(buffer); + return new DeathProtection(deathEffects); } @Override - public void write(final ByteBuf buffer, final FoodEffect value) { - PotionEffect.TYPE.write(buffer, value.effect); - buffer.writeFloat(value.probability); + public void write(final ByteBuf buffer, final DeathProtection value) { + ConsumeEffect.ARRAY_TYPE.write(buffer, value.deathEffects); } }; - public static final Type ARRAY_TYPE = new ArrayType<>(TYPE); - } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Equippable.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Equippable.java new file mode 100644 index 000000000..5c90d29a1 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Equippable.java @@ -0,0 +1,69 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.item.data; + +import com.viaversion.viaversion.api.minecraft.Holder; +import com.viaversion.viaversion.api.minecraft.HolderSet; +import com.viaversion.viaversion.api.minecraft.SoundEvent; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; +import io.netty.buffer.ByteBuf; +import it.unimi.dsi.fastutil.ints.Int2IntFunction; +import org.checkerframework.checker.nullness.qual.Nullable; + +public record Equippable(int equipmentSlot, Holder soundEvent, @Nullable String model, + @Nullable String cameraOverlay, @Nullable HolderSet allowedEntities, boolean dispensable, + boolean swappable, boolean damageOnHurt) { + + public static final Type TYPE = new Type<>(Equippable.class) { + @Override + public Equippable read(final ByteBuf buffer) { + final int equipmentSlot = Types.VAR_INT.readPrimitive(buffer); + final Holder soundEvent = Types.SOUND_EVENT.read(buffer); + final String model = Types.OPTIONAL_STRING.read(buffer); + final String cameraOverlay = Types.OPTIONAL_STRING.read(buffer); + final HolderSet allowedEntities = Types.OPTIONAL_HOLDER_SET.read(buffer); + final boolean dispensable = buffer.readBoolean(); + final boolean swappable = buffer.readBoolean(); + final boolean damageOnHurt = buffer.readBoolean(); + return new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } + + @Override + public void write(final ByteBuf buffer, final Equippable value) { + Types.VAR_INT.writePrimitive(buffer, value.equipmentSlot()); + Types.SOUND_EVENT.write(buffer, value.soundEvent()); + Types.OPTIONAL_STRING.write(buffer, value.model()); + Types.OPTIONAL_STRING.write(buffer, value.cameraOverlay()); + Types.OPTIONAL_HOLDER_SET.write(buffer, value.allowedEntities()); + buffer.writeBoolean(value.dispensable()); + buffer.writeBoolean(value.swappable()); + buffer.writeBoolean(value.damageOnHurt()); + } + }; + + public Equippable rewrite(final Int2IntFunction soundIdRewriter) { + final Holder soundEvent = this.soundEvent.updateId(soundIdRewriter); + return soundEvent == this.soundEvent ? this : new Equippable(equipmentSlot, soundEvent, model, cameraOverlay, allowedEntities, dispensable, swappable, damageOnHurt); + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodProperties.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodProperties1_20_5.java similarity index 64% rename from api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodProperties.java rename to api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodProperties1_20_5.java index c344d3c34..c50113c7b 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodProperties.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodProperties1_20_5.java @@ -25,25 +25,27 @@ package com.viaversion.viaversion.api.minecraft.item.data; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.ArrayType; import com.viaversion.viaversion.api.type.types.version.Types1_21; import io.netty.buffer.ByteBuf; +import org.checkerframework.checker.nullness.qual.Nullable; -public record FoodProperties(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds, - Item usingConvertsTo, FoodEffect[] possibleEffects) { +public record FoodProperties1_20_5(int nutrition, float saturationModifier, boolean canAlwaysEat, float eatSeconds, + @Nullable Item usingConvertsTo, FoodEffect[] possibleEffects) { - public static final Type TYPE1_20_5 = new Type<>(FoodProperties.class) { + public static final Type TYPE1_20_5 = new Type<>(FoodProperties1_20_5.class) { @Override - public FoodProperties read(final ByteBuf buffer) { + public FoodProperties1_20_5 read(final ByteBuf buffer) { final int nutrition = Types.VAR_INT.readPrimitive(buffer); final float saturationModifier = buffer.readFloat(); final boolean canAlwaysEat = buffer.readBoolean(); final float eatSeconds = buffer.readFloat(); final FoodEffect[] possibleEffects = FoodEffect.ARRAY_TYPE.read(buffer); - return new FoodProperties(nutrition, saturationModifier, canAlwaysEat, eatSeconds, null, possibleEffects); + return new FoodProperties1_20_5(nutrition, saturationModifier, canAlwaysEat, eatSeconds, null, possibleEffects); } @Override - public void write(final ByteBuf buffer, final FoodProperties value) { + public void write(final ByteBuf buffer, final FoodProperties1_20_5 value) { Types.VAR_INT.writePrimitive(buffer, value.nutrition); buffer.writeFloat(value.saturationModifier); buffer.writeBoolean(value.canAlwaysEat); @@ -51,20 +53,20 @@ public record FoodProperties(int nutrition, float saturationModifier, boolean ca FoodEffect.ARRAY_TYPE.write(buffer, value.possibleEffects); } }; - public static final Type TYPE1_21 = new Type(FoodProperties.class) { + public static final Type TYPE1_21 = new Type<>(FoodProperties1_20_5.class) { @Override - public FoodProperties read(final ByteBuf buffer) { + public FoodProperties1_20_5 read(final ByteBuf buffer) { final int nutrition = Types.VAR_INT.readPrimitive(buffer); final float saturationModifier = buffer.readFloat(); final boolean canAlwaysEat = buffer.readBoolean(); final float eatSeconds = buffer.readFloat(); final Item usingConvertsTo = Types1_21.OPTIONAL_ITEM.read(buffer); final FoodEffect[] possibleEffects = FoodEffect.ARRAY_TYPE.read(buffer); - return new FoodProperties(nutrition, saturationModifier, canAlwaysEat, eatSeconds, usingConvertsTo, possibleEffects); + return new FoodProperties1_20_5(nutrition, saturationModifier, canAlwaysEat, eatSeconds, usingConvertsTo, possibleEffects); } @Override - public void write(final ByteBuf buffer, final FoodProperties value) { + public void write(final ByteBuf buffer, final FoodProperties1_20_5 value) { Types.VAR_INT.writePrimitive(buffer, value.nutrition); buffer.writeFloat(value.saturationModifier); buffer.writeBoolean(value.canAlwaysEat); @@ -73,4 +75,23 @@ public record FoodProperties(int nutrition, float saturationModifier, boolean ca FoodEffect.ARRAY_TYPE.write(buffer, value.possibleEffects); } }; + + public record FoodEffect(PotionEffect effect, float probability) { + + public static final Type TYPE = new Type<>(FoodEffect.class) { + @Override + public FoodEffect read(final ByteBuf buffer) { + final PotionEffect effect = PotionEffect.TYPE.read(buffer); + final float probability = buffer.readFloat(); + return new FoodEffect(effect, probability); + } + + @Override + public void write(final ByteBuf buffer, final FoodEffect value) { + PotionEffect.TYPE.write(buffer, value.effect); + buffer.writeFloat(value.probability); + } + }; + public static final Type ARRAY_TYPE = new ArrayType<>(TYPE); + } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodProperties1_21_2.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodProperties1_21_2.java new file mode 100644 index 000000000..d6182e113 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/FoodProperties1_21_2.java @@ -0,0 +1,47 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.item.data; + +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; +import io.netty.buffer.ByteBuf; + +public record FoodProperties1_21_2(int nutrition, float saturationModifier, boolean canAlwaysEat) { + + public static final Type TYPE = new Type<>(FoodProperties1_21_2.class) { + @Override + public FoodProperties1_21_2 read(final ByteBuf buffer) { + final int nutrition = Types.VAR_INT.readPrimitive(buffer); + final float saturationModifier = buffer.readFloat(); + final boolean canAlwaysEat = buffer.readBoolean(); + return new FoodProperties1_21_2(nutrition, saturationModifier, canAlwaysEat); + } + + @Override + public void write(final ByteBuf buffer, final FoodProperties1_21_2 value) { + Types.VAR_INT.writePrimitive(buffer, value.nutrition); + buffer.writeFloat(value.saturationModifier); + buffer.writeBoolean(value.canAlwaysEat); + } + }; +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Instrument.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Instrument1_20_5.java similarity index 78% rename from api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Instrument.java rename to api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Instrument1_20_5.java index bb81c61cf..0d62f7789 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Instrument.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Instrument1_20_5.java @@ -29,27 +29,27 @@ import com.viaversion.viaversion.api.type.types.misc.HolderType; import io.netty.buffer.ByteBuf; import it.unimi.dsi.fastutil.ints.Int2IntFunction; -public record Instrument(Holder soundEvent, int useDuration, float range) { +public record Instrument1_20_5(Holder soundEvent, int useDuration, float range) { - public static final HolderType TYPE = new HolderType<>() { + public static final HolderType TYPE = new HolderType<>() { @Override - public Instrument readDirect(final ByteBuf buffer) { + public Instrument1_20_5 readDirect(final ByteBuf buffer) { final Holder soundEvent = Types.SOUND_EVENT.read(buffer); final int useDuration = Types.VAR_INT.readPrimitive(buffer); - final float range = buffer.readFloat(); - return new Instrument(soundEvent, useDuration, range); + final float range = Types.FLOAT.readPrimitive(buffer); + return new Instrument1_20_5(soundEvent, useDuration, range); } @Override - public void writeDirect(final ByteBuf buffer, final Instrument value) { + public void writeDirect(final ByteBuf buffer, final Instrument1_20_5 value) { Types.SOUND_EVENT.write(buffer, value.soundEvent()); Types.VAR_INT.writePrimitive(buffer, value.useDuration()); - buffer.writeFloat(value.range()); + Types.FLOAT.writePrimitive(buffer, value.range()); } }; - public Instrument rewrite(final Int2IntFunction soundIdRewriteFunction) { + public Instrument1_20_5 rewrite(final Int2IntFunction soundIdRewriteFunction) { final Holder soundEvent = this.soundEvent.updateId(soundIdRewriteFunction); - return soundEvent == this.soundEvent ? this : new Instrument(soundEvent, useDuration, range); + return soundEvent == this.soundEvent ? this : new Instrument1_20_5(soundEvent, useDuration, range); } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Instrument1_21_2.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Instrument1_21_2.java new file mode 100644 index 000000000..e6abac244 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/Instrument1_21_2.java @@ -0,0 +1,58 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.item.data; + +import com.viaversion.nbt.tag.Tag; +import com.viaversion.viaversion.api.minecraft.Holder; +import com.viaversion.viaversion.api.minecraft.SoundEvent; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.misc.HolderType; +import io.netty.buffer.ByteBuf; +import it.unimi.dsi.fastutil.ints.Int2IntFunction; + +public record Instrument1_21_2(Holder soundEvent, float useDuration, float range, Tag description) { + + public static final HolderType TYPE = new HolderType<>() { + @Override + public Instrument1_21_2 readDirect(final ByteBuf buffer) { + final Holder soundEvent = Types.SOUND_EVENT.read(buffer); + final float useDuration = Types.FLOAT.readPrimitive(buffer); + final float range = Types.FLOAT.readPrimitive(buffer); + final Tag description = Types.TAG.read(buffer); + return new Instrument1_21_2(soundEvent, useDuration, range, description); + } + + @Override + public void writeDirect(final ByteBuf buffer, final Instrument1_21_2 value) { + Types.SOUND_EVENT.write(buffer, value.soundEvent()); + Types.FLOAT.writePrimitive(buffer, value.useDuration()); + Types.FLOAT.writePrimitive(buffer, value.range()); + Types.TAG.write(buffer, value.description()); + } + }; + + public Instrument1_21_2 rewrite(final Int2IntFunction soundIdRewriteFunction) { + final Holder soundEvent = this.soundEvent.updateId(soundIdRewriteFunction); + return soundEvent == this.soundEvent ? this : new Instrument1_21_2(soundEvent, useDuration, range, description); + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/PotionContents.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/PotionContents.java index 81fdbb956..154c33d36 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/PotionContents.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/PotionContents.java @@ -27,15 +27,20 @@ import com.viaversion.viaversion.api.type.Types; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; -public record PotionContents(@Nullable Integer potion, @Nullable Integer customColor, PotionEffect[] customEffects) { +public record PotionContents(@Nullable Integer potion, @Nullable Integer customColor, PotionEffect[] customEffects, + @Nullable String customName) { - public static final Type TYPE = new Type<>(PotionContents.class) { + public PotionContents(final @Nullable Integer potion, final @Nullable Integer customColor, final PotionEffect[] customEffects) { + this(potion, customColor, customEffects, null); + } + + public static final Type TYPE1_20_5 = new Type<>(PotionContents.class) { @Override public PotionContents read(final ByteBuf buffer) { final Integer potion = buffer.readBoolean() ? Types.VAR_INT.readPrimitive(buffer) : null; final Integer customColor = buffer.readBoolean() ? buffer.readInt() : null; final PotionEffect[] customEffects = PotionEffect.ARRAY_TYPE.read(buffer); - return new PotionContents(potion, customColor, customEffects); + return new PotionContents(potion, customColor, customEffects, null); } @Override @@ -53,4 +58,31 @@ public record PotionContents(@Nullable Integer potion, @Nullable Integer customC PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects); } }; + + public static final Type TYPE1_21_2 = new Type<>(PotionContents.class) { + @Override + public PotionContents read(final ByteBuf buffer) { + final Integer potion = buffer.readBoolean() ? Types.VAR_INT.readPrimitive(buffer) : null; + final Integer customColor = buffer.readBoolean() ? buffer.readInt() : null; + final PotionEffect[] customEffects = PotionEffect.ARRAY_TYPE.read(buffer); + final String customName = Types.OPTIONAL_STRING.read(buffer); + return new PotionContents(potion, customColor, customEffects, customName); + } + + @Override + public void write(final ByteBuf buffer, final PotionContents value) { + buffer.writeBoolean(value.potion != null); + if (value.potion != null) { + Types.VAR_INT.writePrimitive(buffer, value.potion); + } + + buffer.writeBoolean(value.customColor != null); + if (value.customColor != null) { + buffer.writeInt(value.customColor); + } + + PotionEffect.ARRAY_TYPE.write(buffer, value.customEffects); + Types.OPTIONAL_STRING.write(buffer, value.customName); + } + }; } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/UseCooldown.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/UseCooldown.java new file mode 100644 index 000000000..db8cff8f9 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/item/data/UseCooldown.java @@ -0,0 +1,56 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.minecraft.item.data; + +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; +import io.netty.buffer.ByteBuf; +import java.util.function.Function; +import org.checkerframework.checker.nullness.qual.Nullable; + +public record UseCooldown(float seconds, @Nullable String cooldownGroup) { + + public static final Type TYPE = new Type<>(UseCooldown.class) { + @Override + public UseCooldown read(final ByteBuf buffer) { + final float seconds = buffer.readFloat(); + final String cooldownGroup = Types.OPTIONAL_STRING.read(buffer); + return new UseCooldown(seconds, cooldownGroup); + } + + @Override + public void write(final ByteBuf buffer, final UseCooldown value) { + buffer.writeFloat(value.seconds()); + Types.OPTIONAL_STRING.write(buffer, value.cooldownGroup()); + } + }; + + public UseCooldown rewrite(final Function idRewriter) { + if (cooldownGroup == null) { + return this; + } + + final String mappedCooldownGroup = idRewriter.apply(cooldownGroup); + return new UseCooldown(seconds, mappedCooldownGroup); + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/AbstractProtocol.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/AbstractProtocol.java index 8a5b4df3a..46a431cf3 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/AbstractProtocol.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/AbstractProtocol.java @@ -198,6 +198,14 @@ public abstract class AbstractProtocol { + // TODO Temporary solution to handle the finish configuration packet already having changed our tracked protocol state in a previous handler + wrapper.user().getProtocolInfo().setServerState(State.CONFIGURATION); + handler.handle(wrapper); + }); + } + @Override public final void loadMappingData() { getMappingData().load(); diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/Protocol.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/Protocol.java index da6cbc09f..7e5ab8e4e 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/Protocol.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/Protocol.java @@ -36,6 +36,7 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandler; import com.viaversion.viaversion.api.rewriter.ComponentRewriter; import com.viaversion.viaversion.api.rewriter.EntityRewriter; import com.viaversion.viaversion.api.rewriter.ItemRewriter; +import com.viaversion.viaversion.api.rewriter.ParticleRewriter; import com.viaversion.viaversion.api.rewriter.TagRewriter; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.exception.CancelException; @@ -374,6 +375,15 @@ public interface Protocol { private static final List VERSION_LIST = new ArrayList<>(); public static final ProtocolVersion v1_7_2 = register(4, "1.7.2-1.7.5", new SubVersionRange("1.7", 2, 5)); - @Deprecated(forRemoval=true) public static final ProtocolVersion v1_7_1 = v1_7_2; + @Deprecated(forRemoval = true) + public static final ProtocolVersion v1_7_1 = v1_7_2; public static final ProtocolVersion v1_7_6 = register(5, "1.7.6-1.7.10", new SubVersionRange("1.7", 6, 10)); public static final ProtocolVersion v1_8 = register(47, "1.8.x", new SubVersionRange("1.8", 0, 9)); public static final ProtocolVersion v1_9 = register(107, "1.9"); @@ -85,8 +86,14 @@ public class ProtocolVersion implements Comparable { public static final ProtocolVersion v1_20_3 = register(765, "1.20.3-1.20.4", new SubVersionRange("1.20", 3, 4)); public static final ProtocolVersion v1_20_5 = register(766, "1.20.5-1.20.6", new SubVersionRange("1.20", 5, 6)); public static final ProtocolVersion v1_21 = register(767, "1.21-1.21.1", new SubVersionRange("1.21", 0, 1)); + public static final ProtocolVersion v1_21_2 = register(768, "1.21.2-1.21.3", new SubVersionRange("1.21", 2, 3)); + public static final ProtocolVersion v1_21_4 = register(769, "1.21.4"); public static final ProtocolVersion unknown = new ProtocolVersion(VersionType.SPECIAL, -1, -1, "UNKNOWN", null); + static { + unknown.known = false; + } + public static ProtocolVersion register(int version, String name) { return register(version, -1, name); } @@ -150,7 +157,11 @@ public class ProtocolVersion implements Comparable { return protocolVersion; } } - return new ProtocolVersion(VersionType.SPECIAL, version, -1, "Unknown (" + version + ")", null); + + // Will be made nullable instead in the future... + final ProtocolVersion unknown = new ProtocolVersion(versionType, version, -1, "Unknown (" + version + ")", null); + unknown.known = false; + return unknown; } public static @NonNull ProtocolVersion getProtocol(final int version) { @@ -201,6 +212,8 @@ public class ProtocolVersion implements Comparable { private final int snapshotVersion; private final String name; private final Set includedVersions; + @Deprecated // Remove when getProtocol is made nullable + private boolean known = true; /** * Constructs a new ProtocolVersion instance. @@ -285,12 +298,12 @@ public class ProtocolVersion implements Comparable { } /** - * Returns whether the protocol is set. Should only be unknown for unregistered protocols returned by {@link #getProtocol(int)}. + * Returns whether the protocol version is {@link #unknown}. For checking if the protocol version is registered, use {@link #isRegistered(VersionType, int)} * - * @return true if the protocol is set + * @return true if the protocol version is unknown */ public boolean isKnown() { - return version != -1; + return known; } /** diff --git a/api/src/main/java/com/viaversion/viaversion/api/rewriter/EntityRewriter.java b/api/src/main/java/com/viaversion/viaversion/api/rewriter/EntityRewriter.java index d0d6e9696..136f2cf74 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/rewriter/EntityRewriter.java +++ b/api/src/main/java/com/viaversion/viaversion/api/rewriter/EntityRewriter.java @@ -58,6 +58,14 @@ public interface EntityRewriter> extends Rewriter */ int newEntityId(int id); + /** + * Returns the mapped entity (or the same if it has not changed). + * + * @param identifier unmapped entity identifier + * @return mapped entity identifier + */ + String mappedEntityIdentifier(String identifier); + /** * Handles and transforms entity data of an entity. * diff --git a/api/src/main/java/com/viaversion/viaversion/api/rewriter/ParticleRewriter.java b/api/src/main/java/com/viaversion/viaversion/api/rewriter/ParticleRewriter.java new file mode 100644 index 000000000..d78a729e7 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/rewriter/ParticleRewriter.java @@ -0,0 +1,27 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.api.rewriter; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.Particle; + +public interface ParticleRewriter { + + void rewriteParticle(UserConnection connection, Particle particle); + +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/Types.java b/api/src/main/java/com/viaversion/viaversion/api/type/Types.java index 8d6a7068e..063fad8cf 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/Types.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/Types.java @@ -45,12 +45,14 @@ import com.viaversion.viaversion.api.minecraft.item.data.Enchantments; import com.viaversion.viaversion.api.minecraft.ChunkPosition; import com.viaversion.viaversion.api.type.types.ArrayType; import com.viaversion.viaversion.api.type.types.BitSetType; +import com.viaversion.viaversion.api.type.types.BooleanArrayType; import com.viaversion.viaversion.api.type.types.BooleanType; import com.viaversion.viaversion.api.type.types.ByteArrayType; import com.viaversion.viaversion.api.type.types.ByteType; import com.viaversion.viaversion.api.type.types.ComponentType; import com.viaversion.viaversion.api.type.types.DoubleType; import com.viaversion.viaversion.api.type.types.EmptyType; +import com.viaversion.viaversion.api.type.types.FloatArrayType; import com.viaversion.viaversion.api.type.types.FloatType; import com.viaversion.viaversion.api.type.types.IntArrayType; import com.viaversion.viaversion.api.type.types.IntType; @@ -115,14 +117,17 @@ public final class Types { public static final Type OPTIONAL_BYTE_ARRAY_PRIMITIVE = new ByteArrayType.OptionalByteArrayType(); public static final Type SHORT_BYTE_ARRAY = new ShortByteArrayType(); public static final Type REMAINING_BYTES = new RemainingBytesType(); - public static final Type INT_ARRAY_PRIMITIVE = new IntArrayType(); public static final ShortType SHORT = new ShortType(); public static final UnsignedShortType UNSIGNED_SHORT = new UnsignedShortType(); public static final IntType INT = new IntType(); + public static final Type INT_ARRAY_PRIMITIVE = new IntArrayType(); + public static final FloatType FLOAT = new FloatType(); public static final FloatType.OptionalFloatType OPTIONAL_FLOAT = new FloatType.OptionalFloatType(); + public static final Type FLOAT_ARRAY_PRIMITIVE = new FloatArrayType(); + public static final DoubleType DOUBLE = new DoubleType(); public static final LongType LONG = new LongType(); @@ -130,6 +135,7 @@ public final class Types { public static final BooleanType BOOLEAN = new BooleanType(); public static final BooleanType.OptionalBooleanType OPTIONAL_BOOLEAN = new BooleanType.OptionalBooleanType(); + public static final Type BOOLEAN_ARRAY_PRIMITIVE = new BooleanArrayType(); /* Other Types */ public static final Type COMPONENT = new ComponentType(); @@ -149,6 +155,8 @@ public final class Types { public static final VarLongType VAR_LONG = new VarLongType(); /* MC Types */ + public static final Type SERVERBOUND_CUSTOM_PAYLOAD_DATA = new RemainingBytesType(Short.MAX_VALUE); + public static final Type BLOCK_POSITION1_8 = new BlockPositionType1_8(); public static final Type OPTIONAL_POSITION1_8 = new BlockPositionType1_8.OptionalBlockPositionType(); public static final Type BLOCK_POSITION1_14 = new BlockPositionType1_14(); @@ -189,7 +197,10 @@ public final class Types { public static final Type OPTIONAL_PLAYER_MESSAGE_SIGNATURE = new PlayerMessageSignatureType.OptionalPlayerMessageSignatureType(); public static final Type PLAYER_MESSAGE_SIGNATURE_ARRAY = new ArrayType<>(PLAYER_MESSAGE_SIGNATURE); - public static final BitSetType PROFILE_ACTIONS_ENUM = new BitSetType(6); + public static final BitSetType PROFILE_ACTIONS_ENUM1_19_3 = new BitSetType(6); + public static final BitSetType PROFILE_ACTIONS_ENUM1_21_2 = new BitSetType(7); + public static final BitSetType PROFILE_ACTIONS_ENUM1_21_4 = new BitSetType(8); + public static final ByteArrayType SIGNATURE_BYTES = new ByteArrayType(256); public static final BitSetType ACKNOWLEDGED_BIT_SET = new BitSetType(20); public static final ByteArrayType.OptionalByteArrayType OPTIONAL_SIGNATURE_BYTES = new ByteArrayType.OptionalByteArrayType(256); diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/ArrayType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/ArrayType.java index 6f1970e53..51ec67ca7 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/ArrayType.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/ArrayType.java @@ -26,13 +26,22 @@ import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; import io.netty.buffer.ByteBuf; import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; public class ArrayType extends Type { private final Type elementType; + private final int maxLength; public ArrayType(Type type) { + this(type, -1); + } + + public ArrayType(Type type, int maxLength) { + //noinspection unchecked super(type.getTypeName() + " Array", (Class) getArrayClass(type.getOutputClass())); this.elementType = type; + this.maxLength = maxLength; } public static Class getArrayClass(Class componentType) { @@ -43,16 +52,40 @@ public class ArrayType extends Type { @Override public T[] read(ByteBuf buffer) { int amount = Types.VAR_INT.readPrimitive(buffer); - T[] array = (T[]) Array.newInstance(elementType.getOutputClass(), amount); + if (maxLength != -1 && amount > maxLength) { + throw new IllegalArgumentException("Array length " + amount + " is longer than maximum " + maxLength); + } - for (int i = 0; i < amount; i++) { + return amount < Short.MAX_VALUE ? readArray(buffer, amount) : readList(buffer, amount); + } + + private T[] readArray(ByteBuf buffer, int length) { + T[] array = createArray(length); + for (int i = 0; i < length; i++) { array[i] = elementType.read(buffer); } return array; } + private T[] readList(ByteBuf buffer, int length) { + List list = new ArrayList<>(); + for (int i = 0; i < length; i++) { + list.add(elementType.read(buffer)); + } + return list.toArray(createArray(0)); + } + + private T[] createArray(int length) { + //noinspection unchecked + return (T[]) Array.newInstance(elementType.getOutputClass(), length); + } + @Override public void write(ByteBuf buffer, T[] object) { + if (maxLength != -1 && object.length > maxLength) { + throw new IllegalArgumentException("Array length " + object.length + " is longer than maximum " + maxLength); + } + Types.VAR_INT.writePrimitive(buffer, object.length); for (T o : object) { elementType.write(buffer, o); diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/BooleanArrayType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/BooleanArrayType.java new file mode 100644 index 000000000..eea9cbcf6 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/BooleanArrayType.java @@ -0,0 +1,67 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.type.types; + +import com.google.common.base.Preconditions; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; +import io.netty.buffer.ByteBuf; + +// Ok... +public class BooleanArrayType extends Type { + + private final int length; + + public BooleanArrayType(final int length) { + super(boolean[].class); + this.length = length; + } + + public BooleanArrayType() { + super(boolean[].class); + this.length = -1; + } + + @Override + public void write(final ByteBuf buffer, final boolean[] object) { + if (this.length != -1) { + Preconditions.checkArgument(length == object.length, "Length does not match expected length"); + } else { + Types.VAR_INT.writePrimitive(buffer, object.length); + } + for (final boolean b : object) { + buffer.writeBoolean(b); + } + } + + @Override + public boolean[] read(final ByteBuf buffer) { + final int length = this.length == -1 ? Types.VAR_INT.readPrimitive(buffer) : this.length; + Preconditions.checkArgument(buffer.isReadable(length), "Length is fewer than readable bytes"); + final boolean[] array = new boolean[length]; + for (int i = 0; i < length; i++) { + array[i] = buffer.readBoolean(); + } + return array; + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/FloatArrayType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/FloatArrayType.java new file mode 100644 index 000000000..7bbdf1408 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/FloatArrayType.java @@ -0,0 +1,66 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.type.types; + +import com.google.common.base.Preconditions; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; +import io.netty.buffer.ByteBuf; + +public class FloatArrayType extends Type { + + private final int length; + + public FloatArrayType(final int length) { + super(float[].class); + this.length = length; + } + + public FloatArrayType() { + super(float[].class); + this.length = -1; + } + + @Override + public void write(final ByteBuf buffer, final float[] object) { + if (this.length != -1) { + Preconditions.checkArgument(length == object.length, "Length does not match expected length"); + } else { + Types.VAR_INT.writePrimitive(buffer, object.length); + } + for (final float f : object) { + buffer.writeFloat(f); + } + } + + @Override + public float[] read(final ByteBuf buffer) { + final int length = this.length == -1 ? Types.VAR_INT.readPrimitive(buffer) : this.length; + Preconditions.checkArgument(buffer.isReadable(length), "Length is fewer than readable bytes"); + final float[] array = new float[length]; + for (int i = 0; i < length; i++) { + array[i] = buffer.readFloat(); + } + return array; + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/IntType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/IntType.java index fb6bcacbb..b2188a62c 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/IntType.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/IntType.java @@ -36,11 +36,19 @@ public class IntType extends Type implements TypeConverter { return buffer.readInt(); } + public int readPrimitive(ByteBuf buffer) { + return buffer.readInt(); + } + @Override public void write(ByteBuf buffer, Integer object) { buffer.writeInt(object); } + public void writePrimitive(ByteBuf buffer, int object) { + buffer.writeInt(object); + } + @Override public Integer from(Object o) { if (o instanceof Number number) { diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/RemainingBytesType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/RemainingBytesType.java index 212a0e114..998c73e3c 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/RemainingBytesType.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/RemainingBytesType.java @@ -26,19 +26,35 @@ import com.viaversion.viaversion.api.type.Type; import io.netty.buffer.ByteBuf; public class RemainingBytesType extends Type { + private final int maxLength; + public RemainingBytesType() { + this(-1); + } + + public RemainingBytesType(final int maxLength) { super(byte[].class); + this.maxLength = maxLength; } @Override - public byte[] read(ByteBuf buffer) { - byte[] array = new byte[buffer.readableBytes()]; + public byte[] read(final ByteBuf buffer) { + final int bytes = buffer.readableBytes(); + if (maxLength != -1 && bytes > maxLength) { + throw new RuntimeException("Remaining bytes cannot be longer than " + maxLength + " (got " + bytes + ")"); + } + + final byte[] array = new byte[bytes]; buffer.readBytes(array); return array; } @Override - public void write(ByteBuf buffer, byte[] object) { + public void write(final ByteBuf buffer, final byte[] object) { + if (maxLength != -1 && object.length > maxLength) { + throw new RuntimeException("Remaining bytes cannot be longer than " + maxLength + " (got " + object.length + ")"); + } + buffer.writeBytes(object); } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/VarIntType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/VarIntType.java index 1c5820edb..5fa3ebf76 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/VarIntType.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/VarIntType.java @@ -32,6 +32,15 @@ public class VarIntType extends Type implements TypeConverter private static final int VALUE_BITS = 0x7F; private static final int MULTI_BYTE_BITS = ~VALUE_BITS; private static final int MAX_BYTES = 5; + private static final int[] VAR_INT_LENGTHS = new int[65]; + + static { + // Copied from Velocity https://github.com/PaperMC/Velocity/blob/08a42b3723633ea5eb6b96c0bb42180f3c2b07eb/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java#L166 + for (int i = 0; i <= 32; ++i) { + VAR_INT_LENGTHS[i] = (int) Math.ceil((31d - (i - 1)) / 7d); + } + VAR_INT_LENGTHS[32] = 1; // Special case for the number 0. + } public VarIntType() { super("VarInt", Integer.class); @@ -88,4 +97,8 @@ public class VarIntType extends Type implements TypeConverter } throw new UnsupportedOperationException(); } -} \ No newline at end of file + + public static int varIntLength(final int value) { + return VAR_INT_LENGTHS[Integer.numberOfLeadingZeros(value)]; + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkSectionType1_18.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkSectionType1_18.java index 3de74488d..56a1a5e77 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkSectionType1_18.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkSectionType1_18.java @@ -22,6 +22,7 @@ */ package com.viaversion.viaversion.api.type.types.chunk; +import com.viaversion.viaversion.api.minecraft.chunks.Chunk; import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection; import com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionImpl; import com.viaversion.viaversion.api.minecraft.chunks.PaletteType; @@ -54,4 +55,14 @@ public final class ChunkSectionType1_18 extends Type { blockPaletteType.write(buffer, section.palette(PaletteType.BLOCKS)); biomePaletteType.write(buffer, section.palette(PaletteType.BIOMES)); } + + public int serializedSize(final Chunk chunk) { + int length = 0; + for (final ChunkSection section : chunk.getSections()) { + length += Short.BYTES + + blockPaletteType.serializedSize(section.palette(PaletteType.BLOCKS)) + + biomePaletteType.serializedSize(section.palette(PaletteType.BIOMES)); + } + return length; + } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkType1_18.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkType1_18.java index 1d4a8991d..8cdec0c2b 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkType1_18.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkType1_18.java @@ -52,14 +52,10 @@ public final class ChunkType1_18 extends Type { final CompoundTag heightMap = Types.NAMED_COMPOUND_TAG.read(buffer); // Read sections - final ByteBuf sectionsBuf = buffer.readBytes(Types.VAR_INT.readPrimitive(buffer)); + final ByteBuf sectionsBuf = buffer.readSlice(Types.VAR_INT.readPrimitive(buffer)); final ChunkSection[] sections = new ChunkSection[ySectionCount]; - try { - for (int i = 0; i < ySectionCount; i++) { - sections[i] = sectionType.read(sectionsBuf); - } - } finally { - sectionsBuf.release(); + for (int i = 0; i < ySectionCount; i++) { + sections[i] = sectionType.read(sectionsBuf); } final int blockEntitiesLength = Types.VAR_INT.readPrimitive(buffer); @@ -78,16 +74,9 @@ public final class ChunkType1_18 extends Type { Types.NAMED_COMPOUND_TAG.write(buffer, chunk.getHeightMap()); - final ByteBuf sectionBuffer = buffer.alloc().buffer(); - try { - for (final ChunkSection section : chunk.getSections()) { - sectionType.write(sectionBuffer, section); - } - sectionBuffer.readerIndex(0); - Types.VAR_INT.writePrimitive(buffer, sectionBuffer.readableBytes()); - buffer.writeBytes(sectionBuffer); - } finally { - sectionBuffer.release(); // release buffer + Types.VAR_INT.writePrimitive(buffer, sectionType.serializedSize(chunk)); + for (final ChunkSection section : chunk.getSections()) { + sectionType.write(buffer, section); } Types.VAR_INT.writePrimitive(buffer, chunk.blockEntities().size()); diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkType1_20_2.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkType1_20_2.java index ffe709afd..3fb8413ce 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkType1_20_2.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/ChunkType1_20_2.java @@ -52,14 +52,10 @@ public final class ChunkType1_20_2 extends Type { final CompoundTag heightMap = Types.COMPOUND_TAG.read(buffer); // Read sections - final ByteBuf sectionsBuf = buffer.readBytes(Types.VAR_INT.readPrimitive(buffer)); + final ByteBuf sectionsBuf = buffer.readSlice(Types.VAR_INT.readPrimitive(buffer)); final ChunkSection[] sections = new ChunkSection[ySectionCount]; - try { - for (int i = 0; i < ySectionCount; i++) { - sections[i] = sectionType.read(sectionsBuf); - } - } finally { - sectionsBuf.release(); + for (int i = 0; i < ySectionCount; i++) { + sections[i] = sectionType.read(sectionsBuf); } final int blockEntitiesLength = Types.VAR_INT.readPrimitive(buffer); @@ -78,16 +74,9 @@ public final class ChunkType1_20_2 extends Type { Types.COMPOUND_TAG.write(buffer, chunk.getHeightMap()); - final ByteBuf sectionBuffer = buffer.alloc().buffer(); - try { - for (final ChunkSection section : chunk.getSections()) { - sectionType.write(sectionBuffer, section); - } - sectionBuffer.readerIndex(0); - Types.VAR_INT.writePrimitive(buffer, sectionBuffer.readableBytes()); - buffer.writeBytes(sectionBuffer); - } finally { - sectionBuffer.release(); // release buffer + Types.VAR_INT.writePrimitive(buffer, sectionType.serializedSize(chunk)); + for (final ChunkSection section : chunk.getSections()) { + sectionType.write(buffer, section); } Types.VAR_INT.writePrimitive(buffer, chunk.blockEntities().size()); diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/PaletteType1_18.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/PaletteType1_18.java index 7e404fb76..6df3d9485 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/PaletteType1_18.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/chunk/PaletteType1_18.java @@ -27,6 +27,7 @@ import com.viaversion.viaversion.api.minecraft.chunks.DataPaletteImpl; import com.viaversion.viaversion.api.minecraft.chunks.PaletteType; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.VarIntType; import com.viaversion.viaversion.util.CompactArrayUtil; import com.viaversion.viaversion.util.MathUtil; import io.netty.buffer.ByteBuf; @@ -94,13 +95,7 @@ public final class PaletteType1_18 extends Type { return; } - // 1, 2, and 3 bit linear block palettes can't be read by the client - final int min = type == PaletteType.BLOCKS ? 4 : 1; - int bitsPerValue = Math.max(min, MathUtil.ceilLog2(size)); - if (bitsPerValue > type.highestBitsPerValue()) { - bitsPerValue = globalPaletteBits; - } - + final int bitsPerValue = bitsPerValue(size); buffer.writeByte(bitsPerValue); if (bitsPerValue != globalPaletteBits) { @@ -113,4 +108,39 @@ public final class PaletteType1_18 extends Type { Types.LONG_ARRAY_PRIMITIVE.write(buffer, CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, type.size(), bitsPerValue == globalPaletteBits ? palette::idAt : palette::paletteIndexAt)); } + + private int bitsPerValue(final int size) { + // 1, 2, and 3 bit linear block palettes can't be read by the client + final int min = type == PaletteType.BLOCKS ? 4 : 1; + int bitsPerValue = Math.max(min, MathUtil.ceilLog2(size)); + if (bitsPerValue > type.highestBitsPerValue()) { + bitsPerValue = globalPaletteBits; + } + return bitsPerValue; + } + + public int serializedSize(final DataPalette palette) { + // This is a bit of extra work, but worth it to avoid otherwise having to allocate and write to an extra buffer. + // On top of saving memory, it provides small but measurable speedup compared to writing to a separate buffer and then back + final int size = palette.size(); + final int bitsPerValue = bitsPerValue(size); + int serializedTypesSize = 0; + int serializedValuesSize = 1; // At least one byte for 0 length + if (size == 1) { + serializedTypesSize = VarIntType.varIntLength(palette.idByIndex(0)); + } else { + if (bitsPerValue != globalPaletteBits) { + serializedTypesSize = VarIntType.varIntLength(size); + for (int i = 0; i < size; i++) { + serializedTypesSize += VarIntType.varIntLength(palette.idByIndex(i)); + } + } + + final int valuesPerLong = 64 / bitsPerValue; + final int values = (type.size() + valuesPerLong - 1) / valuesPerLong; + serializedValuesSize = VarIntType.varIntLength(values) + (Long.BYTES * values); + } + + return Byte.BYTES + serializedTypesSize + serializedValuesSize; + } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/item/ItemType1_20_5.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/item/ItemType1_20_5.java index 89ef06f88..a713473e5 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/item/ItemType1_20_5.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/item/ItemType1_20_5.java @@ -63,7 +63,7 @@ public class ItemType1_20_5 extends Type { return new Reference2ObjectOpenHashMap<>(); } - final Map, StructuredData> map = new Reference2ObjectOpenHashMap<>(); + final Map, StructuredData> map = new Reference2ObjectOpenHashMap<>(Math.min(valuesSize + markersSize, 128)); for (int i = 0; i < valuesSize; i++) { final StructuredData value = dataType.read(buffer); final StructuredDataKey key = dataType.key(value.id()); diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/item/StructuredDataType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/item/StructuredDataType.java index a1a297fbd..90186aa3b 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/item/StructuredDataType.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/item/StructuredDataType.java @@ -87,5 +87,12 @@ public class StructuredDataType extends Type> { types[id] = key; return this; } + + public DataFiller add(final StructuredDataKey... keys) { + for (final StructuredDataKey key : keys) { + add(key); + } + return this; + } } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/misc/ParticleType.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/misc/ParticleType.java index f02573c07..8e565aacc 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/misc/ParticleType.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/misc/ParticleType.java @@ -29,7 +29,6 @@ import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; -import com.viaversion.viaversion.api.type.types.version.Types1_20_5; import com.viaversion.viaversion.util.Key; import io.netty.buffer.ByteBuf; @@ -77,6 +76,10 @@ public class ParticleType extends DynamicType { particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Blue 0-1 particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4 }; + public static final DataReader DUST1_21_2 = (buf, particle) -> { + particle.add(Types.INT, Types.INT.readPrimitive(buf)); // RGB + particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4 + }; public static final DataReader DUST_TRANSITION = (buf, particle) -> { particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Red 0-1 particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Green 0-1 @@ -86,6 +89,11 @@ public class ParticleType extends DynamicType { particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Green particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Blue }; + public static final DataReader DUST_TRANSITION1_21_2 = (buf, particle) -> { + particle.add(Types.INT, Types.INT.readPrimitive(buf)); // From RGB + particle.add(Types.INT, Types.INT.readPrimitive(buf)); // To RGB + particle.add(Types.FLOAT, Types.FLOAT.readPrimitive(buf)); // Scale 0.01-4 + }; public static final DataReader VIBRATION = (buf, particle) -> { particle.add(Types.BLOCK_POSITION1_14, Types.BLOCK_POSITION1_14.read(buf)); // From block pos @@ -136,7 +144,22 @@ public class ParticleType extends DynamicType { public static final DataReader SHRIEK = (buf, particle) -> { particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Delay }; - public static final DataReader COLOR = (buf, particle) -> particle.add(Types.INT, buf.readInt()); + public static final DataReader COLOR = (buf, particle) -> { + particle.add(Types.INT, Types.INT.readPrimitive(buf)); + }; + public static final DataReader TRAIL1_21_2 = (buf, particle) -> { + particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target X + particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target Y + particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target Z + particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color + }; + public static final DataReader TRAIL1_21_4 = (buf, particle) -> { + particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target X + particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target Y + particle.add(Types.DOUBLE, Types.DOUBLE.readPrimitive(buf)); // Target Z + particle.add(Types.INT, Types.INT.readPrimitive(buf)); // Color + particle.add(Types.VAR_INT, Types.VAR_INT.readPrimitive(buf)); // Duration + }; public static DataReader item(Type item) { return (buf, particle) -> particle.add(item, item.read(buf)); diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21.java index ce496d5ff..b315f98a0 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21.java @@ -50,7 +50,7 @@ public final class Types1_21 { public static final ParticleType PARTICLE = new ParticleType(); public static final ArrayType PARTICLES = new ArrayType<>(PARTICLE); - public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(PARTICLE, PARTICLES); + public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(ITEM, PARTICLE, PARTICLES); public static final Type ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES); public static final Type> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21_2.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21_2.java new file mode 100644 index 000000000..c7c4f5f84 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21_2.java @@ -0,0 +1,55 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.type.types.version; + +import com.viaversion.viaversion.api.minecraft.Particle; +import com.viaversion.viaversion.api.minecraft.data.StructuredData; +import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; +import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21_2; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.types.ArrayType; +import com.viaversion.viaversion.api.type.types.entitydata.EntityDataListType; +import com.viaversion.viaversion.api.type.types.entitydata.EntityDataType; +import com.viaversion.viaversion.api.type.types.item.ItemCostType1_20_5; +import com.viaversion.viaversion.api.type.types.item.ItemType1_20_5; +import com.viaversion.viaversion.api.type.types.item.StructuredDataType; +import com.viaversion.viaversion.api.type.types.misc.ParticleType; +import java.util.List; + +// Most of these are only safe to use after protocol loading +public final class Types1_21_2 { + + public static final StructuredDataType STRUCTURED_DATA = new StructuredDataType(); + public static final Type[]> STRUCTURED_DATA_ARRAY = new ArrayType<>(STRUCTURED_DATA); + public static final ItemType1_20_5 ITEM = new ItemType1_20_5(STRUCTURED_DATA); + public static final Type ITEM_ARRAY = new ArrayType<>(ITEM); + public static final Type ITEM_COST = new ItemCostType1_20_5(STRUCTURED_DATA_ARRAY); + public static final Type OPTIONAL_ITEM_COST = new ItemCostType1_20_5.OptionalItemCostType(ITEM_COST); + + public static final ParticleType PARTICLE = new ParticleType(); + public static final Type PARTICLES = new ArrayType<>(PARTICLE); + public static final EntityDataTypes1_21_2 ENTITY_DATA_TYPES = new EntityDataTypes1_21_2(ITEM, PARTICLE, PARTICLES); + public static final Type ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES); + public static final Type> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA); +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21_4.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21_4.java new file mode 100644 index 000000000..cc4eed9d6 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_21_4.java @@ -0,0 +1,55 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.viaversion.viaversion.api.type.types.version; + +import com.viaversion.viaversion.api.minecraft.Particle; +import com.viaversion.viaversion.api.minecraft.data.StructuredData; +import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; +import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_21; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.types.ArrayType; +import com.viaversion.viaversion.api.type.types.entitydata.EntityDataListType; +import com.viaversion.viaversion.api.type.types.entitydata.EntityDataType; +import com.viaversion.viaversion.api.type.types.item.ItemCostType1_20_5; +import com.viaversion.viaversion.api.type.types.item.ItemType1_20_5; +import com.viaversion.viaversion.api.type.types.item.StructuredDataType; +import com.viaversion.viaversion.api.type.types.misc.ParticleType; +import java.util.List; + +// Most of these are only safe to use after protocol loading +public final class Types1_21_4 { + + public static final StructuredDataType STRUCTURED_DATA = new StructuredDataType(); + public static final Type[]> STRUCTURED_DATA_ARRAY = new ArrayType<>(STRUCTURED_DATA); + public static final ItemType1_20_5 ITEM = new ItemType1_20_5(STRUCTURED_DATA); + public static final Type ITEM_ARRAY = new ArrayType<>(ITEM); + public static final Type ITEM_COST = new ItemCostType1_20_5(STRUCTURED_DATA_ARRAY); + public static final Type OPTIONAL_ITEM_COST = new ItemCostType1_20_5.OptionalItemCostType(ITEM_COST); + + public static final ParticleType PARTICLE = new ParticleType(); + public static final ArrayType PARTICLES = new ArrayType<>(PARTICLE); + public static final EntityDataTypes1_21 ENTITY_DATA_TYPES = new EntityDataTypes1_21(ITEM, PARTICLE, PARTICLES); + public static final Type ENTITY_DATA = new EntityDataType(ENTITY_DATA_TYPES); + public static final Type> ENTITY_DATA_LIST = new EntityDataListType(ENTITY_DATA); +} diff --git a/api/src/main/java/com/viaversion/viaversion/exception/InformativeException.java b/api/src/main/java/com/viaversion/viaversion/exception/InformativeException.java index 820d4762d..4afc16d3a 100644 --- a/api/src/main/java/com/viaversion/viaversion/exception/InformativeException.java +++ b/api/src/main/java/com/viaversion/viaversion/exception/InformativeException.java @@ -22,11 +22,14 @@ */ package com.viaversion.viaversion.exception; -import java.util.HashMap; -import java.util.Map; +import com.viaversion.viaversion.api.Via; +import java.util.ArrayList; +import java.util.List; +import org.checkerframework.checker.nullness.qual.Nullable; public class InformativeException extends RuntimeException { - private final Map info = new HashMap<>(); + private static final int MAX_MESSAGE_LENGTH = 5_000; + private final List dataEntries = new ArrayList<>(); private boolean shouldBePrinted = true; private int sources; @@ -34,8 +37,8 @@ public class InformativeException extends RuntimeException { super(cause); } - public InformativeException set(String key, Object value) { - info.put(key, value); + public InformativeException set(String key, @Nullable Object value) { + dataEntries.add(new DataEntry(key, value)); return this; } @@ -57,14 +60,21 @@ public class InformativeException extends RuntimeException { @Override public String getMessage() { - StringBuilder builder = new StringBuilder("Please report this on the Via support Discord or open an issue on the relevant GitHub repository\n"); + final StringBuilder builder = new StringBuilder("Please report this on the Via support Discord or open an issue on the relevant GitHub repository\n"); boolean first = true; - for (Map.Entry entry : info.entrySet()) { + for (final DataEntry entry : dataEntries) { if (!first) { builder.append(", "); + } else { + first = false; } - builder.append(entry.getKey()).append(": ").append(entry.getValue()); - first = false; + + builder.append(entry.name()).append(": "); + String s = String.valueOf(entry.value()); + if (!Via.getManager().isDebug() && s.length() > 10 && builder.length() + s.length() > MAX_MESSAGE_LENGTH) { + s = s.substring(0, MAX_MESSAGE_LENGTH - builder.length()) + "..."; + } + builder.append(s.replaceAll("\\s", "")); } return builder.toString(); } @@ -74,4 +84,7 @@ public class InformativeException extends RuntimeException { // Don't record this stack return this; } + + private record DataEntry(String name, @Nullable Object value) { + } } diff --git a/api/src/main/java/com/viaversion/viaversion/util/Limit.java b/api/src/main/java/com/viaversion/viaversion/util/Limit.java new file mode 100644 index 000000000..2251fd8a8 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/util/Limit.java @@ -0,0 +1,28 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.util; + +public final class Limit { + + public static int max(final int value, final int max) { + if (value > max) { + throw new IllegalArgumentException("Value " + value + " is higher than the maximum " + max); + } + return value; + } +} diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 83828ac32..b72de159f 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -1,7 +1,6 @@ import org.gradle.api.Project import org.gradle.api.plugins.JavaPluginExtension import org.gradle.jvm.toolchain.JavaLanguageVersion -import java.io.ByteArrayOutputStream fun Project.latestCommitHash(): String { return runGitCommand(listOf("rev-parse", "--short", "HEAD")) @@ -16,12 +15,9 @@ fun Project.branchName(): String { } fun Project.runGitCommand(args: List): String { - val byteOut = ByteArrayOutputStream() - exec { + return providers.exec { commandLine = listOf("git") + args - standardOutput = byteOut - } - return byteOut.toString(Charsets.UTF_8.name()).trim() + }.standardOutput.asBytes.get().toString(Charsets.UTF_8).trim() } fun JavaPluginExtension.javaTarget(version: Int) { diff --git a/build-logic/src/main/kotlin/via.base-conventions.gradle.kts b/build-logic/src/main/kotlin/via.base-conventions.gradle.kts index d094aff73..043784492 100644 --- a/build-logic/src/main/kotlin/via.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/via.base-conventions.gradle.kts @@ -1,5 +1,6 @@ plugins { `java-library` + `jvm-test-suite` } tasks { diff --git a/build.gradle.kts b/build.gradle.kts index a5f64b05b..57044fd9f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,10 +16,10 @@ val main = setOf( projects.viaversionBukkit, projects.viaversionVelocity, projects.viaversionFabric -).map { it.dependencyProject } +).map { it.path } subprojects { - when (this) { + when (path) { in main -> plugins.apply("via.shadow-conventions") else -> plugins.apply("via.base-conventions") } diff --git a/bukkit/src/main/java/com/viaversion/viaversion/ViaVersionPlugin.java b/bukkit/src/main/java/com/viaversion/viaversion/ViaVersionPlugin.java index a11c8cef4..71fde4438 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/ViaVersionPlugin.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/ViaVersionPlugin.java @@ -33,6 +33,7 @@ import com.viaversion.viaversion.bukkit.platform.BukkitViaInjector; import com.viaversion.viaversion.bukkit.platform.BukkitViaLoader; import com.viaversion.viaversion.bukkit.platform.BukkitViaTask; import com.viaversion.viaversion.bukkit.platform.BukkitViaTaskTask; +import com.viaversion.viaversion.bukkit.platform.FoliaViaTask; import com.viaversion.viaversion.bukkit.platform.PaperViaInjector; import com.viaversion.viaversion.dump.PluginInfo; import com.viaversion.viaversion.unsupported.UnsupportedPlugin; @@ -46,6 +47,7 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; @@ -55,6 +57,8 @@ import org.bukkit.plugin.java.JavaPlugin; public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform { private static final boolean FOLIA = PaperViaInjector.hasClass("io.papermc.paper.threadedregions.RegionizedServer"); + private static final Runnable DUMMY_RUNNABLE = () -> { + }; private static ViaVersionPlugin instance; private final BukkitCommandHandler commandHandler = new BukkitCommandHandler(); private final BukkitViaConfig conf; @@ -171,11 +175,36 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform @Override public PlatformTask runSync(Runnable runnable, long delay) { + if (FOLIA) { + // Set the delayed tick to at least 1, as Folia requires this. + return new FoliaViaTask(getServer().getGlobalRegionScheduler().runDelayed(this, (e) -> runnable.run(), delay <= 0L ? 1L : delay)); + } return new BukkitViaTask(getServer().getScheduler().runTaskLater(this, runnable, delay)); } + public PlatformTask runSyncAt(Runnable runnable, Block block) { + if (FOLIA) { + return new FoliaViaTask(getServer().getRegionScheduler().run(this, block.getLocation(), (e) -> runnable.run())); + } + return runSync(runnable); + } + + public PlatformTask runSyncFor(Runnable runnable, Player player) { + if (FOLIA) { + return new FoliaViaTask(player.getScheduler().run(this, (e) -> runnable.run(), DUMMY_RUNNABLE)); + } + return runSync(() -> { + if (player.isOnline()) { + runnable.run(); + } + }); + } + @Override public PlatformTask runRepeatingSync(Runnable runnable, long period) { + if (FOLIA) { + return new FoliaViaTask(getServer().getGlobalRegionScheduler().runAtFixedRate(this, (e) -> runnable.run(), 1, period)); + } return new BukkitViaTask(getServer().getScheduler().runTaskTimer(this, runnable, 0, period)); } diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitDecodeHandler.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitDecodeHandler.java index 2d73afc73..2a0f94b06 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitDecodeHandler.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitDecodeHandler.java @@ -22,6 +22,7 @@ import com.viaversion.viaversion.bukkit.util.NMSUtil; import com.viaversion.viaversion.exception.CancelCodecException; import com.viaversion.viaversion.exception.CancelDecoderException; import com.viaversion.viaversion.exception.InformativeException; +import com.viaversion.viaversion.util.ByteBufUtil; import com.viaversion.viaversion.util.PipelineUtil; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; @@ -39,7 +40,7 @@ public final class BukkitDecodeHandler extends MessageToMessageDecoder } @Override - protected void decode(final ChannelHandlerContext ctx, final ByteBuf bytebuf, final List out) throws Exception { + protected void decode(final ChannelHandlerContext ctx, final ByteBuf bytebuf, final List out) { if (!connection.checkServerboundPacket()) { throw CancelDecoderException.generate(null); } @@ -48,7 +49,7 @@ public final class BukkitDecodeHandler extends MessageToMessageDecoder return; } - final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); + final ByteBuf transformedBuf = ByteBufUtil.copy(ctx.alloc(), bytebuf); try { connection.transformIncoming(transformedBuf, CancelDecoderException::generate); out.add(transformedBuf.retain()); diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitEncodeHandler.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitEncodeHandler.java index 1147ad407..4784cb2c4 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitEncodeHandler.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitEncodeHandler.java @@ -22,6 +22,7 @@ import com.viaversion.viaversion.bukkit.util.NMSUtil; import com.viaversion.viaversion.exception.CancelCodecException; import com.viaversion.viaversion.exception.CancelEncoderException; import com.viaversion.viaversion.exception.InformativeException; +import com.viaversion.viaversion.util.ByteBufUtil; import com.viaversion.viaversion.util.PipelineUtil; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; @@ -52,7 +53,7 @@ public final class BukkitEncodeHandler extends MessageToMessageEncoder return; } - final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); + final ByteBuf transformedBuf = ByteBufUtil.copy(ctx.alloc(), bytebuf); try { final boolean needsCompression = !handledCompression && handleCompressionOrder(ctx, transformedBuf); connection.transformClientbound(transformedBuf, CancelEncoderException::generate); diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/v1_20_5to1_21/LegacyChangeItemListener.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/v1_20_5to1_21/LegacyChangeItemListener.java new file mode 100644 index 000000000..9bfecd4a1 --- /dev/null +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/v1_20_5to1_21/LegacyChangeItemListener.java @@ -0,0 +1,72 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21; + +import com.viaversion.viaversion.ViaVersionPlugin; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.EfficiencyAttributeStorage; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockDamageEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +public class LegacyChangeItemListener extends PlayerChangeItemListener { + + public LegacyChangeItemListener(final ViaVersionPlugin plugin) { + super(plugin); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockDamageEvent(final BlockDamageEvent event) { + final Player player = event.getPlayer(); + final ItemStack item = event.getItemInHand(); + sendAttributeUpdate(player, item, Slot.HAND); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClose(final InventoryCloseEvent event) { + if (event.getPlayer() instanceof Player player && + (event.getInventory().getType() == InventoryType.CRAFTING || + event.getInventory().getType() == InventoryType.PLAYER)) { + sendArmorUpdate(player); + } + } + + private void sendArmorUpdate(final Player player) { + final UserConnection connection = getUserConnection(player); + final EfficiencyAttributeStorage storage = getEfficiencyStorage(connection); + if (storage == null) { + return; + } + + final PlayerInventory inventory = player.getInventory(); + final ItemStack helmet = inventory.getHelmet(); + final ItemStack leggings = swiftSneak != null ? inventory.getLeggings() : null; + final ItemStack boots = depthStrider != null ? inventory.getBoots() : null; + + storage.setEnchants(player.getEntityId(), connection, storage.activeEnchants() + .aquaAffinity(helmet != null ? helmet.getEnchantmentLevel(aquaAffinity) : 0) + .swiftSneak(leggings != null ? leggings.getEnchantmentLevel(swiftSneak) : 0) + .depthStrider(boots != null ? boots.getEnchantmentLevel(depthStrider) : 0)); + } + +} diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/v1_20_5to1_21/PlayerChangeItemListener.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/v1_20_5to1_21/PlayerChangeItemListener.java index 3af953882..1a56c5a5d 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/v1_20_5to1_21/PlayerChangeItemListener.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/v1_20_5to1_21/PlayerChangeItemListener.java @@ -18,7 +18,6 @@ package com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21; import com.viaversion.viaversion.ViaVersionPlugin; -import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.bukkit.listeners.ViaBukkitListener; import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21; @@ -38,11 +37,11 @@ import org.checkerframework.checker.nullness.qual.Nullable; public class PlayerChangeItemListener extends ViaBukkitListener { // Use legacy function and names here to support all versions - private final Enchantment efficiency = getByName("efficiency", "DIG_SPEED"); - private final Enchantment aquaAffinity = getByName("aqua_affinity", "WATER_WORKER"); - private final Enchantment depthStrider = getByName("depth_strider", "DEPTH_STRIDER"); - private final Enchantment soulSpeed = getByName("soul_speed", "SOUL_SPEED"); - private final Enchantment swiftSneak = getByName("swift_sneak", "SWIFT_SNEAK"); + protected final Enchantment efficiency = getByName("efficiency", "DIG_SPEED"); + protected final Enchantment aquaAffinity = getByName("aqua_affinity", "WATER_WORKER"); + protected final Enchantment depthStrider = getByName("depth_strider", "DEPTH_STRIDER"); + protected final Enchantment soulSpeed = getByName("soul_speed", "SOUL_SPEED"); + protected final Enchantment swiftSneak = getByName("swift_sneak", "SWIFT_SNEAK"); public PlayerChangeItemListener(final ViaVersionPlugin plugin) { super(plugin, Protocol1_20_5To1_21.class); @@ -55,35 +54,26 @@ public class PlayerChangeItemListener extends ViaBukkitListener { sendAttributeUpdate(player, item, Slot.HAND); } + protected EfficiencyAttributeStorage getEfficiencyStorage(final UserConnection connection) { + return connection != null ? connection.get(EfficiencyAttributeStorage.class) : null; + } + void sendAttributeUpdate(final Player player, @Nullable final ItemStack item, final Slot slot) { - final UserConnection connection = Via.getAPI().getConnection(player.getUniqueId()); - if (connection == null || !isOnPipe(player)) { - return; - } + final UserConnection connection = getUserConnection(player); + final EfficiencyAttributeStorage storage = getEfficiencyStorage(connection); + if (storage == null) return; - final EfficiencyAttributeStorage storage = connection.get(EfficiencyAttributeStorage.class); - if (storage == null) { - return; - } - - final EfficiencyAttributeStorage.ActiveEnchants activeEnchants = storage.activeEnchants(); - int efficiencyLevel = activeEnchants.efficiency().level(); - int aquaAffinityLevel = activeEnchants.aquaAffinity().level(); - int soulSpeedLevel = activeEnchants.soulSpeed().level(); - int swiftSneakLevel = activeEnchants.swiftSneak().level(); - int depthStriderLevel = activeEnchants.depthStrider().level(); - switch (slot) { - case HAND -> efficiencyLevel = item != null ? item.getEnchantmentLevel(efficiency) : 0; - case HELMET -> aquaAffinityLevel = item != null ? item.getEnchantmentLevel(aquaAffinity) : 0; - case LEGGINGS -> swiftSneakLevel = item != null && swiftSneak != null ? item.getEnchantmentLevel(swiftSneak) : 0; - case BOOTS -> { - depthStriderLevel = item != null && depthStrider != null ? item.getEnchantmentLevel(depthStrider) : 0; - // TODO This needs continuous ticking for the supporting block as a conditional effect - // and is even more prone to desync from high ping than the other attributes - //soulSpeedLevel = item != null && soulSpeed != null ? item.getEnchantmentLevel(soulSpeed) : 0; - } - } - storage.setEnchants(player.getEntityId(), connection, efficiencyLevel, soulSpeedLevel, swiftSneakLevel, aquaAffinityLevel, depthStriderLevel); + EfficiencyAttributeStorage.ActiveEnchants enchants = storage.activeEnchants(); + enchants = switch (slot) { + case HAND -> enchants.efficiency(item != null ? item.getEnchantmentLevel(efficiency) : 0); + case HELMET -> enchants.aquaAffinity(item != null ? item.getEnchantmentLevel(aquaAffinity) : 0); + case LEGGINGS -> enchants.swiftSneak(item != null && swiftSneak != null ? item.getEnchantmentLevel(swiftSneak) : 0); + case BOOTS -> enchants.depthStrider(item != null && depthStrider != null ? item.getEnchantmentLevel(depthStrider) : 0); + // TODO This needs continuous ticking for the supporting block as a conditional effect + // and is even more prone to desync from high ping than the other attributes + //soulSpeedLevel = item != null && soulSpeed != null ? item.getEnchantmentLevel(soulSpeed) : 0; + }; + storage.setEnchants(player.getEntityId(), connection, enchants); } enum Slot { diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaLoader.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaLoader.java index 12cfc29fb..e3d82be67 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaLoader.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/BukkitViaLoader.java @@ -26,23 +26,25 @@ import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.bukkit.listeners.UpdateListener; import com.viaversion.viaversion.bukkit.listeners.multiversion.PlayerSneakListener; import com.viaversion.viaversion.bukkit.listeners.v1_14_4to1_15.EntityToggleGlideListener; -import com.viaversion.viaversion.bukkit.listeners.v1_19_3to1_19_4.ArmorToggleListener; import com.viaversion.viaversion.bukkit.listeners.v1_18_2to1_19.BlockBreakListener; +import com.viaversion.viaversion.bukkit.listeners.v1_19_3to1_19_4.ArmorToggleListener; +import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.LegacyChangeItemListener; +import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.PaperPlayerChangeItemListener; import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.ArmorListener; import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.BlockListener; import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.DeathListener; import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.HandItemCache; import com.viaversion.viaversion.bukkit.listeners.v1_8to1_9.PaperPatch; -import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.PaperPlayerChangeItemListener; -import com.viaversion.viaversion.bukkit.listeners.v1_20_5to1_21.PlayerChangeItemListener; import com.viaversion.viaversion.bukkit.providers.BukkitAckSequenceProvider; import com.viaversion.viaversion.bukkit.providers.BukkitBlockConnectionProvider; import com.viaversion.viaversion.bukkit.providers.BukkitInventoryQuickMoveProvider; +import com.viaversion.viaversion.bukkit.providers.BukkitPickItemProvider; import com.viaversion.viaversion.bukkit.providers.BukkitViaMovementTransmitter; import com.viaversion.viaversion.protocols.v1_11_1to1_12.provider.InventoryQuickMoveProvider; import com.viaversion.viaversion.protocols.v1_12_2to1_13.blockconnections.ConnectionData; import com.viaversion.viaversion.protocols.v1_12_2to1_13.blockconnections.providers.BlockConnectionProvider; import com.viaversion.viaversion.protocols.v1_18_2to1_19.provider.AckSequenceProvider; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.provider.PickItemProvider; import com.viaversion.viaversion.protocols.v1_8to1_9.provider.HandItemProvider; import com.viaversion.viaversion.protocols.v1_8to1_9.provider.MovementTransmitterProvider; import java.util.HashSet; @@ -184,7 +186,12 @@ public class BukkitViaLoader implements ViaPlatformLoader { if (PaperViaInjector.hasClass("io.papermc.paper.event.player.PlayerInventorySlotChangeEvent")) { new PaperPlayerChangeItemListener(plugin).register(); } else { - new PlayerChangeItemListener(plugin).register(); + new LegacyChangeItemListener(plugin).register(); + } + } + if (serverProtocolVersion.olderThan(ProtocolVersion.v1_21_4)) { + if (PaperViaInjector.hasMethod(Material.class, "isItem")) { + Via.getManager().getProviders().use(PickItemProvider.class, new BukkitPickItemProvider(plugin)); } } } diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/FoliaViaTask.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/FoliaViaTask.java new file mode 100644 index 000000000..a1dfb668e --- /dev/null +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/FoliaViaTask.java @@ -0,0 +1,28 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.bukkit.platform; + +import com.viaversion.viaversion.api.platform.PlatformTask; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; + +public record FoliaViaTask(ScheduledTask task) implements PlatformTask { + @Override + public void cancel() { + task.cancel(); + } +} diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/PaperViaInjector.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/PaperViaInjector.java index 366ad3ecb..22eaf5021 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/PaperViaInjector.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/platform/PaperViaInjector.java @@ -65,12 +65,7 @@ public final class PaperViaInjector { } private static boolean hasServerProtocolMethod() { - try { - Class.forName("org.bukkit.UnsafeValues").getDeclaredMethod("getProtocolVersion"); - return true; - } catch (final ClassNotFoundException | NoSuchMethodException e) { - return false; - } + return hasMethod("org.bukkit.UnsafeValues", "getProtocolVersion"); } private static boolean hasPaperInjectionMethod() { @@ -78,12 +73,7 @@ public final class PaperViaInjector { } private static boolean hasIsStoppingMethod() { - try { - Bukkit.class.getDeclaredMethod("isStopping"); - return true; - } catch (final NoSuchMethodException e) { - return false; - } + return hasMethod(Bukkit.class, "isStopping"); } private static boolean hasPacketLimiter() { @@ -98,4 +88,22 @@ public final class PaperViaInjector { return false; } } + + public static boolean hasMethod(final String className, final String method) { + try { + Class.forName(className).getDeclaredMethod(method); + return true; + } catch (final ClassNotFoundException | NoSuchMethodException e) { + return false; + } + } + + public static boolean hasMethod(final Class clazz, final String method, final Class... params) { + try { + clazz.getDeclaredMethod(method, params); + return true; + } catch (final NoSuchMethodException e) { + return false; + } + } } diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/providers/BukkitInventoryQuickMoveProvider.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/providers/BukkitInventoryQuickMoveProvider.java index 77f80588a..09f65a44c 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/providers/BukkitInventoryQuickMoveProvider.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/providers/BukkitInventoryQuickMoveProvider.java @@ -84,7 +84,6 @@ public class BukkitInventoryQuickMoveProvider extends InventoryQuickMoveProvider updateTask = new BukkitInventoryUpdateTask(this, uuid); updateTasks.put(uuid, updateTask); } - // http://wiki.vg/index.php?title=Protocol&oldid=13223#Click_Window updateTask.addItem(windowId, slotId, actionId); if (!registered && Via.getPlatform().isPluginEnabled()) { Via.getPlatform().runSync(updateTask); diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/providers/BukkitPickItemProvider.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/providers/BukkitPickItemProvider.java new file mode 100644 index 000000000..5df39a696 --- /dev/null +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/providers/BukkitPickItemProvider.java @@ -0,0 +1,184 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.bukkit.providers; + +import com.viaversion.viaversion.ViaVersionPlugin; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.BlockPosition; +import com.viaversion.viaversion.bukkit.platform.PaperViaInjector; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.provider.PickItemProvider; +import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemFactory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.BlockStateMeta; +import org.checkerframework.checker.nullness.qual.Nullable; + +public final class BukkitPickItemProvider extends PickItemProvider { + private static final boolean HAS_PLACEMENT_MATERIAL_METHOD = PaperViaInjector.hasMethod("org.bukkit.block.data.BlockData", "getPlacementMaterial"); + private static final boolean HAS_SPAWN_EGG_METHOD = PaperViaInjector.hasMethod(ItemFactory.class, "getSpawnEgg", EntityType.class); + private static final double BLOCK_RANGE = 4.5 + 1; + private static final double BLOCK_RANGE_SQUARED = BLOCK_RANGE * BLOCK_RANGE; + private static final double ENTITY_RANGE = 3 + 3; + private final ViaVersionPlugin plugin; + + public BukkitPickItemProvider(final ViaVersionPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void pickItemFromBlock(final UserConnection connection, final BlockPosition blockPosition, final boolean includeData) { + final UUID uuid = connection.getProtocolInfo().getUuid(); + final Player player = plugin.getServer().getPlayer(uuid); + if (player == null) { + return; + } + + plugin.runSyncFor(() -> { + final Location playerLocation = player.getLocation(); + if (blockPosition.distanceFromCenterSquared(playerLocation.getX(), playerLocation.getY(), playerLocation.getZ()) > BLOCK_RANGE_SQUARED) { + return; + } + + final Block block = player.getWorld().getBlockAt(blockPosition.x(), blockPosition.y(), blockPosition.z()); + if (block.getType() == Material.AIR) { + return; + } + + final ItemStack item = blockToItem(block, includeData && player.getGameMode() == GameMode.CREATIVE); + if (item != null) { + pickItem(player, item); + } + }, player); + } + + private @Nullable ItemStack blockToItem(final Block block, final boolean includeData) { + if (HAS_PLACEMENT_MATERIAL_METHOD) { + final ItemStack item = new ItemStack(block.getBlockData().getPlacementMaterial(), 1); + if (includeData && item.getItemMeta() instanceof final BlockStateMeta blockStateMeta) { + blockStateMeta.setBlockState(block.getState()); + item.setItemMeta(blockStateMeta); + } + return item; + } else if (block.getType().isItem()) { + return new ItemStack(block.getType(), 1); + } + return null; + } + + @Override + public void pickItemFromEntity(final UserConnection connection, final int entityId, final boolean includeData) { + if (!HAS_SPAWN_EGG_METHOD) { + return; + } + + final UUID uuid = connection.getProtocolInfo().getUuid(); + final Player player = plugin.getServer().getPlayer(uuid); + if (player == null) { + return; + } + + plugin.runSyncFor(() -> { + final Entity entity = player.getWorld().getNearbyEntities(player.getLocation(), ENTITY_RANGE, ENTITY_RANGE, ENTITY_RANGE).stream() + .filter(e -> e.getEntityId() == entityId) + .findAny() + .orElse(null); + if (entity == null) { + return; + } + + final Material spawnEggType = Bukkit.getItemFactory().getSpawnEgg(entity.getType()); + if (spawnEggType != null) { + pickItem(player, new ItemStack(spawnEggType, 1)); + } + }, player); + } + + private void pickItem(final Player player, final ItemStack item) { + // Find matching item + final PlayerInventory inventory = player.getInventory(); + final ItemStack[] contents = inventory.getStorageContents(); + int sourceSlot = -1; + for (int i = 0; i < contents.length; i++) { + final ItemStack content = contents[i]; + if (content == null || !content.isSimilar(item)) { + continue; + } + + sourceSlot = i; + break; + } + + if (sourceSlot != -1) { + moveToHotbar(inventory, sourceSlot, contents); + } else if (player.getGameMode() == GameMode.CREATIVE) { + spawnItem(item, inventory, contents); + } + } + + private void spawnItem(final ItemStack item, final PlayerInventory inventory, final ItemStack[] contents) { + final int targetSlot = findEmptyHotbarSlot(inventory, inventory.getHeldItemSlot()); + inventory.setHeldItemSlot(targetSlot); + final ItemStack heldItem = inventory.getItem(targetSlot); + int emptySlot = targetSlot; + if (heldItem != null && heldItem.getType() != Material.AIR) { + // Swap to the first free slot in the inventory, else add it to the current hotbar slot + for (int i = 0; i < contents.length; i++) { + if (contents[i] == null || contents[i].getType() == Material.AIR) { + emptySlot = i; + break; + } + } + } + + inventory.setItem(emptySlot, heldItem); + inventory.setItemInMainHand(item); + } + + private void moveToHotbar(final PlayerInventory inventory, final int sourceSlot, final ItemStack[] contents) { + if (sourceSlot < 9) { + inventory.setHeldItemSlot(sourceSlot); + return; + } + + final int heldSlot = inventory.getHeldItemSlot(); + final int targetSlot = findEmptyHotbarSlot(inventory, heldSlot); + inventory.setHeldItemSlot(targetSlot); + final ItemStack heldItem = inventory.getItem(targetSlot); + inventory.setItemInMainHand(contents[sourceSlot]); + inventory.setItem(sourceSlot, heldItem); + } + + private int findEmptyHotbarSlot(final PlayerInventory inventory, final int heldSlot) { + for (int i = 0; i < 9; i++) { + final ItemStack item = inventory.getItem(i); + if (item == null || item.getType() == Material.AIR) { + return i; + } + } + return heldSlot; + } +} diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 0997957e6..980799ddf 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -18,3 +18,32 @@ java { tasks.named("sourcesJar") { from(project(":viaversion-api").sourceSets.main.get().allSource) } + +// Task to quickly test/debug code changes using https://github.com/ViaVersion/ViaProxy +// For further instructions see the ViaProxy repository README +tasks.register("runViaProxy") { + dependsOn(tasks.shadowJar) + + val viaProxyConfiguration = configurations.create("viaProxy") + viaProxyConfiguration.dependencies.add(dependencies.create(rootProject.libs.viaProxy.get().copy().setTransitive(false))) + + mainClass.set("net.raphimc.viaproxy.ViaProxy") + classpath = viaProxyConfiguration + workingDir = file("run") + jvmArgs = listOf("-DskipUpdateCheck") + + if (System.getProperty("viaproxy.gui.autoStart") != null) { + jvmArgs("-Dviaproxy.gui.autoStart") + } + + doFirst { + val jarsDir = file("$workingDir/jars") + jarsDir.mkdirs() + file("$jarsDir/${project.name}.jar").writeBytes(tasks.shadowJar.get().archiveFile.get().asFile.readBytes()) + } + + doLast { + file("$workingDir/jars/${project.name}.jar").delete() + file("$workingDir/logs").deleteRecursively() + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/ViaListener.java b/common/src/main/java/com/viaversion/viaversion/ViaListener.java index 7c97b7bd3..4d881af5f 100644 --- a/common/src/main/java/com/viaversion/viaversion/ViaListener.java +++ b/common/src/main/java/com/viaversion/viaversion/ViaListener.java @@ -48,7 +48,10 @@ public abstract class ViaListener { * @return True if on pipe */ protected boolean isOnPipe(UUID uuid) { - UserConnection userConnection = getUserConnection(uuid); + return isOnPipe(getUserConnection(uuid)); + } + + protected boolean isOnPipe(UserConnection userConnection) { return userConnection != null && (requiredPipeline == null || userConnection.getProtocolInfo().getPipeline().contains(requiredPipeline)); } diff --git a/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java b/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java index d4b609f06..9e510a209 100644 --- a/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java @@ -244,9 +244,12 @@ public class ViaManagerImpl implements ViaManager { } if (version < 17) { - platform.getLogger().warning("You are running an outdated Java version, please update it to at least Java 17 (your version is " + javaVersion + ")."); + platform.getLogger().warning("You are running an outdated Java version, please update it to at least Java 21 (your version is " + javaVersion + ")."); platform.getLogger().warning("ViaVersion no longer officially supports this version of Java, only offering unsupported compatibility builds."); platform.getLogger().warning("See https://github.com/ViaVersion/ViaVersion/releases/tag/5.0.0 for more information."); + } else if (version < 21) { + platform.getLogger().warning("Please update your Java runtime to at least Java 21 (your version is " + javaVersion + ")."); + platform.getLogger().warning("At some point in the future, ViaVersion will no longer be compatible with this version of Java."); } } diff --git a/common/src/main/java/com/viaversion/viaversion/commands/defaultsubs/DumpSubCmd.java b/common/src/main/java/com/viaversion/viaversion/commands/defaultsubs/DumpSubCmd.java index 26c7bae7c..c4acace9e 100644 --- a/common/src/main/java/com/viaversion/viaversion/commands/defaultsubs/DumpSubCmd.java +++ b/common/src/main/java/com/viaversion/viaversion/commands/defaultsubs/DumpSubCmd.java @@ -30,7 +30,7 @@ public class DumpSubCmd implements ViaSubCommand { @Override public String description() { - return "Dump information about your server, this is helpful if you report bugs."; + return "Dump information about your platform implementation, this is helpful if you report bugs."; } @Override diff --git a/common/src/main/java/com/viaversion/viaversion/commands/defaultsubs/ReloadSubCmd.java b/common/src/main/java/com/viaversion/viaversion/commands/defaultsubs/ReloadSubCmd.java index 2c0817a66..5c850bc65 100644 --- a/common/src/main/java/com/viaversion/viaversion/commands/defaultsubs/ReloadSubCmd.java +++ b/common/src/main/java/com/viaversion/viaversion/commands/defaultsubs/ReloadSubCmd.java @@ -35,7 +35,7 @@ public class ReloadSubCmd implements ViaSubCommand { @Override public boolean execute(ViaCommandSender sender, String[] args) { Via.getManager().getConfigurationProvider().reloadConfigs(); - sendMessage(sender, "&6Configuration successfully reloaded! Some features may need a restart."); + sendMessage(sender, "&6Configuration successfully reloaded! Some config options may require a restart to take effect."); return true; } } diff --git a/common/src/main/java/com/viaversion/viaversion/configuration/AbstractViaConfig.java b/common/src/main/java/com/viaversion/viaversion/configuration/AbstractViaConfig.java index 7c4c81451..98684f865 100644 --- a/common/src/main/java/com/viaversion/viaversion/configuration/AbstractViaConfig.java +++ b/common/src/main/java/com/viaversion/viaversion/configuration/AbstractViaConfig.java @@ -164,7 +164,7 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf handleInvalidItemCount = getBoolean("handle-invalid-item-count", false); cancelBlockSounds = getBoolean("cancel-block-sounds", true); hideScoreboardNumbers = getBoolean("hide-scoreboard-numbers", false); - fix1_21PlacementRotation = getBoolean("fix-1_21-placement-rotation", false); + fix1_21PlacementRotation = getBoolean("fix-1_21-placement-rotation", true); } private BlockedProtocolVersions loadBlockedProtocolVersions() { @@ -554,6 +554,6 @@ public abstract class AbstractViaConfig extends Config implements ViaVersionConf @Override public boolean fix1_21PlacementRotation() { - return false && fix1_21PlacementRotation; // TODO Can't always set onGround to true + return fix1_21PlacementRotation; } } diff --git a/common/src/main/java/com/viaversion/viaversion/connection/UserConnectionImpl.java b/common/src/main/java/com/viaversion/viaversion/connection/UserConnectionImpl.java index 4a7f82dc4..7f1f645e0 100644 --- a/common/src/main/java/com/viaversion/viaversion/connection/UserConnectionImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/connection/UserConnectionImpl.java @@ -29,8 +29,8 @@ import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.packet.Direction; import com.viaversion.viaversion.api.protocol.packet.PacketTracker; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; -import com.viaversion.viaversion.api.protocol.packet.State; import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.VarIntType; import com.viaversion.viaversion.exception.CancelException; import com.viaversion.viaversion.exception.InformativeException; import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl; @@ -55,6 +55,7 @@ import java.util.function.Function; import org.checkerframework.checker.nullness.qual.Nullable; public class UserConnectionImpl implements UserConnection { + private static final int PASSTHROUGH_DATA_BYTES = Long.BYTES * 2 + 2; private static final AtomicLong IDS = new AtomicLong(); private final long id = IDS.incrementAndGet(); private final Map, StorableObject> storedObjects = new ConcurrentHashMap<>(); @@ -244,7 +245,8 @@ public class UserConnectionImpl implements UserConnection { } private void sendRawPacketToServerServerSide(final ByteBuf packet, final boolean currentThread) { - final ByteBuf buf = packet.alloc().buffer(); + final int initialCapacity = active ? packet.readableBytes() + PASSTHROUGH_DATA_BYTES : packet.readableBytes(); + final ByteBuf buf = packet.alloc().buffer(initialCapacity); try { // We'll use passing through because there are some encoder wrappers ChannelHandlerContext context = PipelineUtil @@ -333,7 +335,7 @@ public class UserConnectionImpl implements UserConnection { return; } - int id = Types.VAR_INT.readPrimitive(buf); + final int id = Types.VAR_INT.readPrimitive(buf); if (id == PacketWrapper.PASSTHROUGH_ID) { if (!passthroughTokens.remove(Types.UUID.read(buf))) { throw new IllegalArgumentException("Invalid token"); @@ -341,20 +343,47 @@ public class UserConnectionImpl implements UserConnection { return; } - PacketWrapper wrapper = new PacketWrapperImpl(id, buf, this); - State state = protocolInfo.getState(direction); + final int valuesReaderIndex = buf.readerIndex(); + final PacketWrapperImpl wrapper = new PacketWrapperImpl(id, buf, this); try { - protocolInfo.getPipeline().transform(direction, state, wrapper); - } catch (CancelException ex) { + protocolInfo.getPipeline().transform(direction, protocolInfo.getState(direction), wrapper); + } catch (final CancelException ex) { throw cancelSupplier.apply(ex); } - ByteBuf transformed = buf.alloc().buffer(); + writeToBuffer(wrapper, buf, id, valuesReaderIndex); + } + + private void writeToBuffer(final PacketWrapperImpl wrapper, final ByteBuf buf, final int originalId, final int originalReaderIndex) { + final int remainingBytes = buf.readableBytes(); + if (buf.readerIndex() == originalReaderIndex && wrapper.areStoredPacketValuesEmpty()) { + if (wrapper.getId() == originalId) { + // No changes needed; just set the reader and writer indexes and we're done + buf.setIndex(0, originalReaderIndex + remainingBytes); + return; + } + if (VarIntType.varIntLength(wrapper.getId()) == VarIntType.varIntLength(originalId)) { + // If the var int encoded length is the same, simply replace the id at the head + buf.setIndex(0, 0); + Types.VAR_INT.writePrimitive(buf, wrapper.getId()); + buf.writerIndex(originalReaderIndex + remainingBytes); + return; + } + } + + // Instead of allocating a possible unnecessarily large buffer to write the wrapper contents to, + // only allocate the remaining bytes and write the rest to the original buf's head directly. + final ByteBuf remainingBuf = buf.alloc().buffer(remainingBytes, remainingBytes); try { - wrapper.writeToBuffer(transformed); - buf.clear().writeBytes(transformed); + // Copy before modifying the buffer + remainingBuf.writeBytes(buf, remainingBytes); + + // Reset indexes, write wrapper contents, then the unread bytes + buf.setIndex(0, 0); + wrapper.writeProcessedValues(buf); + buf.writeBytes(remainingBuf); } finally { - transformed.release(); + remainingBuf.release(); } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java index cc00403bb..28e6cac18 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java @@ -76,6 +76,8 @@ import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_ import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.Protocol1_20_3To1_20_5; import com.viaversion.viaversion.protocols.v1_20_5to1_21.Protocol1_20_5To1_21; import com.viaversion.viaversion.protocols.v1_20to1_20_2.Protocol1_20To1_20_2; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_4; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2; import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9; import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.Protocol1_9_1To1_9_3; import com.viaversion.viaversion.protocols.v1_9_3to1_10.Protocol1_9_3To1_10; @@ -192,6 +194,8 @@ public class ProtocolManagerImpl implements ProtocolManager { registerProtocol(new Protocol1_20_3To1_20_5(), ProtocolVersion.v1_20_5, ProtocolVersion.v1_20_3); registerProtocol(new Protocol1_20_5To1_21(), ProtocolVersion.v1_21, ProtocolVersion.v1_20_5); + registerProtocol(new Protocol1_21To1_21_2(), ProtocolVersion.v1_21_2, ProtocolVersion.v1_21); + registerProtocol(new Protocol1_21_2To1_21_4(), ProtocolVersion.v1_21_4, ProtocolVersion.v1_21_2); } @Override diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java index ca562eb41..e93415fd7 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java @@ -222,6 +222,18 @@ public class PacketWrapperImpl implements PacketWrapper { @Override public void writeToBuffer(ByteBuf buffer) throws InformativeException { + writeProcessedValues(buffer); + if (inputBuffer != null) { + buffer.writeBytes(inputBuffer); + } + } + + public boolean areStoredPacketValuesEmpty() { + // Check for read/added packet values, not the input buffer + return packetValues.isEmpty() && readableObjects.isEmpty(); + } + + public void writeProcessedValues(ByteBuf buffer) throws InformativeException { if (id != -1) { Types.VAR_INT.writePrimitive(buffer, id); } @@ -238,16 +250,15 @@ public class PacketWrapperImpl implements PacketWrapper { throw createInformativeException(e, packetValue.type(), i); } } - writeRemaining(buffer); } private InformativeException createInformativeException(final Exception cause, final Type type, final int index) { return new InformativeException(cause) + .set("Packet Type", this.packetType) .set("Index", index) .set("Type", type.getTypeName()) - .set("Packet ID", this.id) - .set("Packet Type", this.packetType) - .set("Data", this.packetValues); + .set("Data", this.packetValues) + .set("Packet ID", this.id); } @Override @@ -264,12 +275,6 @@ public class PacketWrapperImpl implements PacketWrapper { packetValues.clear(); } - private void writeRemaining(ByteBuf output) { - if (inputBuffer != null) { - output.writeBytes(inputBuffer); - } - } - @Override public void send(Class protocol, boolean skipCurrentPipeline) throws InformativeException { send0(protocol, skipCurrentPipeline, true); @@ -320,7 +325,7 @@ public class PacketWrapperImpl implements PacketWrapper { final ProtocolInfo protocolInfo = user().getProtocolInfo(); final List protocols = protocolInfo.getPipeline().pipes(protocolClass, skipCurrentPipeline, direction); apply(direction, protocolInfo.getState(direction), protocols); - final ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); + final ByteBuf output = allocateOutputBuffer(); try { writeToBuffer(output); return output.retain(); @@ -354,7 +359,7 @@ public class PacketWrapperImpl implements PacketWrapper { return cancelledFuture(); } - ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); + ByteBuf output = allocateOutputBuffer(); try { writeToBuffer(output); return user().sendRawPacketFuture(output.retain()); @@ -373,7 +378,7 @@ public class PacketWrapperImpl implements PacketWrapper { return; } - ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); + ByteBuf output = allocateOutputBuffer(); try { writeToBuffer(output); if (currentThread) { @@ -386,6 +391,14 @@ public class PacketWrapperImpl implements PacketWrapper { } } + private ByteBuf allocateOutputBuffer() { + if (inputBuffer == null) { + return user().getChannel().alloc().buffer(); + } + // May have already been partially or fully read + return inputBuffer.alloc().buffer(Math.max(inputBuffer.readableBytes(), 256)); + } + private ChannelFuture cancelledFuture() { return user().getChannel().newFailedFuture(new RuntimeException("Tried to send cancelled packet")); } @@ -454,7 +467,7 @@ public class PacketWrapperImpl implements PacketWrapper { return; } - ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); + ByteBuf output = allocateOutputBuffer(); try { writeToBuffer(output); if (currentThread) { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/base/ClientboundLoginPackets.java b/common/src/main/java/com/viaversion/viaversion/protocols/base/ClientboundLoginPackets.java index 3666b5db1..87c597e97 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/base/ClientboundLoginPackets.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/base/ClientboundLoginPackets.java @@ -23,11 +23,14 @@ import com.viaversion.viaversion.protocols.base.packet.BaseClientboundPacket; public enum ClientboundLoginPackets implements BaseClientboundPacket { LOGIN_DISCONNECT, // 0x00 HELLO, // 0x01 - GAME_PROFILE, // 0x02 + LOGIN_FINISHED, // 0x02 LOGIN_COMPRESSION, // 0x03 CUSTOM_QUERY, // 0x04 COOKIE_REQUEST; // 0x05 + @Deprecated(forRemoval = true) + public static final ClientboundLoginPackets GAME_PROFILE = LOGIN_FINISHED; + @Override public final int getId() { return ordinal(); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/base/v1_7/ClientboundBaseProtocol1_7.java b/common/src/main/java/com/viaversion/viaversion/protocols/base/v1_7/ClientboundBaseProtocol1_7.java index dffe0bfbd..ea9a48e1b 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/base/v1_7/ClientboundBaseProtocol1_7.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/base/v1_7/ClientboundBaseProtocol1_7.java @@ -128,7 +128,7 @@ public class ClientboundBaseProtocol1_7 extends AbstractProtocol { + registerClientbound(ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> { final ProtocolInfo info = wrapper.user().getProtocolInfo(); if (info.serverProtocolVersion().olderThan(ProtocolVersion.v1_16)) { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/template/BlockItemPacketRewriter1_99.java b/common/src/main/java/com/viaversion/viaversion/protocols/template/BlockItemPacketRewriter1_99.java index 655e1db33..c41ce1a3d 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/template/BlockItemPacketRewriter1_99.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/template/BlockItemPacketRewriter1_99.java @@ -18,27 +18,26 @@ package com.viaversion.viaversion.protocols.template; import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2; -import com.viaversion.viaversion.api.type.types.version.Types1_21; -import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter.RecipeRewriter1_20_3; -import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5; -import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5; -import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21; -import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21; +import com.viaversion.viaversion.api.type.types.version.Types1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2; import com.viaversion.viaversion.rewriter.BlockRewriter; +import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter; import com.viaversion.viaversion.rewriter.StructuredItemRewriter; // To replace if needed: // ChunkType1_20_2 -// RecipeRewriter1_20_3 -// Types1_21, Types1_OLD -final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter { +// RecipeDisplayRewriter +// Types1_21_4, Types1_OLD +final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter { public BlockItemPacketRewriter1_99(final Protocol1_99To_98 protocol) { - super(protocol, Types1_21.ITEM, Types1_21.ITEM_ARRAY); + super(protocol, Types1_21_4.ITEM, Types1_21_4.ITEM_ARRAY); /*super(protocol, - Types1_OLD.ITEM, Types1_OLD.ITEM_ARRAY, Types1_21.ITEM, Types1_21.ITEM_ARRAY, - Types1_OLD.ITEM_COST, Types1_OLD.OPTIONAL_ITEM_COST, Types1_21.ITEM_COST, Types1_21.OPTIONAL_ITEM_COST, - Types1_OLD.PARTICLE, Types1_21.PARTICLE + Types1_OLD.ITEM, Types1_OLD.ITEM_ARRAY, Types1_21_4.ITEM, Types1_21_4.ITEM_ARRAY, + Types1_OLD.ITEM_COST, Types1_OLD.OPTIONAL_ITEM_COST, Types1_21_4.ITEM_COST, Types1_21_4.OPTIONAL_ITEM_COST );*/ } @@ -47,31 +46,33 @@ final class BlockItemPacketRewriter1_99 extends StructuredItemRewriter blockRewriter = BlockRewriter.for1_20_2(protocol); - blockRewriter.registerBlockEvent(ClientboundPackets1_21.BLOCK_EVENT); - blockRewriter.registerBlockUpdate(ClientboundPackets1_21.BLOCK_UPDATE); - blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21.SECTION_BLOCKS_UPDATE); - blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21.LEVEL_EVENT, 2001); - blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new); - blockRewriter.registerBlockEntityData(ClientboundPackets1_21.BLOCK_ENTITY_DATA); + final BlockRewriter blockRewriter = BlockRewriter.for1_20_2(protocol); + blockRewriter.registerBlockEvent(ClientboundPackets1_21_2.BLOCK_EVENT); + blockRewriter.registerBlockUpdate(ClientboundPackets1_21_2.BLOCK_UPDATE); + blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_2.SECTION_BLOCKS_UPDATE); + blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_2.LEVEL_EVENT, 2001); + blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_2.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new); + blockRewriter.registerBlockEntityData(ClientboundPackets1_21_2.BLOCK_ENTITY_DATA); // Registers item id changes // Other places using item ids are: Entity data, tags, statistics, effect - // registerOpenWindow(ClientboundPackets1_21.OPEN_WINDOW); - If a new container type was added - registerCooldown(ClientboundPackets1_21.COOLDOWN); - registerSetContent1_17_1(ClientboundPackets1_21.CONTAINER_SET_CONTENT); - registerSetSlot1_17_1(ClientboundPackets1_21.CONTAINER_SET_SLOT); - registerAdvancements1_20_3(ClientboundPackets1_21.UPDATE_ADVANCEMENTS); - registerSetEquipment(ClientboundPackets1_21.SET_EQUIPMENT); - registerContainerClick1_17_1(ServerboundPackets1_20_5.CONTAINER_CLICK); - registerMerchantOffers1_20_5(ClientboundPackets1_21.MERCHANT_OFFERS); - registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT); - registerLevelParticles1_20_5(ClientboundPackets1_21.LEVEL_PARTICLES); - registerExplosion(ClientboundPackets1_21.EXPLODE); // Rewrites the included sound and particles + // registerOpenScreen(ClientboundPackets1_21_2.OPEN_SCREEN); If a new container type was added; also remove from the component rewriter registration + protocol.registerClientbound(ClientboundPackets1_21_2.SET_CURSOR_ITEM, this::passthroughClientboundItem); + registerSetPlayerInventory(ClientboundPackets1_21_2.SET_PLAYER_INVENTORY); + registerCooldown1_21_2(ClientboundPackets1_21_2.COOLDOWN); + registerSetContent1_21_2(ClientboundPackets1_21_2.CONTAINER_SET_CONTENT); + registerSetSlot1_21_2(ClientboundPackets1_21_2.CONTAINER_SET_SLOT); + registerAdvancements1_20_3(ClientboundPackets1_21_2.UPDATE_ADVANCEMENTS); + registerSetEquipment(ClientboundPackets1_21_2.SET_EQUIPMENT); + registerMerchantOffers1_20_5(ClientboundPackets1_21_2.MERCHANT_OFFERS); + registerContainerClick1_21_2(ServerboundPackets1_21_4.CONTAINER_CLICK); + registerSetCreativeModeSlot(ServerboundPackets1_21_4.SET_CREATIVE_MODE_SLOT); - new RecipeRewriter1_20_3<>(protocol).register1_20_5(ClientboundPackets1_21.UPDATE_RECIPES); + final RecipeDisplayRewriter recipeRewriter = new RecipeDisplayRewriter<>(protocol); + recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_2.UPDATE_RECIPES); + recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_2.RECIPE_BOOK_ADD); + recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_2.PLACE_GHOST_RECIPE); // OR do this if serialization of recipes changed and override the relevant method - // Add new serializers to RecipeRewriter, or extend the last one for changes - // new RecipeRewriter1_20_3(this) {}.register1_20_5(ClientboundPackets1_21.DECLARE_RECIPES); + // Add new serializers to RecipeDisplayRewriter, or extend the last one for changes } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/template/ComponentRewriter1_99.java b/common/src/main/java/com/viaversion/viaversion/protocols/template/ComponentRewriter1_99.java new file mode 100644 index 000000000..21ac58a2f --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/template/ComponentRewriter1_99.java @@ -0,0 +1,46 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.template; + +import com.viaversion.nbt.tag.CompoundTag; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2; +import com.viaversion.viaversion.rewriter.ComponentRewriter; +import com.viaversion.viaversion.util.SerializerVersion; + +final class ComponentRewriter1_99 extends ComponentRewriter { + + public ComponentRewriter1_99(final Protocol1_99To_98 protocol) { + super(protocol, ReadType.NBT); + } + + @Override + protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) { + super.handleShowItem(connection, itemTag, componentsTag); + if (componentsTag == null) { + return; + } + + // Remove or update data from componentsTag + } + + @Override + protected SerializerVersion inputSerializerVersion() { + return SerializerVersion.V1_21_4; + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/template/EntityPacketRewriter1_99.java b/common/src/main/java/com/viaversion/viaversion/protocols/template/EntityPacketRewriter1_99.java index fa887cc74..fb063821a 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/template/EntityPacketRewriter1_99.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/template/EntityPacketRewriter1_99.java @@ -17,22 +17,20 @@ */ package com.viaversion.viaversion.protocols.template; -import com.viaversion.viaversion.api.minecraft.RegistryEntry; import com.viaversion.viaversion.api.minecraft.entities.EntityType; -import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5; -import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4; import com.viaversion.viaversion.api.type.Types; -import com.viaversion.viaversion.api.type.types.version.Types1_21; +import com.viaversion.viaversion.api.type.types.version.Types1_21_4; import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21; -import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21; -import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2; import com.viaversion.viaversion.rewriter.EntityRewriter; -import com.viaversion.viaversion.util.Key; +import com.viaversion.viaversion.rewriter.RegistryDataRewriter; // Replace if needed // Types1_OLD -// Types1_21 -final class EntityPacketRewriter1_99 extends EntityRewriter { +// Types1_21_4 +final class EntityPacketRewriter1_99 extends EntityRewriter { public EntityPacketRewriter1_99(final Protocol1_99To_98 protocol) { super(protocol); @@ -41,36 +39,32 @@ final class EntityPacketRewriter1_99 extends EntityRewriter { - final String registryKey = Key.stripMinecraftNamespace(wrapper.passthrough(Types.STRING)); - final RegistryEntry[] entries = wrapper.passthrough(Types.REGISTRY_ENTRY_ARRAY); - handleRegistryData1_20_5(wrapper.user(), registryKey, entries); // Caches dimensions to access data like height later and tracks the amount of biomes sent for chunk data + final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol); + protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle); + + protocol.registerClientbound(ClientboundPackets1_21_2.LOGIN, wrapper -> { + final int entityId = wrapper.passthrough(Types.INT); // Entity id + wrapper.passthrough(Types.BOOLEAN); // Hardcore + wrapper.passthrough(Types.STRING_ARRAY); // World List + wrapper.passthrough(Types.VAR_INT); // Max players + wrapper.passthrough(Types.VAR_INT); // View distance + wrapper.passthrough(Types.VAR_INT); // Simulation distance + wrapper.passthrough(Types.BOOLEAN); // Reduced debug info + wrapper.passthrough(Types.BOOLEAN); // Show death screen + wrapper.passthrough(Types.BOOLEAN); // Limited crafting + + final int dimensionId = wrapper.passthrough(Types.VAR_INT); + final String world = wrapper.passthrough(Types.STRING); + trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); + + trackPlayer(wrapper.user(), entityId); }); - protocol.registerClientbound(ClientboundPackets1_21.LOGIN, new PacketHandlers() { - @Override - public void register() { - map(Types.INT); // Entity id - map(Types.BOOLEAN); // Hardcore - map(Types.STRING_ARRAY); // World List - map(Types.VAR_INT); // Max players - map(Types.VAR_INT); // View distance - map(Types.VAR_INT); // Simulation distance - map(Types.BOOLEAN); // Reduced debug info - map(Types.BOOLEAN); // Show death screen - map(Types.BOOLEAN); // Limited crafting - map(Types.VAR_INT); // Dimension id - map(Types.STRING); // World - handler(worldDataTrackerHandlerByKey1_20_5(3)); // Tracks world height and name for chunk data and entity (un)tracking - handler(playerTrackerHandler()); - } - }); - - protocol.registerClientbound(ClientboundPackets1_21.RESPAWN, wrapper -> { + protocol.registerClientbound(ClientboundPackets1_21_2.RESPAWN, wrapper -> { final int dimensionId = wrapper.passthrough(Types.VAR_INT); final String world = wrapper.passthrough(Types.STRING); trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking @@ -85,20 +79,20 @@ final class EntityPacketRewriter1_99 extends EntityRewriter= SomeAddedIndex) { id++; } - return Types1_21.ENTITY_DATA_TYPES.byId(id); + return Types1_21_4.ENTITY_DATA_TYPES.byId(id); });*/ // Registers registry type id changes registerEntityDataTypeHandler( - Types1_21.ENTITY_DATA_TYPES.itemType, - Types1_21.ENTITY_DATA_TYPES.blockStateType, - Types1_21.ENTITY_DATA_TYPES.optionalBlockStateType, - Types1_21.ENTITY_DATA_TYPES.particleType, - Types1_21.ENTITY_DATA_TYPES.particlesType, - Types1_21.ENTITY_DATA_TYPES.componentType, - Types1_21.ENTITY_DATA_TYPES.optionalComponentType + Types1_21_4.ENTITY_DATA_TYPES.itemType, + Types1_21_4.ENTITY_DATA_TYPES.blockStateType, + Types1_21_4.ENTITY_DATA_TYPES.optionalBlockStateType, + Types1_21_4.ENTITY_DATA_TYPES.particleType, + Types1_21_4.ENTITY_DATA_TYPES.particlesType, + Types1_21_4.ENTITY_DATA_TYPES.componentType, + Types1_21_4.ENTITY_DATA_TYPES.optionalComponentType ); - registerBlockStateHandler(EntityTypes1_20_5.ABSTRACT_MINECART, 11); + registerBlockStateHandler(EntityTypes1_21_4.ABSTRACT_MINECART, 11); } @Override @@ -109,6 +103,6 @@ final class EntityPacketRewriter1_99 extends EntityRewriter { +final class Protocol1_99To_98 extends AbstractProtocol { public static final MappingData MAPPINGS = new MappingDataBase("1.98", "1.99"); private final EntityPacketRewriter1_99 entityRewriter = new EntityPacketRewriter1_99(this); private final BlockItemPacketRewriter1_99 itemRewriter = new BlockItemPacketRewriter1_99(this); - private final TagRewriter tagRewriter = new TagRewriter<>(this); + private final ParticleRewriter particleRewriter = new ParticleRewriter<>(this, /*Types1_OLD.PARTICLE,*/ Types1_21_4.PARTICLE); + private final TagRewriter tagRewriter = new TagRewriter<>(this); + private final ComponentRewriter componentRewriter = new ComponentRewriter1_99(this); public Protocol1_99To_98() { // Passing the class types into the super constructor is needed for automatic packet type id remapping, but can otherwise be omitted - super(ClientboundPacket1_21.class, ClientboundPacket1_21.class, ServerboundPacket1_20_5.class, ServerboundPacket1_20_5.class); + super(ClientboundPacket1_21_2.class, ClientboundPacket1_21_2.class, ServerboundPacket1_21_4.class, ServerboundPacket1_21_4.class); } @Override protected void registerPackets() { super.registerPackets(); - tagRewriter.registerGeneric(ClientboundPackets1_21.UPDATE_TAGS); + tagRewriter.registerGeneric(ClientboundPackets1_21_2.UPDATE_TAGS); tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS); - final SoundRewriter soundRewriter = new SoundRewriter<>(this); - soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND); - soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND_ENTITY); + // If needed for item or component changes + componentRewriter.registerOpenScreen(ClientboundPackets1_21_2.OPEN_SCREEN); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_ACTION_BAR_TEXT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_TITLE_TEXT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_SUBTITLE_TEXT); + componentRewriter.registerBossEvent(ClientboundPackets1_21_2.BOSS_EVENT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISCONNECT); + componentRewriter.registerTabList(ClientboundPackets1_21_2.TAB_LIST); + componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_2.PLAYER_COMBAT_KILL); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SYSTEM_CHAT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISGUISED_CHAT); + componentRewriter.registerPlayerInfoUpdate1_21_4(ClientboundPackets1_21_2.PLAYER_INFO_UPDATE); + componentRewriter.registerPing(); - new StatisticsRewriter<>(this).register(ClientboundPackets1_21.AWARD_STATS); - new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21.UPDATE_ATTRIBUTES); + // If needed for any particle, item, or block changes. Extend ParticleRewriter for particle serializer changes + particleRewriter.registerLevelParticles1_20_5(ClientboundPackets1_21_2.LEVEL_PARTICLES); + particleRewriter.registerExplode1_21_2(ClientboundPackets1_21_2.EXPLODE); // Rewrites the included sound and particles + + final SoundRewriter soundRewriter = new SoundRewriter<>(this); + soundRewriter.registerSound1_19_3(ClientboundPackets1_21_2.SOUND); + soundRewriter.registerSound1_19_3(ClientboundPackets1_21_2.SOUND_ENTITY); + + new StatisticsRewriter<>(this).register(ClientboundPackets1_21_2.AWARD_STATS); + new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21_2.UPDATE_ATTRIBUTES); // Uncomment if an existing type changed serialization format. Mappings for argument type keys can also be defined in mapping files /*new CommandRewriter1_19_4<>(this) { @@ -81,25 +105,29 @@ final class Protocol1_99To_98 extends AbstractProtocol getTagRewriter() { + public ParticleRewriter getParticleRewriter() { + return particleRewriter; + } + + @Override + public TagRewriter getTagRewriter() { return tagRewriter; } @Override - protected PacketTypesProvider createPacketTypesProvider() { + public ComponentRewriter getComponentRewriter() { + return componentRewriter; + } + + @Override + protected PacketTypesProvider createPacketTypesProvider() { return new SimplePacketTypesProvider<>( - packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21.class, ClientboundConfigurationPackets1_21.class), - packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21.class, ClientboundConfigurationPackets1_21.class), - packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class), - packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class) + packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class), + packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class), + packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_4.class, ServerboundConfigurationPackets1_20_5.class), + packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_4.class, ServerboundConfigurationPackets1_20_5.class) ); } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/Protocol1_10To1_11.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/Protocol1_10To1_11.java index b2c2b779f..6e11dd1ba 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/Protocol1_10To1_11.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/Protocol1_10To1_11.java @@ -132,13 +132,13 @@ public class Protocol1_10To1_11 extends AbstractProtocol newData = PotionColorMappings1_11.getNewData(data); + PotionColorMappings1_11.PotionData newData = PotionColorMappings1_11.getNewData(data); if (newData == null) { getLogger().warning("Received unknown potion data: " + data); data = 0; } else { - data = newData.key(); - isInstant = newData.value(); + data = newData.data(); + isInstant = newData.instant(); } if (isInstant) { packetWrapper.set(Types.INT, 0, 2007); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/data/PotionColorMappings1_11.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/data/PotionColorMappings1_11.java index 184974eb3..d504be5e8 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/data/PotionColorMappings1_11.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/data/PotionColorMappings1_11.java @@ -17,14 +17,13 @@ */ package com.viaversion.viaversion.protocols.v1_10to1_11.data; -import com.viaversion.viaversion.util.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.checkerframework.checker.nullness.qual.Nullable; public class PotionColorMappings1_11 { - // to mapping - private static final Int2ObjectMap> POTIONS = new Int2ObjectOpenHashMap<>(37); + private static final Int2ObjectMap POTIONS = new Int2ObjectOpenHashMap<>(37); static { addRewrite(0, 3694022, false); @@ -66,12 +65,14 @@ public class PotionColorMappings1_11 { addRewrite(36, 3381504, false); } - public static Pair getNewData(int oldData) { + public static @Nullable PotionData getNewData(int oldData) { return POTIONS.get(oldData); } private static void addRewrite(int oldData, int newData, boolean isInstant) { - POTIONS.put(oldData, new Pair<>(newData, isInstant)); + POTIONS.put(oldData, new PotionData(newData, isInstant)); } + public record PotionData(int data, boolean instant) { + } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/rewriter/EntityPacketRewriter1_11.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/rewriter/EntityPacketRewriter1_11.java index 943bc4714..9e7e8b0c9 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/rewriter/EntityPacketRewriter1_11.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_10to1_11/rewriter/EntityPacketRewriter1_11.java @@ -24,9 +24,9 @@ import com.viaversion.viaversion.api.minecraft.ClientWorld; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_10; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11.EntityType; -import com.viaversion.viaversion.api.minecraft.item.DataItem; import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_9; +import com.viaversion.viaversion.api.minecraft.item.DataItem; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Types; @@ -37,6 +37,7 @@ import com.viaversion.viaversion.protocols.v1_10to1_11.data.EntityMappings1_11; import com.viaversion.viaversion.protocols.v1_10to1_11.storage.EntityTracker1_11; import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ClientboundPackets1_9_3; import com.viaversion.viaversion.rewriter.EntityRewriter; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.logging.Level; @@ -91,13 +92,27 @@ public class EntityPacketRewriter1_11 extends EntityRewriter { byte type = wrapper.get(Types.BYTE, 0); if (type == EntityTypes1_10.ObjectType.FISHIHNG_HOOK.getId()) { tryFixFishingHookVelocity(wrapper); + } else if (type == EntityTypes1_10.ObjectType.ITEM.getId()) { + // Older clients used stone as fallback as long as the entity data was not set + wrapper.send(Protocol1_10To1_11.class); + wrapper.cancel(); + + final int entityId = wrapper.get(Types.VAR_INT, 0); + + final List entityDataList = new ArrayList<>(); + entityDataList.add(new EntityData(6, EntityDataTypes1_9.ITEM, new DataItem(1, (byte) 1, null))); + + final PacketWrapper setItem = PacketWrapper.create(ClientboundPackets1_9_3.SET_ENTITY_DATA, wrapper.user()); + setItem.write(Types.VAR_INT, entityId); + setItem.write(Types1_9.ENTITY_DATA_LIST, entityDataList); + setItem.send(Protocol1_10To1_11.class); } }); - handler(objectTrackerHandler()); } }); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/Protocol1_12_2To1_13.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/Protocol1_12_2To1_13.java index d679f1849..407dacf77 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/Protocol1_12_2To1_13.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/Protocol1_12_2To1_13.java @@ -34,6 +34,7 @@ import com.viaversion.viaversion.api.protocol.packet.State; import com.viaversion.viaversion.api.protocol.remapper.PacketHandler; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.protocol.remapper.ValueTransformer; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.misc.ParticleType; import com.viaversion.viaversion.api.type.types.version.Types1_13; @@ -145,7 +146,7 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol { + final PacketWrapper tagsPacket = w.create(ClientboundPackets1_13.UPDATE_TAGS, wrapper -> { wrapper.write(Types.VAR_INT, MAPPINGS.getBlockTags().size()); // block tags for (Map.Entry tag : MAPPINGS.getBlockTags().entrySet()) { wrapper.write(Types.STRING, tag.getKey()); @@ -164,7 +165,13 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol wrapper.write(Types.STRING, "viaversion:legacy/" + wrapper.read(Types.VAR_INT))); } }); @@ -587,7 +594,7 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol { String s = wrapper.read(Types.STRING); @@ -768,7 +775,10 @@ public class Protocol1_12_2To1_13 extends AbstractProtocol { + final StringTag name = tag.getStringTag("CustomName"); + if (name != null) { + name.setValue(ComponentUtil.legacyToJsonString(name.getValue())); + } + return -1; + }; + handlers.put("minecraft:chest", customNameHandler); + handlers.put("minecraft:dispenser", customNameHandler); + handlers.put("minecraft:dropper", customNameHandler); + handlers.put("minecraft:enchanting_table", customNameHandler); + handlers.put("minecraft:furnace", customNameHandler); + handlers.put("minecraft:hopper", customNameHandler); + handlers.put("minecraft:shulker_box", customNameHandler); } /** diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/provider/blockentities/FlowerPotHandler.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/provider/blockentities/FlowerPotHandler.java index 97bff3d33..afc16d189 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/provider/blockentities/FlowerPotHandler.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/provider/blockentities/FlowerPotHandler.java @@ -18,16 +18,19 @@ package com.viaversion.viaversion.protocols.v1_12_2to1_13.provider.blockentities; import com.viaversion.nbt.tag.CompoundTag; +import com.viaversion.nbt.tag.NumberTag; +import com.viaversion.nbt.tag.StringTag; +import com.viaversion.nbt.tag.Tag; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.protocols.v1_12_2to1_13.provider.BlockEntityProvider; import com.viaversion.viaversion.util.Key; -import com.viaversion.viaversion.util.Pair; +import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; public class FlowerPotHandler implements BlockEntityProvider.BlockEntityHandler { - // Object -> string (id without namespace) or byte (numeric id) - private static final Map, Integer> flowers = new ConcurrentHashMap<>(); + private static final int EMPTY_POT = 5265; + private static final Map STRING_TO_BYTE_ID = new HashMap<>(); + private static final Map FLOWERS = new HashMap<>(); static { register("air", (byte) 0, (byte) 0, 5265); @@ -55,37 +58,40 @@ public class FlowerPotHandler implements BlockEntityProvider.BlockEntityHandler } - public static void register(String identifier, byte numbericBlockId, byte blockData, int newId) { - flowers.put(new Pair<>(identifier, blockData), newId); - flowers.put(new Pair<>(numbericBlockId, blockData), newId); + private static void register(String identifier, byte blockId, byte blockData, int newId) { + STRING_TO_BYTE_ID.put(identifier, blockId); + FLOWERS.put(new IntIdPair(blockId, blockData), newId); } @Override public int transform(UserConnection user, CompoundTag tag) { - Object item = tag.contains("Item") ? tag.get("Item").getValue() : null; - Object data = tag.contains("Data") ? tag.get("Data").getValue() : null; - // Convert item to String without namespace or to Byte - if (item instanceof String) { - item = Key.stripMinecraftNamespace((String) item); - } else if (item instanceof Number) { - item = ((Number) item).byteValue(); - } else { - item = (byte) 0; + Tag itemTag = tag.get("Item"); + byte item = 0; + if (itemTag instanceof StringTag stringTag) { + item = STRING_TO_BYTE_ID.getOrDefault(Key.stripMinecraftNamespace(stringTag.getValue()), (byte) 0); + } else if (itemTag instanceof NumberTag numberTag) { + item = numberTag.asByte(); } - // Convert data to Byte - if (data instanceof Number) { - data = ((Number) data).byteValue(); - } else { - data = (byte) 0; + byte data = 0; + if (tag.get("Data") instanceof NumberTag dataTag) { + data = dataTag.asByte(); } - Integer flower = flowers.get(new Pair<>(item, (byte) data)); - if (flower != null) return flower; - flower = flowers.get(new Pair<>(item, (byte) 0)); - if (flower != null) return flower; + Integer flower = FLOWERS.get(new IntIdPair(item, data)); + if (flower != null) { + return flower; + } - return 5265; // Fallback to empty pot + flower = FLOWERS.get(new IntIdPair(item, (byte) 0)); + if (flower != null) { + return flower; + } + + return EMPTY_POT; // Fallback to empty pot + } + + private record IntIdPair(int id, byte data) { } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/rewriter/ItemPacketRewriter1_13.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/rewriter/ItemPacketRewriter1_13.java index 26119ee83..7a52f44b6 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/rewriter/ItemPacketRewriter1_13.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_12_2to1_13/rewriter/ItemPacketRewriter1_13.java @@ -205,23 +205,23 @@ public class ItemPacketRewriter1_13 extends ItemRewriter rewrittenChannels = new ArrayList<>(); for (String s : channels) { String rewritten = getOldPluginChannelId(s); if (rewritten != null) { rewrittenChannels.add(rewritten); - } else if (!Via.getConfig().isSuppressConversionWarnings()) { + } else if (Via.getManager().isDebug()) { protocol.getLogger().warning("Ignoring plugin channel in serverbound " + channel + ": " + s); } } - wrapper.write(Types.REMAINING_BYTES, Joiner.on('\0').join(rewrittenChannels).getBytes(StandardCharsets.UTF_8)); + wrapper.write(Types.SERVERBOUND_CUSTOM_PAYLOAD_DATA, Joiner.on('\0').join(rewrittenChannels).getBytes(StandardCharsets.UTF_8)); } wrapper.set(Types.STRING, 0, channel); }); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_1to1_13_2/rewriter/EntityPacketRewriter1_13_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_1to1_13_2/rewriter/EntityPacketRewriter1_13_2.java index 752ba6b5a..c44f60fd3 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_1to1_13_2/rewriter/EntityPacketRewriter1_13_2.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_1to1_13_2/rewriter/EntityPacketRewriter1_13_2.java @@ -17,7 +17,10 @@ */ package com.viaversion.viaversion.protocols.v1_13_1to1_13_2.rewriter; +import com.viaversion.viaversion.api.minecraft.Particle; import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; +import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType; +import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.remapper.PacketHandler; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Types; @@ -30,8 +33,16 @@ public class EntityPacketRewriter1_13_2 { public static void register(Protocol1_13_1To1_13_2 protocol) { final PacketHandler dataTypeHandler = wrapper -> { - for (EntityData data : wrapper.get(Types1_13_2.ENTITY_DATA_LIST, 0)) { - data.setDataType(Types1_13_2.ENTITY_DATA_TYPES.byId(data.dataType().typeId())); + for (final EntityData data : wrapper.get(Types1_13_2.ENTITY_DATA_LIST, 0)) { + final EntityDataType dataType = Types1_13_2.ENTITY_DATA_TYPES.byId(data.dataType().typeId()); + if (dataType == Types1_13_2.ENTITY_DATA_TYPES.particleType) { + final Particle particle = data.value(); + if (particle.id() == 27) { + final Item item = particle.getArgument(0).getValue(); + particle.set(0, Types.ITEM1_13_2, item); + } + } + data.setDataType(dataType); } }; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_2to1_14/Protocol1_13_2To1_14.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_2to1_14/Protocol1_13_2To1_14.java index f663cfaab..99d7ce593 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_2to1_14/Protocol1_13_2To1_14.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_2to1_14/Protocol1_13_2To1_14.java @@ -23,15 +23,16 @@ import com.viaversion.viaversion.api.minecraft.RegistryType; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_14; import com.viaversion.viaversion.api.protocol.AbstractProtocol; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; +import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.misc.ParticleType; import com.viaversion.viaversion.api.type.types.version.Types1_13_2; import com.viaversion.viaversion.api.type.types.version.Types1_14; import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ClientboundPackets1_13; import com.viaversion.viaversion.protocols.v1_12_2to1_13.packet.ServerboundPackets1_13; -import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.ComponentRewriter1_14; import com.viaversion.viaversion.protocols.v1_13_2to1_14.data.MappingData1_14; import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ClientboundPackets1_14; import com.viaversion.viaversion.protocols.v1_13_2to1_14.packet.ServerboundPackets1_14; +import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.ComponentRewriter1_14; import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.EntityPacketRewriter1_14; import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.ItemPacketRewriter1_14; import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.PlayerPacketRewriter1_14; @@ -39,6 +40,7 @@ import com.viaversion.viaversion.protocols.v1_13_2to1_14.rewriter.WorldPacketRew import com.viaversion.viaversion.protocols.v1_13_2to1_14.storage.EntityTracker1_14; import com.viaversion.viaversion.rewriter.CommandRewriter; import com.viaversion.viaversion.rewriter.ComponentRewriter; +import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; @@ -49,6 +51,7 @@ public class Protocol1_13_2To1_14 extends AbstractProtocol particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_13_2To1_14() { @@ -65,6 +68,8 @@ public class Protocol1_13_2To1_14 extends AbstractProtocol(this).registerSound(ClientboundPackets1_13.SOUND); new StatisticsRewriter<>(this).register(ClientboundPackets1_13.AWARD_STATS); + particleRewriter.registerLevelParticles1_13(ClientboundPackets1_13.LEVEL_PARTICLES, Types.FLOAT); + ComponentRewriter componentRewriter = new ComponentRewriter1_14<>(this); componentRewriter.registerComponentPacket(ClientboundPackets1_13.CHAT); @@ -139,6 +144,11 @@ public class Protocol1_13_2To1_14 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_2to1_14/rewriter/ItemPacketRewriter1_14.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_2to1_14/rewriter/ItemPacketRewriter1_14.java index 2cd1c6166..4e544a910 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_2to1_14/rewriter/ItemPacketRewriter1_14.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_13_2to1_14/rewriter/ItemPacketRewriter1_14.java @@ -206,8 +206,6 @@ public class ItemPacketRewriter1_14 extends ItemRewriter particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_13To1_13_1() { @@ -128,6 +130,8 @@ public class Protocol1_13To1_13_1 extends AbstractProtocol(this).register(ClientboundPackets1_13.AWARD_STATS); } @@ -152,6 +156,11 @@ public class Protocol1_13To1_13_1 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_13to1_13_1/rewriter/ItemPacketRewriter1_13_1.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_13to1_13_1/rewriter/ItemPacketRewriter1_13_1.java index 748a43d44..095a21f60 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_13to1_13_1/rewriter/ItemPacketRewriter1_13_1.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_13to1_13_1/rewriter/ItemPacketRewriter1_13_1.java @@ -97,7 +97,5 @@ public class ItemPacketRewriter1_13_1 extends ItemRewriter particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_14_4To1_15() { @@ -95,8 +97,13 @@ public class Protocol1_14_4To1_15 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_15_2to1_16/Protocol1_15_2To1_16.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_15_2to1_16/Protocol1_15_2To1_16.java index ec2841c34..fc55762b0 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_15_2to1_16/Protocol1_15_2To1_16.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_15_2to1_16/Protocol1_15_2To1_16.java @@ -47,6 +47,7 @@ import com.viaversion.viaversion.protocols.v1_15_2to1_16.rewriter.EntityPacketRe import com.viaversion.viaversion.protocols.v1_15_2to1_16.rewriter.ItemPacketRewriter1_16; import com.viaversion.viaversion.protocols.v1_15_2to1_16.rewriter.WorldPacketRewriter1_16; import com.viaversion.viaversion.protocols.v1_15_2to1_16.storage.InventoryTracker1_16; +import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; @@ -63,6 +64,7 @@ public class Protocol1_15_2To1_16 extends AbstractProtocol particleRewriter = new ParticleRewriter<>(this); private final ComponentRewriter1_16 componentRewriter = new ComponentRewriter1_16(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); @@ -77,11 +79,12 @@ public class Protocol1_15_2To1_16 extends AbstractProtocol(this).register(ClientboundPackets1_15.AWARD_STATS); // Login Success - registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE, wrapper -> { + registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> { // Transform string to a uuid UUID uuid = UUID.fromString(wrapper.read(Types.STRING)); wrapper.write(Types.UUID, uuid); @@ -169,16 +172,16 @@ public class Protocol1_15_2To1_16 extends AbstractProtocol 32) { - if (!Via.getConfig().isSuppressConversionWarnings()) { + if (Via.getManager().isDebug()) { getLogger().warning("Ignoring serverbound plugin channel, as it is longer than 32 characters: " + channel); } wrapper.cancel(); } else if (namespacedChannel.equals("minecraft:register") || namespacedChannel.equals("minecraft:unregister")) { - String[] channels = new String(wrapper.read(Types.REMAINING_BYTES), StandardCharsets.UTF_8).split("\0"); + String[] channels = new String(wrapper.read(Types.SERVERBOUND_CUSTOM_PAYLOAD_DATA), StandardCharsets.UTF_8).split("\0"); List checkedChannels = new ArrayList<>(channels.length); for (String registeredChannel : channels) { if (registeredChannel.length() > 32) { - if (!Via.getConfig().isSuppressConversionWarnings()) { + if (Via.getManager().isDebug()) { getLogger().warning("Ignoring serverbound plugin channel register of '" + registeredChannel + "', as it is longer than 32 characters"); } continue; @@ -192,7 +195,7 @@ public class Protocol1_15_2To1_16 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + public ComponentRewriter1_16 getComponentRewriter() { return componentRewriter; } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_15_2to1_16/rewriter/ItemPacketRewriter1_16.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_15_2to1_16/rewriter/ItemPacketRewriter1_16.java index 885761f4f..ff0c96fed 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_15_2to1_16/rewriter/ItemPacketRewriter1_16.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_15_2to1_16/rewriter/ItemPacketRewriter1_16.java @@ -136,8 +136,6 @@ public class ItemPacketRewriter1_16 extends ItemRewriter handleItemToServer(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2))); - - registerLevelParticles(ClientboundPackets1_15.LEVEL_PARTICLES, Types.DOUBLE); } @Override diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_1to1_16_2/Protocol1_16_1To1_16_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_1to1_16_2/Protocol1_16_1To1_16_2.java index 0e62e1cc6..18e71e9fa 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_1to1_16_2/Protocol1_16_1To1_16_2.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_1to1_16_2/Protocol1_16_1To1_16_2.java @@ -31,6 +31,7 @@ import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.packet.ServerboundPac import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.rewriter.EntityPacketRewriter1_16_2; import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.rewriter.ItemPacketRewriter1_16_2; import com.viaversion.viaversion.protocols.v1_16_1to1_16_2.rewriter.WorldPacketRewriter1_16_2; +import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; @@ -40,6 +41,7 @@ public class Protocol1_16_1To1_16_2 extends AbstractProtocol particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_16_1To1_16_2() { @@ -53,6 +55,7 @@ public class Protocol1_16_1To1_16_2 extends AbstractProtocol(this).register(ClientboundPackets1_16.AWARD_STATS); @@ -111,8 +114,13 @@ public class Protocol1_16_1To1_16_2 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_1to1_16_2/rewriter/ItemPacketRewriter1_16_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_1to1_16_2/rewriter/ItemPacketRewriter1_16_2.java index 88c872d0d..8c2fe8d31 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_1to1_16_2/rewriter/ItemPacketRewriter1_16_2.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_1to1_16_2/rewriter/ItemPacketRewriter1_16_2.java @@ -57,7 +57,5 @@ public class ItemPacketRewriter1_16_2 extends ItemRewriter handleItemToServer(wrapper.user(), wrapper.passthrough(Types.ITEM1_13_2))); - - registerLevelParticles(ClientboundPackets1_16.LEVEL_PARTICLES, Types.DOUBLE); } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_4to1_17/Protocol1_16_4To1_17.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_4to1_17/Protocol1_16_4To1_17.java index 41004b37d..39279ba20 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_4to1_17/Protocol1_16_4To1_17.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_4to1_17/Protocol1_16_4To1_17.java @@ -37,6 +37,7 @@ import com.viaversion.viaversion.protocols.v1_16_4to1_17.packet.ServerboundPacke 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; +import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; @@ -46,6 +47,7 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_16_4To1_17() { @@ -86,6 +88,8 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol { wrapper.passthrough(Types.STRING); wrapper.passthrough(Types.STRING); @@ -208,6 +212,11 @@ public final class Protocol1_16_4To1_17 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_4to1_17/rewriter/ItemPacketRewriter1_17.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_4to1_17/rewriter/ItemPacketRewriter1_17.java index 24e46a119..f76592244 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_4to1_17/rewriter/ItemPacketRewriter1_17.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_16_4to1_17/rewriter/ItemPacketRewriter1_17.java @@ -46,7 +46,6 @@ public final class ItemPacketRewriter1_17 extends ItemRewriter(protocol).register(ClientboundPackets1_16_2.UPDATE_RECIPES); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_17_1to1_18/Protocol1_17_1To1_18.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_17_1to1_18/Protocol1_17_1To1_18.java index 9fa698ee4..b268e462e 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_17_1to1_18/Protocol1_17_1To1_18.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_17_1to1_18/Protocol1_17_1To1_18.java @@ -35,6 +35,7 @@ import com.viaversion.viaversion.protocols.v1_17_1to1_18.rewriter.ItemPacketRewr import com.viaversion.viaversion.protocols.v1_17_1to1_18.rewriter.WorldPacketRewriter1_18; import com.viaversion.viaversion.protocols.v1_17_1to1_18.storage.ChunkLightStorage; import com.viaversion.viaversion.protocols.v1_17to1_17_1.packet.ClientboundPackets1_17_1; +import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; @@ -46,6 +47,7 @@ public final class Protocol1_17_1To1_18 extends AbstractProtocol particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_17_1To1_18() { @@ -123,8 +125,13 @@ public final class Protocol1_17_1To1_18 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_17_1to1_18/rewriter/EntityPacketRewriter1_18.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_17_1to1_18/rewriter/EntityPacketRewriter1_18.java index 7d7e90a10..ac4364521 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_17_1to1_18/rewriter/EntityPacketRewriter1_18.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_17_1to1_18/rewriter/EntityPacketRewriter1_18.java @@ -90,7 +90,7 @@ public final class EntityPacketRewriter1_18 extends EntityRewriter loadedChunks = new HashSet<>(); public void storeLight(final int x, final int z, final ChunkLight chunkLight) { - lightPackets.put(getChunkSectionIndex(x, z), chunkLight); + lightPackets.put(ChunkPosition.chunkKey(x, z), chunkLight); } public @Nullable ChunkLight removeLight(final int x, final int z) { - return lightPackets.remove(getChunkSectionIndex(x, z)); + return lightPackets.remove(ChunkPosition.chunkKey(x, z)); } public @Nullable ChunkLight getLight(final int x, final int z) { - return lightPackets.get(getChunkSectionIndex(x, z)); + return lightPackets.get(ChunkPosition.chunkKey(x, z)); } public boolean addLoadedChunk(final int x, final int z) { - return loadedChunks.add(getChunkSectionIndex(x, z)); + return loadedChunks.add(ChunkPosition.chunkKey(x, z)); } public boolean isLoaded(final int x, final int z) { - return loadedChunks.contains(getChunkSectionIndex(x, z)); + return loadedChunks.contains(ChunkPosition.chunkKey(x, z)); } public void clear(final int x, final int z) { - final long index = getChunkSectionIndex(x, z); + final long index = ChunkPosition.chunkKey(x, z); lightPackets.remove(index); loadedChunks.remove(index); } @@ -60,10 +61,6 @@ public final class ChunkLightStorage implements StorableObject { lightPackets.clear(); } - private long getChunkSectionIndex(final int x, final int z) { - return ((x & 0x3FFFFFFL) << 38) | (z & 0x3FFFFFFL); - } - public record ChunkLight(boolean trustEdges, long[] skyLightMask, long[] blockLightMask, long[] emptySkyLightMask, long[] emptyBlockLightMask, byte[][] skyLight, byte[][] blockLight) { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_17to1_17_1/Protocol1_17To1_17_1.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_17to1_17_1/Protocol1_17To1_17_1.java index 6d0d6f128..2c49089b7 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_17to1_17_1/Protocol1_17To1_17_1.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_17to1_17_1/Protocol1_17To1_17_1.java @@ -92,7 +92,9 @@ public final class Protocol1_17To1_17_1 extends AbstractProtocol pagesTag = new ListTag<>(StringTag.class); for (int i = 0; i < pages; i++) { String page = wrapper.read(PAGE_STRING_TYPE); - pagesTag.add(new StringTag(page)); + if (i < 200) { // Apply network limit as per game code + pagesTag.add(new StringTag(page)); + } } // Legacy servers don't like an empty pages list diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_18_2to1_19/Protocol1_18_2To1_19.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_18_2to1_19/Protocol1_18_2To1_19.java index a5319df28..b3d192f57 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_18_2to1_19/Protocol1_18_2To1_19.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_18_2to1_19/Protocol1_18_2To1_19.java @@ -45,6 +45,7 @@ import com.viaversion.viaversion.protocols.v1_18_2to1_19.storage.DimensionRegist import com.viaversion.viaversion.protocols.v1_18_2to1_19.storage.NonceStorage1_19; import com.viaversion.viaversion.protocols.v1_18_2to1_19.storage.SequenceStorage; import com.viaversion.viaversion.rewriter.CommandRewriter; +import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; @@ -57,6 +58,7 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_18_2To1_19() { @@ -232,7 +234,7 @@ public final class Protocol1_18_2To1_19 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_18_2to1_19/rewriter/EntityPacketRewriter1_19.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_18_2to1_19/rewriter/EntityPacketRewriter1_19.java index dc336c801..0d5dd4d39 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_18_2to1_19/rewriter/EntityPacketRewriter1_19.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_18_2to1_19/rewriter/EntityPacketRewriter1_19.java @@ -331,7 +331,7 @@ public final class EntityPacketRewriter1_19 extends EntityRewriter particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_19_1To1_19_3() { @@ -78,6 +80,8 @@ public final class Protocol1_19_1To1_19_3 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_1to1_19_3/rewriter/EntityPacketRewriter1_19_3.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_1to1_19_3/rewriter/EntityPacketRewriter1_19_3.java index cf62c501e..9fa3c25b9 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_1to1_19_3/rewriter/EntityPacketRewriter1_19_3.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_1to1_19_3/rewriter/EntityPacketRewriter1_19_3.java @@ -22,6 +22,7 @@ import com.viaversion.viaversion.api.minecraft.entities.EntityType; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_3; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; 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.version.Types1_19; import com.viaversion.viaversion.api.type.types.version.Types1_19_3; @@ -62,11 +63,16 @@ public final class EntityPacketRewriter1_19_3 extends EntityRewriter { - // Also enable vanilla features + // Also enable vanilla features (set by default in later versions, but keeping it explicit is nicer) final PacketWrapper enableFeaturesPacket = wrapper.create(ClientboundPackets1_19_3.UPDATE_ENABLED_FEATURES); - enableFeaturesPacket.write(Types.VAR_INT, 1); - enableFeaturesPacket.write(Types.STRING, "minecraft:vanilla"); - enableFeaturesPacket.scheduleSend(Protocol1_19_1To1_19_3.class); + enableFeaturesPacket.write(Types.STRING_ARRAY, new String[]{"minecraft:vanilla"}); + + if (wrapper.user().getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_20_2)) { + // Make sure it's included in the configuration packets + enableFeaturesPacket.send(Protocol1_19_1To1_19_3.class); + } else { + enableFeaturesPacket.scheduleSend(Protocol1_19_1To1_19_3.class); + } }); } }); @@ -116,7 +122,7 @@ public final class EntityPacketRewriter1_19_3 extends EntityRewriter recipeRewriter = new RecipeRewriter<>(protocol); protocol.registerClientbound(ClientboundPackets1_19_1.UPDATE_RECIPES, wrapper -> { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_1to1_19_3/rewriter/RecipeRewriter1_19_3.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_1to1_19_3/rewriter/RecipeRewriter1_19_3.java index 9dc66ac5b..12ef5e28f 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_1to1_19_3/rewriter/RecipeRewriter1_19_3.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_1to1_19_3/rewriter/RecipeRewriter1_19_3.java @@ -50,8 +50,7 @@ public class RecipeRewriter1_19_3 extends Recip wrapper.passthrough(Types.STRING); // Group wrapper.passthrough(Types.VAR_INT); // Crafting book category handleIngredients(wrapper); - final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); - wrapper.write(mappedItemType(), result); + handleResult(wrapper); } @Override @@ -62,8 +61,7 @@ public class RecipeRewriter1_19_3 extends Recip for (int i = 0; i < ingredients; i++) { handleIngredient(wrapper); } - final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); - wrapper.write(mappedItemType(), result); + handleResult(wrapper); } @Override @@ -71,8 +69,7 @@ public class RecipeRewriter1_19_3 extends Recip wrapper.passthrough(Types.STRING); // Group wrapper.passthrough(Types.VAR_INT); // Crafting book category handleIngredient(wrapper); - final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); - wrapper.write(mappedItemType(), result); + handleResult(wrapper); wrapper.passthrough(Types.FLOAT); // EXP wrapper.passthrough(Types.VAR_INT); // Cooking time } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_3to1_19_4/Protocol1_19_3To1_19_4.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_3to1_19_4/Protocol1_19_3To1_19_4.java index 9db2a7aba..ba05f3960 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_3to1_19_4/Protocol1_19_3To1_19_4.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_3to1_19_4/Protocol1_19_3To1_19_4.java @@ -22,7 +22,6 @@ import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_4; import com.viaversion.viaversion.api.protocol.AbstractProtocol; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; -import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.misc.ParticleType; import com.viaversion.viaversion.api.type.types.version.Types1_19_4; @@ -36,6 +35,7 @@ import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.rewriter.EntityPacket import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.rewriter.ItemPacketRewriter1_19_4; import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.storage.PlayerVehicleTracker; import com.viaversion.viaversion.rewriter.CommandRewriter; +import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; @@ -48,6 +48,7 @@ public final class Protocol1_19_3To1_19_4 extends AbstractProtocol particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_19_3To1_19_4() { @@ -59,6 +60,8 @@ public final class Protocol1_19_3To1_19_4 extends AbstractProtocol(this).register(ClientboundPackets1_19_3.AWARD_STATS); final SoundRewriter soundRewriter = new SoundRewriter<>(this); @@ -133,6 +136,11 @@ public final class Protocol1_19_3To1_19_4 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_3to1_19_4/rewriter/ItemPacketRewriter1_19_4.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_3to1_19_4/rewriter/ItemPacketRewriter1_19_4.java index 56286be44..f1f50a425 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_3to1_19_4/rewriter/ItemPacketRewriter1_19_4.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_3to1_19_4/rewriter/ItemPacketRewriter1_19_4.java @@ -19,7 +19,6 @@ package com.viaversion.viaversion.protocols.v1_19_3to1_19_4.rewriter; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; -import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_18; import com.viaversion.viaversion.protocols.v1_19_1to1_19_3.packet.ClientboundPackets1_19_3; @@ -91,7 +90,6 @@ public final class ItemPacketRewriter1_19_4 extends ItemRewriter particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_19_4To1_20() { @@ -51,6 +53,7 @@ public final class Protocol1_19_4To1_20 extends AbstractProtocol soundRewriter = new SoundRewriter<>(this); soundRewriter.registerSound1_19_3(ClientboundPackets1_19_4.SOUND); @@ -108,8 +111,13 @@ public final class Protocol1_19_4To1_20 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_4to1_20/rewriter/ItemPacketRewriter1_20.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_4to1_20/rewriter/ItemPacketRewriter1_20.java index d3e0b1861..8f510bf03 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_4to1_20/rewriter/ItemPacketRewriter1_20.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_19_4to1_20/rewriter/ItemPacketRewriter1_20.java @@ -59,7 +59,6 @@ public final class ItemPacketRewriter1_20 extends ItemRewriter { wrapper.passthrough(Types.BOOLEAN); // Reset/clear @@ -193,4 +192,4 @@ public final class ItemPacketRewriter1_20 extends ItemRewriter particleRewriter = new ParticleRewriter<>(this); private final EntityPacketRewriter1_20_3 entityRewriter = new EntityPacketRewriter1_20_3(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); @@ -75,6 +77,7 @@ public final class Protocol1_20_2To1_20_3 extends AbstractProtocol soundRewriter = new SoundRewriter<>(this); soundRewriter.registerSound1_19_3(ClientboundPackets1_20_2.SOUND); @@ -268,7 +271,7 @@ public final class Protocol1_20_2To1_20_3 extends AbstractProtocol { - final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM); + final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM1_19_3); final int entries = wrapper.passthrough(Types.VAR_INT); for (int i = 0; i < entries; i++) { wrapper.passthrough(Types.UUID); @@ -305,7 +308,6 @@ public final class Protocol1_20_2To1_20_3 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public EntityPacketRewriter1_20_3 getEntityRewriter() { return entityRewriter; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_2to1_20_3/rewriter/BlockItemPacketRewriter1_20_3.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_2to1_20_3/rewriter/BlockItemPacketRewriter1_20_3.java index 066ce66fe..eaaa07348 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_2to1_20_3/rewriter/BlockItemPacketRewriter1_20_3.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_2to1_20_3/rewriter/BlockItemPacketRewriter1_20_3.java @@ -17,10 +17,10 @@ */ package com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter; +import com.google.gson.JsonElement; import com.viaversion.nbt.tag.CompoundTag; import com.viaversion.nbt.tag.ListTag; import com.viaversion.nbt.tag.StringTag; -import com.google.gson.JsonElement; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.data.ParticleMappings; @@ -31,17 +31,18 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2; import com.viaversion.viaversion.api.type.types.version.Types1_20_3; -import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPacket1_20_2; -import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPackets1_20_2; -import com.viaversion.viaversion.protocols.v1_20to1_20_2.rewriter.RecipeRewriter1_20_2; import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.Protocol1_20_2To1_20_3; import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ServerboundPacket1_20_3; import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ServerboundPackets1_20_3; +import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPacket1_20_2; +import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ClientboundPackets1_20_2; +import com.viaversion.viaversion.protocols.v1_20to1_20_2.rewriter.RecipeRewriter1_20_2; import com.viaversion.viaversion.rewriter.BlockRewriter; import com.viaversion.viaversion.rewriter.ItemRewriter; import com.viaversion.viaversion.util.ComponentUtil; import com.viaversion.viaversion.util.Key; import com.viaversion.viaversion.util.SerializerVersion; +import java.util.logging.Level; import org.checkerframework.checker.nullness.qual.Nullable; public final class BlockItemPacketRewriter1_20_3 extends ItemRewriter { @@ -90,7 +91,7 @@ public final class BlockItemPacketRewriter1_20_3 extends ItemRewriter extends Recip for (int i = 0; i < ingredients; i++) { handleIngredient(wrapper); } - - final Item item = rewrite(wrapper.user(), wrapper.read(itemType())); // Result - wrapper.write(mappedItemType(), item); + handleResult(wrapper); wrapper.passthrough(Types.BOOLEAN); // Show notification } @@ -64,4 +62,4 @@ public class RecipeRewriter1_20_3 extends Recip protected Type mappedItemArrayType() { return protocol.getItemRewriter().mappedItemArrayType(); } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/Protocol1_20_3To1_20_5.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/Protocol1_20_3To1_20_5.java index 89e92006c..a9c5f6ade 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/Protocol1_20_3To1_20_5.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/Protocol1_20_3To1_20_5.java @@ -49,6 +49,7 @@ import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPac import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter.BlockItemPacketRewriter1_20_5; import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter.ComponentRewriter1_20_5; import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter.EntityPacketRewriter1_20_5; +import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter.ParticleRewriter1_20_5; import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.AcknowledgedMessagesStorage; import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.ArmorTrimStorage; import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundConfigurationPackets1_20_2; @@ -71,6 +72,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol tagRewriter = new TagRewriter<>(this); private final ComponentRewriter1_20_5 componentRewriter = new ComponentRewriter1_20_5<>(this, Types1_20_5.STRUCTURED_DATA); @@ -211,7 +213,7 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol(this).registerDeclareCommands1_19(ClientboundPackets1_20_3.COMMANDS); - registerClientbound(State.LOGIN, ClientboundLoginPackets.GAME_PROFILE, wrapper -> { + registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> { wrapper.passthrough(Types.UUID); // UUID wrapper.passthrough(Types.STRING); // Name @@ -268,14 +270,14 @@ public final class Protocol1_20_3To1_20_5 extends AbstractProtocol getTagRewriter() { return tagRewriter; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/data/MaxStackSize1_20_3.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/data/MaxStackSize1_20_3.java index f98228853..53557b817 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/data/MaxStackSize1_20_3.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/data/MaxStackSize1_20_3.java @@ -17,62 +17,62 @@ */ package com.viaversion.viaversion.protocols.v1_20_3to1_20_5.data; -import java.util.HashMap; -import java.util.Map; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; public final class MaxStackSize1_20_3 { - private static final Map mapping = new HashMap<>(); + private static final Int2IntMap MAPPING = new Int2IntOpenHashMap(); static { fill(521, 537, 1); fill(764, 790, 1); - mapping.put(793, 1); - mapping.put(795, 1); - mapping.put(797, 1); + MAPPING.put(793, 1); + MAPPING.put(795, 1); + MAPPING.put(797, 1); fill(814, 843, 1); - mapping.put(846, 1); - mapping.put(853, 1); + MAPPING.put(846, 1); + MAPPING.put(853, 1); fill(854, 876, 1); fill(883, 905, 16); fill(906, 908, 1); - mapping.put(909, 16); + MAPPING.put(909, 16); fill(911, 917, 1); - mapping.put(924, 16); - mapping.put(927, 1); - mapping.put(928, 1); - mapping.put(930, 1); + MAPPING.put(924, 16); + MAPPING.put(927, 1); + MAPPING.put(928, 1); + MAPPING.put(930, 1); fill(960, 976, 1); - mapping.put(980, 1); - mapping.put(990, 16); - mapping.put(995, 1); - mapping.put(1085, 1); - mapping.put(1086, 16); - mapping.put(1107, 1); - mapping.put(1113, 1); - mapping.put(1116, 16); + MAPPING.put(980, 1); + MAPPING.put(990, 16); + MAPPING.put(995, 1); + MAPPING.put(1085, 1); + MAPPING.put(1086, 16); + MAPPING.put(1107, 1); + MAPPING.put(1113, 1); + MAPPING.put(1116, 16); fill(1117, 1120, 1); - mapping.put(1123, 1); + MAPPING.put(1123, 1); fill(1126, 1141, 16); - mapping.put(1149, 1); - mapping.put(1151, 1); + MAPPING.put(1149, 1); + MAPPING.put(1151, 1); fill(1154, 1156, 1); fill(1159, 1176, 1); - mapping.put(1178, 1); - mapping.put(1182, 1); - mapping.put(1183, 1); + MAPPING.put(1178, 1); + MAPPING.put(1182, 1); + MAPPING.put(1183, 1); fill(1185, 1191, 1); - mapping.put(1212, 16); - mapping.put(1256, 1); + MAPPING.put(1212, 16); + MAPPING.put(1256, 1); } public static int getMaxStackSize(final int identifier) { - return mapping.getOrDefault(identifier, 64); + return MAPPING.getOrDefault(identifier, 64); } private static void fill(final int start, final int end, final int value) { for (int i = start; i <= end; i++) { - mapping.put(i, value); + MAPPING.put(i, value); } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/packet/ServerboundConfigurationPackets1_20_5.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/packet/ServerboundConfigurationPackets1_20_5.java index e418cf61d..86065ec2f 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/packet/ServerboundConfigurationPackets1_20_5.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/packet/ServerboundConfigurationPackets1_20_5.java @@ -18,8 +18,10 @@ package com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet; import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPacket1_21_2; -public enum ServerboundConfigurationPackets1_20_5 implements ServerboundPacket1_20_5 { +public enum ServerboundConfigurationPackets1_20_5 implements ServerboundPacket1_20_5, ServerboundPacket1_21_2, ServerboundPacket1_21_4 { CLIENT_INFORMATION, // 0x00 COOKIE_RESPONSE, // 0x01 diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/BlockItemPacketRewriter1_20_5.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/BlockItemPacketRewriter1_20_5.java index 2bbee0d01..558f40e02 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/BlockItemPacketRewriter1_20_5.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/BlockItemPacketRewriter1_20_5.java @@ -60,9 +60,9 @@ import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent; import com.viaversion.viaversion.api.minecraft.item.data.FilterableString; import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion; import com.viaversion.viaversion.api.minecraft.item.data.Fireworks; -import com.viaversion.viaversion.api.minecraft.item.data.FoodEffect; -import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties; -import com.viaversion.viaversion.api.minecraft.item.data.Instrument; +import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5; +import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5.FoodEffect; +import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5; import com.viaversion.viaversion.api.minecraft.item.data.LodestoneTracker; import com.viaversion.viaversion.api.minecraft.item.data.PotDecorations; import com.viaversion.viaversion.api.minecraft.item.data.PotionContents; @@ -105,8 +105,7 @@ import com.viaversion.viaversion.util.Key; import com.viaversion.viaversion.util.SerializerVersion; import com.viaversion.viaversion.util.UUIDUtil; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -306,8 +305,8 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter recipeRewriter = new RecipeRewriter1_20_3<>(protocol) { - @Override - protected Item rewrite(final UserConnection connection, @Nullable Item item) { - return handleNonEmptyItemToClient(connection, item); - } - }; + final RecipeRewriter1_20_5 recipeRewriter = new RecipeRewriter1_20_5<>(protocol); protocol.registerClientbound(ClientboundPackets1_20_3.UPDATE_RECIPES, wrapper -> { final int size = wrapper.passthrough(Types.VAR_INT); for (int i = 0; i < size; i++) { @@ -465,7 +459,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter overrideArmorMaterials = new Int2ObjectOpenHashMap<>(); + final Map overrideArmorMaterials = new Object2ObjectArrayMap<>(); if (overrideArmorMaterialsTag != null) { for (final Map.Entry entry : overrideArmorMaterialsTag.entrySet()) { if (!(entry.getValue() instanceof StringTag valueTag)) { continue; } - try { - final int id = Integer.parseInt(entry.getKey()); - overrideArmorMaterials.put(id, valueTag.getValue()); - } catch (NumberFormatException ignored) { - } + + overrideArmorMaterials.put(entry.getKey(), valueTag.getValue()); } } @@ -1054,7 +1039,7 @@ public final class BlockItemPacketRewriter1_20_5 extends ItemRewriter extends ComponentRewriter { - private final Map, ConverterPair> converters = new Reference2ObjectOpenHashMap<>(); - private final StructuredDataType structuredDataType; + protected final Map, ConverterPair> converters = new Reference2ObjectOpenHashMap<>(); + protected final StructuredDataType structuredDataType; /** * @param protocol protocol @@ -133,7 +131,7 @@ public class ComponentRewriter1_20_5 extends Co register(StructuredDataKey.CAN_PLACE_ON, this::canPlaceOnToTag, this::canPlaceOnFromTag); register(StructuredDataKey.CAN_BREAK, this::canBreakToTag, this::canBreakFromTag); register(StructuredDataKey.ATTRIBUTE_MODIFIERS1_20_5, this::attributeModifiersToTag, this::attributeModifiersFromTag); - register(StructuredDataKey.CUSTOM_MODEL_DATA, this::customModelDataToTag, this::customModelDataFromTag); + register(StructuredDataKey.CUSTOM_MODEL_DATA1_20_5, this::customModelDataToTag, this::customModelDataFromTag); register(StructuredDataKey.HIDE_ADDITIONAL_TOOLTIP, this::hideAdditionalTooltipToTag, this::hideAdditionalTooltipFromTag); register(StructuredDataKey.HIDE_TOOLTIP, this::hideTooltipToTag, this::hideTooltipFromTag); register(StructuredDataKey.REPAIR_COST, this::repairCostToTag, this::repairCostFromTag); @@ -151,16 +149,16 @@ public class ComponentRewriter1_20_5 extends Co registerEmpty(StructuredDataKey.MAP_POST_PROCESSING); register(StructuredDataKey.CHARGED_PROJECTILES1_20_5, this::chargedProjectilesToTag, this::chargedProjectilesFromTag); register(StructuredDataKey.BUNDLE_CONTENTS1_20_5, this::bundleContentsToTag, this::bundleContentsFromTag); - register(StructuredDataKey.POTION_CONTENTS, this::potionContentsToTag, this::potionContentsFromTag); + register(StructuredDataKey.POTION_CONTENTS1_20_5, this::potionContentsToTag, this::potionContentsFromTag); register(StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, this::suspiciousStewEffectsToTag, this::suspiciousStewEffectsFromTag); register(StructuredDataKey.WRITABLE_BOOK_CONTENT, this::writableBookContentToTag, this::writableBookContentFromTag); register(StructuredDataKey.WRITTEN_BOOK_CONTENT, this::writtenBookContentToTag, this::writtenBookContentFromTag); - register(StructuredDataKey.TRIM, this::trimToTag, this::trimFromTag); + register(StructuredDataKey.TRIM1_20_5, this::trimToTag, this::trimFromTag); register(StructuredDataKey.DEBUG_STICK_STATE, this::debugStickRateToTag, this::debugStickRateFromTag); register(StructuredDataKey.ENTITY_DATA, this::entityDataToTag, this::entityDataFromTag); register(StructuredDataKey.BUCKET_ENTITY_DATA, this::bucketEntityDataToTag, this::bucketEntityDataFromTag); register(StructuredDataKey.BLOCK_ENTITY_DATA, this::blockEntityDataToTag, this::blockEntityDataFromTag); - register(StructuredDataKey.INSTRUMENT, this::instrumentToTag, this::instrumentFromTag); + register(StructuredDataKey.INSTRUMENT1_20_5, this::instrumentToTag, this::instrumentFromTag); register(StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, this::ominousBottleAmplifierToTag, this::ominousBottleAmplifierFromTag); register(StructuredDataKey.RECIPES, this::recipesToTag, this::recipesFromTag); register(StructuredDataKey.LODESTONE_TRACKER, this::lodestoneTrackerToTag, this::lodestoneTrackerFromTag); @@ -336,7 +334,7 @@ public class ComponentRewriter1_20_5 extends Co return readFromTag(connection, key, id, tag); } - private StructuredData readFromTag(final UserConnection connection, final StructuredDataKey key, final int id, final Tag tag) { + protected StructuredData readFromTag(final UserConnection connection, final StructuredDataKey key, final int id, final Tag tag) { final TagConverter converter = tagConverter(key); Preconditions.checkNotNull(converter, "No converter found for: %s", key); return StructuredData.of(key, converter.convert(connection, tag), id); @@ -351,7 +349,6 @@ public class ComponentRewriter1_20_5 extends Co } // --------------------------------------------------------------------------------------- - // Conversion methods protected CompoundTag customDataToTag(final CompoundTag value) { return value; @@ -665,7 +662,7 @@ public class ComponentRewriter1_20_5 extends Co return value; } - protected CompoundTag foodToTag(final FoodProperties value) { + protected CompoundTag foodToTag(final FoodProperties1_20_5 value) { final CompoundTag tag = new CompoundTag(); tag.put("nutrition", nonNegativeIntToTag(value.nutrition())); tag.putFloat("saturation", value.saturationModifier()); @@ -847,6 +844,10 @@ public class ComponentRewriter1_20_5 extends Co customEffects.add(effectTag); } tag.put("custom_effects", customEffects); + if (value.customName() != null) { + tag.putString("custom_name", value.customName()); + } + tag.put("custom_effects", customEffects); return tag; } @@ -935,7 +936,6 @@ public class ComponentRewriter1_20_5 extends Co final CompoundTag title = new CompoundTag(); filterableStringToTag(title, value.title(), 32); tag.put("title", title); - tag.putString("author", value.author()); if (value.generation() != 0) { tag.put("generation", intRangeToTag(value.generation(), 0, 3)); @@ -993,8 +993,8 @@ public class ComponentRewriter1_20_5 extends Co } final CompoundTag overrideArmorMaterialsTag = new CompoundTag(); - for (final Int2ObjectMap.Entry entry : armorTrimMaterial.overrideArmorMaterials().int2ObjectEntrySet()) { - final String materialKey = ArmorMaterials1_20_5.idToKey(entry.getIntKey()); + for (final Map.Entry entry : armorTrimMaterial.overrideArmorMaterials().entrySet()) { + final String materialKey = ArmorMaterials1_20_5.idToKey(Integer.parseInt(entry.getKey())); if (materialKey != null) { overrideArmorMaterialsTag.putString(materialKey, entry.getValue()); } @@ -1110,12 +1110,12 @@ public class ComponentRewriter1_20_5 extends Co return (CompoundTag) value; } - protected Tag instrumentToTag(final Holder value) { + protected Tag instrumentToTag(final Holder value) { if (value.hasId()) { return new StringTag(Instruments1_20_3.idToKey(value.id())); } - final Instrument instrument = value.value(); + final Instrument1_20_5 instrument = value.value(); final CompoundTag tag = new CompoundTag(); final Holder sound = instrument.soundEvent(); if (sound.hasId()) { @@ -1135,7 +1135,7 @@ public class ComponentRewriter1_20_5 extends Co return tag; } - protected Holder instrumentFromTag(final Tag tag) { + protected Holder instrumentFromTag(final Tag tag) { if (tag instanceof StringTag stringTag) { return Holder.of(Instruments1_20_3.keyToId(stringTag.getValue())); } @@ -1833,17 +1833,17 @@ public class ComponentRewriter1_20_5 extends Co // --------------------------------------------------------------------------------------- - private int checkIntRange(final int min, final int max, final int value) { + protected int checkIntRange(final int min, final int max, final int value) { Preconditions.checkArgument(value >= min && value <= max, "Value out of range: " + value); return value; } - private float checkFloatRange(final float min, final float max, final float value) { + protected float checkFloatRange(final float min, final float max, final float value) { Preconditions.checkArgument(value >= min && value <= max, "Value out of range: " + value); return value; } - private String checkStringRange(final int min, final int max, final String value) { + protected String checkStringRange(final int min, final int max, final String value) { final int length = value.length(); Preconditions.checkArgument(length >= min && length <= max, "Value out of range: " + value); return value; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/EntityPacketRewriter1_20_5.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/EntityPacketRewriter1_20_5.java index 5c552b269..8a03b6a08 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/EntityPacketRewriter1_20_5.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/EntityPacketRewriter1_20_5.java @@ -547,14 +547,6 @@ public final class EntityPacketRewriter1_20_5 extends EntityRewriter. + */ +package com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.ParticleMappings; +import com.viaversion.viaversion.api.minecraft.Particle; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.minecraft.item.StructuredItem; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.packet.ClientboundPacket1_20_3; +import com.viaversion.viaversion.rewriter.ParticleRewriter; + +public final class ParticleRewriter1_20_5 extends ParticleRewriter { + + public ParticleRewriter1_20_5(final Protocol protocol) { + super(protocol); + } + + @Override + public void rewriteParticle(final UserConnection connection, final Particle particle) { + super.rewriteParticle(connection, particle); + + final ParticleMappings particleMappings = protocol.getMappingData().getParticleMappings(); + if (particle.id() == particleMappings.mappedId("entity_effect")) { + particle.add(Types.INT, 0); // Default color, changed in the area effect handler + } else if (particle.id() == particleMappings.mappedId("item")) { + final Particle.ParticleData data = particle.getArgument(0); + if (data.getValue().isEmpty()) { + data.setValue(new StructuredItem(1, 1)); + } + } + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/RecipeRewriter1_20_5.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/RecipeRewriter1_20_5.java new file mode 100644 index 000000000..21c28e941 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/RecipeRewriter1_20_5.java @@ -0,0 +1,54 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_20_3to1_20_5.rewriter; + +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.minecraft.item.StructuredItem; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter.RecipeRewriter1_20_3; +import java.util.ArrayList; +import java.util.List; + +final class RecipeRewriter1_20_5 extends RecipeRewriter1_20_3 { + + public RecipeRewriter1_20_5(final Protocol protocol) { + super(protocol); + } + + @Override + protected void handleIngredient(final PacketWrapper wrapper) { + final Item[] items = wrapper.read(itemArrayType()); + final List newItems = new ArrayList<>(items.length); + for (final Item item : items) { + if (item == null || item.isEmpty()) continue; + newItems.add(rewrite(wrapper.user(), item)); + } + wrapper.write(mappedItemArrayType(), newItems.toArray(new Item[0])); + } + + @Override + protected void handleResult(final PacketWrapper wrapper) { + Item result = rewrite(wrapper.user(), wrapper.read(itemType())); + if (result == null || result.isEmpty()) { + result = new StructuredItem(1, 1); + } + wrapper.write(mappedItemType(), result); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/StructuredDataConverter.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/StructuredDataConverter.java index 1951e1294..f07d87f0b 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/StructuredDataConverter.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_3to1_20_5/rewriter/StructuredDataConverter.java @@ -44,8 +44,8 @@ import com.viaversion.viaversion.api.minecraft.item.data.Enchantments; import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent; import com.viaversion.viaversion.api.minecraft.item.data.FilterableString; import com.viaversion.viaversion.api.minecraft.item.data.FireworkExplosion; -import com.viaversion.viaversion.api.minecraft.item.data.FoodEffect; -import com.viaversion.viaversion.api.minecraft.item.data.Instrument; +import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5.FoodEffect; +import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5; import com.viaversion.viaversion.api.minecraft.item.data.PotionEffect; import com.viaversion.viaversion.api.minecraft.item.data.PotionEffectData; import com.viaversion.viaversion.api.minecraft.item.data.StatePropertyMatcher; @@ -65,7 +65,6 @@ import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.storage.BannerPattern import com.viaversion.viaversion.util.ComponentUtil; import com.viaversion.viaversion.util.UUIDUtil; import it.unimi.dsi.fastutil.ints.Int2IntMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import java.util.Arrays; import java.util.Collections; @@ -136,6 +135,7 @@ public final class StructuredDataConverter { } final CompoundTag modifierTag = new CompoundTag(); + modifierTag.put("UUID", new IntArrayTag(UUIDUtil.toIntArray(modifier.modifier().uuid()))); modifierTag.putString("AttributeName", identifier.equals("generic.jump_strength") ? "horse.jump_strength" : identifier); modifierTag.putString("Name", modifier.modifier().name()); modifierTag.putDouble("Amount", modifier.modifier().amount()); @@ -151,7 +151,7 @@ public final class StructuredDataConverter { putHideFlag(tag, HIDE_ATTRIBUTES); } }); - register(StructuredDataKey.CUSTOM_MODEL_DATA, (data, tag) -> tag.putInt("CustomModelData", data)); + register(StructuredDataKey.CUSTOM_MODEL_DATA1_20_5, (data, tag) -> tag.putInt("CustomModelData", data)); register(StructuredDataKey.HIDE_ADDITIONAL_TOOLTIP, (data, tag) -> putHideFlag(tag, 0x20)); register(StructuredDataKey.REPAIR_COST, (data, tag) -> tag.putInt("RepairCost", data)); register(StructuredDataKey.DYED_COLOR, (data, tag) -> { @@ -278,12 +278,12 @@ public final class StructuredDataConverter { } profileTag.put("Properties", propertiesTag); }); - register(StructuredDataKey.INSTRUMENT, (data, tag) -> { + register(StructuredDataKey.INSTRUMENT1_20_5, (data, tag) -> { // Can't do anything with direct values if (!data.hasId()) { if (backupInconvertibleData) { final CompoundTag backupTag = new CompoundTag(); - final Instrument instrument = data.value(); + final Instrument1_20_5 instrument = data.value(); if (instrument.soundEvent().hasId()) { backupTag.putInt("sound_event", instrument.soundEvent().id()); } else { @@ -398,7 +398,7 @@ public final class StructuredDataConverter { enchantmentsTag.add(invalidEnchantment); }); - register(StructuredDataKey.POTION_CONTENTS, (data, tag) -> { + register(StructuredDataKey.POTION_CONTENTS1_20_5, (data, tag) -> { if (data.potion() != null) { final String potion = Potions1_20_5.idToKey(data.potion()); // Include 1.20.5 names if (potion != null) { @@ -513,7 +513,7 @@ public final class StructuredDataConverter { tag.putInt("map_scale_direction", 1); } }); - register(StructuredDataKey.TRIM, (connection, data, tag) -> { + register(StructuredDataKey.TRIM1_20_5, (connection, data, tag) -> { final CompoundTag trimTag = new CompoundTag(); final ArmorTrimStorage trimStorage = connection.get(ArmorTrimStorage.class); if (data.material().isDirect()) { @@ -530,8 +530,8 @@ public final class StructuredDataConverter { final CompoundTag overrideArmorMaterials = new CompoundTag(); if (!material.overrideArmorMaterials().isEmpty()) { - for (final Int2ObjectMap.Entry entry : material.overrideArmorMaterials().int2ObjectEntrySet()) { - overrideArmorMaterials.put(Integer.toString(entry.getIntKey()), new StringTag(entry.getValue())); + for (final Map.Entry entry : material.overrideArmorMaterials().entrySet()) { + overrideArmorMaterials.put(entry.getKey(), new StringTag(entry.getValue())); } materialTag.put("override_armor_materials", overrideArmorMaterials); } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/Protocol1_20_5To1_21.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/Protocol1_20_5To1_21.java index 683131b42..c50c7ac86 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/Protocol1_20_5To1_21.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/Protocol1_20_5To1_21.java @@ -28,6 +28,7 @@ import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvide import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.misc.ParticleType; +import com.viaversion.viaversion.api.type.types.version.Types1_20_5; import com.viaversion.viaversion.api.type.types.version.Types1_21; import com.viaversion.viaversion.data.entity.EntityTrackerBase; import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ClientboundConfigurationPackets1_20_5; @@ -45,7 +46,9 @@ import com.viaversion.viaversion.protocols.v1_20_5to1_21.rewriter.BlockItemPacke import com.viaversion.viaversion.protocols.v1_20_5to1_21.rewriter.ComponentRewriter1_21; import com.viaversion.viaversion.protocols.v1_20_5to1_21.rewriter.EntityPacketRewriter1_21; import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.EfficiencyAttributeStorage; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.storage.PlayerPositionStorage; import com.viaversion.viaversion.rewriter.ComponentRewriter; +import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; @@ -61,6 +64,7 @@ public final class Protocol1_20_5To1_21 extends AbstractProtocol particleRewriter = new ParticleRewriter<>(this, Types1_20_5.PARTICLE, Types1_21.PARTICLE); private final TagRewriter tagRewriter = new TagRewriter<>(this); private final ComponentRewriter componentRewriter = new ComponentRewriter1_21(this); @@ -91,6 +95,9 @@ public final class Protocol1_20_5To1_21 extends AbstractProtocol { componentRewriter.processTag(wrapper.user(), wrapper.passthrough(Types.TAG)); // Message @@ -196,14 +203,14 @@ public final class Protocol1_20_5To1_21 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; @@ -258,4 +276,4 @@ public final class Protocol1_20_5To1_21 extends AbstractProtocol { private static final List DISCS = List.of("11", "13", "5", "blocks", "cat", "chirp", "far", "mall", "mellohi", "otherside", "pigstep", "relic", "stal", "strad", "wait", "ward"); + private static final int HELMET_SLOT = 5; + private static final int CHESTPLATE_SLOT = 6; + private static final int LEGGINGS_SLOT = 7; + private static final int BOOTS_SLOT = 8; + + private static final int AQUA_AFFINITY_ID = 6; + private static final int DEPTH_STRIDER_ID = 8; + private static final int SWIFT_SNEAK_ID = 12; public BlockItemPacketRewriter1_21(final Protocol1_20_5To1_21 protocol) { super(protocol, Types1_20_5.ITEM, Types1_20_5.ITEM_ARRAY, Types1_21.ITEM, Types1_21.ITEM_ARRAY, - Types1_20_5.ITEM_COST, Types1_20_5.OPTIONAL_ITEM_COST, Types1_21.ITEM_COST, Types1_21.OPTIONAL_ITEM_COST, - Types1_20_5.PARTICLE, Types1_21.PARTICLE + Types1_20_5.ITEM_COST, Types1_20_5.OPTIONAL_ITEM_COST, Types1_21.ITEM_COST, Types1_21.OPTIONAL_ITEM_COST ); } @@ -67,14 +77,34 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter { + final short containerId = wrapper.passthrough(Types.UNSIGNED_BYTE); // Container id + wrapper.passthrough(Types.VAR_INT); // State id + final short slotId = wrapper.passthrough(Types.SHORT); // Slot id + final Item item = handleItemToClient(wrapper.user(), wrapper.read(itemType())); + wrapper.write(mappedItemType(), item); + + // When a players' armor is set, update their attributes + if (containerId != 0 || slotId > BOOTS_SLOT || slotId < HELMET_SLOT || slotId == CHESTPLATE_SLOT) { + return; + } + + final EfficiencyAttributeStorage storage = wrapper.user().get(EfficiencyAttributeStorage.class); + Enchantments enchants = item.dataContainer().get(StructuredDataKey.ENCHANTMENTS); + EfficiencyAttributeStorage.ActiveEnchants active = storage.activeEnchants(); + active = switch (slotId) { + case HELMET_SLOT -> active.aquaAffinity(enchants == null ? 0 : enchants.getLevel(AQUA_AFFINITY_ID)); + case LEGGINGS_SLOT -> active.swiftSneak(enchants == null ? 0 : enchants.getLevel(SWIFT_SNEAK_ID)); + case BOOTS_SLOT -> active.depthStrider(enchants == null ? 0 : enchants.getLevel(DEPTH_STRIDER_ID)); + default -> active; + }; + storage.setEnchants(-1, wrapper.user(), active); + }); registerAdvancements1_20_3(ClientboundPackets1_20_5.UPDATE_ADVANCEMENTS); registerSetEquipment(ClientboundPackets1_20_5.SET_EQUIPMENT); registerContainerClick1_17_1(ServerboundPackets1_20_5.CONTAINER_CLICK); registerMerchantOffers1_20_5(ClientboundPackets1_20_5.MERCHANT_OFFERS); registerSetCreativeModeSlot(ServerboundPackets1_20_5.SET_CREATIVE_MODE_SLOT); - registerLevelParticles1_20_5(ClientboundPackets1_20_5.LEVEL_PARTICLES); - registerExplosion(ClientboundPackets1_20_5.EXPLODE); // Rewrites the included sound and particles protocol.registerClientbound(ClientboundPackets1_20_5.HORSE_SCREEN_OPEN, wrapper -> { wrapper.passthrough(Types.UNSIGNED_BYTE); // Container id @@ -113,12 +143,16 @@ public final class BlockItemPacketRewriter1_21 extends StructuredItemRewriter { @@ -52,22 +54,15 @@ public final class EntityPacketRewriter1_21 extends EntityRewriter { - final String type = Key.stripMinecraftNamespace(wrapper.passthrough(Types.STRING)); - final RegistryEntry[] entries = wrapper.passthrough(Types.REGISTRY_ENTRY_ARRAY); - if (type.equals("damage_type")) { - // Add required damage type - final CompoundTag campfireDamageType = new CompoundTag(); - campfireDamageType.putString("scaling", "when_caused_by_living_non_player"); - campfireDamageType.putString("message_id", "inFire"); - campfireDamageType.putFloat("exhaustion", 0.1F); - wrapper.set(Types.REGISTRY_ENTRY_ARRAY, 0, ArrayUtil.add(entries, new RegistryEntry("minecraft:campfire", campfireDamageType))); - } else { - handleRegistryData1_20_5(wrapper.user(), type, entries); - } - }); + final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol); + final CompoundTag campfireDamageType = new CompoundTag(); + campfireDamageType.putString("scaling", "when_caused_by_living_non_player"); + campfireDamageType.putString("message_id", "inFire"); + campfireDamageType.putFloat("exhaustion", 0.1F); + registryDataRewriter.addEntries("damage_type", new RegistryEntry("minecraft:campfire", campfireDamageType)); + protocol.registerClientbound(ClientboundConfigurationPackets1_20_5.REGISTRY_DATA, registryDataRewriter::handle); - protocol.registerClientbound(ClientboundConfigurationPackets1_20_5.FINISH_CONFIGURATION, wrapper -> { + protocol.registerFinishConfiguration(ClientboundConfigurationPackets1_20_5.FINISH_CONFIGURATION, wrapper -> { // Add new registries final PacketWrapper paintingRegistryPacket = wrapper.create(ClientboundConfigurationPackets1_20_5.REGISTRY_DATA); paintingRegistryPacket.write(Types.STRING, "minecraft:painting_variant"); @@ -116,7 +111,8 @@ public final class EntityPacketRewriter1_21 extends EntityRewriter wrapper.user().get(EfficiencyAttributeStorage.class).onLoginSent(wrapper.user())); + handler(wrapper -> wrapper.user().get(EfficiencyAttributeStorage.class) + .onLoginSent(wrapper.get(Types.INT, 0), wrapper.user())); } }); @@ -127,7 +123,49 @@ public final class EntityPacketRewriter1_21 extends EntityRewriter { + if (Via.getConfig().fix1_21PlacementRotation()) { + storePosition(wrapper); + storeOnGround(wrapper); + } + }); + protocol.registerServerbound(ServerboundPackets1_20_5.MOVE_PLAYER_ROT, wrapper -> { + if (Via.getConfig().fix1_21PlacementRotation()) { + wrapper.passthrough(Types.FLOAT); // Yaw + wrapper.passthrough(Types.FLOAT); // Pitch + storeOnGround(wrapper); + } + }); + protocol.registerServerbound(ServerboundPackets1_20_5.MOVE_PLAYER_POS_ROT, wrapper -> { + if (Via.getConfig().fix1_21PlacementRotation()) { + storePosition(wrapper); + wrapper.passthrough(Types.FLOAT); // Yaw + wrapper.passthrough(Types.FLOAT); // Pitch + storeOnGround(wrapper); + } + }); + protocol.registerServerbound(ServerboundPackets1_20_5.MOVE_PLAYER_STATUS_ONLY, wrapper -> { + if (Via.getConfig().fix1_21PlacementRotation()) { + storeOnGround(wrapper); + } + }); + } + + private void storePosition(final PacketWrapper wrapper) { + final double x = wrapper.passthrough(Types.DOUBLE); + final double y = wrapper.passthrough(Types.DOUBLE); + final double z = wrapper.passthrough(Types.DOUBLE); + wrapper.user().get(PlayerPositionStorage.class).setPosition(x, y, z); + } + + private void storeOnGround(final PacketWrapper wrapper) { + final boolean onGround = wrapper.passthrough(Types.BOOLEAN); + wrapper.user().get(PlayerPositionStorage.class).setOnGround(onGround); } @Override diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/storage/EfficiencyAttributeStorage.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/storage/EfficiencyAttributeStorage.java index 485e25399..60f059898 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/storage/EfficiencyAttributeStorage.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/storage/EfficiencyAttributeStorage.java @@ -45,25 +45,10 @@ public final class EfficiencyAttributeStorage implements StorableObject { private volatile boolean loginSent; private ActiveEnchants activeEnchants = DEFAULT; - public void setEnchants(final int entityId, final UserConnection connection, final int efficiency, final int soulSpeed, - final int swiftSneak, final int aquaAffinity, final int depthStrider) { - // Always called from the main thread - if (efficiency == activeEnchants.efficiency.level - && soulSpeed == activeEnchants.soulSpeed.level - && swiftSneak == activeEnchants.swiftSneak.level - && aquaAffinity == activeEnchants.aquaAffinity.level - && depthStrider == activeEnchants.depthStrider.level) { - return; - } - + public void setEnchants(final int entityId, final UserConnection connection, final ActiveEnchants enchants) { + if (activeEnchants == enchants) return; synchronized (lock) { - this.activeEnchants = new ActiveEnchants(entityId, - new ActiveEnchant(activeEnchants.efficiency, efficiency), - new ActiveEnchant(activeEnchants.soulSpeed, soulSpeed), - new ActiveEnchant(activeEnchants.swiftSneak, swiftSneak), - new ActiveEnchant(activeEnchants.aquaAffinity, aquaAffinity), - new ActiveEnchant(activeEnchants.depthStrider, depthStrider) - ); + this.activeEnchants = entityId == -1 ? enchants : enchants.withEntityId(entityId); this.attributesSent = false; } sendAttributesPacket(connection, false); @@ -73,7 +58,10 @@ public final class EfficiencyAttributeStorage implements StorableObject { return activeEnchants; } - public void onLoginSent(final UserConnection connection) { + public void onLoginSent(final int entityId, final UserConnection connection) { + synchronized (lock) { + activeEnchants = activeEnchants.withEntityId(entityId); + } // Always called from the netty thread this.loginSent = true; sendAttributesPacket(connection, false); @@ -128,6 +116,59 @@ public final class EfficiencyAttributeStorage implements StorableObject { public record ActiveEnchants(int entityId, ActiveEnchant efficiency, ActiveEnchant soulSpeed, ActiveEnchant swiftSneak, ActiveEnchant aquaAffinity, ActiveEnchant depthStrider) { + private ActiveEnchants withEntityId(int entityId) { + return this.entityId == entityId ? this : new ActiveEnchants(entityId, + efficiency, + soulSpeed, + swiftSneak, + aquaAffinity, + depthStrider); + } + + public ActiveEnchants efficiency(int level) { + return efficiency.level == level ? this : new ActiveEnchants(entityId, + new ActiveEnchant(efficiency, level), + soulSpeed, + swiftSneak, + aquaAffinity, + depthStrider); + } + + public ActiveEnchants soulSpeed(int level) { + return soulSpeed.level == level ? this : new ActiveEnchants(entityId, + efficiency, + new ActiveEnchant(soulSpeed, level), + swiftSneak, + aquaAffinity, + depthStrider); + } + + public ActiveEnchants swiftSneak(int level) { + return swiftSneak.level == level ? this : new ActiveEnchants(entityId, + efficiency, + soulSpeed, + new ActiveEnchant(swiftSneak, level), + aquaAffinity, + depthStrider); + } + + public ActiveEnchants aquaAffinity(int level) { + return aquaAffinity.level == level ? this : new ActiveEnchants(entityId, + efficiency, + soulSpeed, + swiftSneak, + new ActiveEnchant(aquaAffinity, level), + depthStrider); + } + + public ActiveEnchants depthStrider(int level) { + return depthStrider.level == level ? this : new ActiveEnchants(entityId, + efficiency, + soulSpeed, + swiftSneak, + aquaAffinity, + new ActiveEnchant(depthStrider, level)); + } } public record ActiveEnchant(EnchantAttributeModifier modifier, int previousLevel, int level) { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/storage/PlayerPositionStorage.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/storage/PlayerPositionStorage.java new file mode 100644 index 000000000..beaf4beec --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20_5to1_21/storage/PlayerPositionStorage.java @@ -0,0 +1,54 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_20_5to1_21.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; + +public final class PlayerPositionStorage implements StorableObject { + + private double x; + private double y; + private double z; + private boolean onGround; + + public double x() { + return x; + } + + public double y() { + return y; + } + + public double z() { + return z; + } + + public void setPosition(final double x, final double y, final double z) { + this.x = x; + this.y = y; + this.z = z; + } + + public boolean onGround() { + return onGround; + } + + public void setOnGround(final boolean onGround) { + this.onGround = onGround; + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/Protocol1_20To1_20_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/Protocol1_20To1_20_2.java index f1d9ee7f5..51ea5d553 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/Protocol1_20To1_20_2.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/Protocol1_20To1_20_2.java @@ -53,6 +53,7 @@ import com.viaversion.viaversion.protocols.v1_20to1_20_2.storage.ConfigurationSt import com.viaversion.viaversion.protocols.v1_20to1_20_2.storage.ConfigurationState.BridgePhase; import com.viaversion.viaversion.protocols.v1_20to1_20_2.storage.LastResourcePack; import com.viaversion.viaversion.protocols.v1_20to1_20_2.storage.LastTags; +import com.viaversion.viaversion.rewriter.ParticleRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; import com.viaversion.viaversion.util.Key; @@ -64,6 +65,7 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol particleRewriter = new ParticleRewriter<>(this); private final TagRewriter tagRewriter = new TagRewriter<>(this); public Protocol1_20To1_20_2() { @@ -79,6 +81,8 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol { - tagRewriter.handleGeneric(wrapper); - wrapper.resetReader(); - wrapper.user().put(new LastTags(wrapper)); - }); + registerClientbound(State.CONFIGURATION, ClientboundConfigurationPackets1_20_2.UPDATE_TAGS, this::handleConfigTags); registerClientbound(ClientboundPackets1_19_4.SET_DISPLAY_OBJECTIVE, wrapper -> { final byte slot = wrapper.read(Types.BYTE); @@ -144,7 +144,7 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol { + registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> { wrapper.user().get(ConfigurationState.class).setBridgePhase(BridgePhase.PROFILE_SENT); wrapper.user().getProtocolInfo().setServerState(State.PLAY); }); @@ -225,6 +225,15 @@ public final class Protocol1_20To1_20_2 extends AbstractProtocol getParticleRewriter() { + return particleRewriter; + } + @Override public TagRewriter getTagRewriter() { return tagRewriter; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/rewriter/BlockItemPacketRewriter1_20_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/rewriter/BlockItemPacketRewriter1_20_2.java index 5e843c7c6..2bbf619bd 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/rewriter/BlockItemPacketRewriter1_20_2.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/rewriter/BlockItemPacketRewriter1_20_2.java @@ -24,13 +24,13 @@ import com.viaversion.nbt.tag.StringTag; import com.viaversion.nbt.tag.Tag; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.data.entity.EntityTracker; +import com.viaversion.viaversion.api.minecraft.ChunkPosition; import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity; import com.viaversion.viaversion.api.minecraft.chunks.Chunk; import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection; import com.viaversion.viaversion.api.minecraft.chunks.DataPalette; import com.viaversion.viaversion.api.minecraft.chunks.PaletteType; import com.viaversion.viaversion.api.minecraft.item.Item; -import com.viaversion.viaversion.api.minecraft.ChunkPosition; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; @@ -39,8 +39,8 @@ import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2; import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.packet.ClientboundPackets1_19_4; import com.viaversion.viaversion.protocols.v1_19_3to1_19_4.rewriter.RecipeRewriter1_19_4; import com.viaversion.viaversion.protocols.v1_20to1_20_2.Protocol1_20To1_20_2; -import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundPackets1_20_2; import com.viaversion.viaversion.protocols.v1_20to1_20_2.data.PotionEffects1_20_2; +import com.viaversion.viaversion.protocols.v1_20to1_20_2.packet.ServerboundPackets1_20_2; import com.viaversion.viaversion.rewriter.BlockRewriter; import com.viaversion.viaversion.rewriter.ItemRewriter; import com.viaversion.viaversion.util.MathUtil; @@ -65,7 +65,6 @@ public final class BlockItemPacketRewriter1_20_2 extends ItemRewriter { // Effects start at 1 before 1.20.2 diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/storage/LastTags.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/storage/LastTags.java index 3442a6f78..376584780 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/storage/LastTags.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_20to1_20_2/storage/LastTags.java @@ -31,6 +31,7 @@ import java.util.List; public class LastTags implements StorableObject { private final List registryTags = new ArrayList<>(); + private boolean sentDuringConfigPhase; public LastTags(final PacketWrapper wrapper) { final int length = wrapper.passthrough(Types.VAR_INT); @@ -65,6 +66,14 @@ public class LastTags implements StorableObject { packet.send(Protocol1_20To1_20_2.class); } + public void setSentDuringConfigPhase(final boolean sentDuringConfigPhase) { + this.sentDuringConfigPhase = sentDuringConfigPhase; + } + + public boolean sentDuringConfigPhase() { + return sentDuringConfigPhase; + } + private record RegistryTags(String registryKey, List tags) { } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/Protocol1_21_2To1_21_4.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/Protocol1_21_2To1_21_4.java new file mode 100644 index 000000000..4b1a581a4 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/Protocol1_21_2To1_21_4.java @@ -0,0 +1,244 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21_2to1_21_4; + +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.Particle; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_4; +import com.viaversion.viaversion.api.platform.providers.ViaProviders; +import com.viaversion.viaversion.api.protocol.AbstractProtocol; +import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider; +import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.misc.ParticleType; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.api.type.types.version.Types1_21_4; +import com.viaversion.viaversion.data.entity.EntityTrackerBase; +import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.provider.PickItemProvider; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.rewriter.BlockItemPacketRewriter1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.rewriter.ComponentRewriter1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.rewriter.EntityPacketRewriter1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.rewriter.ParticleRewriter1_21_4; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPacket1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPackets1_21_2; +import com.viaversion.viaversion.rewriter.AttributeRewriter; +import com.viaversion.viaversion.rewriter.ComponentRewriter; +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 java.util.BitSet; + +import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap; + +public final class Protocol1_21_2To1_21_4 extends AbstractProtocol { + + public static final MappingData MAPPINGS = new MappingDataBase("1.21.2", "1.21.4"); + private final EntityPacketRewriter1_21_4 entityRewriter = new EntityPacketRewriter1_21_4(this); + private final BlockItemPacketRewriter1_21_4 itemRewriter = new BlockItemPacketRewriter1_21_4(this); + private final ParticleRewriter particleRewriter = new ParticleRewriter1_21_4(this); + private final TagRewriter tagRewriter = new TagRewriter<>(this); + private final ComponentRewriter componentRewriter = new ComponentRewriter1_21_4(this); + + public Protocol1_21_2To1_21_4() { + super(ClientboundPacket1_21_2.class, ClientboundPacket1_21_2.class, ServerboundPacket1_21_2.class, ServerboundPacket1_21_4.class); + } + + @Override + protected void registerPackets() { + super.registerPackets(); + + tagRewriter.registerGeneric(ClientboundPackets1_21_2.UPDATE_TAGS); + tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS); + + componentRewriter.registerOpenScreen(ClientboundPackets1_21_2.OPEN_SCREEN); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_ACTION_BAR_TEXT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_TITLE_TEXT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SET_SUBTITLE_TEXT); + componentRewriter.registerBossEvent(ClientboundPackets1_21_2.BOSS_EVENT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISCONNECT); + componentRewriter.registerTabList(ClientboundPackets1_21_2.TAB_LIST); + componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21_2.PLAYER_COMBAT_KILL); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.SYSTEM_CHAT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21_2.DISGUISED_CHAT); + componentRewriter.registerPing(); + + particleRewriter.registerExplode1_21_2(ClientboundPackets1_21_2.EXPLODE); + registerClientbound(ClientboundPackets1_21_2.LEVEL_PARTICLES, wrapper -> { + wrapper.passthrough(Types.BOOLEAN); // Override limiter + wrapper.write(Types.BOOLEAN, false); // Always show + wrapper.passthrough(Types.DOUBLE); // X + wrapper.passthrough(Types.DOUBLE); // Y + wrapper.passthrough(Types.DOUBLE); // Z + wrapper.passthrough(Types.FLOAT); // Offset X + wrapper.passthrough(Types.FLOAT); // Offset Y + wrapper.passthrough(Types.FLOAT); // Offset Z + wrapper.passthrough(Types.FLOAT); // Particle Data + wrapper.passthrough(Types.INT); // Particle Count + + final Particle particle = wrapper.passthroughAndMap(Types1_21_2.PARTICLE, Types1_21_4.PARTICLE); + particleRewriter.rewriteParticle(wrapper.user(), particle); + }); + + final SoundRewriter soundRewriter = new SoundRewriter<>(this); + soundRewriter.registerSound1_19_3(ClientboundPackets1_21_2.SOUND); + soundRewriter.registerSound1_19_3(ClientboundPackets1_21_2.SOUND_ENTITY); + + new StatisticsRewriter<>(this).register(ClientboundPackets1_21_2.AWARD_STATS); + new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21_2.UPDATE_ATTRIBUTES); + + registerClientbound(ClientboundPackets1_21_2.PLAYER_INFO_UPDATE, wrapper -> { + // Added "show hat" - true by default, keep it like that + final BitSet actions = wrapper.passthroughAndMap(Types.PROFILE_ACTIONS_ENUM1_21_2, Types.PROFILE_ACTIONS_ENUM1_21_4); + if (!actions.get(5)) { // Update display name + return; + } + + final int entries = wrapper.passthrough(Types.VAR_INT); + for (int i = 0; i < entries; i++) { + wrapper.passthrough(Types.UUID); + if (actions.get(0)) { + wrapper.passthrough(Types.STRING); // Player Name + + final int properties = wrapper.passthrough(Types.VAR_INT); + for (int j = 0; j < properties; j++) { + wrapper.passthrough(Types.STRING); // Name + wrapper.passthrough(Types.STRING); // Value + wrapper.passthrough(Types.OPTIONAL_STRING); // Signature + } + } + if (actions.get(1) && wrapper.passthrough(Types.BOOLEAN)) { + wrapper.passthrough(Types.UUID); // Session UUID + wrapper.passthrough(Types.PROFILE_KEY); + } + if (actions.get(2)) { + wrapper.passthrough(Types.VAR_INT); // Gamemode + } + if (actions.get(3)) { + wrapper.passthrough(Types.BOOLEAN); // Listed + } + if (actions.get(4)) { + wrapper.passthrough(Types.VAR_INT); // Latency + } + componentRewriter.processTag(wrapper.user(), wrapper.passthrough(Types.OPTIONAL_TAG)); + if (actions.get(6)) { + wrapper.passthrough(Types.VAR_INT); // List order + } + } + }); + } + + @Override + protected void onMappingDataLoaded() { + EntityTypes1_21_4.initialize(this); + Types1_21_4.PARTICLE.filler(this) + .reader("block", ParticleType.Readers.BLOCK) + .reader("block_marker", ParticleType.Readers.BLOCK) + .reader("dust_pillar", ParticleType.Readers.BLOCK) + .reader("falling_dust", ParticleType.Readers.BLOCK) + .reader("block_crumble", ParticleType.Readers.BLOCK) + .reader("dust", ParticleType.Readers.DUST1_21_2) + .reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION1_21_2) + .reader("vibration", ParticleType.Readers.VIBRATION1_20_3) + .reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE) + .reader("shriek", ParticleType.Readers.SHRIEK) + .reader("entity_effect", ParticleType.Readers.COLOR) + .reader("trail", ParticleType.Readers.TRAIL1_21_4) + .reader("item", ParticleType.Readers.item(itemRewriter.mappedItemType())); + Types1_21_4.STRUCTURED_DATA.filler(this).add(StructuredDataKey.CUSTOM_DATA, StructuredDataKey.MAX_STACK_SIZE, StructuredDataKey.MAX_DAMAGE, + StructuredDataKey.UNBREAKABLE, StructuredDataKey.RARITY, StructuredDataKey.HIDE_TOOLTIP, StructuredDataKey.DAMAGE_RESISTANT, + StructuredDataKey.CUSTOM_NAME, StructuredDataKey.LORE, StructuredDataKey.ENCHANTMENTS, StructuredDataKey.CAN_PLACE_ON, + StructuredDataKey.CAN_BREAK, StructuredDataKey.CUSTOM_MODEL_DATA1_21_4, StructuredDataKey.HIDE_ADDITIONAL_TOOLTIP, + StructuredDataKey.REPAIR_COST, StructuredDataKey.CREATIVE_SLOT_LOCK, StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, + StructuredDataKey.INTANGIBLE_PROJECTILE, StructuredDataKey.STORED_ENCHANTMENTS, StructuredDataKey.DYED_COLOR, + StructuredDataKey.MAP_COLOR, StructuredDataKey.MAP_ID, StructuredDataKey.MAP_DECORATIONS, StructuredDataKey.MAP_POST_PROCESSING, + StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, StructuredDataKey.WRITABLE_BOOK_CONTENT, + StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_4, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA, + StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA, StructuredDataKey.INSTRUMENT1_21_2, + StructuredDataKey.RECIPES, StructuredDataKey.LODESTONE_TRACKER, StructuredDataKey.FIREWORK_EXPLOSION, StructuredDataKey.FIREWORKS, + StructuredDataKey.PROFILE, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR, + StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES, StructuredDataKey.LOCK, + StructuredDataKey.CONTAINER_LOOT, StructuredDataKey.TOOL, StructuredDataKey.ITEM_NAME, StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, + StructuredDataKey.FOOD1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE, StructuredDataKey.ATTRIBUTE_MODIFIERS1_21, + StructuredDataKey.REPAIRABLE, StructuredDataKey.ENCHANTABLE, StructuredDataKey.CONSUMABLE1_21_2, + StructuredDataKey.USE_COOLDOWN, StructuredDataKey.DAMAGE, StructuredDataKey.EQUIPPABLE, StructuredDataKey.ITEM_MODEL, + StructuredDataKey.GLIDER, StructuredDataKey.TOOLTIP_STYLE, StructuredDataKey.DEATH_PROTECTION, + // Volatile thanks to containing item + StructuredDataKey.CHARGED_PROJECTILES1_21_4, StructuredDataKey.BUNDLE_CONTENTS1_21_4, StructuredDataKey.CONTAINER1_21_4, StructuredDataKey.USE_REMAINDER1_21_4); + super.onMappingDataLoaded(); + } + + @Override + public void register(final ViaProviders providers) { + providers.register(PickItemProvider.class, new PickItemProvider()); + } + + @Override + public void init(final UserConnection connection) { + addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_4.PLAYER)); + } + + @Override + public MappingData getMappingData() { + return MAPPINGS; + } + + @Override + public EntityPacketRewriter1_21_4 getEntityRewriter() { + return entityRewriter; + } + + @Override + public BlockItemPacketRewriter1_21_4 getItemRewriter() { + return itemRewriter; + } + + @Override + public ParticleRewriter getParticleRewriter() { + return particleRewriter; + } + + @Override + public TagRewriter getTagRewriter() { + return tagRewriter; + } + + @Override + public ComponentRewriter getComponentRewriter() { + return componentRewriter; + } + + @Override + protected PacketTypesProvider createPacketTypesProvider() { + return new SimplePacketTypesProvider<>( + packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class), + packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class), + packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_21_2.class, ServerboundConfigurationPackets1_20_5.class), + packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_4.class, ServerboundConfigurationPackets1_20_5.class) + ); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/packet/ServerboundPacket1_21_4.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/packet/ServerboundPacket1_21_4.java new file mode 100644 index 000000000..6b131eabd --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/packet/ServerboundPacket1_21_4.java @@ -0,0 +1,23 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet; + +import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; + +public interface ServerboundPacket1_21_4 extends ServerboundPacketType { +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/packet/ServerboundPackets1_21_4.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/packet/ServerboundPackets1_21_4.java new file mode 100644 index 000000000..29e3065cd --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/packet/ServerboundPackets1_21_4.java @@ -0,0 +1,94 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet; + +public enum ServerboundPackets1_21_4 implements ServerboundPacket1_21_4 { + + ACCEPT_TELEPORTATION, // 0x00 + BLOCK_ENTITY_TAG_QUERY, // 0x01 + BUNDLE_ITEM_SELECTED, // 0x02 + CHANGE_DIFFICULTY, // 0x03 + CHAT_ACK, // 0x04 + CHAT_COMMAND, // 0x05 + CHAT_COMMAND_SIGNED, // 0x06 + CHAT, // 0x07 + CHAT_SESSION_UPDATE, // 0x08 + CHUNK_BATCH_RECEIVED, // 0x09 + CLIENT_COMMAND, // 0x0A + CLIENT_TICK_END, // 0x0B + CLIENT_INFORMATION, // 0x0C + COMMAND_SUGGESTION, // 0x0D + CONFIGURATION_ACKNOWLEDGED, // 0x0E + CONTAINER_BUTTON_CLICK, // 0x0F + CONTAINER_CLICK, // 0x10 + CONTAINER_CLOSE, // 0x11 + CONTAINER_SLOT_STATE_CHANGED, // 0x12 + COOKIE_RESPONSE, // 0x13 + CUSTOM_PAYLOAD, // 0x14 + DEBUG_SAMPLE_SUBSCRIPTION, // 0x15 + EDIT_BOOK, // 0x16 + ENTITY_TAG_QUERY, // 0x17 + INTERACT, // 0x18 + JIGSAW_GENERATE, // 0x19 + KEEP_ALIVE, // 0x1A + LOCK_DIFFICULTY, // 0x1B + MOVE_PLAYER_POS, // 0x1C + MOVE_PLAYER_POS_ROT, // 0x1D + MOVE_PLAYER_ROT, // 0x1E + MOVE_PLAYER_STATUS_ONLY, // 0x1F + MOVE_VEHICLE, // 0x20 + PADDLE_BOAT, // 0x21 + PICK_ITEM_FROM_BLOCK, // 0x22 + PICK_ITEM_FROM_ENTITY, // 0x23 + PING_REQUEST, // 0x24 + PLACE_RECIPE, // 0x25 + PLAYER_ABILITIES, // 0x26 + PLAYER_ACTION, // 0x27 + PLAYER_COMMAND, // 0x28 + PLAYER_INPUT, // 0x29 + PLAYER_LOADED, // 0x2A + PONG, // 0x2B + RECIPE_BOOK_CHANGE_SETTINGS, // 0x2C + RECIPE_BOOK_SEEN_RECIPE, // 0x2D + RENAME_ITEM, // 0x2E + RESOURCE_PACK, // 0x2F + SEEN_ADVANCEMENTS, // 0x30 + SELECT_TRADE, // 0x31 + SET_BEACON, // 0x32 + SET_CARRIED_ITEM, // 0x33 + SET_COMMAND_BLOCK, // 0x34 + SET_COMMAND_MINECART, // 0x35 + SET_CREATIVE_MODE_SLOT, // 0x36 + SET_JIGSAW_BLOCK, // 0x37 + SET_STRUCTURE_BLOCK, // 0x38 + SIGN_UPDATE, // 0x39 + SWING, // 0x3A + TELEPORT_TO_ENTITY, // 0x3B + USE_ITEM_ON, // 0x3C + USE_ITEM; // 0x3D + + @Override + public int getId() { + return ordinal(); + } + + @Override + public String getName() { + return name(); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/provider/PickItemProvider.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/provider/PickItemProvider.java new file mode 100644 index 000000000..c38f5799a --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/provider/PickItemProvider.java @@ -0,0 +1,31 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21_2to1_21_4.provider; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.BlockPosition; +import com.viaversion.viaversion.api.platform.providers.Provider; + +public class PickItemProvider implements Provider { + + public void pickItemFromBlock(final UserConnection connection, final BlockPosition blockPosition, final boolean includeData) { + } + + public void pickItemFromEntity(final UserConnection connection, final int entityId, final boolean includeData) { + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/BlockItemPacketRewriter1_21_4.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/BlockItemPacketRewriter1_21_4.java new file mode 100644 index 000000000..38aff3b2a --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/BlockItemPacketRewriter1_21_4.java @@ -0,0 +1,172 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21_2to1_21_4.rewriter; + +import com.viaversion.nbt.tag.CompoundTag; +import com.viaversion.nbt.tag.IntTag; +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.minecraft.Holder; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2; +import com.viaversion.viaversion.api.minecraft.item.data.CustomModelData1_21_4; +import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.api.type.types.version.Types1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPacket1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.provider.PickItemProvider; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2; +import com.viaversion.viaversion.rewriter.BlockRewriter; +import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter; +import com.viaversion.viaversion.rewriter.StructuredItemRewriter; + +public final class BlockItemPacketRewriter1_21_4 extends StructuredItemRewriter { + + public BlockItemPacketRewriter1_21_4(final Protocol1_21_2To1_21_4 protocol) { + super(protocol, + Types1_21_2.ITEM, Types1_21_2.ITEM_ARRAY, Types1_21_4.ITEM, Types1_21_4.ITEM_ARRAY, + Types1_21_2.ITEM_COST, Types1_21_2.OPTIONAL_ITEM_COST, Types1_21_4.ITEM_COST, Types1_21_4.OPTIONAL_ITEM_COST + ); + } + + @Override + public void registerPackets() { + final BlockRewriter blockRewriter = BlockRewriter.for1_20_2(protocol); + blockRewriter.registerBlockEvent(ClientboundPackets1_21_2.BLOCK_EVENT); + blockRewriter.registerBlockUpdate(ClientboundPackets1_21_2.BLOCK_UPDATE); + blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21_2.SECTION_BLOCKS_UPDATE); + blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21_2.LEVEL_EVENT, 2001); + blockRewriter.registerLevelChunk1_19(ClientboundPackets1_21_2.LEVEL_CHUNK_WITH_LIGHT, ChunkType1_20_2::new); + blockRewriter.registerBlockEntityData(ClientboundPackets1_21_2.BLOCK_ENTITY_DATA); + + protocol.registerClientbound(ClientboundPackets1_21_2.SET_HELD_SLOT, wrapper -> { + final byte slot = wrapper.read(Types.BYTE); + wrapper.write(Types.VAR_INT, (int) slot); + }); + + protocol.registerServerbound(ServerboundPackets1_21_4.PICK_ITEM_FROM_BLOCK, null, wrapper -> { + final BlockPosition blockPosition = wrapper.read(Types.BLOCK_POSITION1_14); + final boolean includeData = wrapper.read(Types.BOOLEAN); + Via.getManager().getProviders().get(PickItemProvider.class).pickItemFromBlock(wrapper.user(), blockPosition, includeData); + wrapper.cancel(); + }); + protocol.registerServerbound(ServerboundPackets1_21_4.PICK_ITEM_FROM_ENTITY, null, wrapper -> { + final int entityId = wrapper.read(Types.VAR_INT); + final boolean includeData = wrapper.read(Types.BOOLEAN); + Via.getManager().getProviders().get(PickItemProvider.class).pickItemFromEntity(wrapper.user(), entityId, includeData); + wrapper.cancel(); + }); + + protocol.registerClientbound(ClientboundPackets1_21_2.SET_CURSOR_ITEM, this::passthroughClientboundItem); + registerSetPlayerInventory(ClientboundPackets1_21_2.SET_PLAYER_INVENTORY); + registerCooldown1_21_2(ClientboundPackets1_21_2.COOLDOWN); + registerSetContent1_21_2(ClientboundPackets1_21_2.CONTAINER_SET_CONTENT); + registerSetSlot1_21_2(ClientboundPackets1_21_2.CONTAINER_SET_SLOT); + registerAdvancements1_20_3(ClientboundPackets1_21_2.UPDATE_ADVANCEMENTS); + registerSetEquipment(ClientboundPackets1_21_2.SET_EQUIPMENT); + registerContainerClick1_21_2(ServerboundPackets1_21_4.CONTAINER_CLICK); + registerMerchantOffers1_20_5(ClientboundPackets1_21_2.MERCHANT_OFFERS); + registerSetCreativeModeSlot(ServerboundPackets1_21_4.SET_CREATIVE_MODE_SLOT); + + final RecipeDisplayRewriter recipeRewriter = new RecipeDisplayRewriter<>(protocol); + recipeRewriter.registerUpdateRecipes(ClientboundPackets1_21_2.UPDATE_RECIPES); + recipeRewriter.registerRecipeBookAdd(ClientboundPackets1_21_2.RECIPE_BOOK_ADD); + recipeRewriter.registerPlaceGhostRecipe(ClientboundPackets1_21_2.PLACE_GHOST_RECIPE); + } + + @Override + public Item handleItemToClient(final UserConnection connection, final Item item) { + super.handleItemToClient(connection, item); + + final StructuredDataContainer dataContainer = item.dataContainer(); + final Integer modelData = dataContainer.get(StructuredDataKey.CUSTOM_MODEL_DATA1_20_5); + if (modelData != null) { + dataContainer.set(StructuredDataKey.CUSTOM_MODEL_DATA1_21_4, new CustomModelData1_21_4( + new float[]{modelData.floatValue()}, + new boolean[0], + new String[0], + new int[0] + )); + saveTag(createCustomTag(item), new IntTag(modelData), "custom_model_data"); + } + + updateItemData(item); + + // Add data components to fix issues in older protocols + appendItemDataFixComponents(connection, item); + return item; + } + + @Override + public Item handleItemToServer(final UserConnection connection, final Item item) { + super.handleItemToServer(connection, item); + + final StructuredDataContainer dataContainer = item.dataContainer(); + final CompoundTag customData = dataContainer.get(StructuredDataKey.CUSTOM_DATA); + if (customData != null) { + if (customData.remove(nbtTagName("custom_model_data")) instanceof final IntTag customModelData) { + dataContainer.set(StructuredDataKey.CUSTOM_MODEL_DATA1_20_5, customModelData.asInt()); + removeCustomTag(dataContainer, customData); + } + } + + downgradeItemData(item); + return item; + } + + private void appendItemDataFixComponents(final UserConnection connection, final Item item) { + final ProtocolVersion serverVersion = connection.getProtocolInfo().serverProtocolVersion(); + if (serverVersion.olderThanOrEqualTo(ProtocolVersion.v1_8)) { + if (item.identifier() == 849 || item.identifier() == 854 || item.identifier() == 859 || item.identifier() == 864 || item.identifier() == 869) { // swords + // Make sword "eatable" to enable clientside instant blocking on 1.8. Set consume animation to block, + // and consume time really high, so the eating animation doesn't play + item.dataContainer().set(StructuredDataKey.CONSUMABLE1_21_2, + new Consumable1_21_2(3600, 3, Holder.of(0), false, new Consumable1_21_2.ConsumeEffect[0])); + } + } + } + + public static void updateItemData(final Item item) { + final StructuredDataContainer dataContainer = item.dataContainer(); + dataContainer.replaceKey(StructuredDataKey.CHARGED_PROJECTILES1_21_2, StructuredDataKey.CHARGED_PROJECTILES1_21_4); + dataContainer.replaceKey(StructuredDataKey.BUNDLE_CONTENTS1_21_2, StructuredDataKey.BUNDLE_CONTENTS1_21_4); + dataContainer.replaceKey(StructuredDataKey.CONTAINER1_21_2, StructuredDataKey.CONTAINER1_21_4); + dataContainer.replaceKey(StructuredDataKey.USE_REMAINDER1_21_2, StructuredDataKey.USE_REMAINDER1_21_4); + dataContainer.replaceKey(StructuredDataKey.TRIM1_21_2, StructuredDataKey.TRIM1_21_4); + dataContainer.remove(StructuredDataKey.CUSTOM_MODEL_DATA1_20_5); + } + + public static void downgradeItemData(final Item item) { + final StructuredDataContainer dataContainer = item.dataContainer(); + dataContainer.replaceKey(StructuredDataKey.CHARGED_PROJECTILES1_21_4, StructuredDataKey.CHARGED_PROJECTILES1_21_2); + dataContainer.replaceKey(StructuredDataKey.BUNDLE_CONTENTS1_21_4, StructuredDataKey.BUNDLE_CONTENTS1_21_2); + dataContainer.replaceKey(StructuredDataKey.CONTAINER1_21_4, StructuredDataKey.CONTAINER1_21_2); + dataContainer.replaceKey(StructuredDataKey.USE_REMAINDER1_21_4, StructuredDataKey.USE_REMAINDER1_21_2); + dataContainer.replaceKey(StructuredDataKey.TRIM1_21_4, StructuredDataKey.TRIM1_21_2); + dataContainer.remove(StructuredDataKey.CUSTOM_MODEL_DATA1_21_4); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/ComponentRewriter1_21_4.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/ComponentRewriter1_21_4.java new file mode 100644 index 000000000..aca4cad7b --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/ComponentRewriter1_21_4.java @@ -0,0 +1,48 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21_2to1_21_4.rewriter; + +import com.viaversion.nbt.tag.CompoundTag; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_4; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2; +import com.viaversion.viaversion.rewriter.ComponentRewriter; +import com.viaversion.viaversion.util.SerializerVersion; +import com.viaversion.viaversion.util.TagUtil; + +public final class ComponentRewriter1_21_4 extends ComponentRewriter { + + public ComponentRewriter1_21_4(final Protocol1_21_2To1_21_4 protocol) { + super(protocol, ReadType.NBT); + } + + @Override + protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) { + super.handleShowItem(connection, itemTag, componentsTag); + if (componentsTag == null) { + return; + } + + TagUtil.removeNamespaced(componentsTag, "custom_model_data"); + } + + @Override + protected SerializerVersion inputSerializerVersion() { + return SerializerVersion.V1_20_5; + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/EntityPacketRewriter1_21_4.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/EntityPacketRewriter1_21_4.java new file mode 100644 index 000000000..68006430f --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/EntityPacketRewriter1_21_4.java @@ -0,0 +1,151 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +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; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.api.type.types.version.Types1_21_4; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.Protocol1_21_2To1_21_4; +import com.viaversion.viaversion.protocols.v1_21_2to1_21_4.packet.ServerboundPackets1_21_4; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2; +import com.viaversion.viaversion.rewriter.EntityRewriter; +import com.viaversion.viaversion.rewriter.RegistryDataRewriter; +import com.viaversion.viaversion.util.Key; + +public final class EntityPacketRewriter1_21_4 extends EntityRewriter { + + public EntityPacketRewriter1_21_4(final Protocol1_21_2To1_21_4 protocol) { + super(protocol); + } + + @Override + public void registerPackets() { + registerTrackerWithData1_19(ClientboundPackets1_21_2.ADD_ENTITY, EntityTypes1_21_4.FALLING_BLOCK); + registerSetEntityData(ClientboundPackets1_21_2.SET_ENTITY_DATA, Types1_21_2.ENTITY_DATA_LIST, Types1_21_4.ENTITY_DATA_LIST); + 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 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); + } + }; + protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle); + + protocol.registerClientbound(ClientboundPackets1_21_2.LOGIN, wrapper -> { + final int entityId = wrapper.passthrough(Types.INT); // Entity id + wrapper.passthrough(Types.BOOLEAN); // Hardcore + wrapper.passthrough(Types.STRING_ARRAY); // World List + wrapper.passthrough(Types.VAR_INT); // Max players + wrapper.passthrough(Types.VAR_INT); // View distance + wrapper.passthrough(Types.VAR_INT); // Simulation distance + wrapper.passthrough(Types.BOOLEAN); // Reduced debug info + wrapper.passthrough(Types.BOOLEAN); // Show death screen + wrapper.passthrough(Types.BOOLEAN); // Limited crafting + + final int dimensionId = wrapper.passthrough(Types.VAR_INT); + final String world = wrapper.passthrough(Types.STRING); + trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); + + trackPlayer(wrapper.user(), entityId); + }); + + protocol.registerClientbound(ClientboundPackets1_21_2.RESPAWN, wrapper -> { + final int dimensionId = wrapper.passthrough(Types.VAR_INT); + final String world = wrapper.passthrough(Types.STRING); + trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); // Tracks world height and name for chunk data and entity (un)tracking + }); + + protocol.registerServerbound(ServerboundPackets1_21_4.MOVE_VEHICLE, wrapper -> { + wrapper.passthrough(Types.DOUBLE); // X + wrapper.passthrough(Types.DOUBLE); // Y + wrapper.passthrough(Types.DOUBLE); // Z + wrapper.passthrough(Types.FLOAT); // Yaw + wrapper.passthrough(Types.FLOAT); // Pitch + wrapper.read(Types.BOOLEAN); // On ground + }); + protocol.cancelServerbound(ServerboundPackets1_21_4.PLAYER_LOADED); + } + + @Override + protected void registerRewrites() { + filter().mapDataType(Types1_21_4.ENTITY_DATA_TYPES::byId); + + registerEntityDataTypeHandler( + Types1_21_4.ENTITY_DATA_TYPES.itemType, + Types1_21_4.ENTITY_DATA_TYPES.blockStateType, + Types1_21_4.ENTITY_DATA_TYPES.optionalBlockStateType, + Types1_21_4.ENTITY_DATA_TYPES.particleType, + Types1_21_4.ENTITY_DATA_TYPES.particlesType, + Types1_21_4.ENTITY_DATA_TYPES.componentType, + Types1_21_4.ENTITY_DATA_TYPES.optionalComponentType + ); + registerBlockStateHandler(EntityTypes1_21_4.ABSTRACT_MINECART, 11); + + filter().type(EntityTypes1_21_4.CREAKING).addIndex(18); // Is tearing down + filter().type(EntityTypes1_21_4.SALMON).index(17).handler((event, data) -> { + final String type = data.value(); + final int typeId = switch (type) { + case "small" -> 0; + case "large" -> 2; + default -> 1; // medium + }; + data.setTypeAndValue(Types1_21_4.ENTITY_DATA_TYPES.varIntType, typeId); + }); + } + + @Override + public void onMappingDataLoaded() { + mapTypes(); + } + + @Override + public EntityType typeFromId(final int type) { + return EntityTypes1_21_4.getTypeFromId(type); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/ParticleRewriter1_21_4.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/ParticleRewriter1_21_4.java new file mode 100644 index 000000000..3890f83a5 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21_2to1_21_4/rewriter/ParticleRewriter1_21_4.java @@ -0,0 +1,46 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21_2to1_21_4.rewriter; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.Particle; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.api.type.types.version.Types1_21_4; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2; +import com.viaversion.viaversion.rewriter.ParticleRewriter; +import java.util.concurrent.ThreadLocalRandom; + +public final class ParticleRewriter1_21_4 extends ParticleRewriter { + + public ParticleRewriter1_21_4(final Protocol protocol) { + super(protocol, Types1_21_2.PARTICLE, Types1_21_4.PARTICLE); + } + + @Override + public void rewriteParticle(final UserConnection connection, final Particle particle) { + super.rewriteParticle(connection, particle); + + final String identifier = protocol.getMappingData().getParticleMappings().mappedIdentifier(particle.id()); + if ("minecraft:trail".equals(identifier)) { + // Duration + particle.add(Types.VAR_INT, ThreadLocalRandom.current().nextInt(40) + 10); + } + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/Protocol1_21To1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/Protocol1_21To1_21_2.java new file mode 100644 index 000000000..13221e0a9 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/Protocol1_21To1_21_2.java @@ -0,0 +1,292 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.MappingData; +import com.viaversion.viaversion.api.data.MappingDataBase; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_2; +import com.viaversion.viaversion.api.protocol.AbstractProtocol; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider; +import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import com.viaversion.viaversion.api.rewriter.ComponentRewriter; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.misc.ParticleType; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets; +import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5; +import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5; +import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPacket1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPacket1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPackets1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.BlockItemPacketRewriter1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.ComponentRewriter1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.EntityPacketRewriter1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.ParticleRewriter1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ChunkLoadTracker; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.EntityTracker1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.GroundFlagTracker; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage; +import com.viaversion.viaversion.rewriter.AttributeRewriter; +import com.viaversion.viaversion.rewriter.SoundRewriter; +import com.viaversion.viaversion.rewriter.StatisticsRewriter; +import com.viaversion.viaversion.rewriter.TagRewriter; +import java.util.BitSet; + +import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap; + +public final class Protocol1_21To1_21_2 extends AbstractProtocol { + + public static final MappingData MAPPINGS = new MappingDataBase("1.21", "1.21.2"); + private final EntityPacketRewriter1_21_2 entityRewriter = new EntityPacketRewriter1_21_2(this); + private final BlockItemPacketRewriter1_21_2 itemRewriter = new BlockItemPacketRewriter1_21_2(this); + private final ParticleRewriter1_21_2 particleRewriter = new ParticleRewriter1_21_2(this); + private final TagRewriter tagRewriter = new TagRewriter<>(this); + private final ComponentRewriter1_21_2 componentRewriter = new ComponentRewriter1_21_2(this); + + public Protocol1_21To1_21_2() { + super(ClientboundPacket1_21.class, ClientboundPacket1_21_2.class, ServerboundPacket1_20_5.class, ServerboundPacket1_21_2.class); + } + + @Override + protected void registerPackets() { + super.registerPackets(); + + tagRewriter.registerGeneric(ClientboundPackets1_21.UPDATE_TAGS); + tagRewriter.registerGeneric(ClientboundConfigurationPackets1_21.UPDATE_TAGS); + + componentRewriter.registerOpenScreen(ClientboundPackets1_21.OPEN_SCREEN); + componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_ACTION_BAR_TEXT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_TITLE_TEXT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21.SET_SUBTITLE_TEXT); + componentRewriter.registerBossEvent(ClientboundPackets1_21.BOSS_EVENT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21.DISCONNECT); + componentRewriter.registerTabList(ClientboundPackets1_21.TAB_LIST); + componentRewriter.registerPlayerCombatKill1_20(ClientboundPackets1_21.PLAYER_COMBAT_KILL); + componentRewriter.registerComponentPacket(ClientboundPackets1_21.SYSTEM_CHAT); + componentRewriter.registerComponentPacket(ClientboundPackets1_21.DISGUISED_CHAT); + componentRewriter.registerPing(); + + particleRewriter.registerLevelParticles1_20_5(ClientboundPackets1_21.LEVEL_PARTICLES); + + final SoundRewriter soundRewriter = new SoundRewriter<>(this); + soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND); + soundRewriter.registerSound1_19_3(ClientboundPackets1_21.SOUND_ENTITY); + + new StatisticsRewriter<>(this).register(ClientboundPackets1_21.AWARD_STATS); + new AttributeRewriter<>(this).register1_21(ClientboundPackets1_21.UPDATE_ATTRIBUTES); + + registerServerbound(ServerboundPackets1_21_2.CLIENT_INFORMATION, this::clientInformation); + registerServerbound(ServerboundConfigurationPackets1_20_5.CLIENT_INFORMATION, this::clientInformation); + + cancelServerbound(ServerboundPackets1_21_2.BUNDLE_ITEM_SELECTED); + cancelServerbound(ServerboundPackets1_21_2.CLIENT_TICK_END); + + registerClientbound(State.LOGIN, ClientboundLoginPackets.LOGIN_FINISHED, wrapper -> { + wrapper.passthrough(Types.UUID); // UUID + wrapper.passthrough(Types.STRING); // Name + + final int properties = wrapper.passthrough(Types.VAR_INT); + for (int i = 0; i < properties; i++) { + wrapper.passthrough(Types.STRING); // Name + wrapper.passthrough(Types.STRING); // Value + wrapper.passthrough(Types.OPTIONAL_STRING); // Signature + } + + wrapper.read(Types.BOOLEAN); // Strict error handling + }); + + registerClientbound(ClientboundPackets1_21.SET_TIME, wrapper -> { + wrapper.passthrough(Types.LONG); // Game time + long dayTime = wrapper.read(Types.LONG); + boolean doDaylightCycle = true; + if (dayTime < 0) { + dayTime = -dayTime; + doDaylightCycle = false; + } + wrapper.write(Types.LONG, dayTime); + wrapper.write(Types.BOOLEAN, doDaylightCycle); + }); + + registerClientbound(ClientboundPackets1_21.PLAYER_INFO_UPDATE, wrapper -> { + final BitSet actions = wrapper.passthroughAndMap(Types.PROFILE_ACTIONS_ENUM1_19_3, Types.PROFILE_ACTIONS_ENUM1_21_2); + if (!actions.get(5)) { // Update display name + return; + } + + final int entries = wrapper.passthrough(Types.VAR_INT); + for (int i = 0; i < entries; i++) { + wrapper.passthrough(Types.UUID); + if (actions.get(0)) { + wrapper.passthrough(Types.STRING); // Player Name + + final int properties = wrapper.passthrough(Types.VAR_INT); + for (int j = 0; j < properties; j++) { + wrapper.passthrough(Types.STRING); // Name + wrapper.passthrough(Types.STRING); // Value + wrapper.passthrough(Types.OPTIONAL_STRING); // Signature + } + } + if (actions.get(1) && wrapper.passthrough(Types.BOOLEAN)) { + wrapper.passthrough(Types.UUID); // Session UUID + wrapper.passthrough(Types.PROFILE_KEY); + } + if (actions.get(2)) { + wrapper.passthrough(Types.VAR_INT); // Gamemode + } + if (actions.get(3)) { + wrapper.passthrough(Types.BOOLEAN); // Listed + } + if (actions.get(4)) { + wrapper.passthrough(Types.VAR_INT); // Latency + } + componentRewriter.processTag(wrapper.user(), wrapper.passthrough(Types.OPTIONAL_TAG)); + } + }); + + registerClientbound(ClientboundPackets1_21.BUNDLE_DELIMITER, wrapper -> wrapper.user().get(BundleStateTracker.class).toggleBundling()); + registerServerbound(ServerboundPackets1_21_2.PONG, wrapper -> { + final int id = wrapper.passthrough(Types.INT); // id + final PlayerPositionStorage playerPositionStorage = wrapper.user().get(PlayerPositionStorage.class); + if (playerPositionStorage != null && playerPositionStorage.checkPong(id)) { + wrapper.cancel(); + } + }); + } + + private void clientInformation(final PacketWrapper wrapper) { + wrapper.passthrough(Types.STRING); // Locale + wrapper.passthrough(Types.BYTE); // View distance + wrapper.passthrough(Types.VAR_INT); // Chat visibility + wrapper.passthrough(Types.BOOLEAN); // Chat colors + wrapper.passthrough(Types.UNSIGNED_BYTE); // Skin parts + wrapper.passthrough(Types.VAR_INT); // Main hand + wrapper.passthrough(Types.BOOLEAN); // Text filtering enabled + wrapper.passthrough(Types.BOOLEAN); // Allow listing + wrapper.read(Types.VAR_INT); // Particle status + } + + @Override + protected void onMappingDataLoaded() { + EntityTypes1_21_2.initialize(this); + Types1_21_2.PARTICLE.filler(this) + .reader("block", ParticleType.Readers.BLOCK) + .reader("block_marker", ParticleType.Readers.BLOCK) + .reader("dust_pillar", ParticleType.Readers.BLOCK) + .reader("falling_dust", ParticleType.Readers.BLOCK) + .reader("block_crumble", ParticleType.Readers.BLOCK) + .reader("dust", ParticleType.Readers.DUST1_21_2) + .reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION1_21_2) + .reader("vibration", ParticleType.Readers.VIBRATION1_20_3) + .reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE) + .reader("shriek", ParticleType.Readers.SHRIEK) + .reader("entity_effect", ParticleType.Readers.COLOR) + .reader("trail", ParticleType.Readers.TRAIL1_21_2) + .reader("item", ParticleType.Readers.item(Types1_21_2.ITEM)); + Types1_21_2.STRUCTURED_DATA.filler(this).add(StructuredDataKey.CUSTOM_DATA, StructuredDataKey.MAX_STACK_SIZE, StructuredDataKey.MAX_DAMAGE, + StructuredDataKey.UNBREAKABLE, StructuredDataKey.RARITY, StructuredDataKey.HIDE_TOOLTIP, StructuredDataKey.DAMAGE_RESISTANT, + StructuredDataKey.CUSTOM_NAME, StructuredDataKey.LORE, StructuredDataKey.ENCHANTMENTS, StructuredDataKey.CAN_PLACE_ON, + StructuredDataKey.CAN_BREAK, StructuredDataKey.CUSTOM_MODEL_DATA1_20_5, StructuredDataKey.HIDE_ADDITIONAL_TOOLTIP, + StructuredDataKey.REPAIR_COST, StructuredDataKey.CREATIVE_SLOT_LOCK, StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, + StructuredDataKey.INTANGIBLE_PROJECTILE, StructuredDataKey.STORED_ENCHANTMENTS, StructuredDataKey.DYED_COLOR, + StructuredDataKey.MAP_COLOR, StructuredDataKey.MAP_ID, StructuredDataKey.MAP_DECORATIONS, StructuredDataKey.MAP_POST_PROCESSING, + StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.SUSPICIOUS_STEW_EFFECTS, StructuredDataKey.WRITABLE_BOOK_CONTENT, + StructuredDataKey.WRITTEN_BOOK_CONTENT, StructuredDataKey.TRIM1_21_2, StructuredDataKey.DEBUG_STICK_STATE, StructuredDataKey.ENTITY_DATA, + StructuredDataKey.BUCKET_ENTITY_DATA, StructuredDataKey.BLOCK_ENTITY_DATA, StructuredDataKey.INSTRUMENT1_21_2, + StructuredDataKey.RECIPES, StructuredDataKey.LODESTONE_TRACKER, StructuredDataKey.FIREWORK_EXPLOSION, StructuredDataKey.FIREWORKS, + StructuredDataKey.PROFILE, StructuredDataKey.NOTE_BLOCK_SOUND, StructuredDataKey.BANNER_PATTERNS, StructuredDataKey.BASE_COLOR, + StructuredDataKey.POT_DECORATIONS, StructuredDataKey.BLOCK_STATE, StructuredDataKey.BEES, StructuredDataKey.LOCK, + StructuredDataKey.CONTAINER_LOOT, StructuredDataKey.TOOL, StructuredDataKey.ITEM_NAME, StructuredDataKey.OMINOUS_BOTTLE_AMPLIFIER, + StructuredDataKey.FOOD1_21_2, StructuredDataKey.JUKEBOX_PLAYABLE, StructuredDataKey.ATTRIBUTE_MODIFIERS1_21, + StructuredDataKey.REPAIRABLE, StructuredDataKey.ENCHANTABLE, StructuredDataKey.CONSUMABLE1_21_2, + StructuredDataKey.USE_COOLDOWN, StructuredDataKey.DAMAGE, StructuredDataKey.EQUIPPABLE, StructuredDataKey.ITEM_MODEL, + StructuredDataKey.GLIDER, StructuredDataKey.TOOLTIP_STYLE, StructuredDataKey.DEATH_PROTECTION, + // Volatile thanks to containing item + StructuredDataKey.CHARGED_PROJECTILES1_21_2, StructuredDataKey.BUNDLE_CONTENTS1_21_2, StructuredDataKey.CONTAINER1_21_2, StructuredDataKey.USE_REMAINDER1_21_2); + super.onMappingDataLoaded(); + } + + @Override + public void init(final UserConnection connection) { + addEntityTracker(connection, new EntityTracker1_21_2(connection)); + connection.put(new BundleStateTracker()); + connection.put(new GroundFlagTracker()); + + final ProtocolVersion protocolVersion = connection.getProtocolInfo().protocolVersion(); + if (protocolVersion.olderThan(ProtocolVersion.v1_21_4)) { // Only needed for 1.21.2/1.21.3 + connection.put(new PlayerPositionStorage()); + } + + // <= 1.21.1 clients allowed loaded chunks to get replaced with new data without unloading them first. + // 1.21.2 introduced a graphical bug where it doesn't properly render the new data unless the chunk is unloaded beforehand. + // 1.21.4 fixed this bug, so the workaround is no longer needed. + if (protocolVersion.equals(ProtocolVersion.v1_21_2)) { + connection.put(new ChunkLoadTracker()); + } + } + + @Override + public MappingData getMappingData() { + return MAPPINGS; + } + + @Override + public EntityPacketRewriter1_21_2 getEntityRewriter() { + return entityRewriter; + } + + @Override + public BlockItemPacketRewriter1_21_2 getItemRewriter() { + return itemRewriter; + } + + @Override + public ParticleRewriter1_21_2 getParticleRewriter() { + return particleRewriter; + } + + @Override + public TagRewriter getTagRewriter() { + return tagRewriter; + } + + @Override + public ComponentRewriter getComponentRewriter() { + return componentRewriter; + } + + @Override + protected PacketTypesProvider createPacketTypesProvider() { + return new SimplePacketTypesProvider<>( + packetTypeMap(unmappedClientboundPacketType, ClientboundPackets1_21.class, ClientboundConfigurationPackets1_21.class), + packetTypeMap(mappedClientboundPacketType, ClientboundPackets1_21_2.class, ClientboundConfigurationPackets1_21.class), + packetTypeMap(mappedServerboundPacketType, ServerboundPackets1_20_5.class, ServerboundConfigurationPackets1_20_5.class), + packetTypeMap(unmappedServerboundPacketType, ServerboundPackets1_21_2.class, ServerboundConfigurationPackets1_20_5.class) + ); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ClientboundPacket1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ClientboundPacket1_21_2.java new file mode 100644 index 000000000..59c1ede63 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ClientboundPacket1_21_2.java @@ -0,0 +1,23 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.packet; + +import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; + +public interface ClientboundPacket1_21_2 extends ClientboundPacketType { +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ClientboundPackets1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ClientboundPackets1_21_2.java new file mode 100644 index 000000000..132ab5770 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ClientboundPackets1_21_2.java @@ -0,0 +1,163 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.packet; + +public enum ClientboundPackets1_21_2 implements ClientboundPacket1_21_2 { + + BUNDLE_DELIMITER, // 0x00 + ADD_ENTITY, // 0x01 + ADD_EXPERIENCE_ORB, // 0x02 + ANIMATE, // 0x03 + AWARD_STATS, // 0x04 + BLOCK_CHANGED_ACK, // 0x05 + BLOCK_DESTRUCTION, // 0x06 + BLOCK_ENTITY_DATA, // 0x07 + BLOCK_EVENT, // 0x08 + BLOCK_UPDATE, // 0x09 + BOSS_EVENT, // 0x0A + CHANGE_DIFFICULTY, // 0x0B + CHUNK_BATCH_FINISHED, // 0x0C + CHUNK_BATCH_START, // 0x0D + CHUNKS_BIOMES, // 0x0E + CLEAR_TITLES, // 0x0F + COMMAND_SUGGESTIONS, // 0x10 + COMMANDS, // 0x11 + CONTAINER_CLOSE, // 0x12 + CONTAINER_SET_CONTENT, // 0x13 + CONTAINER_SET_DATA, // 0x14 + CONTAINER_SET_SLOT, // 0x15 + COOKIE_REQUEST, // 0x16 + COOLDOWN, // 0x17 + CUSTOM_CHAT_COMPLETIONS, // 0x18 + CUSTOM_PAYLOAD, // 0x19 + DAMAGE_EVENT, // 0x1A + DEBUG_SAMPLE, // 0x1B + DELETE_CHAT, // 0x1C + DISCONNECT, // 0x1D + DISGUISED_CHAT, // 0x1E + ENTITY_EVENT, // 0x1F + ENTITY_POSITION_SYNC, // 0x20 + EXPLODE, // 0x21 + FORGET_LEVEL_CHUNK, // 0x22 + GAME_EVENT, // 0x23 + HORSE_SCREEN_OPEN, // 0x24 + HURT_ANIMATION, // 0x25 + INITIALIZE_BORDER, // 0x26 + KEEP_ALIVE, // 0x27 + LEVEL_CHUNK_WITH_LIGHT, // 0x28 + LEVEL_EVENT, // 0x29 + LEVEL_PARTICLES, // 0x2A + LIGHT_UPDATE, // 0x2B + LOGIN, // 0x2C + MAP_ITEM_DATA, // 0x2D + MERCHANT_OFFERS, // 0x2E + MOVE_ENTITY_POS, // 0x2F + MOVE_ENTITY_POS_ROT, // 0x30 + MOVE_MINECART_ALONG_TRACK, // 0x31 + MOVE_ENTITY_ROT, // 0x32 + MOVE_VEHICLE, // 0x33 + OPEN_BOOK, // 0x34 + OPEN_SCREEN, // 0x35 + OPEN_SIGN_EDITOR, // 0x36 + PING, // 0x37 + PONG_RESPONSE, // 0x38 + PLACE_GHOST_RECIPE, // 0x39 + PLAYER_ABILITIES, // 0x3A + PLAYER_CHAT, // 0x3B + PLAYER_COMBAT_END, // 0x3C + PLAYER_COMBAT_ENTER, // 0x3D + PLAYER_COMBAT_KILL, // 0x3E + PLAYER_INFO_REMOVE, // 0x3F + PLAYER_INFO_UPDATE, // 0x40 + PLAYER_LOOK_AT, // 0x41 + PLAYER_POSITION, // 0x42 + PLAYER_ROTATION, // 0x43 + RECIPE_BOOK_ADD, // 0x44 + RECIPE_BOOK_REMOVE, // 0x45 + RECIPE_BOOK_SETTINGS, // 0x46 + REMOVE_ENTITIES, // 0x47 + REMOVE_MOB_EFFECT, // 0x48 + RESET_SCORE, // 0x49 + RESOURCE_PACK_POP, // 0x4A + RESOURCE_PACK_PUSH, // 0x4B + RESPAWN, // 0x4C + ROTATE_HEAD, // 0x4D + SECTION_BLOCKS_UPDATE, // 0x4E + SELECT_ADVANCEMENTS_TAB, // 0x4F + SERVER_DATA, // 0x50 + SET_ACTION_BAR_TEXT, // 0x51 + SET_BORDER_CENTER, // 0x52 + SET_BORDER_LERP_SIZE, // 0x53 + SET_BORDER_SIZE, // 0x54 + SET_BORDER_WARNING_DELAY, // 0x55 + SET_BORDER_WARNING_DISTANCE, // 0x56 + SET_CAMERA, // 0x57 + SET_CHUNK_CACHE_CENTER, // 0x58 + SET_CHUNK_CACHE_RADIUS, // 0x59 + SET_CURSOR_ITEM, // 0x5A + SET_DEFAULT_SPAWN_POSITION, // 0x5B + SET_DISPLAY_OBJECTIVE, // 0x5C + SET_ENTITY_DATA, // 0x5D + SET_ENTITY_LINK, // 0x5E + SET_ENTITY_MOTION, // 0x5F + SET_EQUIPMENT, // 0x60 + SET_EXPERIENCE, // 0x61 + SET_HEALTH, // 0x62 + SET_HELD_SLOT, // 0x63 + SET_OBJECTIVE, // 0x64 + SET_PASSENGERS, // 0x65 + SET_PLAYER_INVENTORY, // 0x66 + SET_PLAYER_TEAM, // 0x67 + SET_SCORE, // 0x68 + SET_SIMULATION_DISTANCE, // 0x69 + SET_SUBTITLE_TEXT, // 0x6A + SET_TIME, // 0x6B + SET_TITLE_TEXT, // 0x6C + SET_TITLES_ANIMATION, // 0x6D + SOUND_ENTITY, // 0x6E + SOUND, // 0x6F + START_CONFIGURATION, // 0x70 + STOP_SOUND, // 0x71 + STORE_COOKIE, // 0x72 + SYSTEM_CHAT, // 0x73 + TAB_LIST, // 0x74 + TAG_QUERY, // 0x75 + TAKE_ITEM_ENTITY, // 0x76 + TELEPORT_ENTITY, // 0x77 + TICKING_STATE, // 0x78 + TICKING_STEP, // 0x79 + TRANSFER, // 0x7A + UPDATE_ADVANCEMENTS, // 0x7B + UPDATE_ATTRIBUTES, // 0x7C + UPDATE_MOB_EFFECT, // 0x7D + UPDATE_RECIPES, // 0x7E + UPDATE_TAGS, // 0x7F + PROJECTILE_POWER, // 0x80 + CUSTOM_REPORT_DETAILS, // 0x81 + SERVER_LINKS; // 0x82 + + @Override + public int getId() { + return ordinal(); + } + + @Override + public String getName() { + return name(); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ServerboundPacket1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ServerboundPacket1_21_2.java new file mode 100644 index 000000000..4999141e6 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ServerboundPacket1_21_2.java @@ -0,0 +1,23 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.packet; + +import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; + +public interface ServerboundPacket1_21_2 extends ServerboundPacketType { +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ServerboundPackets1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ServerboundPackets1_21_2.java new file mode 100644 index 000000000..3e5d837c7 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/packet/ServerboundPackets1_21_2.java @@ -0,0 +1,92 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.packet; + +public enum ServerboundPackets1_21_2 implements ServerboundPacket1_21_2 { + + ACCEPT_TELEPORTATION, // 0x00 + BLOCK_ENTITY_TAG_QUERY, // 0x01 + BUNDLE_ITEM_SELECTED, // 0x02 + CHANGE_DIFFICULTY, // 0x03 + CHAT_ACK, // 0x04 + CHAT_COMMAND, // 0x05 + CHAT_COMMAND_SIGNED, // 0x06 + CHAT, // 0x07 + CHAT_SESSION_UPDATE, // 0x08 + CHUNK_BATCH_RECEIVED, // 0x09 + CLIENT_COMMAND, // 0x0A + CLIENT_TICK_END, // 0x0B + CLIENT_INFORMATION, // 0x0C + COMMAND_SUGGESTION, // 0x0D + CONFIGURATION_ACKNOWLEDGED, // 0x0E + CONTAINER_BUTTON_CLICK, // 0x0F + CONTAINER_CLICK, // 0x10 + CONTAINER_CLOSE, // 0x11 + CONTAINER_SLOT_STATE_CHANGED, // 0x12 + COOKIE_RESPONSE, // 0x13 + CUSTOM_PAYLOAD, // 0x14 + DEBUG_SAMPLE_SUBSCRIPTION, // 0x15 + EDIT_BOOK, // 0x16 + ENTITY_TAG_QUERY, // 0x17 + INTERACT, // 0x18 + JIGSAW_GENERATE, // 0x19 + KEEP_ALIVE, // 0x1A + LOCK_DIFFICULTY, // 0x1B + MOVE_PLAYER_POS, // 0x1C + MOVE_PLAYER_POS_ROT, // 0x1D + MOVE_PLAYER_ROT, // 0x1E + MOVE_PLAYER_STATUS_ONLY, // 0x1F + MOVE_VEHICLE, // 0x20 + PADDLE_BOAT, // 0x21 + PICK_ITEM, // 0x22 + PING_REQUEST, // 0x23 + PLACE_RECIPE, // 0x24 + PLAYER_ABILITIES, // 0x25 + PLAYER_ACTION, // 0x26 + PLAYER_COMMAND, // 0x27 + PLAYER_INPUT, // 0x28 + PONG, // 0x29 + RECIPE_BOOK_CHANGE_SETTINGS, // 0x2A + RECIPE_BOOK_SEEN_RECIPE, // 0x2B + RENAME_ITEM, // 0x2C + RESOURCE_PACK, // 0x2D + SEEN_ADVANCEMENTS, // 0x2E + SELECT_TRADE, // 0x2F + SET_BEACON, // 0x30 + SET_CARRIED_ITEM, // 0x31 + SET_COMMAND_BLOCK, // 0x32 + SET_COMMAND_MINECART, // 0x33 + SET_CREATIVE_MODE_SLOT, // 0x34 + SET_JIGSAW_BLOCK, // 0x35 + SET_STRUCTURE_BLOCK, // 0x36 + SIGN_UPDATE, // 0x37 + SWING, // 0x38 + TELEPORT_TO_ENTITY, // 0x39 + USE_ITEM_ON, // 0x3A + USE_ITEM; // 0x3B + + @Override + public int getId() { + return ordinal(); + } + + @Override + public String getName() { + return name(); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/BlockItemPacketRewriter1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/BlockItemPacketRewriter1_21_2.java new file mode 100644 index 000000000..a545720f6 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/BlockItemPacketRewriter1_21_2.java @@ -0,0 +1,647 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter; + +import com.viaversion.nbt.tag.ByteTag; +import com.viaversion.nbt.tag.CompoundTag; +import com.viaversion.nbt.tag.IntArrayTag; +import com.viaversion.nbt.tag.ListTag; +import com.viaversion.nbt.tag.StringTag; +import com.viaversion.nbt.tag.Tag; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.FullMappings; +import com.viaversion.viaversion.api.data.MappingData; +import com.viaversion.viaversion.api.data.Mappings; +import com.viaversion.viaversion.api.minecraft.BlockPosition; +import com.viaversion.viaversion.api.minecraft.ChunkPosition; +import com.viaversion.viaversion.api.minecraft.Holder; +import com.viaversion.viaversion.api.minecraft.HolderSet; +import com.viaversion.viaversion.api.minecraft.Particle; +import com.viaversion.viaversion.api.minecraft.SoundEvent; +import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity; +import com.viaversion.viaversion.api.minecraft.chunks.Chunk; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer; +import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.minecraft.item.data.Consumable1_21_2; +import com.viaversion.viaversion.api.minecraft.item.data.DamageResistant; +import com.viaversion.viaversion.api.minecraft.item.data.Enchantments; +import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_20_5; +import com.viaversion.viaversion.api.minecraft.item.data.FoodProperties1_21_2; +import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_20_5; +import com.viaversion.viaversion.api.minecraft.item.data.Instrument1_21_2; +import com.viaversion.viaversion.api.minecraft.item.data.PotionEffect; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.chunk.ChunkType1_20_2; +import com.viaversion.viaversion.api.type.types.version.Types1_21; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPacket1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPackets1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ChunkLoadTracker; +import com.viaversion.viaversion.rewriter.BlockRewriter; +import com.viaversion.viaversion.rewriter.SoundRewriter; +import com.viaversion.viaversion.rewriter.StructuredItemRewriter; +import com.viaversion.viaversion.util.ComponentUtil; +import com.viaversion.viaversion.util.Key; +import com.viaversion.viaversion.util.Limit; +import com.viaversion.viaversion.util.SerializerVersion; +import com.viaversion.viaversion.util.TagUtil; +import com.viaversion.viaversion.util.Unit; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +public final class BlockItemPacketRewriter1_21_2 extends StructuredItemRewriter { + + private static final int RECIPE_NOTIFICATION_FLAG = 1 << 0; + private static final int RECIPE_HIGHLIGHT_FLAG = 1 << 1; + private static final int RECIPE_INIT = 0; + private static final int RECIPE_ADD = 1; + private static final int RECIPE_REMOVE = 2; + + public BlockItemPacketRewriter1_21_2(final Protocol1_21To1_21_2 protocol) { + super(protocol, + Types1_21.ITEM, Types1_21.ITEM_ARRAY, Types1_21_2.ITEM, Types1_21_2.ITEM_ARRAY, + Types1_21.ITEM_COST, Types1_21.OPTIONAL_ITEM_COST, Types1_21_2.ITEM_COST, Types1_21_2.OPTIONAL_ITEM_COST + ); + } + + @Override + public void registerPackets() { + final BlockRewriter blockRewriter = BlockRewriter.for1_20_2(protocol); + blockRewriter.registerBlockEvent(ClientboundPackets1_21.BLOCK_EVENT); + blockRewriter.registerBlockUpdate(ClientboundPackets1_21.BLOCK_UPDATE); + blockRewriter.registerSectionBlocksUpdate1_20(ClientboundPackets1_21.SECTION_BLOCKS_UPDATE); + blockRewriter.registerLevelEvent1_21(ClientboundPackets1_21.LEVEL_EVENT, 2001); + blockRewriter.registerBlockEntityData(ClientboundPackets1_21.BLOCK_ENTITY_DATA); + + registerAdvancements1_20_3(ClientboundPackets1_21.UPDATE_ADVANCEMENTS); + registerSetEquipment(ClientboundPackets1_21.SET_EQUIPMENT); + registerMerchantOffers1_20_5(ClientboundPackets1_21.MERCHANT_OFFERS); + registerSetCreativeModeSlot(ServerboundPackets1_21_2.SET_CREATIVE_MODE_SLOT); + + protocol.registerClientbound(ClientboundPackets1_21.COOLDOWN, wrapper -> { + final MappingData mappingData = protocol.getMappingData(); + final int itemId = wrapper.read(Types.VAR_INT); + final int mappedItemId = mappingData.getNewItemId(itemId); + wrapper.write(Types.STRING, mappingData.getFullItemMappings().mappedIdentifier(mappedItemId)); + }); + + protocol.registerClientbound(ClientboundPackets1_21.CONTAINER_SET_CONTENT, wrapper -> { + updateContainerId(wrapper); + wrapper.passthrough(Types.VAR_INT); // State id + final Item[] items = wrapper.read(itemArrayType()); + wrapper.write(mappedItemArrayType(), items); + for (int i = 0; i < items.length; i++) { + items[i] = handleItemToClient(wrapper.user(), items[i]); + } + passthroughClientboundItem(wrapper); + }); + protocol.registerClientbound(ClientboundPackets1_21.CONTAINER_SET_SLOT, wrapper -> { + updateContainerId(wrapper); + final int containerId = wrapper.get(Types.VAR_INT, 0); + if (containerId == -1) { // cursor item + wrapper.setPacketType(ClientboundPackets1_21_2.SET_CURSOR_ITEM); + wrapper.resetReader(); + wrapper.read(Types.VAR_INT); // container id + wrapper.read(Types.VAR_INT); // State id + wrapper.read(Types.SHORT); // Slot id + } else if (containerId == -2) { // cursor item + wrapper.setPacketType(ClientboundPackets1_21_2.SET_PLAYER_INVENTORY); + wrapper.resetReader(); + wrapper.read(Types.VAR_INT); // container id + wrapper.read(Types.VAR_INT); // State id + wrapper.write(Types.VAR_INT, (int) wrapper.read(Types.SHORT)); // Slot id + } else { + wrapper.passthrough(Types.VAR_INT); // State id + wrapper.passthrough(Types.SHORT); // Slot id + } + passthroughClientboundItem(wrapper); + }); + protocol.registerClientbound(ClientboundPackets1_21.CONTAINER_CLOSE, this::updateContainerId); + protocol.registerClientbound(ClientboundPackets1_21.CONTAINER_SET_DATA, this::updateContainerId); + protocol.registerClientbound(ClientboundPackets1_21.HORSE_SCREEN_OPEN, this::updateContainerId); + protocol.registerClientbound(ClientboundPackets1_21.SET_CARRIED_ITEM, ClientboundPackets1_21_2.SET_HELD_SLOT); + protocol.registerServerbound(ServerboundPackets1_21_2.CONTAINER_CLOSE, this::updateContainerIdServerbound); + protocol.registerServerbound(ServerboundPackets1_21_2.CONTAINER_CLICK, wrapper -> { + updateContainerIdServerbound(wrapper); + wrapper.passthrough(Types.VAR_INT); // State id + wrapper.passthrough(Types.SHORT); // Slot + wrapper.passthrough(Types.BYTE); // Button + wrapper.passthrough(Types.VAR_INT); // Mode + final int length = Limit.max(wrapper.passthrough(Types.VAR_INT), 128); + for (int i = 0; i < length; i++) { + wrapper.passthrough(Types.SHORT); // Slot + passthroughServerboundItem(wrapper); + } + passthroughServerboundItem(wrapper); + }); + protocol.registerClientbound(ClientboundPackets1_21.PLACE_GHOST_RECIPE, wrapper -> { + this.updateContainerId(wrapper); + + final String recipeKey = wrapper.read(Types.STRING); + final RecipeRewriter1_21_2.Recipe recipe = wrapper.user().get(RecipeRewriter1_21_2.class).recipe(recipeKey); + if (recipe == null) { + wrapper.cancel(); + return; + } + + wrapper.write(Types.VAR_INT, recipe.recipeDisplayId()); + recipe.writeRecipeDisplay(wrapper); + }); + protocol.registerServerbound(ServerboundPackets1_21_2.PLACE_RECIPE, wrapper -> { + this.updateContainerIdServerbound(wrapper); + convertServerboundRecipeDisplayId(wrapper); + }); + protocol.registerServerbound(ServerboundPackets1_21_2.RECIPE_BOOK_SEEN_RECIPE, this::convertServerboundRecipeDisplayId); + + protocol.registerServerbound(ServerboundPackets1_21_2.USE_ITEM_ON, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Hand + wrapper.passthrough(Types.BLOCK_POSITION1_14); // Block position + wrapper.passthrough(Types.VAR_INT); // Direction + wrapper.passthrough(Types.FLOAT); // X + wrapper.passthrough(Types.FLOAT); // Y + wrapper.passthrough(Types.FLOAT); // Z + wrapper.passthrough(Types.BOOLEAN); // Inside + wrapper.read(Types.BOOLEAN); // World border hit + }); + + protocol.registerClientbound(ClientboundPackets1_21.EXPLODE, wrapper -> { + final int centerX = (int) Math.floor(wrapper.passthrough(Types.DOUBLE)); // Center X + final int centerY = (int) Math.floor(wrapper.passthrough(Types.DOUBLE)); // Center Y + final int centerZ = (int) Math.floor(wrapper.passthrough(Types.DOUBLE)); // Center Z + + final float power = wrapper.read(Types.FLOAT); // Power + final List affectedBlocks = new ArrayList<>(); + final int blocks = wrapper.read(Types.VAR_INT); + for (int i = 0; i < blocks; i++) { + final int x = centerX + wrapper.read(Types.BYTE); // Relative X + final int y = centerY + wrapper.read(Types.BYTE); // Relative Y + final int z = centerZ + wrapper.read(Types.BYTE); // Relative Z + affectedBlocks.add(new BlockPosition(x, y, z)); + } + + final float knockbackX = wrapper.read(Types.FLOAT); + final float knockbackY = wrapper.read(Types.FLOAT); + final float knockbackZ = wrapper.read(Types.FLOAT); + if (knockbackX != 0 || knockbackY != 0 || knockbackZ != 0) { + wrapper.write(Types.BOOLEAN, true); + wrapper.write(Types.DOUBLE, (double) knockbackX); + wrapper.write(Types.DOUBLE, (double) knockbackY); + wrapper.write(Types.DOUBLE, (double) knockbackZ); + } else { + wrapper.write(Types.BOOLEAN, false); + } + + final int blockInteractionMode = wrapper.read(Types.VAR_INT); + if (blockInteractionMode == 1 || blockInteractionMode == 2) { + for (final BlockPosition affectedBlock : affectedBlocks) { + final PacketWrapper blockUpdate = PacketWrapper.create(ClientboundPackets1_21_2.BLOCK_UPDATE, wrapper.user()); + blockUpdate.write(Types.BLOCK_POSITION1_14, affectedBlock); // position + blockUpdate.write(Types.VAR_INT, 0); // block state + blockUpdate.send(Protocol1_21To1_21_2.class); + } + } + + final Particle smallExplosionParticle = wrapper.read(Types1_21.PARTICLE); + final Particle largeExplosionParticle = wrapper.read(Types1_21.PARTICLE); + if (power >= 2.0F && blockInteractionMode != 0) { + protocol.getParticleRewriter().rewriteParticle(wrapper.user(), largeExplosionParticle); + wrapper.write(Types1_21_2.PARTICLE, largeExplosionParticle); + } else { + protocol.getParticleRewriter().rewriteParticle(wrapper.user(), smallExplosionParticle); + wrapper.write(Types1_21_2.PARTICLE, smallExplosionParticle); + } + + new SoundRewriter<>(protocol).soundHolderHandler().handle(wrapper); + }); + + protocol.registerClientbound(ClientboundPackets1_21.UPDATE_RECIPES, wrapper -> { + final FullMappings recipeSerializerMappings = protocol.getMappingData().getRecipeSerializerMappings(); + final RecipeRewriter1_21_2 rewriter = new RecipeRewriter1_21_2(protocol); + wrapper.user().put(rewriter); + + final int size = wrapper.read(Types.VAR_INT); + for (int i = 0; i < size; i++) { + final String recipeIdentifier = wrapper.read(Types.STRING); + final int serializerTypeId = wrapper.read(Types.VAR_INT); + final String serializerTypeIdentifier = recipeSerializerMappings.identifier(serializerTypeId); + rewriter.setCurrentRecipeIdentifier(recipeIdentifier); + rewriter.handleRecipeType(wrapper, serializerTypeIdentifier); + } + rewriter.finalizeRecipes(); + + // These are used for client predictions, such smithing or furnace inputs. + // Other recipes will be written in RECIPE/RECIPE_BOOK_ADD + rewriter.writeUpdateRecipeInputs(wrapper); + }); + + protocol.registerClientbound(ClientboundPackets1_21.RECIPE, ClientboundPackets1_21_2.RECIPE_BOOK_ADD, wrapper -> { + final int state = wrapper.passthrough(Types.VAR_INT); + + // Pairs of open + filtering for: Crafting, furnace, blast furnace, smoker + final PacketWrapper settingsPacket = wrapper.create(ClientboundPackets1_21_2.RECIPE_BOOK_SETTINGS); + for (int i = 0; i < 4 * 2; i++) { + settingsPacket.write(Types.BOOLEAN, wrapper.read(Types.BOOLEAN)); + } + settingsPacket.send(Protocol1_21To1_21_2.class); + + // Read recipe keys from the packet + final String[] recipes = wrapper.read(Types.STRING_ARRAY); + Set toHighlight = Set.of(); + if (state == RECIPE_INIT) { + final String[] highlightRecipes = wrapper.read(Types.STRING_ARRAY); + toHighlight = Set.of(highlightRecipes); + } + + final RecipeRewriter1_21_2 recipeRewriter = wrapper.user().get(RecipeRewriter1_21_2.class); + if (recipeRewriter == null) { + protocol.getLogger().severe("Recipes not yet sent for recipe add packet"); + wrapper.cancel(); + return; + } + + wrapper.clearPacket(); + + if (state == RECIPE_REMOVE) { + wrapper.setPacketType(ClientboundPackets1_21_2.RECIPE_BOOK_REMOVE); + + final int[] ids = new int[recipes.length]; + for (int i = 0; i < recipes.length; i++) { + final String recipeKey = recipes[i]; + final RecipeRewriter1_21_2.Recipe recipe = recipeRewriter.recipe(recipeKey); + if (recipe == null) { + protocol.getLogger().severe("Recipe not found for key " + recipeKey); + wrapper.cancel(); + return; + } + + ids[i] = recipe.index(); + } + + wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, ids); + return; + } + + // Add or init recipes + int size = recipes.length; + wrapper.write(Types.VAR_INT, size); + for (final String recipeKey : recipes) { + final RecipeRewriter1_21_2.Recipe recipe = recipeRewriter.recipe(recipeKey); + if (recipe == null) { + // Stonecutting and smithing recipes, or bad data + size--; + continue; + } + + wrapper.write(Types.VAR_INT, recipe.index()); // Display ID, just an arbitrary index as determined by the server + + wrapper.write(Types.VAR_INT, recipe.recipeDisplayId()); + recipe.writeRecipeDisplay(wrapper); + + wrapper.write(Types.OPTIONAL_VAR_INT, recipe.group() != -1 ? recipe.group() : null); + wrapper.write(Types.VAR_INT, recipe.category()); + + final Item[][] ingredients = recipe.ingredients(); + if (ingredients != null) { + wrapper.write(Types.BOOLEAN, true); + + // Why are some of these empty? Who knows, but they can't be + final List filteredIngredients = Arrays.stream(ingredients).filter(ingredient -> ingredient.length > 0).map(recipeRewriter::toHolderSet).toList(); + wrapper.write(Types.VAR_INT, filteredIngredients.size()); + for (final HolderSet ingredient : filteredIngredients) { + wrapper.write(Types.HOLDER_SET, ingredient); + } + } else { + wrapper.write(Types.BOOLEAN, false); + } + + byte flags = 0; + if (state == RECIPE_ADD) { + if (recipe.showNotification()) { + flags |= RECIPE_NOTIFICATION_FLAG; + } + flags |= RECIPE_HIGHLIGHT_FLAG; + } else if (toHighlight.contains(recipeKey)) { + flags |= RECIPE_HIGHLIGHT_FLAG; + } + wrapper.write(Types.BYTE, flags); + } + + // Update final size + wrapper.set(Types.VAR_INT, 0, size); + + wrapper.write(Types.BOOLEAN, state == RECIPE_INIT); // Replace + }); + + protocol.registerClientbound(ClientboundPackets1_21.LEVEL_CHUNK_WITH_LIGHT, wrapper -> { + final Chunk chunk = blockRewriter.handleChunk1_19(wrapper, ChunkType1_20_2::new); + final Mappings blockEntityMappings = protocol.getMappingData().getBlockEntityMappings(); + if (blockEntityMappings != null) { + final List blockEntities = chunk.blockEntities(); + for (int i = 0; i < blockEntities.size(); i++) { + final BlockEntity blockEntity = blockEntities.get(i); + final int id = blockEntity.typeId(); + final int mappedId = blockEntityMappings.getNewIdOrDefault(id, id); + if (id != mappedId) { + blockEntities.set(i, blockEntity.withTypeId(mappedId)); + } + } + } + + final ChunkLoadTracker chunkLoadTracker = wrapper.user().get(ChunkLoadTracker.class); + if (chunkLoadTracker == null) { + return; + } + + if (chunkLoadTracker.isChunkLoaded(chunk.getX(), chunk.getZ())) { + // Unload the old chunk, so the new one can be loaded without graphical glitches + // Bundling it prevents the client from falling through the world during the chunk swap + final boolean isBundling = wrapper.user().get(BundleStateTracker.class).isBundling(); + if (!isBundling) { + final PacketWrapper bundleStart = wrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER); + bundleStart.send(Protocol1_21To1_21_2.class); + } + + final PacketWrapper forgetLevelChunk = wrapper.create(ClientboundPackets1_21_2.FORGET_LEVEL_CHUNK); + forgetLevelChunk.write(Types.CHUNK_POSITION, new ChunkPosition(chunk.getX(), chunk.getZ())); + forgetLevelChunk.send(Protocol1_21To1_21_2.class); + wrapper.send(Protocol1_21To1_21_2.class); + wrapper.cancel(); + + if (!isBundling) { + final PacketWrapper bundleEnd = wrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER); + bundleEnd.send(Protocol1_21To1_21_2.class); + } + } else { + chunkLoadTracker.addChunk(chunk.getX(), chunk.getZ()); + } + }); + protocol.registerClientbound(ClientboundPackets1_21.FORGET_LEVEL_CHUNK, wrapper -> { + final ChunkPosition chunkPosition = wrapper.passthrough(Types.CHUNK_POSITION); + + final ChunkLoadTracker chunkLoadTracker = wrapper.user().get(ChunkLoadTracker.class); + if (chunkLoadTracker != null) { + chunkLoadTracker.removeChunk(chunkPosition.chunkX(), chunkPosition.chunkZ()); + } + }); + } + + private void convertServerboundRecipeDisplayId(final PacketWrapper wrapper) { + final int recipeDisplayId = wrapper.read(Types.VAR_INT); + final RecipeRewriter1_21_2.Recipe recipe = wrapper.user().get(RecipeRewriter1_21_2.class).recipe(recipeDisplayId); + if (recipe == null) { + wrapper.cancel(); + return; + } + + wrapper.write(Types.STRING, recipe.identifier()); + } + + @Override + public Item handleItemToClient(final UserConnection connection, final Item item) { + if (item.isEmpty()) { + return item; + } + + super.handleItemToClient(connection, item); + + // Handle food properties item manually here - the only protocol that has it + // The other way around it's handled by the super handleItemToServer method + final StructuredDataContainer data = item.dataContainer(); + final FoodProperties1_20_5 food = data.get(StructuredDataKey.FOOD1_21); + if (food != null && food.usingConvertsTo() != null) { + this.handleItemToClient(connection, food.usingConvertsTo()); + } + + updateItemData(item); + + final Enchantments enchantments = data.get(StructuredDataKey.ENCHANTMENTS); + if (enchantments != null && enchantments.size() != 0) { + // Level 0 is no longer allowed + final IntList enchantmentIds = new IntArrayList(); + enchantments.enchantments().int2IntEntrySet().removeIf(entry -> { + if (entry.getIntValue() == 0) { + enchantmentIds.add(entry.getIntKey()); + return true; + } + return false; + }); + + if (!enchantmentIds.isEmpty()) { + final IntArrayTag enchantmentIdsTag = new IntArrayTag(enchantmentIds.toIntArray()); + saveTag(createCustomTag(item), enchantmentIdsTag, "0_enchants"); + } + if (enchantments.size() == 0 && !data.has(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE)) { + data.set(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE, true); + saveTag(createCustomTag(item), new ByteTag(true), "remove_glint"); + } + } + + // Item name is now overridden by custom implemented display names (compass, player head, potion, shield, tipped arrow) + final int identifier = item.identifier(); + if (identifier == 952 || identifier == 1147 || identifier == 1039 || identifier == 1203 || identifier == 1200 || identifier == 1204 || identifier == 1202) { + final Tag itemName = data.get(StructuredDataKey.ITEM_NAME); + if (itemName != null && !data.has(StructuredDataKey.CUSTOM_NAME)) { + final CompoundTag name = new CompoundTag(); + name.putBoolean("italic", false); + name.putString("text", ""); + name.put("extra", new ListTag<>(Collections.singletonList(itemName))); + + data.set(StructuredDataKey.CUSTOM_NAME, name); + saveTag(createCustomTag(item), new ByteTag(true), "remove_custom_name"); + } + } + return item; + } + + @Override + public Item handleItemToServer(final UserConnection connection, final Item item) { + if (item.isEmpty()) { + return item; + } + + super.handleItemToServer(connection, item); + downgradeItemData(item); + + final StructuredDataContainer dataContainer = item.dataContainer(); + final CompoundTag customData = dataContainer.get(StructuredDataKey.CUSTOM_DATA); + if (customData == null) { + return item; + } + + if (customData.remove(nbtTagName("remove_custom_name")) != null) { + dataContainer.remove(StructuredDataKey.CUSTOM_NAME); + removeCustomTag(dataContainer, customData); + } + + final IntArrayTag emptyEnchantments = customData.getIntArrayTag(nbtTagName("0_enchants")); + if (emptyEnchantments != null) { + Enchantments enchantments = dataContainer.get(StructuredDataKey.ENCHANTMENTS); + if (enchantments == null) { + enchantments = new Enchantments(true); + dataContainer.set(StructuredDataKey.ENCHANTMENTS, enchantments); + } + for (final int enchantmentId : emptyEnchantments.getValue()) { + enchantments.enchantments().put(enchantmentId, 0); + } + customData.remove(nbtTagName("0_enchants")); + + if (customData.remove(nbtTagName("remove_glint")) != null) { + dataContainer.remove(StructuredDataKey.ENCHANTMENT_GLINT_OVERRIDE); + } + removeCustomTag(dataContainer, customData); + } + return item; + } + + private void updateContainerId(final PacketWrapper wrapper) { + // Container id handling was always a bit whack with most reading them as unsigned bytes, some as bytes, some already as var ints. + // In VV they're generally read as unsigned bytes to not have to look the type up every time, but we need to make sure they're + // properly converted to ints when used + final short containerId = wrapper.read(Types.UNSIGNED_BYTE); + final int intId = (byte) containerId; + wrapper.write(Types.VAR_INT, intId); + } + + private void updateContainerIdServerbound(final PacketWrapper wrapper) { + final int containerId = wrapper.read(Types.VAR_INT); + wrapper.write(Types.UNSIGNED_BYTE, (short) containerId); + } + + public static void updateItemData(final Item item) { + final StructuredDataContainer dataContainer = item.dataContainer(); + dataContainer.replace(StructuredDataKey.INSTRUMENT1_20_5, StructuredDataKey.INSTRUMENT1_21_2, instrument -> { + if (instrument.hasId()) { + return Holder.of(instrument.id()); + } + final Instrument1_20_5 value = instrument.value(); + return Holder.of(new Instrument1_21_2(value.soundEvent(), value.useDuration() / 20F, value.range(), new StringTag(""))); + }); + dataContainer.replace(StructuredDataKey.FOOD1_21, StructuredDataKey.FOOD1_21_2, food -> { + final Holder sound = Holder.of(new SoundEvent("minecraft:entity.generic.eat", null)); + final Consumable1_21_2.ConsumeEffect[] consumeEffects = new Consumable1_21_2.ConsumeEffect[food.possibleEffects().length]; + for (int i = 0; i < consumeEffects.length; i++) { + final FoodProperties1_20_5.FoodEffect effect = food.possibleEffects()[i]; + final Consumable1_21_2.ApplyStatusEffects applyStatusEffects = new Consumable1_21_2.ApplyStatusEffects(new PotionEffect[]{effect.effect()}, effect.probability()); + consumeEffects[i] = new Consumable1_21_2.ConsumeEffect<>(0 /* add status effect */, Consumable1_21_2.ApplyStatusEffects.TYPE, applyStatusEffects); + } + + dataContainer.set(StructuredDataKey.CONSUMABLE1_21_2, new Consumable1_21_2(food.eatSeconds(), 1 /* eat */, sound, true, consumeEffects)); + if (food.usingConvertsTo() != null) { + dataContainer.set(StructuredDataKey.USE_REMAINDER1_21_2, food.usingConvertsTo()); + } + return new FoodProperties1_21_2(food.nutrition(), food.saturationModifier(), food.canAlwaysEat()); + }); + dataContainer.replaceKey(StructuredDataKey.CONTAINER1_21, StructuredDataKey.CONTAINER1_21_2); + dataContainer.replaceKey(StructuredDataKey.CHARGED_PROJECTILES1_21, StructuredDataKey.CHARGED_PROJECTILES1_21_2); + dataContainer.replaceKey(StructuredDataKey.BUNDLE_CONTENTS1_21, StructuredDataKey.BUNDLE_CONTENTS1_21_2); + dataContainer.replaceKey(StructuredDataKey.POTION_CONTENTS1_20_5, StructuredDataKey.POTION_CONTENTS1_21_2); + dataContainer.replace(StructuredDataKey.FIRE_RESISTANT, StructuredDataKey.DAMAGE_RESISTANT, fireResistant -> new DamageResistant("minecraft:is_fire")); + dataContainer.replace(StructuredDataKey.LOCK, tag -> { + final String lock = ((StringTag) tag).getValue(); + final CompoundTag predicateTag = new CompoundTag(); + final CompoundTag itemComponentsTag = new CompoundTag(); + predicateTag.put("components", itemComponentsTag); + // As json here... + itemComponentsTag.putString("custom_name", ComponentUtil.plainToJson(lock).toString()); + return predicateTag; + }); + dataContainer.replace(StructuredDataKey.TRIM1_20_5, StructuredDataKey.TRIM1_21_2, trim -> { + // TODO Rewrite from int to string id via sent registry + if (trim.material().isDirect()) { + trim.material().value().overrideArmorMaterials().clear(); + } + return trim; + }); + } + + public static void downgradeItemData(final Item item) { + final StructuredDataContainer dataContainer = item.dataContainer(); + dataContainer.replace(StructuredDataKey.LOCK, StructuredDataKey.LOCK, lock -> { + final CompoundTag predicateTag = (CompoundTag) lock; + final CompoundTag itemComponentsTag = predicateTag.getCompoundTag("components"); + if (itemComponentsTag != null) { + // Back from json in the string tag to plain text + final StringTag customName = TagUtil.getNamespacedStringTag(itemComponentsTag, "custom_name"); + return new StringTag(SerializerVersion.V1_20_5.toComponent(customName.getValue()).asUnformattedString()); + } + return null; + }); + dataContainer.replace(StructuredDataKey.INSTRUMENT1_21_2, StructuredDataKey.INSTRUMENT1_20_5, instrument -> { + if (instrument.hasId()) { + return Holder.of(instrument.id()); + } + final Instrument1_21_2 value = instrument.value(); + return Holder.of(new Instrument1_20_5(value.soundEvent(), (int) (value.useDuration() * 20), value.range())); + }); + dataContainer.replace(StructuredDataKey.FOOD1_21_2, StructuredDataKey.FOOD1_21, food -> { + final Consumable1_21_2 consumableData = dataContainer.get(StructuredDataKey.CONSUMABLE1_21_2); + final Item useRemainderData = dataContainer.get(StructuredDataKey.USE_REMAINDER1_21_2); + final float eatSeconds = consumableData != null ? consumableData.consumeSeconds() : 1.6F; + final List foodEffects = new ArrayList<>(); + if (consumableData != null) { + for (Consumable1_21_2.ConsumeEffect consumeEffect : consumableData.consumeEffects()) { + if (consumeEffect.value() instanceof Consumable1_21_2.ApplyStatusEffects applyStatusEffects) { + for (PotionEffect effect : applyStatusEffects.effects()) { + foodEffects.add(new FoodProperties1_20_5.FoodEffect(effect, applyStatusEffects.probability())); + } + } + } + } + return new FoodProperties1_20_5(food.nutrition(), food.saturationModifier(), food.canAlwaysEat(), eatSeconds, useRemainderData, foodEffects.toArray(new FoodProperties1_20_5.FoodEffect[0])); + }); + dataContainer.replace(StructuredDataKey.TRIM1_21_2, StructuredDataKey.TRIM1_20_5, trim -> { + // TODO + if (trim.material().isDirect()) { + trim.material().value().overrideArmorMaterials().clear(); + } + return trim; + }); + dataContainer.replaceKey(StructuredDataKey.CONTAINER1_21_2, StructuredDataKey.CONTAINER1_21); + dataContainer.replaceKey(StructuredDataKey.CHARGED_PROJECTILES1_21_2, StructuredDataKey.CHARGED_PROJECTILES1_21); + dataContainer.replaceKey(StructuredDataKey.BUNDLE_CONTENTS1_21_2, StructuredDataKey.BUNDLE_CONTENTS1_21); + dataContainer.replaceKey(StructuredDataKey.POTION_CONTENTS1_21_2, StructuredDataKey.POTION_CONTENTS1_20_5); + dataContainer.replace(StructuredDataKey.DAMAGE_RESISTANT, StructuredDataKey.FIRE_RESISTANT, damageResistant -> { + if (Key.stripMinecraftNamespace(damageResistant.typesTagKey()).equals("is_fire")) { + return Unit.INSTANCE; + } + return null; + }); + dataContainer.remove(StructuredDataKey.REPAIRABLE); + dataContainer.remove(StructuredDataKey.ENCHANTABLE); + dataContainer.remove(StructuredDataKey.CONSUMABLE1_21_2); + dataContainer.remove(StructuredDataKey.USE_REMAINDER1_21_2); + dataContainer.remove(StructuredDataKey.USE_COOLDOWN); + dataContainer.remove(StructuredDataKey.ITEM_MODEL); + dataContainer.remove(StructuredDataKey.EQUIPPABLE); + dataContainer.remove(StructuredDataKey.GLIDER); + dataContainer.remove(StructuredDataKey.TOOLTIP_STYLE); + dataContainer.remove(StructuredDataKey.DEATH_PROTECTION); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/ComponentRewriter1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/ComponentRewriter1_21_2.java new file mode 100644 index 000000000..8bbe83214 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/ComponentRewriter1_21_2.java @@ -0,0 +1,123 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter; + +import com.viaversion.nbt.tag.CompoundTag; +import com.viaversion.nbt.tag.ListTag; +import com.viaversion.nbt.tag.NumberTag; +import com.viaversion.nbt.tag.StringTag; +import com.viaversion.nbt.tag.Tag; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.FullMappings; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2; +import com.viaversion.viaversion.rewriter.ComponentRewriter; +import com.viaversion.viaversion.util.SerializerVersion; +import com.viaversion.viaversion.util.TagUtil; +import java.util.Collections; +import java.util.Iterator; + +public final class ComponentRewriter1_21_2 extends ComponentRewriter { + + public ComponentRewriter1_21_2(final Protocol1_21To1_21_2 protocol) { + super(protocol, ReadType.NBT); + } + + @Override + protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, final CompoundTag componentsTag) { + super.handleShowItem(connection, itemTag, componentsTag); + if (componentsTag == null) { + return; + } + + convertAttributes(componentsTag, protocol.getMappingData().getAttributeMappings()); + + final CompoundTag instrument = TagUtil.getNamespacedCompoundTag(componentsTag, "instrument"); + if (instrument != null) { + instrument.putString("description", ""); + } + + final CompoundTag food = TagUtil.getNamespacedCompoundTag(componentsTag, "food"); + if (food != null) { + final CompoundTag convertsTo = food.getCompoundTag("using_converts_to"); + if (convertsTo != null) { + food.remove("using_converts_to"); + componentsTag.put("minecraft:use_remainder", convertsTo); + } + food.remove("eat_seconds"); + food.remove("effects"); + } + + + final CompoundTag enchantments = TagUtil.getNamespacedCompoundTag(componentsTag, "enchantments"); + if (enchantments != null) { + final CompoundTag levels = enchantments.getCompoundTag("levels"); + levels.entrySet().removeIf(entry -> ((NumberTag) entry.getValue()).asInt() == 0); + } + + TagUtil.removeNamespaced(componentsTag, "fire_resistant"); + TagUtil.removeNamespaced(componentsTag, "lock"); + + final StringTag customName = TagUtil.getNamespacedStringTag(componentsTag, "custom_name"); + final StringTag itemName = TagUtil.getNamespacedStringTag(componentsTag, "item_name"); + if (customName != null || itemName == null) { + return; + } + + final int identifier = protocol.getMappingData().getFullItemMappings().mappedId(itemTag.getString("id")); + if (identifier == 952 || identifier == 1147 || identifier == 1039 || identifier == 1203 || identifier == 1200 || identifier == 1204 || identifier == 1202) { + final var input = inputSerializerVersion(); + final var output = outputSerializerVersion(); + + final CompoundTag name = new CompoundTag(); + name.putBoolean("italic", false); + name.putString("text", ""); + final Tag nameTag = input.toTag(input.toComponent(itemName.getValue())); + name.put("extra", new ListTag<>(Collections.singletonList(nameTag))); + + componentsTag.put("minecraft:custom_name", new StringTag(output.toString(output.toComponent(name)))); + } + } + + public static void convertAttributes(final CompoundTag componentsTag, final FullMappings mappings) { + final CompoundTag attributeModifiers = TagUtil.getNamespacedCompoundTag(componentsTag, "attribute_modifiers"); + if (attributeModifiers == null) { + return; + } + + final ListTag modifiers = attributeModifiers.getListTag("modifiers", CompoundTag.class); + final Iterator iterator = modifiers.iterator(); + while (iterator.hasNext()) { + final CompoundTag modifier = iterator.next(); + final StringTag attribute = modifier.getStringTag("type"); + final String mappedAttribute = mappings.mappedIdentifier(attribute.getValue()); + if (mappedAttribute != null) { + attribute.setValue(mappedAttribute); + } else { + iterator.remove(); + } + } + } + + @Override + protected SerializerVersion inputSerializerVersion() { + return SerializerVersion.V1_20_5; + } + + // Only cosmetic changes in the 1.21.2 serializer +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/EntityPacketRewriter1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/EntityPacketRewriter1_21_2.java new file mode 100644 index 000000000..1926ff2fa --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/EntityPacketRewriter1_21_2.java @@ -0,0 +1,601 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter; + +import com.viaversion.nbt.tag.CompoundTag; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.entity.EntityTracker; +import com.viaversion.viaversion.api.minecraft.RegistryEntry; +import com.viaversion.viaversion.api.minecraft.entities.EntityType; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_2; +import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.version.Types1_21; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundConfigurationPackets1_21; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPackets1_21; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ClientboundPackets1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPackets1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ChunkLoadTracker; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ClientVehicleStorage; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.EntityTracker1_21_2; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.GroundFlagTracker; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage; +import com.viaversion.viaversion.rewriter.EntityRewriter; +import com.viaversion.viaversion.rewriter.RegistryDataRewriter; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +public final class EntityPacketRewriter1_21_2 extends EntityRewriter { + + private static final String[] GOAT_HORN_INSTRUMENTS = { + "ponder_goat_horn", + "sing_goat_horn", + "seek_goat_horn", + "feel_goat_horn", + "admire_goat_horn", + "call_goat_horn", + "yearn_goat_horn", + "dream_goat_horn" + }; + private static final float IMPULSE = 0.98F; + + public EntityPacketRewriter1_21_2(final Protocol1_21To1_21_2 protocol) { + super(protocol); + } + + @Override + public void registerPackets() { + registerTrackerWithData1_19(ClientboundPackets1_21.ADD_ENTITY, EntityTypes1_21_2.FALLING_BLOCK); + registerSetEntityData(ClientboundPackets1_21.SET_ENTITY_DATA, Types1_21.ENTITY_DATA_LIST, Types1_21_2.ENTITY_DATA_LIST); + registerRemoveEntities(ClientboundPackets1_21.REMOVE_ENTITIES); + + protocol.appendClientbound(ClientboundPackets1_21.ADD_ENTITY, wrapper -> { + final int entityType = wrapper.get(Types.VAR_INT, 1); + + final EntityType type = typeFromId(entityType); + if (type == null || !type.isOrHasParent(EntityTypes1_21_2.ABSTRACT_BOAT)) { + return; + } + + final int entityId = wrapper.get(Types.VAR_INT, 0); + final UUID uuid = wrapper.get(Types.UUID, 0); + + final double x = wrapper.get(Types.DOUBLE, 0); + final double y = wrapper.get(Types.DOUBLE, 1); + final double z = wrapper.get(Types.DOUBLE, 2); + + final float pitch = wrapper.get(Types.BYTE, 0) * 256.0F / 360.0F; + final float yaw = wrapper.get(Types.BYTE, 1) * 256.0F / 360.0F; + + final int data = wrapper.get(Types.VAR_INT, 2); + + final EntityTracker1_21_2 tracker = tracker(wrapper.user()); + final EntityTracker1_21_2.BoatEntity entity = tracker.trackBoatEntity(entityId, uuid, data); + entity.setPosition(x, y, z); + entity.setRotation(yaw, pitch); + }); + + protocol.registerFinishConfiguration(ClientboundConfigurationPackets1_21.FINISH_CONFIGURATION, wrapper -> { + final PacketWrapper instrumentsPacket = wrapper.create(ClientboundConfigurationPackets1_21.REGISTRY_DATA); + instrumentsPacket.write(Types.STRING, "minecraft:instrument"); + final RegistryEntry[] entries = new RegistryEntry[GOAT_HORN_INSTRUMENTS.length]; + for (int i = 0; i < GOAT_HORN_INSTRUMENTS.length; i++) { + final CompoundTag tag = new CompoundTag(); + tag.putString("sound_event", "item.goat_horn.sound." + i); + tag.putFloat("use_duration", 7); + tag.putInt("range", 256); + tag.putString("description", ""); + entries[i] = new RegistryEntry(GOAT_HORN_INSTRUMENTS[i], tag); + } + instrumentsPacket.write(Types.REGISTRY_ENTRY_ARRAY, entries); + instrumentsPacket.send(Protocol1_21To1_21_2.class); + }); + + final RegistryDataRewriter registryDataRewriter = registryDataRewriter(); + protocol.registerClientbound(ClientboundConfigurationPackets1_21.REGISTRY_DATA, registryDataRewriter::handle); + + protocol.registerClientbound(ClientboundPackets1_21.LOGIN, new PacketHandlers() { + @Override + public void register() { + map(Types.INT); // Entity id + map(Types.BOOLEAN); // Hardcore + map(Types.STRING_ARRAY); // World List + map(Types.VAR_INT); // Max players + map(Types.VAR_INT); // View distance + map(Types.VAR_INT); // Simulation distance + map(Types.BOOLEAN); // Reduced debug info + map(Types.BOOLEAN); // Show death screen + map(Types.BOOLEAN); // Limited crafting + map(Types.VAR_INT); // Dimension id + map(Types.STRING); // World + map(Types.LONG); // Seed + map(Types.BYTE); // Gamemode + map(Types.BYTE); // Previous gamemode + map(Types.BOOLEAN); // Debug + map(Types.BOOLEAN); // Flat + map(Types.OPTIONAL_GLOBAL_POSITION); // Last death location + map(Types.VAR_INT); // Portal cooldown + handler(worldDataTrackerHandlerByKey1_20_5(3)); + handler(playerTrackerHandler()); + create(Types.VAR_INT, 64); // Sea level, was hardcoded at 64 before + } + }); + + protocol.registerClientbound(ClientboundPackets1_21.RESPAWN, wrapper -> { + final int dimensionId = wrapper.passthrough(Types.VAR_INT); + final String world = wrapper.passthrough(Types.STRING); + wrapper.passthrough(Types.LONG); // Seed + wrapper.passthrough(Types.BYTE); // Gamemode + wrapper.passthrough(Types.BYTE); // Previous gamemode + wrapper.passthrough(Types.BOOLEAN); // Debug + wrapper.passthrough(Types.BOOLEAN); // Flat + wrapper.passthrough(Types.OPTIONAL_GLOBAL_POSITION); // Last death location + wrapper.passthrough(Types.VAR_INT); // Portal cooldown + + wrapper.write(Types.VAR_INT, 64); // Sea level + + final EntityTracker entityTracker = tracker(wrapper.user()); + if (entityTracker.currentWorld() != null && !entityTracker.currentWorld().equals(world)) { + final ChunkLoadTracker chunkLoadTracker = wrapper.user().get(ChunkLoadTracker.class); + if (chunkLoadTracker != null) { + chunkLoadTracker.clear(); + } + } + + trackWorldDataByKey1_20_5(wrapper.user(), dimensionId, world); + + wrapper.user().put(new GroundFlagTracker()); + wrapper.user().remove(ClientVehicleStorage.class); + }); + + protocol.registerClientbound(ClientboundPackets1_21.PLAYER_POSITION, wrapper -> { + wrapper.write(Types.VAR_INT, 0); // Teleport id, set at the end + + wrapper.passthrough(Types.DOUBLE); // X + wrapper.passthrough(Types.DOUBLE); // Y + wrapper.passthrough(Types.DOUBLE); // Z + + wrapper.write(Types.DOUBLE, 0D); // Delta movement X + wrapper.write(Types.DOUBLE, 0D); // Delta movement Y + wrapper.write(Types.DOUBLE, 0D); // Delta movement Z + + wrapper.passthrough(Types.FLOAT); // Y rot + wrapper.passthrough(Types.FLOAT); // X rot + + int relativeArguments = wrapper.read(Types.BYTE) & 0b00011111; + if ((relativeArguments & (1 << 0)) != 0) { // relative X + relativeArguments |= 1 << 5; // relative delta movement X + } + if ((relativeArguments & (1 << 1)) != 0) { // relative Y + relativeArguments |= 1 << 6; // relative delta movement Y + } + if ((relativeArguments & (1 << 2)) != 0) { // relative Z + relativeArguments |= 1 << 7; // relative delta movement Z + } + wrapper.write(Types.INT, relativeArguments); + + final int teleportId = wrapper.read(Types.VAR_INT); + wrapper.set(Types.VAR_INT, 0, teleportId); + + final PlayerPositionStorage positionStorage = wrapper.user().get(PlayerPositionStorage.class); + if (positionStorage == null) { + return; + } + + // Accept teleportation and player position were swapped. + // Send a ping first to then capture and send the player position the accept teleportation + final boolean isBundling = wrapper.user().get(BundleStateTracker.class).isBundling(); + if (!isBundling) { + final PacketWrapper bundleStart = wrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER); + bundleStart.send(Protocol1_21To1_21_2.class); + } + + final int pingId = ThreadLocalRandom.current().nextInt(); + positionStorage.addPendingPong(pingId); + final PacketWrapper ping = wrapper.create(ClientboundPackets1_21_2.PING); + ping.write(Types.INT, pingId); // id + ping.send(Protocol1_21To1_21_2.class); + wrapper.send(Protocol1_21To1_21_2.class); + wrapper.cancel(); + + if (!isBundling) { + final PacketWrapper bundleEnd = wrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER); + bundleEnd.send(Protocol1_21To1_21_2.class); + } + }); + + protocol.registerClientbound(ClientboundPackets1_21.SET_PASSENGERS, wrapper -> { + final int vehicleId = wrapper.passthrough(Types.VAR_INT); + final int[] passengerIds = wrapper.passthrough(Types.VAR_INT_ARRAY_PRIMITIVE); + final ClientVehicleStorage storage = wrapper.user().get(ClientVehicleStorage.class); + if (storage != null && vehicleId == storage.vehicleId()) { + wrapper.user().remove(ClientVehicleStorage.class); + } + + final EntityTracker1_21_2 tracker = tracker(wrapper.user()); + final EntityTracker1_21_2.BoatEntity entity = tracker.trackedBoatEntity(vehicleId); + if (entity != null) { + entity.setPassengers(passengerIds); + } + + final int clientEntityId = tracker(wrapper.user()).clientEntityId(); + for (final int passenger : passengerIds) { + if (passenger == clientEntityId) { + wrapper.user().put(new ClientVehicleStorage(vehicleId)); + break; + } + } + }); + protocol.appendClientbound(ClientboundPackets1_21.REMOVE_ENTITIES, wrapper -> { + final ClientVehicleStorage vehicleStorage = wrapper.user().get(ClientVehicleStorage.class); + if (vehicleStorage == null) { + return; + } + + final int[] entityIds = wrapper.get(Types.VAR_INT_ARRAY_PRIMITIVE, 0); + for (final int entityId : entityIds) { + if (entityId == vehicleStorage.vehicleId()) { + wrapper.user().remove(ClientVehicleStorage.class); + break; + } + } + }); + protocol.registerServerbound(ServerboundPackets1_21_2.PLAYER_INPUT, wrapper -> { + // Previously only used while in a vehicle, now always sent + // Filter them appropriately + if (!wrapper.user().has(ClientVehicleStorage.class)) { + wrapper.cancel(); + return; + } + + final byte flags = wrapper.read(Types.BYTE); + final boolean left = (flags & 1 << 2) != 0; + final boolean right = (flags & 1 << 3) != 0; + wrapper.write(Types.FLOAT, left ? IMPULSE : (right ? -IMPULSE : 0F)); + + final boolean forward = (flags & 1 << 0) != 0; + final boolean backward = (flags & 1 << 1) != 0; + wrapper.write(Types.FLOAT, forward ? IMPULSE : (backward ? -IMPULSE : 0F)); + + byte updatedFlags = 0; + if ((flags & 1 << 4) != 0) { + updatedFlags |= 1; + } + if ((flags & 1 << 5) != 0) { + updatedFlags |= 2; + } + wrapper.write(Types.BYTE, updatedFlags); + }); + + protocol.registerClientbound(ClientboundPackets1_21.TELEPORT_ENTITY, ClientboundPackets1_21_2.ENTITY_POSITION_SYNC, wrapper -> { + final int entityId = wrapper.passthrough(Types.VAR_INT); // Entity ID + + final double x = wrapper.passthrough(Types.DOUBLE); // X + final double y = wrapper.passthrough(Types.DOUBLE); // Y + final double z = wrapper.passthrough(Types.DOUBLE); // Z + + // Unused... + wrapper.write(Types.DOUBLE, 0D); // Delta movement X + wrapper.write(Types.DOUBLE, 0D); // Delta movement Y + wrapper.write(Types.DOUBLE, 0D); // Delta movement Z + + // Unpack y and x rot + final float yaw = wrapper.read(Types.BYTE) * 360F / 256F; + final float pitch = wrapper.read(Types.BYTE) * 360F / 256F; + wrapper.write(Types.FLOAT, yaw); + wrapper.write(Types.FLOAT, pitch); + + final EntityTracker1_21_2 tracker = tracker(wrapper.user()); + final EntityTracker1_21_2.BoatEntity trackedEntity = tracker.trackedBoatEntity(entityId); + if (trackedEntity == null) { + return; + } + trackedEntity.setPosition(x, y, z); + trackedEntity.setRotation(yaw, pitch); + }); + protocol.registerClientbound(ClientboundPackets1_21.MOVE_ENTITY_POS, wrapper -> storeEntityPositionRotation(wrapper, true, false)); + protocol.registerClientbound(ClientboundPackets1_21.MOVE_ENTITY_POS_ROT, wrapper -> storeEntityPositionRotation(wrapper, true, true)); + protocol.registerClientbound(ClientboundPackets1_21.MOVE_ENTITY_ROT, wrapper -> storeEntityPositionRotation(wrapper, false, true)); + + protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_POS, wrapper -> { + wrapper.passthrough(Types.DOUBLE); // X + wrapper.passthrough(Types.DOUBLE); // Y + wrapper.passthrough(Types.DOUBLE); // Z + handleOnGround(wrapper); + }); + protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_POS_ROT, wrapper -> { + final double x = wrapper.passthrough(Types.DOUBLE); // X + final double y = wrapper.passthrough(Types.DOUBLE); // Y + final double z = wrapper.passthrough(Types.DOUBLE); // Z + final float yaw = wrapper.passthrough(Types.FLOAT); // Yaw + final float pitch = wrapper.passthrough(Types.FLOAT); // Pitch + handleOnGround(wrapper); + + final PlayerPositionStorage playerPositionStorage = wrapper.user().get(PlayerPositionStorage.class); + if (playerPositionStorage != null && playerPositionStorage.checkCaptureNextPlayerPositionPacket()) { + // Capture this packet and send it after accept teleportation + final boolean onGround = wrapper.get(Types.BOOLEAN, 0); + playerPositionStorage.setPlayerPosition(new PlayerPositionStorage.PlayerPosition(x, y, z, yaw, pitch, onGround)); + wrapper.cancel(); + } + }); + protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_ROT, wrapper -> { + wrapper.passthrough(Types.FLOAT); // Yaw + wrapper.passthrough(Types.FLOAT); // Pitch + handleOnGround(wrapper); + }); + protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_STATUS_ONLY, wrapper -> { + final GroundFlagTracker tracker = wrapper.user().get(GroundFlagTracker.class); + final boolean prevOnGround = tracker.onGround(); + final boolean prevHorizontalCollision = tracker.horizontalCollision(); + + handleOnGround(wrapper); + if (prevOnGround == tracker.onGround() && prevHorizontalCollision != tracker.horizontalCollision()) { + // Newer clients will send idle packets even though the on ground state didn't change, ignore them + wrapper.cancel(); + } + }); + protocol.registerServerbound(ServerboundPackets1_21_2.ACCEPT_TELEPORTATION, wrapper -> { + final PlayerPositionStorage playerPositionStorage = wrapper.user().get(PlayerPositionStorage.class); + if (playerPositionStorage != null && playerPositionStorage.checkHasPlayerPosition()) { + // Send move player after accept teleportation + wrapper.sendToServer(Protocol1_21To1_21_2.class); + wrapper.cancel(); + playerPositionStorage.sendMovePlayerPosRot(wrapper.user()); + } + }); + } + + private RegistryDataRewriter registryDataRewriter() { + final CompoundTag enderpearlData = new CompoundTag(); + enderpearlData.putString("scaling", "when_caused_by_living_non_player"); + enderpearlData.putString("message_id", "fall"); + enderpearlData.putFloat("exhaustion", 0.0F); + + final CompoundTag maceSmashData = new CompoundTag(); + maceSmashData.putString("scaling", "when_caused_by_living_non_player"); + maceSmashData.putString("message_id", "mace_smash"); + maceSmashData.putFloat("exhaustion", 0.1F); + + final RegistryDataRewriter registryDataRewriter = new RegistryDataRewriter(protocol); + registryDataRewriter.addEntries( + "damage_type", + new RegistryEntry("minecraft:ender_pearl", enderpearlData), + new RegistryEntry("minecraft:mace_smash", maceSmashData) + ); + registryDataRewriter.addEnchantmentEffectRewriter("damage_item", tag -> tag.putString("type", "change_item_damage")); + return registryDataRewriter; + } + + private void handleOnGround(final PacketWrapper wrapper) { + final GroundFlagTracker tracker = wrapper.user().get(GroundFlagTracker.class); + + final short data = wrapper.read(Types.UNSIGNED_BYTE); + wrapper.write(Types.BOOLEAN, tracker.setOnGround((data & 1) != 0)); // Ignoring horizontal collision data + tracker.setHorizontalCollision((data & 2) != 0); + } + + private void storeEntityPositionRotation(final PacketWrapper wrapper, final boolean position, final boolean rotation) { + final int entityId = wrapper.passthrough(Types.VAR_INT); // Entity id + + final EntityTracker1_21_2 tracker = tracker(wrapper.user()); + final EntityTracker1_21_2.BoatEntity trackedEntity = tracker.trackedBoatEntity(entityId); + if (trackedEntity == null) { + return; + } + if (position) { + final double x = wrapper.passthrough(Types.SHORT) / 4096.0; // Delta X + final double y = wrapper.passthrough(Types.SHORT) / 4096.0; // Delta Y + final double z = wrapper.passthrough(Types.SHORT) / 4096.0; // Delta Z + trackedEntity.setPosition(trackedEntity.x() + x, trackedEntity.y() + y, trackedEntity.z() + z); + } + if (rotation) { + final float yaw = wrapper.passthrough(Types.BYTE) * 360.0F / 256.0F; + final float pitch = wrapper.passthrough(Types.BYTE) * 360.0F / 256.0F; + trackedEntity.setRotation(yaw, pitch); + } + } + + @Override + protected void registerRewrites() { + filter().mapDataType(Types1_21_2.ENTITY_DATA_TYPES::byId); + + registerEntityDataTypeHandler( + Types1_21_2.ENTITY_DATA_TYPES.itemType, + Types1_21_2.ENTITY_DATA_TYPES.blockStateType, + Types1_21_2.ENTITY_DATA_TYPES.optionalBlockStateType, + Types1_21_2.ENTITY_DATA_TYPES.particleType, + Types1_21_2.ENTITY_DATA_TYPES.particlesType, + Types1_21_2.ENTITY_DATA_TYPES.componentType, + Types1_21_2.ENTITY_DATA_TYPES.optionalComponentType + ); + registerBlockStateHandler(EntityTypes1_21_2.ABSTRACT_MINECART, 11); + + filter().type(EntityTypes1_21_2.ABSTRACT_BOAT).handler((event, data) -> { + final int dataIndex = event.index(); + // Boat type - now set as own entity type + // Idea is to remove the old entity, then add a new one and re-apply entity data and passengers + if (dataIndex > 11) { + event.setIndex(dataIndex - 1); + return; + } + if (dataIndex != 11) { + return; + } + event.cancel(); + + final EntityTracker1_21_2 tracker = tracker(event.user()); + final EntityTracker1_21_2.BoatEntity entity = tracker.trackedBoatEntity(event.entityId()); + if (entity == null) { + return; + } + + final boolean isBundling = event.user().get(BundleStateTracker.class).isBundling(); + if (!isBundling) { + final PacketWrapper bundleStart = PacketWrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER, event.user()); + bundleStart.send(Protocol1_21To1_21_2.class); + } + + // Remove old entity + final PacketWrapper removeEntityPacket = PacketWrapper.create(ClientboundPackets1_21_2.REMOVE_ENTITIES, event.user()); + removeEntityPacket.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[]{event.entityId()}); + removeEntityPacket.send(Protocol1_21To1_21_2.class); + + // Detect correct boat entity type from entity data + final int boatType = (int) data.getValue(); + EntityType entityType; + if (tracker.entityType(event.entityId()).isOrHasParent(EntityTypes1_21_2.ABSTRACT_CHEST_BOAT)) { + entityType = entityTypeFromChestBoatType(boatType); + } else { + entityType = entityTypeFromBoatType(boatType); + } + + // Spawn new entity + final PacketWrapper spawnEntityPacket = PacketWrapper.create(ClientboundPackets1_21_2.ADD_ENTITY, event.user()); + spawnEntityPacket.write(Types.VAR_INT, event.entityId()); // Entity ID + spawnEntityPacket.write(Types.UUID, entity.uuid()); // Entity UUID + spawnEntityPacket.write(Types.VAR_INT, entityType.getId()); // Entity type + spawnEntityPacket.write(Types.DOUBLE, entity.x()); // X + spawnEntityPacket.write(Types.DOUBLE, entity.y()); // Y + spawnEntityPacket.write(Types.DOUBLE, entity.z()); // Z + spawnEntityPacket.write(Types.BYTE, (byte) Math.floor(entity.pitch() * 256.0F / 360.0F)); // Pitch + spawnEntityPacket.write(Types.BYTE, (byte) Math.floor(entity.yaw() * 256.0F / 360.0F)); // Yaw + spawnEntityPacket.write(Types.BYTE, (byte) 0); // Head yaw + spawnEntityPacket.write(Types.VAR_INT, entity.data()); // Data + spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity X + spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity Y + spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity Z + spawnEntityPacket.send(Protocol1_21To1_21_2.class); + + // Update tracked entity in storage with new entity type + tracker.updateBoatType(event.entityId(), entityType); + + // Re-apply entity data previously set + final PacketWrapper setEntityDataPacket = PacketWrapper.create(ClientboundPackets1_21_2.SET_ENTITY_DATA, event.user()); + setEntityDataPacket.write(Types.VAR_INT, event.entityId()); + setEntityDataPacket.write(Types1_21_2.ENTITY_DATA_LIST, entity.entityData()); + setEntityDataPacket.send(Protocol1_21To1_21_2.class); + + // Re-attach all passengers + if (entity.passengers() != null) { + final PacketWrapper setPassengersPacket = PacketWrapper.create(ClientboundPackets1_21_2.SET_PASSENGERS, event.user()); + setPassengersPacket.write(Types.VAR_INT, event.entityId()); + setPassengersPacket.write(Types.VAR_INT_ARRAY_PRIMITIVE, entity.passengers()); + setPassengersPacket.send(Protocol1_21To1_21_2.class); + } + + if (!isBundling) { + final PacketWrapper bundleEnd = PacketWrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER, event.user()); + bundleEnd.send(Protocol1_21To1_21_2.class); + } + }); + + filter().type(EntityTypes1_21_2.SALMON).addIndex(17); // Data type + filter().type(EntityTypes1_21_2.AGEABLE_WATER_CREATURE).addIndex(16); // Baby + + filter().type(EntityTypes1_21_2.ABSTRACT_ARROW).addIndex(10); // In ground + } + + @Override + public void handleEntityData(final int entityId, final List dataList, final UserConnection connection) { + super.handleEntityData(entityId, dataList, connection); + + final EntityTracker1_21_2 tracker = tracker(connection); + final EntityType entityType = tracker.entityType(entityId); + if (entityType == null || !entityType.isOrHasParent(EntityTypes1_21_2.ABSTRACT_BOAT)) { + return; + } + + final List entityData = tracker.trackedBoatEntity(entityId).entityData(); + entityData.removeIf(first -> dataList.stream().anyMatch(second -> first.id() == second.id())); + for (final EntityData data : dataList) { + final Object value = data.value(); + if (value instanceof Item item) { + entityData.add(new EntityData(data.id(), data.dataType(), item.copy())); + } else { + entityData.add(new EntityData(data.id(), data.dataType(), value)); + } + } + } + + private EntityType entityTypeFromBoatType(final int boatType) { + if (boatType == 0) { + return EntityTypes1_21_2.OAK_BOAT; + } else if (boatType == 1) { + return EntityTypes1_21_2.SPRUCE_BOAT; + } else if (boatType == 2) { + return EntityTypes1_21_2.BIRCH_BOAT; + } else if (boatType == 3) { + return EntityTypes1_21_2.JUNGLE_BOAT; + } else if (boatType == 4) { + return EntityTypes1_21_2.ACACIA_BOAT; + } else if (boatType == 5) { + return EntityTypes1_21_2.CHERRY_BOAT; + } else if (boatType == 6) { + return EntityTypes1_21_2.DARK_OAK_BOAT; + } else if (boatType == 7) { + return EntityTypes1_21_2.MANGROVE_BOAT; + } else if (boatType == 8) { + return EntityTypes1_21_2.BAMBOO_RAFT; + } else { + return EntityTypes1_21_2.OAK_BOAT; // Fallback + } + } + + private EntityType entityTypeFromChestBoatType(final int chestBoatType) { + if (chestBoatType == 0) { + return EntityTypes1_21_2.OAK_CHEST_BOAT; + } else if (chestBoatType == 1) { + return EntityTypes1_21_2.SPRUCE_CHEST_BOAT; + } else if (chestBoatType == 2) { + return EntityTypes1_21_2.BIRCH_CHEST_BOAT; + } else if (chestBoatType == 3) { + return EntityTypes1_21_2.JUNGLE_CHEST_BOAT; + } else if (chestBoatType == 4) { + return EntityTypes1_21_2.ACACIA_CHEST_BOAT; + } else if (chestBoatType == 5) { + return EntityTypes1_21_2.CHERRY_CHEST_BOAT; + } else if (chestBoatType == 6) { + return EntityTypes1_21_2.DARK_OAK_CHEST_BOAT; + } else if (chestBoatType == 7) { + return EntityTypes1_21_2.MANGROVE_CHEST_BOAT; + } else if (chestBoatType == 8) { + return EntityTypes1_21_2.BAMBOO_CHEST_RAFT; + } else { + return EntityTypes1_21_2.OAK_CHEST_BOAT; // Fallback + } + } + + @Override + public EntityType typeFromId(final int type) { + return EntityTypes1_21_2.getTypeFromId(type); + } + + @Override + public void onMappingDataLoaded() { + mapTypes(); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/ParticleRewriter1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/ParticleRewriter1_21_2.java new file mode 100644 index 000000000..369e28a9c --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/ParticleRewriter1_21_2.java @@ -0,0 +1,55 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.Particle; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.version.Types1_21; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21; +import com.viaversion.viaversion.rewriter.ParticleRewriter; + +public final class ParticleRewriter1_21_2 extends ParticleRewriter { + + public ParticleRewriter1_21_2(final Protocol protocol) { + super(protocol, Types1_21.PARTICLE, Types1_21_2.PARTICLE); + } + + private void floatsToARGB(final Particle particle, final int fromIndex) { + final Particle.ParticleData r = particle.removeArgument(fromIndex); + final Particle.ParticleData g = particle.removeArgument(fromIndex); + final Particle.ParticleData b = particle.removeArgument(fromIndex); + final int rgb = 255 << 24 | (int) (r.getValue() * 255) << 16 | (int) (g.getValue() * 255) << 8 | (int) (b.getValue() * 255); + particle.add(fromIndex, Types.INT, rgb); + } + + @Override + public void rewriteParticle(final UserConnection connection, final Particle particle) { + super.rewriteParticle(connection, particle); + + final String identifier = protocol.getMappingData().getParticleMappings().mappedIdentifier(particle.id()); + if ("minecraft:dust_color_transition".equals(identifier)) { + floatsToARGB(particle, 0); + floatsToARGB(particle, 1); + } else if ("minecraft:dust".equals(identifier)) { + floatsToARGB(particle, 0); + } + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/RecipeRewriter1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/RecipeRewriter1_21_2.java new file mode 100644 index 000000000..aaebcfc6c --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/RecipeRewriter1_21_2.java @@ -0,0 +1,350 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter; + +import com.viaversion.viaversion.api.connection.StorableObject; +import com.viaversion.viaversion.api.minecraft.HolderSet; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.api.type.types.version.Types1_21_2; +import com.viaversion.viaversion.protocols.v1_20_2to1_20_3.rewriter.RecipeRewriter1_20_3; +import com.viaversion.viaversion.protocols.v1_20_5to1_21.packet.ClientboundPacket1_21; +import com.viaversion.viaversion.util.Key; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.checkerframework.checker.nullness.qual.Nullable; + +// Use directly as a connection storage. Slightly weird, but easiest and closed off from other packages +final class RecipeRewriter1_21_2 extends RecipeRewriter1_20_3 implements StorableObject { + + private static final int[] EMPTY_ARRAY = new int[0]; + private final List stoneCutterRecipes = new ArrayList<>(); + private final Object2IntMap recipeGroups = new Object2IntOpenHashMap<>(); + private final Map recipesByKey = new HashMap<>(); + private final Map recipeInputs = new Object2ObjectArrayMap<>(); + private final List recipes = new ArrayList<>(); + private String currentRecipeIdentifier; + + public void setCurrentRecipeIdentifier(final String recipeIdentifier) { + this.currentRecipeIdentifier = Key.stripMinecraftNamespace(recipeIdentifier); + } + + RecipeRewriter1_21_2(final Protocol protocol) { + super(protocol); + recipeGroups.defaultReturnValue(-1); + + recipeHandlers.put("smelting", wrapper -> handleSmelting("furnace_input", wrapper)); + recipeHandlers.put("blasting", wrapper -> handleSmelting("blast_furnace_input", wrapper)); + recipeHandlers.put("smoking", wrapper -> handleSmelting("smoker_input", wrapper)); + recipeHandlers.put("campfire_cooking", wrapper -> handleSmelting("campfire_input", wrapper)); + } + + @Override + public void handleSimpleRecipe(final PacketWrapper wrapper) { + final int category = wrapper.read(Types.VAR_INT); + // Special recipes aren't sent to the client + } + + @Override + public void handleStonecutting(final PacketWrapper wrapper) { + final int group = readRecipeGroup(wrapper); + final Item[] ingredient = readIngredient(wrapper); + final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); + + final StoneCutterRecipe recipe = new StoneCutterRecipe(currentRecipeIdentifier, group, ingredient, result); + stoneCutterRecipes.add(recipe); // Sent separately in update_recipes + } + + private void addRecipe(final Recipe recipe) { + recipes.add(recipe); + recipesByKey.put(currentRecipeIdentifier, recipe); + } + + @Override + public void handleSmithingTransform(final PacketWrapper wrapper) { + readRecipeInputs("smithing_template", wrapper); + readRecipeInputs("smithing_base", wrapper); + readRecipeInputs("smithing_addition", wrapper); + wrapper.read(itemType()); // Result + } + + @Override + public void handleSmithingTrim(final PacketWrapper wrapper) { + readRecipeInputs("smithing_template", wrapper); + readRecipeInputs("smithing_base", wrapper); + readRecipeInputs("smithing_addition", wrapper); + } + + @Override + public void handleCraftingShaped(final PacketWrapper wrapper) { + final int group = readRecipeGroup(wrapper); + final int category = wrapper.read(Types.VAR_INT); + final int width = wrapper.read(Types.VAR_INT); + final int height = wrapper.read(Types.VAR_INT); + final int ingredientsSize = width * height; + final Item[][] ingredients = new Item[ingredientsSize][]; + for (int i = 0; i < ingredientsSize; i++) { + ingredients[i] = readIngredient(wrapper); + } + final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); + final boolean showNotification = wrapper.read(Types.BOOLEAN); + + final ShapedRecipe recipe = new ShapedRecipe(recipesByKey.size(), currentRecipeIdentifier, group, category, width, height, ingredients, result, showNotification); + addRecipe(recipe); + } + + @Override + public void handleCraftingShapeless(final PacketWrapper wrapper) { + final int group = readRecipeGroup(wrapper); + final int category = wrapper.read(Types.VAR_INT); + final int ingredientsSize = wrapper.read(Types.VAR_INT); + final Item[][] ingredients = new Item[ingredientsSize][]; + for (int i = 0; i < ingredientsSize; i++) { + ingredients[i] = readIngredient(wrapper); + } + final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); + + final ShapelessRecipe recipe = new ShapelessRecipe(recipesByKey.size(), currentRecipeIdentifier, group, category, ingredients, result); + addRecipe(recipe); + } + + public void handleSmelting(final String key, final PacketWrapper wrapper) { + final int group = readRecipeGroup(wrapper); + final int category = wrapper.read(Types.VAR_INT); + final Item[] ingredient = readRecipeInputs(key, wrapper); + final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); + final float experience = wrapper.read(Types.FLOAT); + final int cookingTime = wrapper.read(Types.VAR_INT); + + final FurnaceRecipe recipe = new FurnaceRecipe(recipesByKey.size(), currentRecipeIdentifier, group, category, ingredient, result, cookingTime, experience); + addRecipe(recipe); + } + + private int readRecipeGroup(final PacketWrapper wrapper) { + final String recipeGroup = Key.stripMinecraftNamespace(wrapper.read(Types.STRING)); + if (recipeGroup.isEmpty()) { + return -1; + } + + if (recipeGroups.containsKey(recipeGroup)) { + return recipeGroups.getInt(recipeGroup); + } + + final int size = recipeGroups.size(); + recipeGroups.put(recipeGroup, size); + return size; + } + + private Item[] readIngredient(final PacketWrapper wrapper) { + final Item[] items = wrapper.read(itemArrayType()); + for (int i = 0; i < items.length; i++) { + final Item item = items[i]; + items[i] = rewrite(wrapper.user(), item); + } + return items; + } + + public HolderSet toHolderSet(final Item[] ingredient) { + // Ingredients are no longer full items, already store them as just holder sets + final int[] ids = new int[ingredient.length]; + for (int i = 0; i < ingredient.length; i++) { + ids[i] = ingredient[i].identifier(); + } + return HolderSet.of(ids); + } + + public @Nullable Recipe recipe(final String key) { + return recipesByKey.get(Key.stripMinecraftNamespace(key)); + } + + public @Nullable Recipe recipe(final int displayId) { + return displayId >= 0 && displayId < recipes.size() ? recipes.get(displayId) : null; + } + + public void finalizeRecipes() { + // Need to be sorted alphabetically + stoneCutterRecipes.sort(Comparator.comparing(recipe -> recipe.identifier)); + } + + public void writeUpdateRecipeInputs(final PacketWrapper wrapper) { + // Smithing and smelting inputs + wrapper.write(Types.VAR_INT, recipeInputs.size()); + for (final Map.Entry entry : recipeInputs.entrySet()) { + wrapper.write(Types.STRING, entry.getKey()); + wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, entry.getValue().toArray(EMPTY_ARRAY)); + } + + // Stonecutter recipes + wrapper.write(Types.VAR_INT, stoneCutterRecipes.size()); + for (final StoneCutterRecipe recipe : stoneCutterRecipes) { + final HolderSet ingredient = toHolderSet(recipe.ingredient()); + wrapper.write(Types.HOLDER_SET, ingredient); + writeItemDisplay(wrapper, recipe.result()); + } + } + + private Item[] readRecipeInputs(final String key, final PacketWrapper wrapper) { + // Collect inputs for new UPDATE_RECIPE + final Item[] ingredient = readIngredient(wrapper); + final IntSet ids = recipeInputs.computeIfAbsent(key, $ -> new IntOpenHashSet(ingredient.length)); + for (final Item item : ingredient) { + ids.add(item.identifier()); + } + return ingredient; + } + + interface Recipe { + int SLOT_DISPLAY_EMPTY = 0; + int SLOT_DISPLAY_ANY_FUEL = 1; + int SLOT_DISPLAY_ITEM = 3; + int SLOT_DISPLAY_COMPOSITE = 7; + + int index(); + + String identifier(); + + int recipeDisplayId(); + + default Item @Nullable [][] ingredients() { + final Item[] ingredient = ingredient(); + return ingredient == null ? null : new Item[][]{ingredient}; + } + + default Item @Nullable [] ingredient() { + return null; + } + + default int group() { + return -1; + } + + default boolean showNotification() { + return true; + } + + int category(); + + void writeRecipeDisplay(PacketWrapper wrapper); + } + + record ShapelessRecipe(int index, String identifier, int group, int category, Item[][] ingredients, + Item result) implements Recipe { + @Override + public int recipeDisplayId() { + return 0; + } + + @Override + public void writeRecipeDisplay(final PacketWrapper wrapper) { + writeIngredientsDisplay(wrapper, ingredients); + writeItemDisplay(wrapper, result); + writeCraftingStationDisplay(wrapper); + } + } + + record ShapedRecipe(int index, String identifier, int group, int category, int width, int height, + Item[][] ingredients, Item result, boolean showNotification) implements Recipe { + @Override + public int recipeDisplayId() { + return 1; + } + + @Override + public void writeRecipeDisplay(final PacketWrapper wrapper) { + wrapper.write(Types.VAR_INT, width); + wrapper.write(Types.VAR_INT, height); + writeIngredientsDisplay(wrapper, ingredients); + writeItemDisplay(wrapper, result); + writeCraftingStationDisplay(wrapper); + } + } + + record FurnaceRecipe(int index, String identifier, int group, int category, Item[] ingredient, + Item result, int duration, float experience) implements Recipe { + @Override + public int recipeDisplayId() { + return 2; + } + + @Override + public void writeRecipeDisplay(final PacketWrapper wrapper) { + writeIngredientDisplay(wrapper, ingredient); + wrapper.write(Types.VAR_INT, SLOT_DISPLAY_ANY_FUEL); // Fuel + writeItemDisplay(wrapper, result); + writeCraftingStationDisplay(wrapper); + wrapper.write(Types.VAR_INT, duration); + wrapper.write(Types.FLOAT, experience); + } + } + + record StoneCutterRecipe(String identifier, int group, Item[] ingredient, Item result) { + + public int recipeDisplayId() { + return 3; + } + + public void writeRecipeDisplay(final PacketWrapper wrapper) { + writeIngredientDisplay(wrapper, ingredient); + writeItemDisplay(wrapper, result); + writeCraftingStationDisplay(wrapper); + } + } + + private static void writeIngredientsDisplay(final PacketWrapper wrapper, final Item[][] ingredients) { + wrapper.write(Types.VAR_INT, ingredients.length); + for (final Item[] ingredient : ingredients) { + writeIngredientDisplay(wrapper, ingredient); + } + } + + private static void writeIngredientDisplay(final PacketWrapper wrapper, final Item[] ingredient) { + if (ingredient.length == 0) { + wrapper.write(Types.VAR_INT, Recipe.SLOT_DISPLAY_EMPTY); + return; + } + if (ingredient.length == 1) { + writeItemDisplay(wrapper, ingredient[0]); + return; + } + + wrapper.write(Types.VAR_INT, Recipe.SLOT_DISPLAY_COMPOSITE); + wrapper.write(Types.VAR_INT, ingredient.length); + for (final Item item : ingredient) { + writeItemDisplay(wrapper, item); + } + } + + private static void writeItemDisplay(final PacketWrapper wrapper, final Item item) { + wrapper.write(Types.VAR_INT, Recipe.SLOT_DISPLAY_ITEM); + wrapper.write(Types1_21_2.ITEM, item.copy()); + } + + private static void writeCraftingStationDisplay(final PacketWrapper wrapper) { + wrapper.write(Types.VAR_INT, Recipe.SLOT_DISPLAY_EMPTY); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/BundleStateTracker.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/BundleStateTracker.java new file mode 100644 index 000000000..fd93aef9e --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/BundleStateTracker.java @@ -0,0 +1,34 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; + +public class BundleStateTracker implements StorableObject { + + private boolean bundling; + + public boolean isBundling() { + return this.bundling; + } + + public void toggleBundling() { + this.bundling = !this.bundling; + } + +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/ChunkLoadTracker.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/ChunkLoadTracker.java new file mode 100644 index 000000000..c1f8cbb00 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/ChunkLoadTracker.java @@ -0,0 +1,45 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; +import com.viaversion.viaversion.api.minecraft.ChunkPosition; +import java.util.HashSet; +import java.util.Set; + +public class ChunkLoadTracker implements StorableObject { + + private final Set loadedChunks = new HashSet<>(); + + public void addChunk(final int x, final int z) { + this.loadedChunks.add(ChunkPosition.chunkKey(x, z)); + } + + public void removeChunk(final int x, final int z) { + this.loadedChunks.remove(ChunkPosition.chunkKey(x, z)); + } + + public boolean isChunkLoaded(final int x, final int z) { + return this.loadedChunks.contains(ChunkPosition.chunkKey(x, z)); + } + + public void clear() { + this.loadedChunks.clear(); + } + +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/ClientVehicleStorage.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/ClientVehicleStorage.java new file mode 100644 index 000000000..303e1438b --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/ClientVehicleStorage.java @@ -0,0 +1,23 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; + +public record ClientVehicleStorage(int vehicleId) implements StorableObject { +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/EntityTracker1_21_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/EntityTracker1_21_2.java new file mode 100644 index 000000000..72a312b7a --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/EntityTracker1_21_2.java @@ -0,0 +1,135 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.entities.EntityType; +import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_2; +import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; +import com.viaversion.viaversion.data.entity.EntityTrackerBase; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public final class EntityTracker1_21_2 extends EntityTrackerBase { + + private final Int2ObjectMap boats = new Int2ObjectOpenHashMap<>(); + + public EntityTracker1_21_2(final UserConnection connection) { + super(connection, EntityTypes1_21_2.PLAYER); + } + + public BoatEntity trackBoatEntity(final int entityId, final UUID uuid, final int data) { + final BoatEntity entity = new BoatEntity(uuid, data); + boats.put(entityId, entity); + return entity; + } + + public BoatEntity trackedBoatEntity(final int entityId) { + return boats.get(entityId); + } + + @Override + public void removeEntity(final int id) { + super.removeEntity(id); + boats.remove(id); + } + + public void updateBoatType(final int entityId, final EntityType type) { + final BoatEntity entity = boats.get(entityId); + removeEntity(entityId); + boats.put(entityId, entity); + addEntity(entityId, type); + } + + public static class BoatEntity { + + private final List entityData = new ArrayList<>(); + + private final UUID uuid; + private final int data; + + private double x; + private double y; + private double z; + + private float yaw; + private float pitch; + + private int[] passengers; + + public BoatEntity(final UUID uuid, final int data) { + this.uuid = uuid; + this.data = data; + } + + public void setPosition(final double x, final double y, final double z) { + this.x = x; + this.y = y; + this.z = z; + } + + public void setRotation(final float yaw, final float pitch) { + this.yaw = yaw; + this.pitch = pitch; + } + + public void setPassengers(final int[] passengers) { + this.passengers = passengers; + } + + public UUID uuid() { + return uuid; + } + + public int data() { + return data; + } + + public double x() { + return x; + } + + public double y() { + return y; + } + + public double z() { + return z; + } + + public float yaw() { + return yaw; + } + + public float pitch() { + return pitch; + } + + public List entityData() { + return entityData; + } + + public int[] passengers() { + return passengers; + } + } + +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/GroundFlagTracker.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/GroundFlagTracker.java new file mode 100644 index 000000000..0d44d8829 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/GroundFlagTracker.java @@ -0,0 +1,43 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; + +public final class GroundFlagTracker implements StorableObject { + + private boolean onGround; + private boolean horizontalCollision; + + public boolean onGround() { + return this.onGround; + } + + public boolean setOnGround(boolean onGround) { + return this.onGround = onGround; + } + + public boolean horizontalCollision() { + return this.horizontalCollision; + } + + public void setHorizontalCollision(boolean horizontalCollision) { + this.horizontalCollision = horizontalCollision; + } + +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/PlayerPositionStorage.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/PlayerPositionStorage.java new file mode 100644 index 000000000..4537b9d5e --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/storage/PlayerPositionStorage.java @@ -0,0 +1,94 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage; + +import com.viaversion.viaversion.api.connection.StorableObject; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPackets1_20_5; +import com.viaversion.viaversion.protocols.v1_21to1_21_2.Protocol1_21To1_21_2; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; + +public class PlayerPositionStorage implements StorableObject { + + private final IntSet pendingPongs = new IntOpenHashSet(); + private boolean captureNextPlayerPositionPacket; + private PlayerPosition playerPosition; + + public void addPendingPong(final int id) { + if (!this.pendingPongs.add(id)) { + throw new IllegalStateException("Pong already pending for id " + id); + } + } + + public boolean checkPong(final int id) { + if (this.pendingPongs.remove(id)) { + this.reset(); // Ensure we don't have any leftover state + this.captureNextPlayerPositionPacket = true; + return true; + } else { + return false; + } + } + + public boolean checkCaptureNextPlayerPositionPacket() { + if (this.captureNextPlayerPositionPacket) { + this.captureNextPlayerPositionPacket = false; + return true; + } else { // Packet order was wrong + this.reset(); + return false; + } + } + + public void setPlayerPosition(final PlayerPosition playerPosition) { + this.playerPosition = playerPosition; + } + + public boolean checkHasPlayerPosition() { + if (this.playerPosition != null) { + return true; + } else { // Packet order was wrong (ACCEPT_TELEPORTATION before MOVE_PLAYER_POS_ROT packet) + this.reset(); + return false; + } + } + + public void sendMovePlayerPosRot(final UserConnection user) { + final PacketWrapper movePlayerPosRot = PacketWrapper.create(ServerboundPackets1_20_5.MOVE_PLAYER_POS_ROT, user); + movePlayerPosRot.write(Types.DOUBLE, this.playerPosition.x); // X + movePlayerPosRot.write(Types.DOUBLE, this.playerPosition.y); // Y + movePlayerPosRot.write(Types.DOUBLE, this.playerPosition.z); // Z + movePlayerPosRot.write(Types.FLOAT, this.playerPosition.yaw); // Yaw + movePlayerPosRot.write(Types.FLOAT, this.playerPosition.pitch); // Pitch + movePlayerPosRot.write(Types.BOOLEAN, this.playerPosition.onGround); // On Ground + movePlayerPosRot.sendToServer(Protocol1_21To1_21_2.class); + this.reset(); + } + + private void reset() { + this.captureNextPlayerPositionPacket = false; + this.playerPosition = null; + } + + public record PlayerPosition(double x, double y, double z, float yaw, float pitch, boolean onGround) { + } + +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/rewriter/WorldPacketRewriter1_9.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/rewriter/WorldPacketRewriter1_9.java index d0bb3c3a8..ed24927b9 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/rewriter/WorldPacketRewriter1_9.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/rewriter/WorldPacketRewriter1_9.java @@ -21,8 +21,8 @@ import com.viaversion.nbt.tag.CompoundTag; import com.viaversion.nbt.tag.StringTag; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.minecraft.BlockFace; -import com.viaversion.viaversion.api.minecraft.ClientWorld; import com.viaversion.viaversion.api.minecraft.BlockPosition; +import com.viaversion.viaversion.api.minecraft.ChunkPosition; import com.viaversion.viaversion.api.minecraft.chunks.BaseChunk; import com.viaversion.viaversion.api.minecraft.chunks.Chunk; import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection; @@ -30,6 +30,7 @@ import com.viaversion.viaversion.api.minecraft.item.DataItem; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.api.type.types.chunk.BulkChunkType1_8; @@ -133,7 +134,7 @@ public class WorldPacketRewriter1_9 { ClientWorld1_9 clientWorld = wrapper.user().getClientWorld(Protocol1_8To1_9.class); Chunk chunk = wrapper.read(ChunkType1_8.forEnvironment(clientWorld.getEnvironment())); - long chunkHash = ClientWorld1_9.toLong(chunk.getX(), chunk.getZ()); + long chunkHash = ChunkPosition.chunkKey(chunk.getX(), chunk.getZ()); // Check if the chunk should be handled as an unload packet if (chunk.isFullChunk() && chunk.getBitmask() == 0) { @@ -152,7 +153,7 @@ public class WorldPacketRewriter1_9 { for (BlockFace face : BlockFace.HORIZONTAL) { int chunkX = chunk.getX() + face.modX(); int chunkZ = chunk.getZ() + face.modZ(); - if (!clientWorld.getLoadedChunks().contains(ClientWorld1_9.toLong(chunkX, chunkZ))) { + if (!clientWorld.getLoadedChunks().contains(ChunkPosition.chunkKey(chunkX, chunkZ))) { PacketWrapper unloadChunk = wrapper.create(ClientboundPackets1_9.FORGET_LEVEL_CHUNK); unloadChunk.write(Types.INT, chunkX); unloadChunk.write(Types.INT, chunkZ); @@ -171,7 +172,7 @@ public class WorldPacketRewriter1_9 { for (BlockFace face : BlockFace.HORIZONTAL) { int chunkX = chunk.getX() + face.modX(); int chunkZ = chunk.getZ() + face.modZ(); - if (!clientWorld.getLoadedChunks().contains(ClientWorld1_9.toLong(chunkX, chunkZ))) { + if (!clientWorld.getLoadedChunks().contains(ChunkPosition.chunkKey(chunkX, chunkZ))) { PacketWrapper emptyChunk = wrapper.create(ClientboundPackets1_9.LEVEL_CHUNK); Chunk c = new BaseChunk(chunkX, chunkZ, true, false, 0, new ChunkSection[16], new int[256], new ArrayList<>()); emptyChunk.write(chunkType, c); @@ -194,14 +195,14 @@ public class WorldPacketRewriter1_9 { chunkData.write(chunkType, chunk); chunkData.send(Protocol1_8To1_9.class); - clientWorld.getLoadedChunks().add(ClientWorld1_9.toLong(chunk.getX(), chunk.getZ())); + clientWorld.getLoadedChunks().add(ChunkPosition.chunkKey(chunk.getX(), chunk.getZ())); // Send empty chunks surrounding the loaded chunk to force 1.9+ clients to render the new chunk if (Via.getConfig().isChunkBorderFix()) { for (BlockFace face : BlockFace.HORIZONTAL) { int chunkX = chunk.getX() + face.modX(); int chunkZ = chunk.getZ() + face.modZ(); - if (!clientWorld.getLoadedChunks().contains(ClientWorld1_9.toLong(chunkX, chunkZ))) { + if (!clientWorld.getLoadedChunks().contains(ChunkPosition.chunkKey(chunkX, chunkZ))) { PacketWrapper emptyChunk = wrapper.create(ClientboundPackets1_9.LEVEL_CHUNK); Chunk c = new BaseChunk(chunkX, chunkZ, true, false, 0, new ChunkSection[16], new int[256], new ArrayList<>()); emptyChunk.write(chunkType, c); @@ -297,8 +298,9 @@ public class WorldPacketRewriter1_9 { wrapper.write(Types.UNSIGNED_BYTE, (short) 255); // Write item in hand Item item = Via.getManager().getProviders().get(HandItemProvider.class).getHandItem(wrapper.user()); - // Blocking patch - if (Via.getConfig().isShieldBlocking()) { + // Blocking patch for 1.9-1.21.3 clients + if (Via.getConfig().isShieldBlocking() && + wrapper.user().getProtocolInfo().protocolVersion().olderThan(ProtocolVersion.v1_21_4)) { EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_8To1_9.class); // Check if the shield is already there or if we have to give it here diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/ClientWorld1_9.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/ClientWorld1_9.java index 7defcd00e..953976af7 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/ClientWorld1_9.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/ClientWorld1_9.java @@ -17,16 +17,13 @@ */ package com.viaversion.viaversion.protocols.v1_8to1_9.storage; -import com.google.common.collect.Sets; import com.viaversion.viaversion.api.minecraft.ClientWorld; +import java.util.HashSet; import java.util.Set; public class ClientWorld1_9 extends ClientWorld { - private final Set loadedChunks = Sets.newConcurrentHashSet(); - public static long toLong(int msw, int lsw) { - return ((long) msw << 32) + lsw + 2147483648L; - } + private final Set loadedChunks = new HashSet<>(); public Set getLoadedChunks() { return loadedChunks; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/CommandBlockStorage.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/CommandBlockStorage.java index 994d69d48..b629092e3 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/CommandBlockStorage.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/CommandBlockStorage.java @@ -21,53 +21,35 @@ import com.viaversion.nbt.tag.ByteTag; import com.viaversion.nbt.tag.CompoundTag; import com.viaversion.viaversion.api.connection.StorableObject; import com.viaversion.viaversion.api.minecraft.BlockPosition; -import com.viaversion.viaversion.util.Pair; +import com.viaversion.viaversion.api.minecraft.ChunkPosition; +import java.util.HashMap; import java.util.Map; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; public class CommandBlockStorage implements StorableObject { - private final Map, Map> storedCommandBlocks = new ConcurrentHashMap<>(); + private final Map> storedCommandBlocks = new HashMap<>(); private boolean permissions; public void unloadChunk(int x, int z) { - Pair chunkPos = new Pair<>(x, z); - storedCommandBlocks.remove(chunkPos); + storedCommandBlocks.remove(ChunkPosition.chunkKey(x, z)); } public void addOrUpdateBlock(BlockPosition position, CompoundTag tag) { - Pair chunkPos = getChunkCoords(position); - - if (!storedCommandBlocks.containsKey(chunkPos)) { - storedCommandBlocks.put(chunkPos, new ConcurrentHashMap<>()); - } - - Map blocks = storedCommandBlocks.get(chunkPos); - - if (blocks.containsKey(position) && blocks.get(position).equals(tag)) { - return; - } - + long chunkKey = ChunkPosition.chunkKeyForBlock(position.x(), position.z()); + Map blocks = storedCommandBlocks.computeIfAbsent(chunkKey, k -> new HashMap<>()); blocks.put(position, tag); } - private Pair getChunkCoords(BlockPosition position) { - int chunkX = Math.floorDiv(position.x(), 16); - int chunkZ = Math.floorDiv(position.z(), 16); - - return new Pair<>(chunkX, chunkZ); - } - public Optional getCommandBlock(BlockPosition position) { - Pair chunkCoords = getChunkCoords(position); - - Map blocks = storedCommandBlocks.get(chunkCoords); - if (blocks == null) + Map blocks = storedCommandBlocks.get(ChunkPosition.chunkKeyForBlock(position.x(), position.z())); + if (blocks == null) { return Optional.empty(); + } CompoundTag tag = blocks.get(position); - if (tag == null) + if (tag == null) { return Optional.empty(); + } tag = tag.copy(); tag.put("powered", new ByteTag((byte) 0)); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/EntityTracker1_9.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/EntityTracker1_9.java index 1fa542101..7da66cfc8 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/EntityTracker1_9.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_8to1_9/storage/EntityTracker1_9.java @@ -23,20 +23,22 @@ import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.legacy.bossbar.BossBar; import com.viaversion.viaversion.api.legacy.bossbar.BossColor; import com.viaversion.viaversion.api.legacy.bossbar.BossStyle; -import com.viaversion.viaversion.api.minecraft.GameMode; import com.viaversion.viaversion.api.minecraft.BlockPosition; +import com.viaversion.viaversion.api.minecraft.GameMode; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_9.EntityType; -import com.viaversion.viaversion.api.minecraft.item.DataItem; -import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes1_9; +import com.viaversion.viaversion.api.minecraft.item.DataItem; +import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.data.entity.EntityTrackerBase; import com.viaversion.viaversion.protocols.v1_8to1_9.Protocol1_8To1_9; import com.viaversion.viaversion.protocols.v1_8to1_9.packet.ClientboundPackets1_9; import com.viaversion.viaversion.protocols.v1_8to1_9.provider.BossBarProvider; import com.viaversion.viaversion.protocols.v1_8to1_9.provider.EntityIdProvider; +import com.viaversion.viaversion.util.ComponentUtil; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -101,6 +103,11 @@ public class EntityTracker1_9 extends EntityTrackerBase { * The item in the offhand will be cleared if there is no sword in the main hand. */ public void syncShieldWithSword() { + if (user().getProtocolInfo().protocolVersion().newerThanOrEqualTo(ProtocolVersion.v1_21_4)) { + // If sword blocking is done through consumables, don't add a shield. + return; + } + boolean swordInHand = hasSwordInHand(); // Update if there is no sword in the main hand or if the player has no shield in the second hand but a sword in the main hand @@ -182,7 +189,9 @@ public class EntityTracker1_9 extends EntityTrackerBase { if (entityData.id() == 0) { // Byte byte data = (byte) entityData.getValue(); - if (entityId != getProvidedEntityId() && Via.getConfig().isShieldBlocking()) { + // If sword blocking is done through consumables (1.21.4+), don't add a shield. + if (entityId != getProvidedEntityId() && Via.getConfig().isShieldBlocking() + && user().getProtocolInfo().protocolVersion().olderThan(ProtocolVersion.v1_21_4)) { if ((data & 0x10) == 0x10) { if (validBlocking.contains(entityId)) { Item shield = new DataItem(442, (byte) 1, (short) 0, null); @@ -233,7 +242,11 @@ public class EntityTracker1_9 extends EntityTrackerBase { if (entityData.id() == 2) { BossBar bar = bossBarMap.get(entityId); String title = (String) entityData.getValue(); - title = title.isEmpty() ? (type == EntityType.ENDER_DRAGON ? DRAGON_TRANSLATABLE : WITHER_TRANSLATABLE) : title; + if (title.isEmpty()) { + title = type == EntityType.ENDER_DRAGON ? DRAGON_TRANSLATABLE : WITHER_TRANSLATABLE; + } else { + title = ComponentUtil.plainToJson(title).toString(); + } if (bar == null) { bar = Via.getAPI().legacyAPI().createLegacyBossBar(title, BossColor.PINK, BossStyle.SOLID); bossBarMap.put(entityId, bar); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/v1_9_3to1_10/Protocol1_9_3To1_10.java b/common/src/main/java/com/viaversion/viaversion/protocols/v1_9_3to1_10/Protocol1_9_3To1_10.java index 42cdb524d..b89fb8d16 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/v1_9_3to1_10/Protocol1_9_3To1_10.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/v1_9_3to1_10/Protocol1_9_3To1_10.java @@ -36,7 +36,6 @@ import com.viaversion.viaversion.protocols.v1_9_1to1_9_3.packet.ServerboundPacke import com.viaversion.viaversion.protocols.v1_9_3to1_10.rewriter.ItemPacketRewriter1_10; import com.viaversion.viaversion.protocols.v1_9_3to1_10.storage.ResourcePackTracker; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; public class Protocol1_9_3To1_10 extends AbstractProtocol { @@ -49,12 +48,12 @@ public class Protocol1_9_3To1_10 extends AbstractProtocol, List> TRANSFORM_ENTITY_DATA = new ValueTransformer<>(Types1_9.ENTITY_DATA_LIST) { @Override public List transform(PacketWrapper wrapper, List inputValue) { - List dataList = new CopyOnWriteArrayList<>(inputValue); - for (EntityData data : dataList) { - if (data.id() >= 5) + for (EntityData data : inputValue) { + if (data.id() >= 5) { data.setId(data.id() + 1); + } } - return dataList; + return inputValue; } }; private final ItemPacketRewriter1_10 itemRewriter = new ItemPacketRewriter1_10(this); diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/BlockRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/BlockRewriter.java index d855104bc..21ef7032a 100644 --- a/common/src/main/java/com/viaversion/viaversion/rewriter/BlockRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/BlockRewriter.java @@ -35,7 +35,6 @@ import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.remapper.PacketHandler; -import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.util.MathUtil; @@ -68,83 +67,61 @@ public class BlockRewriter { } public void registerBlockEvent(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(positionType); // Location - map(Types.UNSIGNED_BYTE); // Action id - map(Types.UNSIGNED_BYTE); // Action param - map(Types.VAR_INT); // Block id - /!\ NOT BLOCK STATE - handler(wrapper -> { - if (protocol.getMappingData().getBlockMappings() == null) { - return; - } + protocol.registerClientbound(packetType, wrapper -> { + if (protocol.getMappingData().getBlockMappings() == null) { + return; + } - int id = wrapper.get(Types.VAR_INT, 0); - int mappedId = protocol.getMappingData().getNewBlockId(id); - if (mappedId == -1) { - // Block (action) has been removed - wrapper.cancel(); - return; - } + wrapper.passthrough(positionType); // Location + wrapper.passthrough(Types.UNSIGNED_BYTE); // Action id + wrapper.passthrough(Types.UNSIGNED_BYTE); // Action param + final int blockId = wrapper.passthrough(Types.VAR_INT); + final int mappedId = protocol.getMappingData().getNewBlockId(blockId); + if (mappedId == -1) { + wrapper.cancel(); + return; + } - wrapper.set(Types.VAR_INT, 0, mappedId); - }); + if (blockId != mappedId) { + wrapper.set(Types.VAR_INT, 0, mappedId); } }); } public void registerBlockUpdate(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(positionType); - map(Types.VAR_INT); - handler(wrapper -> wrapper.set(Types.VAR_INT, 0, protocol.getMappingData().getNewBlockStateId(wrapper.get(Types.VAR_INT, 0)))); - } + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(positionType); + + final int blockId = wrapper.read(Types.VAR_INT); + wrapper.write(Types.VAR_INT, protocol.getMappingData().getNewBlockStateId(blockId)); }); } public void registerChunkBlocksUpdate(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.INT); // 0 - Chunk X - map(Types.INT); // 1 - Chunk Z - handler(wrapper -> { - for (BlockChangeRecord record : wrapper.passthrough(Types.BLOCK_CHANGE_ARRAY)) { - record.setBlockId(protocol.getMappingData().getNewBlockStateId(record.getBlockId())); - } - }); + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.INT); // Chunk X + wrapper.passthrough(Types.INT); // Chunk Z + for (BlockChangeRecord record : wrapper.passthrough(Types.BLOCK_CHANGE_ARRAY)) { + record.setBlockId(protocol.getMappingData().getNewBlockStateId(record.getBlockId())); } }); } public void registerSectionBlocksUpdate(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.LONG); // Chunk position - map(Types.BOOLEAN); // Suppress light updates - handler(wrapper -> { - for (BlockChangeRecord record : wrapper.passthrough(Types.VAR_LONG_BLOCK_CHANGE_ARRAY)) { - record.setBlockId(protocol.getMappingData().getNewBlockStateId(record.getBlockId())); - } - }); + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.LONG); // Chunk position + wrapper.passthrough(Types.BOOLEAN); // Suppress light updates + for (BlockChangeRecord record : wrapper.passthrough(Types.VAR_LONG_BLOCK_CHANGE_ARRAY)) { + record.setBlockId(protocol.getMappingData().getNewBlockStateId(record.getBlockId())); } }); } public void registerSectionBlocksUpdate1_20(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.LONG); // Chunk position - handler(wrapper -> { - for (BlockChangeRecord record : wrapper.passthrough(Types.VAR_LONG_BLOCK_CHANGE_ARRAY)) { - record.setBlockId(protocol.getMappingData().getNewBlockStateId(record.getBlockId())); - } - }); + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.LONG); // Chunk position + for (BlockChangeRecord record : wrapper.passthrough(Types.VAR_LONG_BLOCK_CHANGE_ARRAY)) { + record.setBlockId(protocol.getMappingData().getNewBlockStateId(record.getBlockId())); } }); } diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/ComponentRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/ComponentRewriter.java index 3aeffef77..59d7529ec 100644 --- a/common/src/main/java/com/viaversion/viaversion/rewriter/ComponentRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/ComponentRewriter.java @@ -33,7 +33,6 @@ import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.State; -import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Types; import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets; import com.viaversion.viaversion.util.ComponentUtil; @@ -66,17 +65,11 @@ public class ComponentRewriter implements com.v } public void registerBossEvent(final C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.UUID); - map(Types.VAR_INT); - handler(wrapper -> { - final int action = wrapper.get(Types.VAR_INT, 0); - if (action == 0 || action == 3) { - passthroughAndProcess(wrapper); - } - }); + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.UUID); + final int action = wrapper.passthrough(Types.VAR_INT); + if (action == 0 || action == 3) { + passthroughAndProcess(wrapper); } }); } @@ -112,24 +105,18 @@ public class ComponentRewriter implements com.v } public void registerLegacyOpenWindow(final C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.UNSIGNED_BYTE); // Id - map(Types.STRING); // Window Type - handler(wrapper -> processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT))); - } + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.UNSIGNED_BYTE); // Id + wrapper.passthrough(Types.STRING); // Window Type + processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT)); }); } public void registerOpenScreen(final C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.VAR_INT); // Id - map(Types.VAR_INT); // Window Type - handler(wrapper -> passthroughAndProcess(wrapper)); - } + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Id + wrapper.passthrough(Types.VAR_INT); // Window Type + passthroughAndProcess(wrapper); }); } @@ -142,10 +129,11 @@ public class ComponentRewriter implements com.v public void registerPlayerInfoUpdate1_20_3(final C packetType) { protocol.registerClientbound(packetType, wrapper -> { - final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM); + final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM1_19_3); if (!actions.get(5)) { // Update display name return; } + final int entries = wrapper.passthrough(Types.VAR_INT); for (int i = 0; i < entries; i++) { wrapper.passthrough(Types.UUID); @@ -177,24 +165,64 @@ public class ComponentRewriter implements com.v }); } - public void registerPlayerCombatKill(final C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.VAR_INT); // Player ID - map(Types.INT); // Killer ID - handler(wrapper -> processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT))); + public void registerPlayerInfoUpdate1_21_4(final C packetType) { + protocol.registerClientbound(packetType, wrapper -> { + final BitSet actions = wrapper.passthrough(Types.PROFILE_ACTIONS_ENUM1_21_4); + if (!actions.get(5)) { // Update display name + return; + } + + final int entries = wrapper.passthrough(Types.VAR_INT); + for (int i = 0; i < entries; i++) { + wrapper.passthrough(Types.UUID); + if (actions.get(0)) { + wrapper.passthrough(Types.STRING); // Player Name + + final int properties = wrapper.passthrough(Types.VAR_INT); + for (int j = 0; j < properties; j++) { + wrapper.passthrough(Types.STRING); // Name + wrapper.passthrough(Types.STRING); // Value + wrapper.passthrough(Types.OPTIONAL_STRING); // Signature + } + } + if (actions.get(1) && wrapper.passthrough(Types.BOOLEAN)) { + wrapper.passthrough(Types.UUID); // Session UUID + wrapper.passthrough(Types.PROFILE_KEY); + } + if (actions.get(2)) { + wrapper.passthrough(Types.VAR_INT); // Gamemode + } + if (actions.get(3)) { + wrapper.passthrough(Types.BOOLEAN); // Listed + } + if (actions.get(4)) { + wrapper.passthrough(Types.VAR_INT); // Latency + } + + processTag(wrapper.user(), wrapper.passthrough(Types.OPTIONAL_TAG)); + + if (actions.get(6)) { + wrapper.passthrough(Types.VAR_INT); // List order + } + if (actions.get(7)) { + wrapper.passthrough(Types.BOOLEAN); // Show hat + } } }); } + public void registerPlayerCombatKill(final C packetType) { + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Player ID + wrapper.passthrough(Types.INT); // Killer ID + processText(wrapper.user(), wrapper.passthrough(Types.COMPONENT)); + }); + } + public void registerPlayerCombatKill1_20(final C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.VAR_INT); // Player ID - handler(wrapper -> passthroughAndProcess(wrapper)); - } + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Player ID + passthroughAndProcess(wrapper); }); } @@ -346,6 +374,11 @@ public class ComponentRewriter implements com.v final CompoundTag contents = hoverEventTag.getCompoundTag("contents"); if (contents != null) { processTag(connection, contents.get("name")); + + final StringTag typeTag = contents.getStringTag("type"); + if (typeTag != null && protocol.getEntityRewriter() != null) { + typeTag.setValue(protocol.getEntityRewriter().mappedEntityIdentifier(typeTag.getValue())); + } } } else if (action.equals("show_item")) { convertLegacyContents(hoverEventTag); @@ -358,13 +391,25 @@ public class ComponentRewriter implements com.v final CompoundTag componentsTag = contentsTag.getCompoundTag("components"); handleShowItem(connection, contentsTag, componentsTag); if (componentsTag != null) { + final CompoundTag useRemainder = TagUtil.getNamespacedCompoundTag(componentsTag, "use_remainder"); + if (useRemainder != null) { + handleShowItem(connection, useRemainder); + } handleContainerContents(connection, componentsTag); + if (inputSerializerVersion() != null) { + handleWrittenBookContents(connection, componentsTag); + } + handleItemArrayContents(connection, componentsTag, "bundle_contents"); handleItemArrayContents(connection, componentsTag, "charged_projectiles"); } } } + protected final void handleShowItem(final UserConnection connection, final CompoundTag itemTag) { + handleShowItem(connection, itemTag, itemTag.getCompoundTag("components")); + } + protected void handleShowItem(final UserConnection connection, final CompoundTag itemTag, @Nullable final CompoundTag componentsTag) { final StringTag idTag = itemTag.getStringTag("id"); final String mappedId = protocol.getMappingData().getFullItemMappings().mappedIdentifier(idTag.getValue()); @@ -380,11 +425,44 @@ public class ComponentRewriter implements com.v } for (final CompoundTag entryTag : container) { - final CompoundTag itemTag = entryTag.getCompoundTag("item"); - handleShowItem(connection, itemTag, itemTag.getCompoundTag("components")); + handleShowItem(connection, entryTag.getCompoundTag("item")); } } + protected void handleWrittenBookContents(final UserConnection connection, final CompoundTag tag) { + final CompoundTag book = TagUtil.getNamespacedCompoundTag(tag, "minecraft:written_book_content"); + if (book == null) { + return; + } + + final ListTag pagesTag = book.getListTag("pages", CompoundTag.class); + if (pagesTag == null) { + return; + } + + for (final CompoundTag compoundTag : pagesTag) { + final StringTag raw = compoundTag.getStringTag("raw"); + processJsonString(connection, raw); + + final StringTag filtered = compoundTag.getStringTag("filtered"); + processJsonString(connection, filtered); + } + } + + private void processJsonString(final UserConnection connection, final StringTag tag) { + if (tag == null) { + return; + } + + final var input = inputSerializerVersion(); + final var output = outputSerializerVersion(); + + final Tag asTag = input.toTag(input.toComponent(tag.getValue())); + processTag(connection, asTag); + + tag.setValue(output.toString(output.toComponent(asTag))); + } + protected void handleItemArrayContents(final UserConnection connection, final CompoundTag tag, final String key) { final ListTag container = TagUtil.getNamespacedCompoundTagList(tag, key); if (container == null) { @@ -396,16 +474,16 @@ public class ComponentRewriter implements com.v } } - protected SerializerVersion inputSerializerVersion() { + protected @Nullable SerializerVersion inputSerializerVersion() { return null; } - protected SerializerVersion outputSerializerVersion() { - return null; + protected @Nullable SerializerVersion outputSerializerVersion() { + return inputSerializerVersion(); // Only matters if the nbt serializer changed } private void convertLegacyContents(final CompoundTag hoverEvent) { - if (inputSerializerVersion() == null || outputSerializerVersion() == null) { + if (inputSerializerVersion() == null) { return; } diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java index 4cc4354d5..7efdf89a7 100644 --- a/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java @@ -24,23 +24,21 @@ import com.viaversion.nbt.tag.NumberTag; import com.viaversion.nbt.tag.Tag; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.FullMappings; import com.viaversion.viaversion.api.data.Int2IntMapMappings; import com.viaversion.viaversion.api.data.Mappings; -import com.viaversion.viaversion.api.data.ParticleMappings; import com.viaversion.viaversion.api.data.entity.DimensionData; import com.viaversion.viaversion.api.data.entity.EntityTracker; import com.viaversion.viaversion.api.data.entity.TrackedEntity; import com.viaversion.viaversion.api.minecraft.Particle; -import com.viaversion.viaversion.api.minecraft.RegistryEntry; import com.viaversion.viaversion.api.minecraft.entities.EntityType; import com.viaversion.viaversion.api.minecraft.entitydata.EntityData; import com.viaversion.viaversion.api.minecraft.entitydata.EntityDataType; -import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.remapper.PacketHandler; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; -import com.viaversion.viaversion.api.rewriter.ItemRewriter; import com.viaversion.viaversion.api.rewriter.RewriterBase; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; @@ -51,7 +49,6 @@ import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEventImpl; import com.viaversion.viaversion.util.Key; import com.viaversion.viaversion.util.TagUtil; import java.util.ArrayList; -import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -62,7 +59,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; public abstract class EntityRewriter> extends RewriterBase implements com.viaversion.viaversion.api.rewriter.EntityRewriter { - private static final EntityData[] EMPTY_ARRAY = new EntityData[0]; protected final List entityDataFilters = new ArrayList<>(); protected final boolean trackMappedType; protected Mappings typeMappings; @@ -158,6 +154,17 @@ public abstract class EntityRewriter { + wrapper.passthrough(Types.VAR_INT); // Entity ID + wrapper.passthrough(Types.UUID); // Entity UUID + wrapper.passthrough(Types.VAR_INT); // Entity Type + trackerHandler().handle(wrapper); }); } @@ -264,15 +270,15 @@ public abstract class EntityRewriter { int entityId = wrapper.get(Types.VAR_INT, 0); @@ -286,31 +292,22 @@ public abstract class EntityRewriter { - if (protocol.getMappingData() == null) { - return; - } + protocol.registerClientbound(packetType, wrapper -> { + final int entityId = wrapper.passthrough(Types.VAR_INT); + wrapper.passthrough(Types.UUID); // Entity UUID + final int entityTypeId = wrapper.passthrough(Types.VAR_INT); + wrapper.passthrough(Types.DOUBLE); // X + wrapper.passthrough(Types.DOUBLE); // Y + wrapper.passthrough(Types.DOUBLE); // Z + wrapper.passthrough(Types.BYTE); // Pitch + wrapper.passthrough(Types.BYTE); // Yaw + wrapper.passthrough(Types.BYTE); // Head yaw + final int data = wrapper.passthrough(Types.VAR_INT); - int entityId = wrapper.get(Types.VAR_INT, 0); - EntityType entityType = tracker(wrapper.user()).entityType(entityId); - if (entityType == fallingBlockType) { - wrapper.set(Types.VAR_INT, 2, protocol.getMappingData().getNewBlockStateId(wrapper.get(Types.VAR_INT, 2))); - } - }); + final EntityType entityType = trackAndRewrite(wrapper, entityTypeId, entityId); + if (protocol.getMappingData() != null && entityType == fallingBlockType) { + final int mappedBlockStateId = protocol.getMappingData().getNewBlockStateId(data); + wrapper.set(Types.VAR_INT, 2, mappedBlockStateId); } }); } @@ -377,12 +374,13 @@ public abstract class EntityRewriter { - final EntityTracker tracker = tracker(wrapper.user()); - final int entityId = wrapper.get(Types.INT, 0); - tracker.setClientEntityId(entityId); - tracker.addEntity(entityId, tracker.playerType()); - }; + return wrapper -> trackPlayer(wrapper.user(), wrapper.get(Types.INT, 0)); + } + + public void trackPlayer(final UserConnection connection, final int entityId) { + final EntityTracker tracker = tracker(connection); + tracker.setClientEntityId(entityId); + tracker.addEntity(entityId, tracker.playerType()); } /** @@ -505,21 +503,15 @@ public abstract class EntityRewriter dimensionDataMap = new HashMap<>(entries.length); - for (int i = 0; i < entries.length; i++) { - final RegistryEntry entry = entries[i]; - final String key = Key.stripMinecraftNamespace(entry.key()); - final DimensionData dimensionData = entry.tag() != null - ? new DimensionDataImpl(i, (CompoundTag) entry.tag()) - : DimensionDataImpl.withDefaultsFor(key, i); - dimensionDataMap.put(key, dimensionData); - } - tracker(connection).setDimensions(dimensionDataMap); + public EntityType trackAndRewrite(final PacketWrapper wrapper, final int typeId, final int entityId) { + final int mappedTypeId = newEntityId(typeId); + if (mappedTypeId != typeId) { + wrapper.set(Types.VAR_INT, 1, mappedTypeId); } + + final EntityType entityType = typeFromId(trackMappedType ? mappedTypeId : typeId); + tracker(wrapper.user()).addEntity(entityId, entityType); + return entityType; } // --------------------------------------------------------------------------- @@ -535,16 +527,7 @@ public abstract class EntityRewriter { int entityId = wrapper.get(Types.VAR_INT, 0); int type = wrapper.get(Types.VAR_INT, 1); - - int newType = newEntityId(type); - if (newType != type) { - wrapper.set(Types.VAR_INT, 1, newType); - } - - EntityType entType = typeFromId(trackMappedType ? newType : type); - // Register Type ID - tracker(wrapper.user()).addEntity(entityId, entType); - + trackAndRewrite(wrapper, type, entityId); if (dataType != null) { handleEntityData(entityId, wrapper.get(dataType, 0), wrapper.user()); } @@ -581,34 +564,6 @@ public abstract class EntityRewriter data = particle.getArgument(0); - data.setValue(protocol.getMappingData().getNewBlockStateId(data.getValue())); - } else if (mappings.isItemParticle(id) && protocol.getItemRewriter() != null) { - Particle.ParticleData data = particle.getArgument(0); - ItemRewriter itemRewriter = protocol.getItemRewriter(); - Item item = itemRewriter.handleItemToClient(connection, data.getValue()); - if (itemRewriter.mappedItemType() != null && itemRewriter.itemType() != itemRewriter.mappedItemType()) { - // Replace the type - particle.set(0, itemRewriter.mappedItemType(), item); - } else { - data.setValue(item); - } - } - - particle.setId(protocol.getMappingData().getNewParticleId(id)); - } - private void logException(Exception e, @Nullable EntityType type, List entityDataList, EntityData entityData) { if (!Via.getConfig().isSuppressMetadataErrors() || Via.getManager().isDebug()) { protocol.getLogger().severe("An error occurred in entity data handler " + this.getClass().getSimpleName() diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/ItemRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/ItemRewriter.java index d9a66f176..d0f5e96be 100644 --- a/common/src/main/java/com/viaversion/viaversion/rewriter/ItemRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/ItemRewriter.java @@ -20,20 +20,19 @@ package com.viaversion.viaversion.rewriter; import com.google.gson.JsonElement; import com.viaversion.nbt.tag.Tag; import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.FullMappings; import com.viaversion.viaversion.api.data.Mappings; -import com.viaversion.viaversion.api.data.ParticleMappings; -import com.viaversion.viaversion.api.minecraft.Particle; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; -import com.viaversion.viaversion.api.protocol.remapper.PacketHandler; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.rewriter.ComponentRewriter; import com.viaversion.viaversion.api.rewriter.RewriterBase; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.util.Limit; import org.checkerframework.checker.nullness.qual.Nullable; public class ItemRewriter mappedItemCostType; private final Type optionalItemCostType; private final Type mappedOptionalItemCostType; - private final Type particleType; - private final Type mappedParticleType; public ItemRewriter( T protocol, Type itemType, Type itemArrayType, Type mappedItemType, Type mappedItemArrayType, - Type itemCostType, Type optionalItemCostType, Type mappedItemCostType, Type mappedOptionalItemCostType, - Type particleType, Type mappedParticleType + Type itemCostType, Type optionalItemCostType, Type mappedItemCostType, Type mappedOptionalItemCostType ) { super(protocol); this.itemType = itemType; @@ -64,12 +60,10 @@ public class ItemRewriter itemType, Type itemArrayType, Type mappedItemType, Type mappedItemArrayType) { - this(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType, null, null, null, null, null, null); + this(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType, null, null, null, null); } public ItemRewriter(T protocol, Type itemType, Type itemArrayType) { @@ -105,30 +99,30 @@ public class ItemRewriter { - Item[] items = wrapper.passthroughAndMap(itemArrayType, mappedItemArrayType); - for (int i = 0; i < items.length; i++) { - items[i] = handleItemToClient(wrapper.user(), items[i]); - } + registerSetContent1_17_1(packetType, Types.UNSIGNED_BYTE); + } - handleClientboundItem(wrapper); - }); + public void registerSetContent1_21_2(C packetType) { + registerSetContent1_17_1(packetType, Types.VAR_INT); + } + + private void registerSetContent1_17_1(C packetType, Type containerIdType) { + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(containerIdType); // Container id + wrapper.passthrough(Types.VAR_INT); // State id + Item[] items = wrapper.passthroughAndMap(itemArrayType, mappedItemArrayType); + for (int i = 0; i < items.length; i++) { + items[i] = handleItemToClient(wrapper.user(), items[i]); } + + passthroughClientboundItem(wrapper); }); } public void registerOpenScreen(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.VAR_INT); // Container id - handler(wrapper -> handleMenuType(wrapper)); - } + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Container id + handleMenuType(wrapper); }); } @@ -144,105 +138,103 @@ public class ItemRewriter handleClientboundItem(wrapper)); - } + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.UNSIGNED_BYTE); // Container id + wrapper.passthrough(Types.SHORT); // Slot id + passthroughClientboundItem(wrapper); }); } public void registerSetSlot1_17_1(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.UNSIGNED_BYTE); // Window id - map(Types.VAR_INT); // State id - map(Types.SHORT); // Slot id - handler(wrapper -> handleClientboundItem(wrapper)); - } + registerSetSlot1_17_1(packetType, Types.UNSIGNED_BYTE); + } + + public void registerSetSlot1_21_2(C packetType) { + registerSetSlot1_17_1(packetType, Types.VAR_INT); + } + + private void registerSetSlot1_17_1(C packetType, Type containerIdType) { + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(containerIdType); // Container id + wrapper.passthrough(Types.VAR_INT); // State id + wrapper.passthrough(Types.SHORT); // Slot id + passthroughClientboundItem(wrapper); }); } // Sub 1.16 public void registerSetEquippedItem(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.VAR_INT); // Entity ID - map(Types.VAR_INT); // Slot ID - handler(wrapper -> handleClientboundItem(wrapper)); - } + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Entity ID + wrapper.passthrough(Types.VAR_INT); // Slot ID + passthroughClientboundItem(wrapper); }); } // 1.16+ public void registerSetEquipment(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.VAR_INT); // 0 - Entity ID + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Entity ID - handler(wrapper -> { - byte slot; - do { - slot = wrapper.passthrough(Types.BYTE); - // & 0x7F into an extra variable if slot is needed - handleClientboundItem(wrapper); - } while (slot < 0); - }); - } + byte slot; + do { + slot = wrapper.passthrough(Types.BYTE); + // & 0x7F into an extra variable if slot is needed + passthroughClientboundItem(wrapper); + } while (slot < 0); }); } public void registerSetCreativeModeSlot(S packetType) { - protocol.registerServerbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.SHORT); // 0 - Slot - handler(wrapper -> handleServerboundItem(wrapper)); - } + protocol.registerServerbound(packetType, wrapper -> { + wrapper.passthrough(Types.SHORT); // Slot + passthroughServerboundItem(wrapper); }); } public void registerContainerClick(S packetType) { - protocol.registerServerbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.UNSIGNED_BYTE); // 0 - Window ID - map(Types.SHORT); // 1 - Slot - map(Types.BYTE); // 2 - Button - map(Types.SHORT); // 3 - Action number - map(Types.VAR_INT); // 4 - Mode - handler(wrapper -> handleServerboundItem(wrapper)); - } + protocol.registerServerbound(packetType, wrapper -> { + wrapper.passthrough(Types.UNSIGNED_BYTE); // Container ID + wrapper.passthrough(Types.SHORT); // Slot + wrapper.passthrough(Types.BYTE); // Button + wrapper.passthrough(Types.SHORT); // Action number + wrapper.passthrough(Types.VAR_INT); // Mode + passthroughServerboundItem(wrapper); }); } public void registerContainerClick1_17_1(S packetType) { - protocol.registerServerbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.UNSIGNED_BYTE); // Window Id - map(Types.VAR_INT); // State id - map(Types.SHORT); // Slot - map(Types.BYTE); // Button - map(Types.VAR_INT); // Mode + registerContainerClick1_17_1(packetType, Types.UNSIGNED_BYTE); + } - handler(wrapper -> { - // Affected items - int length = wrapper.passthrough(Types.VAR_INT); - for (int i = 0; i < length; i++) { - wrapper.passthrough(Types.SHORT); // Slot - handleServerboundItem(wrapper); - } + public void registerContainerClick1_21_2(S packetType) { + registerContainerClick1_17_1(packetType, Types.VAR_INT); + } - // Carried item - handleServerboundItem(wrapper); - }); + public void registerContainerClick1_17_1(S packetType, Type containerIdType) { + protocol.registerServerbound(packetType, wrapper -> { + wrapper.passthrough(containerIdType); // Container id + wrapper.passthrough(Types.VAR_INT); // State id + wrapper.passthrough(Types.SHORT); // Slot + wrapper.passthrough(Types.BYTE); // Button + wrapper.passthrough(Types.VAR_INT); // Mode + + // Affected items + final int length = Limit.max(wrapper.passthrough(Types.VAR_INT), 128); + for (int i = 0; i < length; i++) { + wrapper.passthrough(Types.SHORT); // Slot + passthroughServerboundItem(wrapper); } + + // Carried item + passthroughServerboundItem(wrapper); + }); + } + + public void registerSetPlayerInventory(C packetType) { + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Slot + passthroughClientboundItem(wrapper); }); } @@ -253,6 +245,15 @@ public class ItemRewriter { + String itemIdentifier = wrapper.read(Types.STRING); + if (itemIdentifier != null) { + itemIdentifier = mappedIdentifier(protocol.getMappingData().getFullItemMappings(), itemIdentifier); + } + wrapper.write(Types.STRING, itemIdentifier); + }); + } public void registerCustomPayloadTradeList(C packetType) { protocol.registerClientbound(packetType, new PacketHandlers() { @@ -274,11 +275,11 @@ public class ItemRewriter { - Mappings mappings = protocol.getMappingData().getEnchantmentMappings(); - if (mappings == null) { - return; - } - - short property = wrapper.passthrough(Types.SHORT); - if (property >= 4 && property <= 6) { // Enchantment id - short enchantmentId = (short) mappings.getNewId(wrapper.read(Types.SHORT)); - wrapper.write(Types.SHORT, enchantmentId); - } - }); - } - }); - } - - // Not the very best place for this, but has to stay here until *everything* is abstracted - public void registerLevelParticles(C packetType, Type coordType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.INT); // 0 - Particle ID - map(Types.BOOLEAN); // 1 - Long Distance - map(coordType); // 2 - X - map(coordType); // 3 - Y - map(coordType); // 4 - Z - map(Types.FLOAT); // 5 - Offset X - map(Types.FLOAT); // 6 - Offset Y - map(Types.FLOAT); // 7 - Offset Z - map(Types.FLOAT); // 8 - Particle Data - map(Types.INT); // 9 - Particle Count - handler(levelParticlesHandler()); - } - }); - } - - public void registerLevelParticles1_19(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.VAR_INT); // 0 - Particle ID - map(Types.BOOLEAN); // 1 - Long Distance - map(Types.DOUBLE); // 2 - X - map(Types.DOUBLE); // 3 - Y - map(Types.DOUBLE); // 4 - Z - map(Types.FLOAT); // 5 - Offset X - map(Types.FLOAT); // 6 - Offset Y - map(Types.FLOAT); // 7 - Offset Z - map(Types.FLOAT); // 8 - Particle Data - map(Types.INT); // 9 - Particle Count - handler(levelParticlesHandler(Types.VAR_INT)); - } - }); - } - - public void registerLevelParticles1_20_5(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.BOOLEAN); // Long Distance - map(Types.DOUBLE); // X - map(Types.DOUBLE); // Y - map(Types.DOUBLE); // Z - map(Types.FLOAT); // Offset X - map(Types.FLOAT); // Offset Y - map(Types.FLOAT); // Offset Z - map(Types.FLOAT); // Particle Data - map(Types.INT); // Particle Count - handler(wrapper -> { - final Particle particle = wrapper.passthroughAndMap(particleType, mappedParticleType); - rewriteParticle(wrapper.user(), particle); - }); - } - }); - } - - public void registerExplosion(C packetType) { - final SoundRewriter soundRewriter = new SoundRewriter<>(protocol); protocol.registerClientbound(packetType, wrapper -> { - wrapper.passthrough(Types.DOUBLE); // X - wrapper.passthrough(Types.DOUBLE); // Y - wrapper.passthrough(Types.DOUBLE); // Z - wrapper.passthrough(Types.FLOAT); // Power - final int blocks = wrapper.passthrough(Types.VAR_INT); - for (int i = 0; i < blocks; i++) { - wrapper.passthrough(Types.BYTE); // Relative X - wrapper.passthrough(Types.BYTE); // Relative Y - wrapper.passthrough(Types.BYTE); // Relative Z - } - wrapper.passthrough(Types.FLOAT); // Knockback X - wrapper.passthrough(Types.FLOAT); // Knockback Y - wrapper.passthrough(Types.FLOAT); // Knockback Z - wrapper.passthrough(Types.VAR_INT); // Block interaction type + wrapper.passthrough(Types.UNSIGNED_BYTE); // Container id - final Particle smallExplosionParticle = wrapper.passthroughAndMap(particleType, mappedParticleType); - final Particle largeExplosionParticle = wrapper.passthroughAndMap(particleType, mappedParticleType); - rewriteParticle(wrapper.user(), smallExplosionParticle); - rewriteParticle(wrapper.user(), largeExplosionParticle); - - soundRewriter.soundHolderHandler().handle(wrapper); - }); - } - - public PacketHandler levelParticlesHandler() { - return levelParticlesHandler(Types.INT); - } - - public PacketHandler levelParticlesHandler(Type idType) { - return wrapper -> { - int id = wrapper.get(idType, 0); - if (id == -1) { + Mappings mappings = protocol.getMappingData().getEnchantmentMappings(); + if (mappings == null) { return; } - ParticleMappings mappings = protocol.getMappingData().getParticleMappings(); - if (mappings.isBlockParticle(id)) { - int data = wrapper.read(Types.VAR_INT); - wrapper.write(Types.VAR_INT, protocol.getMappingData().getNewBlockStateId(data)); - } else if (mappings.isItemParticle(id)) { - handleClientboundItem(wrapper); + short property = wrapper.passthrough(Types.SHORT); + if (property >= 4 && property <= 6) { // Enchantment id + short enchantmentId = (short) mappings.getNewId(wrapper.read(Types.SHORT)); + wrapper.write(Types.SHORT, enchantmentId); } - - int mappedId = protocol.getMappingData().getNewParticleId(id); - if (mappedId != id) { - wrapper.set(idType, 0, mappedId); - } - }; + }); } - private void handleClientboundItem(final PacketWrapper wrapper) { + protected void passthroughClientboundItem(final PacketWrapper wrapper) { final Item item = handleItemToClient(wrapper.user(), wrapper.read(itemType)); wrapper.write(mappedItemType, item); } - private void handleServerboundItem(final PacketWrapper wrapper) { + protected void passthroughServerboundItem(final PacketWrapper wrapper) { final Item item = handleItemToServer(wrapper.user(), wrapper.read(mappedItemType)); wrapper.write(itemType, item); } - protected void rewriteParticle(UserConnection connection, Particle particle) { - ParticleMappings mappings = protocol.getMappingData().getParticleMappings(); - int id = particle.id(); - if (mappings.isBlockParticle(id)) { - Particle.ParticleData data = particle.getArgument(0); - data.setValue(protocol.getMappingData().getNewBlockStateId(data.getValue())); - } else if (mappings.isItemParticle(id)) { - Particle.ParticleData data = particle.getArgument(0); - Item item = handleItemToClient(connection, data.getValue()); - if (mappedItemType() != null && itemType() != mappedItemType()) { - // Replace the type - particle.set(0, mappedItemType(), item); - } else { - data.setValue(item); - } + protected @Nullable String mappedIdentifier(final FullMappings mappings, final String identifier) { + // Check if the original exists before mapping + if (mappings.id(identifier) == -1) { + return identifier; } + return mappings.mappedIdentifier(identifier); + } - particle.setId(protocol.getMappingData().getNewParticleId(id)); + protected @Nullable String unmappedIdentifier(final FullMappings mappings, final String mappedIdentifier) { + if (mappings.mappedId(mappedIdentifier) == -1) { + return mappedIdentifier; + } + return mappings.identifier(mappedIdentifier); } @Override diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/ParticleRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/ParticleRewriter.java new file mode 100644 index 000000000..3315d1578 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/ParticleRewriter.java @@ -0,0 +1,219 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.rewriter; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.ParticleMappings; +import com.viaversion.viaversion.api.minecraft.Particle; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; +import com.viaversion.viaversion.api.protocol.remapper.PacketHandler; +import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; +import com.viaversion.viaversion.api.rewriter.ItemRewriter; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.Types; + +public class ParticleRewriter implements com.viaversion.viaversion.api.rewriter.ParticleRewriter { + + protected final Protocol protocol; + private final Type particleType; + private final Type mappedParticleType; + + public ParticleRewriter(final Protocol protocol) { + this(protocol, null); + } + + public ParticleRewriter(final Protocol protocol, final Type particleType) { + this.protocol = protocol; + this.particleType = particleType; + this.mappedParticleType = particleType; + } + + public ParticleRewriter(final Protocol protocol, final Type particleType, final Type mappedParticleType) { + this.protocol = protocol; + this.particleType = particleType; + this.mappedParticleType = mappedParticleType; + } + + public void registerLevelParticles1_13(C packetType, Type coordType) { + protocol.registerClientbound(packetType, new PacketHandlers() { + @Override + public void register() { + map(Types.INT); // 0 - Particle ID + map(Types.BOOLEAN); // 1 - Long Distance + map(coordType); // 2 - X + map(coordType); // 3 - Y + map(coordType); // 4 - Z + map(Types.FLOAT); // 5 - Offset X + map(Types.FLOAT); // 6 - Offset Y + map(Types.FLOAT); // 7 - Offset Z + map(Types.FLOAT); // 8 - Particle Data + map(Types.INT); // 9 - Particle Count + handler(levelParticlesHandler1_13(Types.INT)); + } + }); + } + + public void registerLevelParticles1_19(C packetType) { + protocol.registerClientbound(packetType, new PacketHandlers() { + @Override + public void register() { + map(Types.VAR_INT); // 0 - Particle ID + map(Types.BOOLEAN); // 1 - Long Distance + map(Types.DOUBLE); // 2 - X + map(Types.DOUBLE); // 3 - Y + map(Types.DOUBLE); // 4 - Z + map(Types.FLOAT); // 5 - Offset X + map(Types.FLOAT); // 6 - Offset Y + map(Types.FLOAT); // 7 - Offset Z + map(Types.FLOAT); // 8 - Particle Data + map(Types.INT); // 9 - Particle Count + handler(levelParticlesHandler1_13(Types.VAR_INT)); + } + }); + } + + public PacketHandler levelParticlesHandler1_13(Type idType) { + return wrapper -> { + int id = wrapper.get(idType, 0); + if (id == -1) { + return; + } + + ParticleMappings mappings = protocol.getMappingData().getParticleMappings(); + if (mappings.isBlockParticle(id)) { + int data = wrapper.read(Types.VAR_INT); + wrapper.write(Types.VAR_INT, protocol.getMappingData().getNewBlockStateId(data)); + } else if (mappings.isItemParticle(id)) { + ItemRewriter itemRewriter = protocol.getItemRewriter(); + final Item item = wrapper.read(itemRewriter.itemType()); + wrapper.write(itemRewriter.mappedItemType(), itemRewriter.handleItemToClient(wrapper.user(), item)); + } + + int mappedId = protocol.getMappingData().getNewParticleId(id); + if (mappedId != id) { + wrapper.set(idType, 0, mappedId); + } + }; + } + + public void registerLevelParticles1_20_5(final C packetType) { + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.BOOLEAN); // Override limiter + wrapper.passthrough(Types.DOUBLE); // X + wrapper.passthrough(Types.DOUBLE); // Y + wrapper.passthrough(Types.DOUBLE); // Z + wrapper.passthrough(Types.FLOAT); // Offset X + wrapper.passthrough(Types.FLOAT); // Offset Y + wrapper.passthrough(Types.FLOAT); // Offset Z + wrapper.passthrough(Types.FLOAT); // Particle Data + wrapper.passthrough(Types.INT); // Particle Count + + final Particle particle = wrapper.passthroughAndMap(particleType, mappedParticleType); + rewriteParticle(wrapper.user(), particle); + }); + } + + public void registerLevelParticles1_21_4(final C packetType) { + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.BOOLEAN); // Override limiter + wrapper.passthrough(Types.BOOLEAN); // Always show + wrapper.passthrough(Types.DOUBLE); // X + wrapper.passthrough(Types.DOUBLE); // Y + wrapper.passthrough(Types.DOUBLE); // Z + wrapper.passthrough(Types.FLOAT); // Offset X + wrapper.passthrough(Types.FLOAT); // Offset Y + wrapper.passthrough(Types.FLOAT); // Offset Z + wrapper.passthrough(Types.FLOAT); // Particle Data + wrapper.passthrough(Types.INT); // Particle Count + + final Particle particle = wrapper.passthroughAndMap(particleType, mappedParticleType); + rewriteParticle(wrapper.user(), particle); + }); + } + + public void registerExplode1_20_5(final C packetType) { + final SoundRewriter soundRewriter = new SoundRewriter<>(protocol); + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.DOUBLE); // X + wrapper.passthrough(Types.DOUBLE); // Y + wrapper.passthrough(Types.DOUBLE); // Z + wrapper.passthrough(Types.FLOAT); // Power + final int blocks = wrapper.passthrough(Types.VAR_INT); + for (int i = 0; i < blocks; i++) { + wrapper.passthrough(Types.BYTE); // Relative X + wrapper.passthrough(Types.BYTE); // Relative Y + wrapper.passthrough(Types.BYTE); // Relative Z + } + wrapper.passthrough(Types.FLOAT); // Knockback X + wrapper.passthrough(Types.FLOAT); // Knockback Y + wrapper.passthrough(Types.FLOAT); // Knockback Z + wrapper.passthrough(Types.VAR_INT); // Block interaction type + + final Particle smallExplosionParticle = wrapper.passthroughAndMap(particleType, mappedParticleType); + final Particle largeExplosionParticle = wrapper.passthroughAndMap(particleType, mappedParticleType); + rewriteParticle(wrapper.user(), smallExplosionParticle); + rewriteParticle(wrapper.user(), largeExplosionParticle); + + soundRewriter.soundHolderHandler().handle(wrapper); + }); + } + + public void registerExplode1_21_2(final C packetType) { + final SoundRewriter soundRewriter = new SoundRewriter<>(protocol); + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.DOUBLE); // X + wrapper.passthrough(Types.DOUBLE); // Y + wrapper.passthrough(Types.DOUBLE); // Z + if (wrapper.passthrough(Types.BOOLEAN)) { + wrapper.passthrough(Types.DOUBLE); // Knockback X + wrapper.passthrough(Types.DOUBLE); // Knockback Y + wrapper.passthrough(Types.DOUBLE); // Knockback Z + } + + final Particle explosionParticle = wrapper.read(particleType); + wrapper.write(mappedParticleType, explosionParticle); + rewriteParticle(wrapper.user(), explosionParticle); + + soundRewriter.soundHolderHandler().handle(wrapper); + }); + } + + @Override + public void rewriteParticle(final UserConnection connection, final Particle particle) { + final ParticleMappings mappings = protocol.getMappingData().getParticleMappings(); + final ItemRewriter itemRewriter = protocol.getItemRewriter(); + final int id = particle.id(); + if (mappings.isBlockParticle(id)) { + final Particle.ParticleData data = particle.getArgument(0); + data.setValue(protocol.getMappingData().getNewBlockStateId(data.getValue())); + } else if (mappings.isItemParticle(id) && itemRewriter != null) { + final Particle.ParticleData data = particle.getArgument(0); + final Item item = itemRewriter.handleItemToClient(connection, data.getValue()); + if (itemRewriter.mappedItemType() != null && itemRewriter.itemType() != itemRewriter.mappedItemType()) { + // Replace the type + particle.set(0, itemRewriter.mappedItemType(), item); + } else { + data.setValue(item); + } + } + + particle.setId(protocol.getMappingData().getNewParticleId(id)); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/RecipeDisplayRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/RecipeDisplayRewriter.java new file mode 100644 index 000000000..a9316641a --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/RecipeDisplayRewriter.java @@ -0,0 +1,194 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.rewriter; + +import com.viaversion.viaversion.api.minecraft.HolderSet; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.rewriter.ItemRewriter; +import com.viaversion.viaversion.api.type.Types; + +// Base for 1.21.2 and onwards +public class RecipeDisplayRewriter { + protected final Protocol protocol; + + public RecipeDisplayRewriter(final Protocol protocol) { + this.protocol = protocol; + } + + public void registerUpdateRecipes(final C packetType) { + protocol.registerClientbound(packetType, wrapper -> { + final int size = wrapper.passthrough(Types.VAR_INT); + for (int i = 0; i < size; i++) { + wrapper.passthrough(Types.STRING); // Recipe group + rewriteItemIds(wrapper.passthrough(Types.VAR_INT_ARRAY_PRIMITIVE)); + } + + final int stonecutterRecipesSize = wrapper.passthrough(Types.VAR_INT); + for (int i = 0; i < stonecutterRecipesSize; i++) { + handleIngredient(wrapper); + handleSlotDisplay(wrapper); + } + }); + } + + public void registerRecipeBookAdd(final C packetType) { + protocol.registerClientbound(packetType, wrapper -> { + final int size = wrapper.passthrough(Types.VAR_INT); + for (int i = 0; i < size; i++) { + wrapper.passthrough(Types.VAR_INT); // Display ID + handleRecipeDisplay(wrapper); + wrapper.passthrough(Types.OPTIONAL_VAR_INT); // Group + wrapper.passthrough(Types.VAR_INT); // Category + if (wrapper.passthrough(Types.BOOLEAN)) { + final int ingredientsSize = wrapper.passthrough(Types.VAR_INT); + for (int j = 0; j < ingredientsSize; j++) { + handleIngredient(wrapper); // Items + } + } + wrapper.passthrough(Types.BYTE); // Flags + } + }); + } + + public void registerPlaceGhostRecipe(final C packetType) { + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Container ID + handleRecipeDisplay(wrapper); + }); + } + + protected void handleShapeless(final PacketWrapper wrapper) { + handleSlotDisplayList(wrapper); // Ingredients + handleSlotDisplay(wrapper); // Result + handleSlotDisplay(wrapper); // Crafting station + } + + protected void handleShaped(final PacketWrapper wrapper) { + wrapper.passthrough(Types.VAR_INT); // Width + wrapper.passthrough(Types.VAR_INT); // Height + handleSlotDisplayList(wrapper); // Ingredients + handleSlotDisplay(wrapper); // Result + handleSlotDisplay(wrapper); // Crafting station + } + + protected void handleFurnace(final PacketWrapper wrapper) { + handleSlotDisplay(wrapper); // Ingredient + handleSlotDisplay(wrapper); // Fuel + handleSlotDisplay(wrapper); // Result + handleSlotDisplay(wrapper); // Crafting station + wrapper.passthrough(Types.VAR_INT); // Duration + wrapper.passthrough(Types.FLOAT); // Experience + } + + protected void handleStoneCutter(final PacketWrapper wrapper) { + handleSlotDisplay(wrapper); // Input + handleSlotDisplay(wrapper); // Result + handleSlotDisplay(wrapper); // Crafting station + } + + protected void handleSmithing(final PacketWrapper wrapper) { + handleSlotDisplay(wrapper); // Template + handleSlotDisplay(wrapper); // Base + handleSlotDisplay(wrapper); // Addition + handleSlotDisplay(wrapper); // Result + handleSlotDisplay(wrapper); // Crafting station + } + + protected void handleRecipeDisplay(final PacketWrapper wrapper) { + final int type = wrapper.passthrough(Types.VAR_INT); + switch (type) { + case 0 -> handleShapeless(wrapper); + case 1 -> handleShaped(wrapper); + case 2 -> handleFurnace(wrapper); + case 3 -> handleStoneCutter(wrapper); + case 4 -> handleSmithing(wrapper); + } + } + + protected void handleSlotDisplay(final PacketWrapper wrapper) { + // empty and any_fuel are empty + final int type = wrapper.passthrough(Types.VAR_INT); + switch (type) { + case 2 -> handleItemId(wrapper); // Item type + case 3 -> handleItem(wrapper); // Item + case 4 -> wrapper.passthrough(Types.STRING); // Tag key + case 5 -> handleSmithingTrimSlotDisplay(wrapper); // Smithing trim + case 6 -> handleWithRemainderSlotDisplay(wrapper); // With remainder + case 7 -> handleSlotDisplayList(wrapper); // Composite + } + } + + protected void handleSlotDisplayList(final PacketWrapper wrapper) { + final int size = wrapper.passthrough(Types.VAR_INT); + for (int i = 0; i < size; i++) { + handleSlotDisplay(wrapper); + } + } + + protected void handleSmithingTrimSlotDisplay(final PacketWrapper wrapper) { + handleSlotDisplay(wrapper); // Base + handleSlotDisplay(wrapper); // Material + handleSlotDisplay(wrapper); // Pattern + } + + protected void handleWithRemainderSlotDisplay(final PacketWrapper wrapper) { + handleSlotDisplay(wrapper); // Input + handleSlotDisplay(wrapper); // Remainder + } + + protected void handleIngredient(final PacketWrapper wrapper) { + final HolderSet items = wrapper.passthrough(Types.HOLDER_SET); + if (items.hasTagKey()) { + return; + } + + final int[] ids = items.ids(); + for (int i = 0; i < ids.length; i++) { + ids[i] = rewriteItemId(ids[i]); + } + } + + protected void handleItemId(final PacketWrapper wrapper) { + final int id = wrapper.read(Types.VAR_INT); + wrapper.write(Types.VAR_INT, rewriteItemId(id)); + } + + protected void handleItem(final PacketWrapper wrapper) { + final ItemRewriter itemRewriter = protocol.getItemRewriter(); + final Item item = wrapper.read(itemRewriter.itemType()); + itemRewriter.handleItemToClient(wrapper.user(), item); + wrapper.write(itemRewriter.mappedItemType(), item); + } + + protected int rewriteItemId(final int id) { + if (protocol.getMappingData() != null && protocol.getMappingData().getItemMappings() != null) { + return protocol.getMappingData().getItemMappings().getNewIdOrDefault(id, id); + } + return id; + } + + protected void rewriteItemIds(final int[] ids) { + for (int i = 0; i < ids.length; i++) { + final int id = ids[i]; + ids[i] = rewriteItemId(id); + } + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/RecipeRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/RecipeRewriter.java index b653d12c0..12d59adc7 100644 --- a/common/src/main/java/com/viaversion/viaversion/rewriter/RecipeRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/RecipeRewriter.java @@ -18,6 +18,7 @@ package com.viaversion.viaversion.rewriter; import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.FullMappings; import com.viaversion.viaversion.api.minecraft.item.Item; import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; @@ -29,6 +30,7 @@ import java.util.HashMap; import java.util.Map; import org.checkerframework.checker.nullness.qual.Nullable; +// Base up to and including 1.21.1 public class RecipeRewriter { protected final Protocol protocol; @@ -80,13 +82,22 @@ public class RecipeRewriter { public void register1_20_5(C packetType) { protocol.registerClientbound(packetType, wrapper -> { - int size = wrapper.passthrough(Types.VAR_INT); + final int size = wrapper.passthrough(Types.VAR_INT); + int newSize = size; for (int i = 0; i < size; i++) { - wrapper.passthrough(Types.STRING); // Recipe Identifier + final String recipeIdentifier = wrapper.read(Types.STRING); - final int typeId = wrapper.passthrough(Types.VAR_INT); - final String type = protocol.getMappingData().getRecipeSerializerMappings().identifier(typeId); - handleRecipeType(wrapper, type); + final FullMappings recipeSerializerMappings = protocol.getMappingData().getRecipeSerializerMappings(); + final int typeId = wrapper.read(Types.VAR_INT); + final int mappedId = recipeSerializerMappings.getNewId(typeId); + if (mappedId != -1) { + wrapper.write(Types.STRING, recipeIdentifier); + wrapper.write(Types.VAR_INT, mappedId); + } else { + wrapper.set(Types.VAR_INT, 0, --newSize); + } + + handleRecipeType(wrapper, Key.stripMinecraftNamespace(recipeSerializerMappings.identifier(typeId))); // Use the original } }); } @@ -97,23 +108,19 @@ public class RecipeRewriter { for (int i = 0; i < ingredientsNo; i++) { handleIngredient(wrapper); } - - final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); - wrapper.write(mappedItemType(), result); + handleResult(wrapper); } public void handleCraftingShapeless(PacketWrapper wrapper) { wrapper.passthrough(Types.STRING); // Group handleIngredients(wrapper); - final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); - wrapper.write(mappedItemType(), result); + handleResult(wrapper); } public void handleSmelting(PacketWrapper wrapper) { wrapper.passthrough(Types.STRING); // Group handleIngredient(wrapper); - final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); - wrapper.write(mappedItemType(), result); + handleResult(wrapper); wrapper.passthrough(Types.FLOAT); // EXP wrapper.passthrough(Types.VAR_INT); // Cooking time } @@ -121,15 +128,13 @@ public class RecipeRewriter { public void handleStonecutting(PacketWrapper wrapper) { wrapper.passthrough(Types.STRING); // Group handleIngredient(wrapper); - final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); - wrapper.write(mappedItemType(), result); + handleResult(wrapper); } public void handleSmithing(PacketWrapper wrapper) { handleIngredient(wrapper); // Base handleIngredient(wrapper); // Addition - final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); - wrapper.write(mappedItemType(), result); + handleResult(wrapper); } public void handleSimpleRecipe(final PacketWrapper wrapper) { @@ -140,8 +145,7 @@ public class RecipeRewriter { handleIngredient(wrapper); // Template handleIngredient(wrapper); // Base handleIngredient(wrapper); // Additions - final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); - wrapper.write(mappedItemType(), result); + handleResult(wrapper); } public void handleSmithingTrim(final PacketWrapper wrapper) { @@ -150,6 +154,13 @@ public class RecipeRewriter { handleIngredient(wrapper); // Additions } + protected int rewrite(final int itemId) { + if (protocol.getMappingData() != null && protocol.getItemRewriter() != null) { + return protocol.getMappingData().getNewItemId(itemId); + } + return itemId; + } + protected @Nullable Item rewrite(UserConnection connection, @Nullable Item item) { if (protocol.getItemRewriter() != null) { return protocol.getItemRewriter().handleItemToClient(connection, item); @@ -172,6 +183,11 @@ public class RecipeRewriter { } } + protected void handleResult(final PacketWrapper wrapper) { + final Item result = rewrite(wrapper.user(), wrapper.read(itemType())); + wrapper.write(mappedItemType(), result); + } + @FunctionalInterface public interface RecipeConsumer { diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/RegistryDataRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/RegistryDataRewriter.java new file mode 100644 index 000000000..4dc02c2f7 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/RegistryDataRewriter.java @@ -0,0 +1,235 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.rewriter; + +import com.viaversion.nbt.tag.CompoundTag; +import com.viaversion.nbt.tag.ListTag; +import com.viaversion.nbt.tag.StringTag; +import com.viaversion.nbt.tag.Tag; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.FullMappings; +import com.viaversion.viaversion.api.data.entity.DimensionData; +import com.viaversion.viaversion.api.minecraft.RegistryEntry; +import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.type.Types; +import com.viaversion.viaversion.data.entity.DimensionDataImpl; +import com.viaversion.viaversion.util.Key; +import com.viaversion.viaversion.util.TagUtil; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +public class RegistryDataRewriter { + private final Map> enchantmentEffectRewriters = new Object2ObjectArrayMap<>(); + private final Map> toAdd = new Object2ObjectArrayMap<>(); + private final Protocol protocol; + + public RegistryDataRewriter(Protocol protocol) { + this.protocol = protocol; + } + + public void handle(final PacketWrapper wrapper) { + final String registryKey = wrapper.passthrough(Types.STRING); + RegistryEntry[] entries = wrapper.read(Types.REGISTRY_ENTRY_ARRAY); + entries = handle(wrapper.user(), registryKey, entries); + wrapper.write(Types.REGISTRY_ENTRY_ARRAY, entries); + } + + public RegistryEntry[] handle(final UserConnection connection, String key, RegistryEntry[] entries) { + key = Key.stripMinecraftNamespace(key); + if (key.equals("enchantment")) { + updateEnchantments(entries); + } else if (key.equals("trim_material")) { + updateTrimMaterials(entries); + } + + final List toAdd = this.toAdd.get(key); + if (toAdd != null) { + final int length = entries.length; + final int toAddLength = toAdd.size(); + entries = Arrays.copyOf(entries, length + toAddLength); + for (int i = 0; i < toAddLength; i++) { + entries[length + i] = toAdd.get(i).copy(); + } + } + + trackDimensionAndBiomes(connection, key, entries); + return entries; + } + + public void addEntries(final String registryKey, final RegistryEntry... entries) { + toAdd.computeIfAbsent(Key.stripMinecraftNamespace(registryKey), $ -> new ArrayList<>()).addAll(List.of(entries)); + } + + public void addEnchantmentEffectRewriter(final String key, final Consumer rewriter) { + enchantmentEffectRewriters.put(Key.stripMinecraftNamespace(key), rewriter); + } + + public void trackDimensionAndBiomes(final UserConnection connection, final String registryKey, final RegistryEntry[] entries) { + if (registryKey.equals("worldgen/biome")) { + protocol.getEntityRewriter().tracker(connection).setBiomesSent(entries.length); + } else if (registryKey.equals("dimension_type")) { + final Map dimensionDataMap = new HashMap<>(entries.length); + for (int i = 0; i < entries.length; i++) { + final RegistryEntry entry = entries[i]; + final String key = Key.stripMinecraftNamespace(entry.key()); + final DimensionData dimensionData = entry.tag() != null + ? new DimensionDataImpl(i, (CompoundTag) entry.tag()) + : DimensionDataImpl.withDefaultsFor(key, i); + dimensionDataMap.put(key, dimensionData); + } + protocol.getEntityRewriter().tracker(connection).setDimensions(dimensionDataMap); + } + } + + public void updateEnchantments(final RegistryEntry[] entries) { + for (final RegistryEntry entry : entries) { + if (entry.tag() == null) { + continue; + } + + final CompoundTag tag = (CompoundTag) entry.tag(); + if (protocol.getMappingData().getFullItemMappings() != null) { + updateItemList(tag.getListTag("supported_items", StringTag.class)); + updateItemList(tag.getListTag("primary_items", StringTag.class)); + } + + final CompoundTag effects = tag.getCompoundTag("effects"); + if (effects == null) { + continue; + } + + // Go through all effects, almost all of them may contain an "effect" element + for (final Map.Entry effectEntry : effects.entrySet()) { + if (effectEntry.getValue() instanceof final CompoundTag compoundTag) { + updateNestedEffect(compoundTag); + } else if (effectEntry.getValue() instanceof final ListTag listTag && listTag.getElementType() == CompoundTag.class) { + for (final Tag effectTag : listTag) { + updateNestedEffect((CompoundTag) effectTag); + } + } + } + + updateAttributesFields(effects); + } + } + + public void updateTrimMaterials(final RegistryEntry[] entries) { + if (protocol.getMappingData().getFullItemMappings() == null) { + return; + } + + for (final RegistryEntry entry : entries) { + if (entry.tag() == null) { + continue; + } + + final StringTag ingredientTag = ((CompoundTag) entry.tag()).getStringTag("ingredient"); + final String mappedIngredient = protocol.getMappingData().getFullItemMappings().mappedIdentifier(ingredientTag.getValue()); + ingredientTag.setValue(mappedIngredient); + } + } + + private void updateNestedEffect(final CompoundTag effectsTag) { + final CompoundTag effect = effectsTag.getCompoundTag("effect"); + if (effect == null) { + return; + } + + runEffectRewriters(effect); + + final ListTag innerEffects = effect.getListTag("effects", CompoundTag.class); + if (innerEffects == null) { + return; + } + + for (final CompoundTag innerEffect : innerEffects) { + runEffectRewriters(innerEffect); + } + } + + private void updateAttributesFields(final CompoundTag effects) { + if (!hasAttributeMappings()) { + return; + } + + final ListTag attributesList = TagUtil.getNamespacedCompoundTagList(effects, "attributes"); + if (attributesList == null) { + return; + } + + for (final CompoundTag attributeData : attributesList) { + updateAttributeField(attributeData); + } + } + + private void runEffectRewriters(final CompoundTag effectTag) { + String effect = effectTag.getString("type"); + if (effect == null) { + return; + } + + effect = Key.stripMinecraftNamespace(effect); + updateAttributeField(effectTag); + + final Consumer rewriter = enchantmentEffectRewriters.get(effect); + if (rewriter != null) { + rewriter.accept(effectTag); + } + } + + private void updateAttributeField(final CompoundTag attributeData) { + final StringTag attributeTag = attributeData.getStringTag("attribute"); + if (attributeTag == null) { + return; + } + + final FullMappings mappings = protocol.getMappingData().getAttributeMappings(); + final String attribute = Key.stripMinecraftNamespace(attributeTag.getValue()); + String mappedAttribute = mappings.mappedIdentifier(attribute); + if (mappedAttribute == null) { + mappedAttribute = mappings.mappedIdentifier(0); // Dummy + } + attributeTag.setValue(mappedAttribute); + } + + private boolean hasAttributeMappings() { + return protocol.getMappingData() != null && protocol.getMappingData().getAttributeMappings() != null; + } + + private void updateItemList(final ListTag listTag) { + if (listTag == null) { + return; + } + for (final StringTag tag : listTag) { + updateItem(tag); + } + } + + private void updateItem(final StringTag tag) { + final String mapped = protocol.getMappingData().getFullItemMappings().mappedIdentifier(tag.getValue()); + if (mapped != null) { + tag.setValue(mapped); + } + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/SoundRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/SoundRewriter.java index 15ffbadc1..ca4e03ed0 100644 --- a/common/src/main/java/com/viaversion/viaversion/rewriter/SoundRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/SoundRewriter.java @@ -22,7 +22,6 @@ import com.viaversion.viaversion.api.minecraft.SoundEvent; import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.remapper.PacketHandler; -import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.type.Types; public class SoundRewriter { @@ -40,12 +39,9 @@ public class SoundRewriter { } public void registerSound(C packetType) { - protocol.registerClientbound(packetType, new PacketHandlers() { - @Override - public void register() { - map(Types.VAR_INT); // Sound id - handler(getSoundHandler()); - } + protocol.registerClientbound(packetType, wrapper -> { + wrapper.passthrough(Types.VAR_INT); // Sound id + getSoundHandler().handle(wrapper); }); } diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/StructuredItemRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/StructuredItemRewriter.java index fe3b72e63..26ea5ccf8 100644 --- a/common/src/main/java/com/viaversion/viaversion/rewriter/StructuredItemRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/StructuredItemRewriter.java @@ -23,29 +23,32 @@ import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.data.FullMappings; import com.viaversion.viaversion.api.data.MappingData; import com.viaversion.viaversion.api.minecraft.Holder; -import com.viaversion.viaversion.api.minecraft.Particle; import com.viaversion.viaversion.api.minecraft.data.StructuredData; import com.viaversion.viaversion.api.minecraft.data.StructuredDataContainer; import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey; import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.api.minecraft.item.data.FilterableComponent; +import com.viaversion.viaversion.api.minecraft.item.data.WrittenBook; import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; import com.viaversion.viaversion.api.type.Type; import it.unimi.dsi.fastutil.ints.Int2IntFunction; import java.util.Map; +import java.util.function.Function; import org.checkerframework.checker.nullness.qual.Nullable; public class StructuredItemRewriter> extends ItemRewriter { + public static final String MARKER_KEY = "VV|custom_data"; + public StructuredItemRewriter( T protocol, Type itemType, Type itemArrayType, Type mappedItemType, Type mappedItemArrayType, - Type itemCostType, Type optionalItemCostType, Type mappedItemCostType, Type mappedOptionalItemCostType, - Type particleType, Type mappedParticleType + Type itemCostType, Type optionalItemCostType, Type mappedItemCostType, Type mappedOptionalItemCostType ) { - super(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType, itemCostType, optionalItemCostType, mappedItemCostType, mappedOptionalItemCostType, particleType, mappedParticleType); + super(protocol, itemType, itemArrayType, mappedItemType, mappedItemArrayType, itemCostType, optionalItemCostType, mappedItemCostType, mappedOptionalItemCostType); } public StructuredItemRewriter(T protocol, Type itemType, Type itemArrayType, Type mappedItemType, Type mappedItemArrayType) { @@ -114,8 +117,15 @@ public class StructuredItemRewriter value.rewrite(itemIdRewriter)); + container.replace(StructuredDataKey.TRIM1_20_5, value -> value.rewrite(itemIdRewriter)); + container.replace(StructuredDataKey.TRIM1_21_2, value -> value.rewrite(itemIdRewriter)); + container.replace(StructuredDataKey.TRIM1_21_4, value -> value.rewrite(itemIdRewriter)); container.replace(StructuredDataKey.POT_DECORATIONS, value -> value.rewrite(itemIdRewriter)); + container.replace(StructuredDataKey.REPAIRABLE, value -> value.rewrite(itemIdRewriter)); + } + if (mappingData.getFullItemMappings() != null) { + final Function itemIdRewriter = clientbound ? id -> mappedIdentifier(mappingData.getFullItemMappings(), id) : id -> unmappedIdentifier(mappingData.getFullItemMappings(), id); + container.replace(StructuredDataKey.USE_COOLDOWN, value -> value.rewrite(itemIdRewriter)); } if (mappingData.getBlockMappings() != null) { final Int2IntFunction blockIdRewriter = clientbound ? mappingData::getNewBlockId : mappingData::getOldBlockId; @@ -125,7 +135,8 @@ public class StructuredItemRewriter value.isDirect() ? Holder.of(value.value().rewrite(soundIdRewriter)) : value); + container.replace(StructuredDataKey.INSTRUMENT1_20_5, value -> value.isDirect() ? Holder.of(value.value().rewrite(soundIdRewriter)) : value); + container.replace(StructuredDataKey.INSTRUMENT1_21_2, value -> value.isDirect() ? Holder.of(value.value().rewrite(soundIdRewriter)) : value); container.replace(StructuredDataKey.JUKEBOX_PLAYABLE, value -> value.rewrite(soundIdRewriter)); } if (clientbound && protocol.getComponentRewriter() != null) { @@ -138,6 +149,16 @@ public class StructuredItemRewriter implements com.viavers public void handleGeneric(final PacketWrapper wrapper) { final int length = wrapper.passthrough(Types.VAR_INT); - int editedLength = length; + int finalLength = length; + final Set readTypes = EnumSet.noneOf(RegistryType.class); for (int i = 0; i < length; i++) { final String registryKey = wrapper.read(Types.STRING); - if (toRemoveRegistries.contains(Key.stripMinecraftNamespace(registryKey))) { - wrapper.set(Types.VAR_INT, 0, --editedLength); + final String strippedKey = Key.stripMinecraftNamespace(registryKey); + if (toRemoveRegistries.contains(strippedKey)) { + finalLength--; + final int tagsSize = wrapper.read(Types.VAR_INT); for (int j = 0; j < tagsSize; j++) { wrapper.read(Types.STRING); @@ -157,7 +161,29 @@ public class TagRewriter implements com.viavers } wrapper.write(Types.STRING, registryKey); - handle(wrapper, Key.stripMinecraftNamespace(registryKey)); + + final RegistryType type = RegistryType.getByKey(strippedKey); + if (type != null) { + handle(wrapper, type); + readTypes.add(type); + } else { + handle(wrapper, null, null, null, null); + } + } + + for (final Map.Entry> entry : toAdd.entrySet()) { + if (readTypes.contains(entry.getKey())) { + continue; + } + + // Registry wasn't present in the packet, add them here + wrapper.write(Types.STRING, entry.getKey().resourceLocation()); + appendNewTags(wrapper, entry.getKey()); + finalLength++; + } + + if (length != finalLength) { + wrapper.set(Types.VAR_INT, 0, finalLength); } } diff --git a/common/src/main/java/com/viaversion/viaversion/util/ByteBufUtil.java b/common/src/main/java/com/viaversion/viaversion/util/ByteBufUtil.java new file mode 100644 index 000000000..beaa41a30 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/util/ByteBufUtil.java @@ -0,0 +1,29 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2024 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.util; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; + +public final class ByteBufUtil { + + public static ByteBuf copy(final ByteBufAllocator allocator, final ByteBuf from) { + final int bytes = from.readableBytes(); + return allocator.buffer(bytes).writeBytes(from, bytes); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/util/ComponentUtil.java b/common/src/main/java/com/viaversion/viaversion/util/ComponentUtil.java index 45778bbe3..131138c18 100644 --- a/common/src/main/java/com/viaversion/viaversion/util/ComponentUtil.java +++ b/common/src/main/java/com/viaversion/viaversion/util/ComponentUtil.java @@ -60,7 +60,9 @@ public final class ComponentUtil { final ATextComponent component = SerializerVersion.V1_20_3.toComponent(tag); return component != null ? SerializerVersion.V1_19_4.toJson(component) : null; } catch (final Exception e) { - Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting tag: " + tag, e); + if (!Via.getConfig().isSuppressConversionWarnings()) { + Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting tag: " + tag, e); + } return plainToJson(""); } } @@ -74,7 +76,9 @@ public final class ComponentUtil { final ATextComponent component = SerializerVersion.V1_19_4.toComponent(element); return trimStrings(SerializerVersion.V1_20_3.toTag(component)); } catch (final Exception e) { - Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + element, e); + if (!Via.getConfig().isSuppressConversionWarnings()) { + Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting component: " + element, e); + } return new StringTag(""); } } @@ -101,7 +105,9 @@ public final class ComponentUtil { final ATextComponent component = SerializerVersion.V1_20_5.toComponent(tag); return component != null ? SerializerVersion.V1_20_3.toString(component) : null; } catch (final Exception e) { - Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting tag: " + tag, e); + if (!Via.getConfig().isSuppressConversionWarnings()) { + Via.getPlatform().getLogger().log(Level.SEVERE, "Error converting tag: " + tag, e); + } return plainToJson("").toString(); } } diff --git a/common/src/main/java/com/viaversion/viaversion/util/SerializerVersion.java b/common/src/main/java/com/viaversion/viaversion/util/SerializerVersion.java index 1d1d8fa99..6b19d2c27 100644 --- a/common/src/main/java/com/viaversion/viaversion/util/SerializerVersion.java +++ b/common/src/main/java/com/viaversion/viaversion/util/SerializerVersion.java @@ -19,6 +19,7 @@ package com.viaversion.viaversion.util; import com.google.gson.JsonElement; import com.viaversion.nbt.tag.Tag; +import com.viaversion.viaversion.rewriter.ComponentRewriter; import net.lenni0451.mcstructs.snbt.SNbtSerializer; import net.lenni0451.mcstructs.snbt.exceptions.SNbtDeserializeException; import net.lenni0451.mcstructs.snbt.exceptions.SNbtSerializeException; @@ -26,6 +27,13 @@ import net.lenni0451.mcstructs.text.ATextComponent; import net.lenni0451.mcstructs.text.serializer.TextComponentCodec; import net.lenni0451.mcstructs.text.serializer.TextComponentSerializer; +/** + * Wrapper enum to unify text component and string nbt serialization functions across different versions. + * Only contains versions which have actual changes we handle. + * + * @see ComponentUtil + * @see ComponentRewriter + */ public enum SerializerVersion { V1_6(TextComponentSerializer.V1_6, null), V1_7(TextComponentSerializer.V1_7, SNbtSerializer.V1_7), @@ -40,7 +48,8 @@ public enum SerializerVersion { V1_18(TextComponentSerializer.V1_18, SNbtSerializer.V1_14), V1_19_4(TextComponentSerializer.V1_19_4, SNbtSerializer.V1_14), V1_20_3(TextComponentCodec.V1_20_3, SNbtSerializer.V1_14), - V1_20_5(TextComponentCodec.V1_20_5, SNbtSerializer.V1_14); + V1_20_5(TextComponentCodec.V1_20_5, SNbtSerializer.V1_14), + V1_21_4(TextComponentCodec.V1_21_4, SNbtSerializer.V1_14); final TextComponentSerializer jsonSerializer; final SNbtSerializer snbtSerializer; @@ -115,4 +124,4 @@ public enum SerializerVersion { throw new RuntimeException(e); } } -} \ No newline at end of file +} diff --git a/common/src/main/java/com/viaversion/viaversion/util/SetWrapper.java b/common/src/main/java/com/viaversion/viaversion/util/SetWrapper.java deleted file mode 100644 index b95bb6122..000000000 --- a/common/src/main/java/com/viaversion/viaversion/util/SetWrapper.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion - * Copyright (C) 2016-2024 ViaVersion and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.viaversion.viaversion.util; - -import com.google.common.collect.ForwardingSet; -import java.util.Collection; -import java.util.Set; -import java.util.function.Consumer; -import org.checkerframework.checker.nullness.qual.NonNull; - -public class SetWrapper extends ForwardingSet { - - private final Set set; - private final Consumer addListener; - - public SetWrapper(Set set, Consumer addListener) { - this.set = set; - this.addListener = addListener; - } - - @Override - public boolean add(@NonNull E element) { - addListener.accept(element); - - return super.add(element); - } - - @Override - public boolean addAll(Collection collection) { - for (E element : collection) { - addListener.accept(element); - } - - return super.addAll(collection); - } - - @Override - protected Set delegate() { - return originalSet(); - } - - public Set originalSet() { - return this.set; - } -} diff --git a/common/src/main/java/com/viaversion/viaversion/util/TagUtil.java b/common/src/main/java/com/viaversion/viaversion/util/TagUtil.java index fa51e322e..a0ca17a11 100644 --- a/common/src/main/java/com/viaversion/viaversion/util/TagUtil.java +++ b/common/src/main/java/com/viaversion/viaversion/util/TagUtil.java @@ -19,6 +19,8 @@ package com.viaversion.viaversion.util; import com.viaversion.nbt.tag.CompoundTag; import com.viaversion.nbt.tag.ListTag; +import com.viaversion.nbt.tag.NumberTag; +import com.viaversion.nbt.tag.StringTag; import com.viaversion.nbt.tag.Tag; import java.util.Map; import org.checkerframework.checker.nullness.qual.Nullable; @@ -59,6 +61,10 @@ public final class TagUtil { return tag.remove(Key.namespaced(key)) != null || tag.remove(Key.stripMinecraftNamespace(key)) != null; } + public static boolean containsNamespaced(final CompoundTag tag, final String key) { + return tag.contains(Key.namespaced(key)) || tag.contains(Key.stripMinecraftNamespace(key)); + } + public static @Nullable CompoundTag getNamespacedCompoundTag(final CompoundTag tag, final String key) { final CompoundTag compoundTag = tag.getCompoundTag(Key.namespaced(key)); return compoundTag != null ? compoundTag : tag.getCompoundTag(Key.stripMinecraftNamespace(key)); @@ -69,6 +75,16 @@ public final class TagUtil { return listTag != null ? listTag : tag.getListTag(Key.stripMinecraftNamespace(key), CompoundTag.class); } + public static @Nullable StringTag getNamespacedStringTag(final CompoundTag tag, final String key) { + final StringTag stringTag = tag.getStringTag(Key.namespaced(key)); + return stringTag != null ? stringTag : tag.getStringTag(Key.stripMinecraftNamespace(key)); + } + + public static @Nullable NumberTag getNamespacedNumberTag(final CompoundTag tag, final String key) { + final NumberTag numberTag = tag.getNumberTag(Key.namespaced(key)); + return numberTag != null ? numberTag : tag.getNumberTag(Key.stripMinecraftNamespace(key)); + } + public static Tag handleDeep(final Tag tag, final TagUpdater consumer) { return handleDeep(null, tag, consumer); } diff --git a/common/src/main/resources/assets/viaversion/config.yml b/common/src/main/resources/assets/viaversion/config.yml index 7476272f0..c528b1e87 100644 --- a/common/src/main/resources/assets/viaversion/config.yml +++ b/common/src/main/resources/assets/viaversion/config.yml @@ -17,7 +17,7 @@ send-supported-versions: false # You can use both this and the block-protocols option at the same time as well. block-versions: [] # Block specific Minecraft protocol version numbers. -# List of all Minecraft protocol versions: https://wiki.vg/Protocol_version_numbers, or use a generator: https://via.krusic22.com +# List of all Minecraft protocol versions: https://minecraft.wiki/w/Protocol_version, or use a generator: https://via.krusic22.com block-protocols: [] # Change the blocked disconnect message block-disconnect-msg: "You are using an unsupported Minecraft version!" @@ -25,7 +25,7 @@ block-disconnect-msg: "You are using an unsupported Minecraft version!" # (We don't suggest using reload either, use a plugin manager) # You can customize the message we kick people with if you use ProtocolLib here. reload-disconnect-msg: "Server reload, please rejoin!" -# We warn when there's an error converting item and block data over versions, should we suppress these? (Only suggested if spamming) +# We warn when there's an error converting item/block or component/nbt data over versions, should we suppress these? (Only suggested if spamming) suppress-conversion-warnings: false # #----------------------------------------------------------# @@ -46,7 +46,7 @@ velocity-ping-save: true # # The format for the following is: # servername: protocolversion -# You can find protocol ids on https://wiki.vg/Protocol_version_numbers +# You can find protocol ids on https://minecraft.wiki/w/Protocol_version # It will fall back to the default option if none found. velocity-servers: {} # @@ -168,7 +168,7 @@ handle-invalid-item-count: false hide-scoreboard-numbers: false # # Fixes 1.21+ clients on 1.20.5 servers placing water/lava buckets at the wrong location when moving fast, NOTE: This may cause issues with anti-cheat plugins. -fix-1_21-placement-rotation: false +fix-1_21-placement-rotation: true # #----------------------------------------------------------# # 1.9+ CLIENTS ON 1.8 SERVERS OPTIONS # diff --git a/common/src/main/resources/assets/viaversion/data/blockConnections.nbt b/common/src/main/resources/assets/viaversion/data/blockConnections.nbt index 2e6c5f1bc..0f81075b4 100644 Binary files a/common/src/main/resources/assets/viaversion/data/blockConnections.nbt and b/common/src/main/resources/assets/viaversion/data/blockConnections.nbt differ diff --git a/common/src/main/resources/assets/viaversion/data/enchantments-1.21.nbt b/common/src/main/resources/assets/viaversion/data/enchantments-1.21.nbt index 91baa7abd..5989737d8 100644 Binary files a/common/src/main/resources/assets/viaversion/data/enchantments-1.21.nbt and b/common/src/main/resources/assets/viaversion/data/enchantments-1.21.nbt differ diff --git a/common/src/main/resources/assets/viaversion/data/identifier-table.nbt b/common/src/main/resources/assets/viaversion/data/identifier-table.nbt index b32d3f93e..9bd03a145 100644 Binary files a/common/src/main/resources/assets/viaversion/data/identifier-table.nbt and b/common/src/main/resources/assets/viaversion/data/identifier-table.nbt differ diff --git a/common/src/main/resources/assets/viaversion/data/identifiers-1.20.3.nbt b/common/src/main/resources/assets/viaversion/data/identifiers-1.20.3.nbt index e7b983600..bd755500c 100644 Binary files a/common/src/main/resources/assets/viaversion/data/identifiers-1.20.3.nbt and b/common/src/main/resources/assets/viaversion/data/identifiers-1.20.3.nbt differ diff --git a/common/src/main/resources/assets/viaversion/data/identifiers-1.20.5.nbt b/common/src/main/resources/assets/viaversion/data/identifiers-1.20.5.nbt index c0b39df8b..b4c3fb6bc 100644 Binary files a/common/src/main/resources/assets/viaversion/data/identifiers-1.20.5.nbt and b/common/src/main/resources/assets/viaversion/data/identifiers-1.20.5.nbt differ diff --git a/common/src/main/resources/assets/viaversion/data/identifiers-1.21.2.nbt b/common/src/main/resources/assets/viaversion/data/identifiers-1.21.2.nbt new file mode 100644 index 000000000..bf1533582 Binary files /dev/null and b/common/src/main/resources/assets/viaversion/data/identifiers-1.21.2.nbt differ diff --git a/common/src/main/resources/assets/viaversion/data/identifiers-1.21.4.nbt b/common/src/main/resources/assets/viaversion/data/identifiers-1.21.4.nbt new file mode 100644 index 000000000..ec2233211 Binary files /dev/null and b/common/src/main/resources/assets/viaversion/data/identifiers-1.21.4.nbt differ diff --git a/common/src/main/resources/assets/viaversion/data/identifiers-1.21.nbt b/common/src/main/resources/assets/viaversion/data/identifiers-1.21.nbt index 96637200a..3cb86a680 100644 Binary files a/common/src/main/resources/assets/viaversion/data/identifiers-1.21.nbt and b/common/src/main/resources/assets/viaversion/data/identifiers-1.21.nbt differ diff --git a/common/src/main/resources/assets/viaversion/data/itemrecipes1_12_2to1_13.json b/common/src/main/resources/assets/viaversion/data/itemrecipes1_12_2to1_13.json index 15c045238..17bac8a51 100644 --- a/common/src/main/resources/assets/viaversion/data/itemrecipes1_12_2to1_13.json +++ b/common/src/main/resources/assets/viaversion/data/itemrecipes1_12_2to1_13.json @@ -497,18 +497,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/22": { @@ -811,30 +807,22 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/27": { @@ -899,18 +887,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -1099,9 +1083,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -1532,18 +1514,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/38": { @@ -2074,12 +2052,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 12, @@ -2092,9 +2066,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 12, @@ -2227,30 +2199,22 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/54": { @@ -2275,18 +2239,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -2341,12 +2301,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 199, @@ -2383,9 +2339,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 199, @@ -2542,9 +2496,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -2687,12 +2639,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 14, @@ -2705,9 +2653,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 14, @@ -2906,9 +2852,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 14, @@ -2945,18 +2889,14 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], + [], [ { "id": 565, "amount": 1 } ], - [ - null - ], + [], [ { "id": 565, @@ -2975,18 +2915,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 565, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/69": { @@ -3443,18 +3379,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/77": { @@ -3603,9 +3535,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 13, @@ -3632,9 +3562,7 @@ "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/78": { @@ -3647,9 +3575,7 @@ "width": 2, "height": 2, "ingredients": [ - [ - null - ], + [], [ { "id": 477, @@ -3662,9 +3588,7 @@ "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/79": { @@ -3757,12 +3681,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 68, @@ -3791,9 +3711,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 68, @@ -4010,18 +3928,14 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], + [], [ { "id": 542, "amount": 1 } ], - [ - null - ], + [], [ { "id": 542, @@ -4040,18 +3954,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 542, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/86": { @@ -4364,12 +4274,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 350, @@ -4398,9 +4304,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 350, @@ -4899,18 +4803,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/105": { @@ -4929,9 +4829,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -4962,9 +4860,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -4983,18 +4879,14 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], + [], [ { "id": 717, "amount": 1 } ], - [ - null - ], + [], [ { "id": 692, @@ -5013,18 +4905,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 493, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/107": { @@ -5037,18 +4925,14 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], + [], [ { "id": 717, "amount": 1 } ], - [ - null - ], + [], [ { "id": 692, @@ -5067,18 +4951,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 493, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/108": { @@ -5105,12 +4985,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 258, @@ -5139,9 +5015,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 258, @@ -5292,12 +5166,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 144, @@ -5310,9 +5180,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 144, @@ -5941,18 +5809,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/126": { @@ -6857,18 +6721,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/146": { @@ -7555,18 +7415,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/160": { @@ -7681,12 +7537,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 13, @@ -7699,9 +7551,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 13, @@ -8048,12 +7898,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 220, @@ -8066,9 +7912,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 220, @@ -8339,9 +8183,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -9158,18 +9000,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/194": { @@ -9684,18 +9522,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/205": { @@ -10286,18 +10120,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/220": { @@ -10804,18 +10634,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/231": { @@ -10876,9 +10702,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 545, @@ -10891,9 +10715,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 545, @@ -10936,9 +10758,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 545, @@ -10963,9 +10783,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 545, @@ -11026,9 +10844,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 545, @@ -11041,9 +10857,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 545, @@ -11110,9 +10924,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 499, @@ -11125,15 +10937,9 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], - [ - null - ], + [], + [], + [], [ { "id": 499, @@ -11242,9 +11048,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -11275,9 +11079,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -11332,12 +11134,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 16, @@ -11350,9 +11148,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 16, @@ -11551,9 +11347,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 16, @@ -11996,30 +11790,22 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/254": { @@ -12074,9 +11860,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -12089,9 +11873,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -12206,18 +11988,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -12260,9 +12038,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -12335,9 +12111,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -12398,9 +12172,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -12413,9 +12185,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -12572,9 +12342,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -12623,9 +12391,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -12650,18 +12416,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/268": { @@ -13220,18 +12982,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/279": { @@ -13722,18 +13480,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/289": { @@ -13834,9 +13588,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 478, @@ -13909,30 +13661,22 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/294": { @@ -13969,9 +13713,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 478, @@ -13984,9 +13726,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 478, @@ -14017,18 +13757,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -14071,9 +13807,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 478, @@ -14098,9 +13832,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 478, @@ -14227,9 +13959,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 478, @@ -14242,9 +13972,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 478, @@ -14287,9 +14015,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -14632,27 +14358,21 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 64, "amount": 1 } ], - [ - null - ], + [], [ { "id": 64, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/309": { @@ -14713,9 +14433,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 12, @@ -14758,27 +14476,21 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 551, "amount": 1 } ], - [ - null - ], + [], [ { "id": 551, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/312": { @@ -14813,21 +14525,15 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], - [ - null - ], + [], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -14846,9 +14552,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 499, @@ -15237,18 +14941,14 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], + [], [ { "id": 557, "amount": 1 } ], - [ - null - ], + [], [ { "id": 476, @@ -15405,9 +15105,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 12, @@ -15624,30 +15322,22 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/332": { @@ -15684,9 +15374,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 476, @@ -15699,9 +15387,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 476, @@ -15732,18 +15418,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -15786,9 +15468,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 476, @@ -15813,9 +15493,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 476, @@ -15876,9 +15554,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 476, @@ -15891,9 +15567,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 476, @@ -16002,9 +15676,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -16047,9 +15719,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -16332,12 +16002,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 18, @@ -16350,9 +16016,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 18, @@ -16551,9 +16215,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 18, @@ -17068,18 +16730,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/360": { @@ -17238,18 +16896,14 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], + [], [ { "id": 477, "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -17268,18 +16922,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/363": { @@ -17292,18 +16942,14 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], + [], [ { "id": 167, "amount": 1 } ], - [ - null - ], + [], [ { "id": 167, @@ -17550,18 +17196,14 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], + [], [ { "id": 478, "amount": 1 } ], - [ - null - ], + [], [ { "id": 478, @@ -17580,18 +17222,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 478, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/370": { @@ -17864,9 +17502,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 13, @@ -17989,9 +17625,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -18004,9 +17638,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -18049,12 +17681,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 692, @@ -18145,27 +17773,21 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/381": { @@ -18634,18 +18256,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/390": { @@ -18664,12 +18282,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 135, @@ -18682,9 +18296,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 135, @@ -18781,18 +18393,14 @@ "width": 3, "height": 2, "ingredients": [ - [ - null - ], + [], [ { "id": 620, "amount": 1 } ], - [ - null - ], + [], [ { "id": 12, @@ -18879,9 +18487,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 13, @@ -18908,9 +18514,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 13, @@ -18937,9 +18541,7 @@ "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/396": { @@ -18952,9 +18554,7 @@ "width": 3, "height": 3, "ingredients": [ - [ - null - ], + [], [ { "id": 492, @@ -18973,18 +18573,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 499, "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -19333,9 +18929,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 13, @@ -19828,18 +19422,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/412": { @@ -20324,18 +19914,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/422": { @@ -20384,12 +19970,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 15, @@ -20402,9 +19984,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 15, @@ -20603,9 +20183,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 15, @@ -20678,18 +20256,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 493, "amount": 1 } ], - [ - null - ] + [] ] }, "viaversion:legacy/430": { @@ -20816,18 +20390,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, "amount": 1 } ], - [ - null - ], + [], [ { "id": 492, @@ -20876,18 +20446,14 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, "amount": 1 } ], - [ - null - ], + [], [ { "id": 477, @@ -21042,12 +20608,8 @@ "amount": 1 } ], - [ - null - ], - [ - null - ], + [], + [], [ { "id": 17, @@ -21060,9 +20622,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 17, @@ -21261,9 +20821,7 @@ "amount": 1 } ], - [ - null - ], + [], [ { "id": 17, diff --git a/common/src/main/resources/assets/viaversion/data/mappings-1.21.2to1.21.4.nbt b/common/src/main/resources/assets/viaversion/data/mappings-1.21.2to1.21.4.nbt new file mode 100644 index 000000000..edad0b2db Binary files /dev/null and b/common/src/main/resources/assets/viaversion/data/mappings-1.21.2to1.21.4.nbt differ diff --git a/common/src/main/resources/assets/viaversion/data/mappings-1.21to1.21.2.nbt b/common/src/main/resources/assets/viaversion/data/mappings-1.21to1.21.2.nbt new file mode 100644 index 000000000..8f68a1f6c Binary files /dev/null and b/common/src/main/resources/assets/viaversion/data/mappings-1.21to1.21.2.nbt differ diff --git a/fabric/src/main/resources/fabric.mod.json b/fabric/src/main/resources/fabric.mod.json index 1c4db1ea2..3f78e5a44 100644 --- a/fabric/src/main/resources/fabric.mod.json +++ b/fabric/src/main/resources/fabric.mod.json @@ -22,8 +22,7 @@ "RK_01" ], "depends": { - "fabricloader": ">=0.14.0", - "viafabric": ">=0.4.10" + "viafabric": ">=0.4.14" }, "custom": { "modmenu:api": true, diff --git a/gradle.properties b/gradle.properties index c54bb755e..826392112 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,10 +1,10 @@ # Project properties - we put these here so they can be modified without causing a recompile of the build scripts -projectVersion=5.0.4-SNAPSHOT +projectVersion=5.2.1-SNAPSHOT # Smile emoji -mcVersions=1.21.1,1.21,1.20.6,1.20.5,1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9 -mcVersionRange=1.8-1.21.1 -velocityVersion=3.3 +mcVersions=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.4 +velocityVersion=3.4 # Gradle properties org.gradle.daemon=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 44c0992d3..efbfc235e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,24 +2,24 @@ metadata.format.version = "1.1" [versions] -gson = "2.10.1" -fastutil = "8.5.12" -vianbt = "5.0.0" -mcstructs = "5-2.5.3" +gson = "2.11.0" +fastutil = "8.5.15" +vianbt = "5.0.1" +mcstructs = "5-2.5.5-SNAPSHOT" # Common provided netty = "4.0.20.Final" guava = "17.0" snakeYaml = "2.2" -junit = "5.10.2" -checkerQual = "3.43.0" +junit = "5.11.3" +checkerQual = "3.48.1" # Platforms paper = "1.20.4-R0.1-SNAPSHOT" legacyBukkit = "1.8.8-R0.1-SNAPSHOT" velocity = "3.1.1" - +viaProxy = "3.3.7-SNAPSHOT" [libraries] @@ -40,6 +40,7 @@ checkerQual = { group = "org.checkerframework", name = "checker-qual", version.r paper = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" } legacyBukkit = { group = "org.bukkit", name = "bukkit", version.ref = "legacyBukkit" } velocity = { group = "com.velocitypowered", name = "velocity-api", version.ref = "velocity" } +viaProxy = { group = "net.raphimc", name = "ViaProxy", version.ref = "viaProxy" } [bundles] diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fb602ee2a..eb1a55be0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=31c55713e40233a8303827ceb42ca48a47267a0ad4bab9177123121e71524c26 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip +distributionSha256Sum=f397b287023acdba1e9f6fc5ea72d22dd63669d59ed4a289a29b1a76eee151c6 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityDecodeHandler.java b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityDecodeHandler.java index e92648efe..0df6ff9c6 100644 --- a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityDecodeHandler.java +++ b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityDecodeHandler.java @@ -20,6 +20,7 @@ package com.viaversion.viaversion.velocity.handlers; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.exception.CancelCodecException; import com.viaversion.viaversion.exception.CancelDecoderException; +import com.viaversion.viaversion.util.ByteBufUtil; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; @@ -43,7 +44,7 @@ public class VelocityDecodeHandler extends MessageToMessageDecoder { return; } - ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); + ByteBuf transformedBuf = ByteBufUtil.copy(ctx.alloc(), bytebuf); try { info.transformIncoming(transformedBuf, CancelDecoderException::generate); out.add(transformedBuf.retain()); diff --git a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityEncodeHandler.java b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityEncodeHandler.java index ef1911777..71f0b500c 100644 --- a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityEncodeHandler.java +++ b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityEncodeHandler.java @@ -20,6 +20,7 @@ package com.viaversion.viaversion.velocity.handlers; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.exception.CancelCodecException; import com.viaversion.viaversion.exception.CancelEncoderException; +import com.viaversion.viaversion.util.ByteBufUtil; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; @@ -42,7 +43,7 @@ public class VelocityEncodeHandler extends MessageToMessageEncoder { return; } - ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf); + ByteBuf transformedBuf = ByteBufUtil.copy(ctx.alloc(), bytebuf); try { info.transformOutgoing(transformedBuf, CancelEncoderException::generate); out.add(transformedBuf.retain());