Compare commits

...
41 Commits
Author SHA1 Message Date
Nassim Jahnke b4870a49e3 1.19.3-rc3 protocol changes (but not actually supporting the snapshot)
Definitely still 4.5.0
2022-12-06 12:20:48 +01:00
Nassim Jahnke f7a48d028b 4.5.0 Release 2022-12-05 20:29:24 +01:00
Nassim Jahnke 382ef3953a Merge remote-tracking branch 'origin/master' into dev 2022-12-05 19:55:29 +01:00
Nassim Jahnke 9be32ca18b Make slightly more sense of CompactArrayUtil
... and make it less vanilla copy pasty

The magic array is a reciprocal table of 3-tuples, although 1 and 2 are always the same but for the ones including right shifts
2022-12-02 14:34:32 +01:00
Nassim Jahnke e0cd121a58 1.19.3-rc1 2022-12-01 16:41:19 +01:00
Nassim Jahnke 96631cee0c 1.19.3-pre3 2022-11-29 17:26:51 +01:00
Nassim Jahnke 8c0487fc05 1.19.3-pre2 2022-11-23 18:02:33 +01:00
Nassim Jahnke aec60f8cef 1.19.3-pre1 2022-11-22 17:11:11 +01:00
Nassim Jahnke a3080800b0 More minor refactoring 2022-11-22 17:04:06 +01:00
Kevin Ludwig 85f9414b95 Fix recipe book not being empty when using a multi-server configuration, with servers which are pre-1.12. (#3156) 2022-11-20 12:31:01 +01:00
Nassim Jahnke e7f07d1fdb Update mappings file 2022-11-16 16:39:16 +01:00
Nassim Jahnke 83efd0a267 22w46a (maybe) 2022-11-16 16:03:18 +01:00
Nassim Jahnke 5c05c61fbf 22w45a 2022-11-09 16:09:23 +01:00
Nassim Jahnke fad350c811 Small refactoring 2022-11-03 18:30:59 +01:00
Nassim Jahnke d3d8d1cab3 22w44a (maybe) 2022-11-02 15:49:40 +01:00
RK_01 a3437ca6ba Fix 1.19 -> 1.18.2 player info display name translation: Empty text edge case (#3146) 2022-10-27 10:36:46 +02:00
Kevin Ludwig 17bd048d10 Fix missing zombie_pigman (1.15.2) => zombified_piglin (1.16) translation in mob_spawner entity (#3147) 2022-10-27 10:32:31 +02:00
F 955b76f599 Fix use-new-effect-indicator option for 1.13+ clients (#3127) 2022-10-27 10:30:03 +02:00
Nassim Jahnke e3dc9e5b66 22w43a 2022-10-26 18:09:42 +02:00
Nassim Jahnke 6095128007 Remove javassist dependency, reduces file size by ~1mb 2022-10-25 17:31:13 +02:00
Nassim Jahnke 0355447d53 Remove more of the old compat layer 2022-10-25 15:55:42 +02:00
Nassim Jahnke 58fd0bdc9e Remove 1.8 PS compat hack 2022-10-25 10:36:09 +02:00
Nassim Jahnke cdc35aa5dc Merge remote-tracking branch 'origin/master' into dev 2022-10-25 10:36:02 +02:00
RK_01 10efba31cf Update 1.9 -> 1.8 ATTACH_ENTITY data reading (#3144) 2022-10-25 10:35:45 +02:00
Nassim Jahnke ef204c2ab2 Fix argument type handling 2022-10-23 18:27:44 +02:00
Nassim Jahnke 555e1a7722 Fix long metatype reading, some internal type reading changes 2022-10-22 10:19:27 +02:00
Nassim Jahnke 7400784e4f 22w42 (except for command completions) 2022-10-20 19:34:04 +02:00
Nassim Jahnke 2154f0a2cf Almost works 2022-10-19 23:18:39 +02:00
Nassim Jahnke 14b11bdd10 Start working on 22w42a 2022-10-19 21:58:08 +02:00
Nassim Jahnke c5738a2203 Add Via channel handlers instead of wrapping Vanilla handlers on Bukkit (#3132) 2022-10-19 21:29:24 +02:00
MrMicky 43ad855499 Rewrite signs and books components on 1.16 (#2712) 2022-10-16 21:22:48 +02:00
Kichura 2533619339 Update actions, Gradle 7.5.1 (#3139) 2022-10-15 19:20:20 +02:00
Nassim Jahnke b133dad642 Fix random long gen for seeded sounds 2022-10-08 21:50:09 +02:00
RK_01 464a85c52b Replaced hardcoded chunk section out of bounds check (#3136) 2022-10-07 23:07:50 +02:00
Gero 7698ee7683 Some minor performance improvements and cleanups (#3134) 2022-10-04 13:25:55 +02:00
BuzzTheGamer23 c7eb2e4b97 Change Maven version from deprecated LATEST (#2913) 2022-10-01 11:23:02 +02:00
creeper123123321 e71c88f860 Add sanity checks for some block nbt (#3129) 2022-10-01 10:14:41 +02:00
RK_01 c96b2bd859 Fix 1.19 -> 1.18.2 title translation: empty text edge case (#3115) 2022-09-02 16:00:45 +02:00
Nassim Jahnke ce4f21b7d8 Fix Paper packet limiter check on new versions 2022-08-25 13:03:40 +02:00
Nassim Jahnke 2a55025e99 Version bump 2022-08-21 14:58:00 +02:00
Nassim Jahnke c86da22f4e Fix config header duplication on reload
Fixes #3100
2022-08-21 14:57:32 +02:00
97 changed files with 29607 additions and 1021 deletions

No files matched your search

+1 -1
View File
@@ -7,7 +7,7 @@ body:
attributes:
value: |
**Before reporting a bug, please see if using master/dev builds from https://ci.viaversion.com/ fixes your issue.**
Whenever you see fit, you can upload images or video to any of the textfields.
Whenever you see fit, you can upload images or videos to any of the text fields.
- type: input
attributes:
+4 -4
View File
@@ -10,19 +10,19 @@ jobs:
# Only run on PRs if the source branch is on a different repo. We do not need to run everything twice.
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1
- name: Set up JDK 11
uses: actions/setup-java@v2
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: 11
- name: Build with Gradle
run: ./gradlew build
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
with:
name: artifact
path: build/libs
+1 -1
View File
@@ -51,7 +51,7 @@ You can find official dev builds here:
<dependency>
<groupId>com.viaversion</groupId>
<artifactId>viaversion-api</artifactId>
<version>LATEST</version>
<version>[4.0.0,5.0.0)</version>
<scope>provided</scope>
</dependency>
```
@@ -85,6 +85,7 @@ public class ProtocolVersion {
public static final ProtocolVersion v1_18_2 = register(758, "1.18.2");
public static final ProtocolVersion v1_19 = register(759, "1.19");
public static final ProtocolVersion v1_19_1 = register(760, "1.19.1");
public static final ProtocolVersion v1_19_3 = register(761, "1.19.3");
public static final ProtocolVersion unknown = register(-1, "UNKNOWN");
public static ProtocolVersion register(int version, String name) {
@@ -42,4 +42,6 @@ public interface BlockEntity {
int typeId();
@Nullable CompoundTag tag();
BlockEntity withTypeId(int typeId);
}
@@ -56,4 +56,9 @@ public final class BlockEntityImpl implements BlockEntity {
public CompoundTag tag() {
return tag;
}
@Override
public BlockEntity withTypeId(int typeId) {
return new BlockEntityImpl(packedXZ, y, typeId, tag);
}
}
@@ -40,6 +40,18 @@ public interface ChunkSection {
return y << 8 | z << 4 | x;
}
static int xFromIndex(int idx) {
return idx & 0xF;
}
static int yFromIndex(int idx) {
return idx >> 8 & 0xF;
}
static int zFromIndex(int idx) {
return idx >> 4 & 0xF;
}
@Deprecated/*(forRemoval = true)*/
default int getFlatBlock(int idx) {
return palette(PaletteType.BLOCKS).idAt(idx);
@@ -0,0 +1,275 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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 org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Locale;
public enum Entity1_19_3Types 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),
FIREWORK_ROCKET(ENTITY),
ITEM(ENTITY),
LLAMA_SPIT(ENTITY),
TNT(ENTITY),
SHULKER_BULLET(ENTITY),
FISHING_BOBBER(ENTITY),
LIVINGENTITY(ENTITY, null),
ARMOR_STAND(LIVINGENTITY),
MARKER(ENTITY),
PLAYER(LIVINGENTITY),
ABSTRACT_INSENTIENT(LIVINGENTITY, null),
ENDER_DRAGON(ABSTRACT_INSENTIENT),
BEE(ABSTRACT_INSENTIENT),
ABSTRACT_CREATURE(ABSTRACT_INSENTIENT, null),
ABSTRACT_AGEABLE(ABSTRACT_CREATURE, null),
VILLAGER(ABSTRACT_AGEABLE),
WANDERING_TRADER(ABSTRACT_AGEABLE),
// Animals
ABSTRACT_ANIMAL(ABSTRACT_AGEABLE, null),
AXOLOTL(ABSTRACT_ANIMAL),
DOLPHIN(ABSTRACT_INSENTIENT),
CHICKEN(ABSTRACT_ANIMAL),
COW(ABSTRACT_ANIMAL),
MOOSHROOM(COW),
PANDA(ABSTRACT_INSENTIENT),
PIG(ABSTRACT_ANIMAL),
POLAR_BEAR(ABSTRACT_ANIMAL),
RABBIT(ABSTRACT_ANIMAL),
SHEEP(ABSTRACT_ANIMAL),
TURTLE(ABSTRACT_ANIMAL),
FOX(ABSTRACT_ANIMAL),
FROG(ABSTRACT_ANIMAL),
GOAT(ABSTRACT_ANIMAL),
ABSTRACT_TAMEABLE_ANIMAL(ABSTRACT_ANIMAL, null),
CAT(ABSTRACT_TAMEABLE_ANIMAL),
OCELOT(ABSTRACT_TAMEABLE_ANIMAL),
WOLF(ABSTRACT_TAMEABLE_ANIMAL),
ABSTRACT_PARROT(ABSTRACT_TAMEABLE_ANIMAL, null),
PARROT(ABSTRACT_PARROT),
// Horses
ABSTRACT_HORSE(ABSTRACT_ANIMAL, null),
CHESTED_HORSE(ABSTRACT_HORSE, null),
DONKEY(CHESTED_HORSE),
MULE(CHESTED_HORSE),
LLAMA(CHESTED_HORSE),
TRADER_LLAMA(CHESTED_HORSE),
HORSE(ABSTRACT_HORSE),
SKELETON_HORSE(ABSTRACT_HORSE),
ZOMBIE_HORSE(ABSTRACT_HORSE),
CAMEL(ABSTRACT_HORSE),
// Golem
ABSTRACT_GOLEM(ABSTRACT_CREATURE, null),
SNOW_GOLEM(ABSTRACT_GOLEM),
IRON_GOLEM(ABSTRACT_GOLEM),
SHULKER(ABSTRACT_GOLEM),
// Fish
ABSTRACT_FISHES(ABSTRACT_CREATURE, null),
COD(ABSTRACT_FISHES),
PUFFERFISH(ABSTRACT_FISHES),
SALMON(ABSTRACT_FISHES),
TROPICAL_FISH(ABSTRACT_FISHES),
// Monsters
ABSTRACT_MONSTER(ABSTRACT_CREATURE, null),
BLAZE(ABSTRACT_MONSTER),
CREEPER(ABSTRACT_MONSTER),
ENDERMITE(ABSTRACT_MONSTER),
ENDERMAN(ABSTRACT_MONSTER),
GIANT(ABSTRACT_MONSTER),
SILVERFISH(ABSTRACT_MONSTER),
VEX(ABSTRACT_MONSTER),
WITCH(ABSTRACT_MONSTER),
WITHER(ABSTRACT_MONSTER),
RAVAGER(ABSTRACT_MONSTER),
ABSTRACT_PIGLIN(ABSTRACT_MONSTER, null),
PIGLIN(ABSTRACT_PIGLIN),
PIGLIN_BRUTE(ABSTRACT_PIGLIN),
HOGLIN(ABSTRACT_ANIMAL),
STRIDER(ABSTRACT_ANIMAL),
TADPOLE(ABSTRACT_FISHES),
ZOGLIN(ABSTRACT_MONSTER),
WARDEN(ABSTRACT_MONSTER),
// Illagers
ABSTRACT_ILLAGER_BASE(ABSTRACT_MONSTER, null),
ABSTRACT_EVO_ILLU_ILLAGER(ABSTRACT_ILLAGER_BASE, null),
EVOKER(ABSTRACT_EVO_ILLU_ILLAGER),
ILLUSIONER(ABSTRACT_EVO_ILLU_ILLAGER),
VINDICATOR(ABSTRACT_ILLAGER_BASE),
PILLAGER(ABSTRACT_ILLAGER_BASE),
// Skeletons
ABSTRACT_SKELETON(ABSTRACT_MONSTER, null),
SKELETON(ABSTRACT_SKELETON),
STRAY(ABSTRACT_SKELETON),
WITHER_SKELETON(ABSTRACT_SKELETON),
// Guardians
GUARDIAN(ABSTRACT_MONSTER),
ELDER_GUARDIAN(GUARDIAN),
// Spiders
SPIDER(ABSTRACT_MONSTER),
CAVE_SPIDER(SPIDER),
// Zombies
ZOMBIE(ABSTRACT_MONSTER),
DROWNED(ZOMBIE),
HUSK(ZOMBIE),
ZOMBIFIED_PIGLIN(ZOMBIE),
ZOMBIE_VILLAGER(ZOMBIE),
// Flying entities
ABSTRACT_FLYING(ABSTRACT_INSENTIENT, null),
GHAST(ABSTRACT_FLYING),
PHANTOM(ABSTRACT_FLYING),
ABSTRACT_AMBIENT(ABSTRACT_INSENTIENT, null),
BAT(ABSTRACT_AMBIENT),
ALLAY(ABSTRACT_CREATURE),
ABSTRACT_WATERMOB(ABSTRACT_INSENTIENT, null),
SQUID(ABSTRACT_WATERMOB),
GLOW_SQUID(SQUID),
// Slimes
SLIME(ABSTRACT_INSENTIENT),
MAGMA_CUBE(SLIME),
// Hangable objects
ABSTRACT_HANGING(ENTITY, null),
LEASH_KNOT(ABSTRACT_HANGING),
ITEM_FRAME(ABSTRACT_HANGING),
GLOW_ITEM_FRAME(ITEM_FRAME),
PAINTING(ABSTRACT_HANGING),
ABSTRACT_LIGHTNING(ENTITY, null),
LIGHTNING_BOLT(ABSTRACT_LIGHTNING),
// Arrows
ABSTRACT_ARROW(ENTITY, null),
ARROW(ABSTRACT_ARROW),
SPECTRAL_ARROW(ABSTRACT_ARROW),
TRIDENT(ABSTRACT_ARROW),
// Fireballs
ABSTRACT_FIREBALL(ENTITY, null),
DRAGON_FIREBALL(ABSTRACT_FIREBALL),
FIREBALL(ABSTRACT_FIREBALL),
SMALL_FIREBALL(ABSTRACT_FIREBALL),
WITHER_SKULL(ABSTRACT_FIREBALL),
// Projectiles
PROJECTILE_ABSTRACT(ENTITY, null),
SNOWBALL(PROJECTILE_ABSTRACT),
ENDER_PEARL(PROJECTILE_ABSTRACT),
EGG(PROJECTILE_ABSTRACT),
POTION(PROJECTILE_ABSTRACT),
EXPERIENCE_BOTTLE(PROJECTILE_ABSTRACT),
// Vehicles
MINECART_ABSTRACT(ENTITY, null),
CHESTED_MINECART_ABSTRACT(MINECART_ABSTRACT, null),
CHEST_MINECART(CHESTED_MINECART_ABSTRACT),
HOPPER_MINECART(CHESTED_MINECART_ABSTRACT),
MINECART(MINECART_ABSTRACT),
FURNACE_MINECART(MINECART_ABSTRACT),
COMMAND_BLOCK_MINECART(MINECART_ABSTRACT),
TNT_MINECART(MINECART_ABSTRACT),
SPAWNER_MINECART(MINECART_ABSTRACT),
BOAT(ENTITY),
CHEST_BOAT(BOAT);
private static final EntityType[] TYPES = EntityTypeUtil.createSizedArray(values());
private final EntityType parent;
private final String identifier;
private int id = -1;
Entity1_19_3Types(final EntityType parent) {
this.parent = parent;
this.identifier = "minecraft:" + name().toLowerCase(Locale.ROOT);
}
Entity1_19_3Types(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);
}
}
@@ -0,0 +1,60 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.metadata.types;
import com.viaversion.viaversion.api.minecraft.metadata.MetaType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.minecraft.ParticleType;
public final class MetaTypes1_19_3 extends AbstractMetaTypes {
public final MetaType byteType = add(0, Type.BYTE);
public final MetaType varIntType = add(1, Type.VAR_INT);
public final MetaType longType = add(2, Type.VAR_LONG);
public final MetaType floatType = add(3, Type.FLOAT);
public final MetaType stringType = add(4, Type.STRING);
public final MetaType componentType = add(5, Type.COMPONENT);
public final MetaType optionalComponentType = add(6, Type.OPTIONAL_COMPONENT);
public final MetaType itemType = add(7, Type.FLAT_VAR_INT_ITEM);
public final MetaType booleanType = add(8, Type.BOOLEAN);
public final MetaType rotationType = add(9, Type.ROTATION);
public final MetaType positionType = add(10, Type.POSITION1_14);
public final MetaType optionalPositionType = add(11, Type.OPTIONAL_POSITION_1_14);
public final MetaType directionType = add(12, Type.VAR_INT);
public final MetaType optionalUUIDType = add(13, Type.OPTIONAL_UUID);
public final MetaType blockStateType = add(14, Type.VAR_INT);
public final MetaType nbtType = add(15, Type.NBT);
public final MetaType particleType;
public final MetaType villagerDatatType = add(17, Type.VILLAGER_DATA);
public final MetaType optionalVarIntType = add(18, Type.OPTIONAL_VAR_INT);
public final MetaType poseType = add(19, Type.VAR_INT);
public final MetaType catVariantType = add(20, Type.VAR_INT);
public final MetaType frogVariantType = add(21, Type.VAR_INT);
public final MetaType optionalGlobalPosition = add(22, Type.OPTIONAL_GLOBAL_POSITION);
public final MetaType paintingVariantType = add(23, Type.VAR_INT);
public MetaTypes1_19_3(final ParticleType particleType) {
super(24);
this.particleType = add(16, particleType);
}
}
@@ -82,6 +82,7 @@ public class ProtocolVersion {
public static final ProtocolVersion v1_18_2 = register(758, "1.18.2");
public static final ProtocolVersion v1_19 = register(759, "1.19");
public static final ProtocolVersion v1_19_1 = register(760, "1.19.1/2", new VersionRange("1.19", 1, 2));
public static final ProtocolVersion v1_19_3 = register(761, "1.19.3");
public static final ProtocolVersion unknown = register(-1, "UNKNOWN");
public static ProtocolVersion register(int version, String name) {
@@ -87,6 +87,7 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
public static final ByteType BYTE = new ByteType();
public static final UnsignedByteType UNSIGNED_BYTE = new UnsignedByteType();
public static final Type<byte[]> BYTE_ARRAY_PRIMITIVE = new ByteArrayType();
public static final Type<byte[]> OPTIONAL_BYTE_ARRAY_PRIMITIVE = new ByteArrayType.OptionalByteArrayType();
public static final Type<byte[]> SHORT_BYTE_ARRAY = new ShortByteArrayType();
public static final Type<byte[]> REMAINING_BYTES = new RemainingBytesType();
@@ -95,6 +96,7 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
public static final IntType INT = new IntType();
public static final FloatType FLOAT = new FloatType();
public static final FloatType.OptionalFloatType OPTIONAL_FLOAT = new FloatType.OptionalFloatType();
public static final DoubleType DOUBLE = new DoubleType();
public static final LongType LONG = new LongType();
@@ -0,0 +1,56 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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 io.netty.buffer.ByteBuf;
import java.util.Arrays;
import java.util.BitSet;
public class BitSetType extends Type<BitSet> {
private final int length;
private final int bytesLength;
public BitSetType(final int length) {
super(BitSet.class);
this.length = length;
this.bytesLength = -Math.floorDiv(-length, 8); // Ceiled quotient
}
@Override
public BitSet read(ByteBuf buffer) {
final byte[] bytes = new byte[bytesLength];
buffer.readBytes(bytes);
return BitSet.valueOf(bytes);
}
@Override
public void write(ByteBuf buffer, BitSet object) {
Preconditions.checkArgument(object.length() <= length, "BitSet of length " + object.length() + " larger than max length " + length);
final byte[] bytes = object.toByteArray();
buffer.writeBytes(Arrays.copyOf(bytes, bytesLength));
}
}
@@ -23,26 +23,51 @@
package com.viaversion.viaversion.api.type.types;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public class ByteArrayType extends Type<byte[]> {
private final int length;
public ByteArrayType(final int length) {
super(byte[].class);
this.length = length;
}
public ByteArrayType() {
super(byte[].class);
this.length = -1;
}
@Override
public void write(ByteBuf buffer, byte[] object) throws Exception {
Type.VAR_INT.writePrimitive(buffer, object.length);
public void write(final ByteBuf buffer, final byte[] object) throws Exception {
if (this.length != -1) {
Preconditions.checkArgument(length == object.length, "Length does not match expected length");
} else {
Type.VAR_INT.writePrimitive(buffer, object.length);
}
buffer.writeBytes(object);
}
@Override
public byte[] read(ByteBuf buffer) throws Exception {
int length = Type.VAR_INT.readPrimitive(buffer);
public byte[] read(final ByteBuf buffer) throws Exception {
final int length = this.length == -1 ? Type.VAR_INT.readPrimitive(buffer) : this.length;
Preconditions.checkArgument(buffer.isReadable(length), "Length is fewer than readable bytes");
byte[] array = new byte[length];
final byte[] array = new byte[length];
buffer.readBytes(array);
return array;
}
public static final class OptionalByteArrayType extends OptionalType<byte[]> {
public OptionalByteArrayType() {
super(Type.BYTE_ARRAY_PRIMITIVE);
}
public OptionalByteArrayType(final int length) {
super(new ByteArrayType(length));
}
}
}
@@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.type.types;
import com.viaversion.viaversion.api.type.OptionalType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.TypeConverter;
import io.netty.buffer.ByteBuf;
@@ -67,4 +68,11 @@ public class FloatType extends Type<Float> implements TypeConverter<Float> {
}
return (Float) o;
}
public static final class OptionalFloatType extends OptionalType<Float> {
public OptionalFloatType() {
super(Type.FLOAT);
}
}
}
@@ -24,6 +24,8 @@ package com.viaversion.viaversion.api.type.types.version;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionImpl;
import com.viaversion.viaversion.api.minecraft.chunks.DataPalette;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
@@ -38,16 +40,14 @@ public class ChunkSectionType1_8 extends Type<ChunkSection> {
@Override
public ChunkSection read(ByteBuf buffer) throws Exception {
ChunkSection chunkSection = new ChunkSectionImpl(true);
DataPalette blocks = chunkSection.palette(PaletteType.BLOCKS);
// 0 index needs to be air in 1.9
chunkSection.addPaletteEntry(0);
blocks.addId(0);
ByteBuf littleEndianView = buffer.order(ByteOrder.LITTLE_ENDIAN);
for (int i = 0; i < ChunkSection.SIZE; i++) {
int mask = littleEndianView.readShort();
int type = mask >> 4;
int data = mask & 0xF;
chunkSection.setBlockWithData(i, type, data);
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
blocks.setIdAt(idx, littleEndianView.readShort());
}
return chunkSection;
@@ -55,15 +55,11 @@ public class ChunkSectionType1_8 extends Type<ChunkSection> {
@Override
public void write(ByteBuf buffer, ChunkSection chunkSection) throws Exception {
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int block = chunkSection.getFlatBlock(x, y, z);
buffer.writeByte(block);
buffer.writeByte(block >> 8);
}
}
DataPalette blocks = chunkSection.palette(PaletteType.BLOCKS);
ByteBuf littleEndianView = buffer.order(ByteOrder.LITTLE_ENDIAN);
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
littleEndianView.writeShort(blocks.idAt(idx));
}
}
}
@@ -0,0 +1,39 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 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.metadata.Metadata;
import com.viaversion.viaversion.api.minecraft.metadata.types.MetaTypes1_19_3;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.minecraft.MetaListType;
import com.viaversion.viaversion.api.type.types.minecraft.ParticleType;
import java.util.List;
public final class Types1_19_3 {
public static final ParticleType PARTICLE = new ParticleType(); // Only safe to use after protocol loading
public static final MetaTypes1_19_3 META_TYPES = new MetaTypes1_19_3(PARTICLE);
public static final Type<Metadata> METADATA = new MetadataType(META_TYPES);
public static final Type<List<Metadata>> METADATA_LIST = new MetaListType(METADATA);
}
@@ -24,29 +24,28 @@ package com.viaversion.viaversion.util;
import java.util.function.IntToLongFunction;
public class CompactArrayUtil {
//Oh no
private static final int[] MAGIC = {
-1, -1, 0, Integer.MIN_VALUE, 0, 0, 1431655765, 1431655765, 0, Integer.MIN_VALUE,
0, 1, 858993459, 858993459, 0, 715827882, 715827882, 0, 613566756, 613566756,
0, Integer.MIN_VALUE, 0, 2, 477218588, 477218588, 0, 429496729, 429496729, 0,
390451572, 390451572, 0, 357913941, 357913941, 0, 330382099, 330382099, 0, 306783378,
306783378, 0, 286331153, 286331153, 0, Integer.MIN_VALUE, 0, 3, 252645135, 252645135,
0, 238609294, 238609294, 0, 226050910, 226050910, 0, 214748364, 214748364, 0,
204522252, 204522252, 0, 195225786, 195225786, 0, 186737708, 186737708, 0, 178956970,
178956970, 0, 171798691, 171798691, 0, 165191049, 165191049, 0, 159072862, 159072862,
0, 153391689, 153391689, 0, 148102320, 148102320, 0, 143165576, 143165576, 0,
138547332, 138547332, 0, Integer.MIN_VALUE, 0, 4, 130150524, 130150524, 0, 126322567,
126322567, 0, 122713351, 122713351, 0, 119304647, 119304647, 0, 116080197, 116080197,
0, 113025455, 113025455, 0, 110127366, 110127366, 0, 107374182, 107374182, 0,
104755299, 104755299, 0, 102261126, 102261126, 0, 99882960, 99882960, 0, 97612893,
97612893, 0, 95443717, 95443717, 0, 93368854, 93368854, 0, 91382282, 91382282,
0, 89478485, 89478485, 0, 87652393, 87652393, 0, 85899345, 85899345, 0,
84215045, 84215045, 0, 82595524, 82595524, 0, 81037118, 81037118, 0, 79536431,
79536431, 0, 78090314, 78090314, 0, 76695844, 76695844, 0, 75350303, 75350303,
0, 74051160, 74051160, 0, 72796055, 72796055, 0, 71582788, 71582788, 0,
70409299, 70409299, 0, 69273666, 69273666, 0, 68174084, 68174084, 0, Integer.MIN_VALUE,
0, 5};
public final class CompactArrayUtil {
private static final long[] RECIPROCAL_MULT_AND_ADD = {
0xffffffffL, 0x00000000, 0x55555555, 0x00000000, 0x33333333, 0x2aaaaaaa, 0x24924924, 0x00000000,
0x1c71c71c, 0x19999999, 0x1745d174, 0x15555555, 0x13b13b13, 0x12492492, 0x11111111, 0x00000000,
0xf0f0f0f, 0xe38e38e, 0xd79435e, 0xccccccc, 0xc30c30c, 0xba2e8ba, 0xb21642c, 0xaaaaaaa,
0xa3d70a3, 0x9d89d89, 0x97b425e, 0x9249249, 0x8d3dcb0, 0x8888888, 0x8421084, 0x00000000,
0x7c1f07c, 0x7878787, 0x7507507, 0x71c71c7, 0x6eb3e45, 0x6bca1af, 0x6906906, 0x6666666,
0x63e7063, 0x6186186, 0x5f417d0, 0x5d1745d, 0x5b05b05, 0x590b216, 0x572620a, 0x5555555,
0x5397829, 0x51eb851, 0x5050505, 0x4ec4ec4, 0x4d4873e, 0x4bda12f, 0x4a7904a, 0x4924924,
0x47dc11f, 0x469ee58, 0x456c797, 0x4444444, 0x4325c53, 0x4210842, 0x4104104, 0x00000000
};
// Incrementally shift with each 0x80000000/0x00000000 tuple
private static final int[] RECIPROCAL_RIGHT_SHIFT = {
0, 0, 0, 1, 0, 0, 0, 2,
0, 0, 0, 0, 0, 0, 0, 3,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 4,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 5
};
private CompactArrayUtil() {
throw new AssertionError();
@@ -55,10 +54,10 @@ public class CompactArrayUtil {
public static long[] createCompactArrayWithPadding(int bitsPerEntry, int entries, IntToLongFunction valueGetter) {
long maxEntryValue = (1L << bitsPerEntry) - 1;
char valuesPerLong = (char) (64 / bitsPerEntry);
int magicIndex = 3 * (valuesPerLong - 1);
long divideMul = Integer.toUnsignedLong(MAGIC[magicIndex]);
long divideAdd = Integer.toUnsignedLong(MAGIC[magicIndex + 1]);
int divideShift = MAGIC[magicIndex + 2];
int magicIndex = valuesPerLong - 1;
long divideAdd = RECIPROCAL_MULT_AND_ADD[magicIndex];
long divideMul = divideAdd != 0 ? divideAdd : 0x80000000L; // Special case for the 0x80000000/0x00000000 tuple
int divideShift = RECIPROCAL_RIGHT_SHIFT[magicIndex];
int size = (entries + valuesPerLong - 1) / valuesPerLong;
long[] data = new long[size];
@@ -76,10 +75,10 @@ public class CompactArrayUtil {
public static void iterateCompactArrayWithPadding(int bitsPerEntry, int entries, long[] data, BiIntConsumer consumer) {
long maxEntryValue = (1L << bitsPerEntry) - 1;
char valuesPerLong = (char) (64 / bitsPerEntry);
int magicIndex = 3 * (valuesPerLong - 1);
long divideMul = Integer.toUnsignedLong(MAGIC[magicIndex]);
long divideAdd = Integer.toUnsignedLong(MAGIC[magicIndex + 1]);
int divideShift = MAGIC[magicIndex + 2];
int magicIndex = valuesPerLong - 1;
long divideAdd = RECIPROCAL_MULT_AND_ADD[magicIndex];
long divideMul = divideAdd != 0 ? divideAdd : 0x80000000L;
int divideShift = RECIPROCAL_RIGHT_SHIFT[magicIndex];
for (int i = 0; i < entries; i++) {
int cellIndex = (int) (i * divideMul + divideAdd >> 32L >> divideShift);
@@ -34,29 +34,21 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class PipelineUtil {
private static Method DECODE_METHOD;
private static Method ENCODE_METHOD;
private static Method MTM_DECODE;
public final class PipelineUtil {
private static final Method DECODE_METHOD;
private static final Method ENCODE_METHOD;
private static final Method MTM_DECODE;
static {
try {
DECODE_METHOD = ByteToMessageDecoder.class.getDeclaredMethod("decode", ChannelHandlerContext.class, ByteBuf.class, List.class);
DECODE_METHOD.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
ENCODE_METHOD = MessageToByteEncoder.class.getDeclaredMethod("encode", ChannelHandlerContext.class, Object.class, ByteBuf.class);
ENCODE_METHOD.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
MTM_DECODE = MessageToMessageDecoder.class.getDeclaredMethod("decode", ChannelHandlerContext.class, Object.class, List.class);
MTM_DECODE.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@@ -25,7 +25,6 @@ tasks {
publishShadowJar()
fun ShadowJar.configureRelocations() {
relocate("javassist", "com.viaversion.viaversion.libs.javassist")
relocate("com.google.gson", "com.viaversion.viaversion.libs.gson")
relocate("com.github.steveice10.opennbt", "com.viaversion.viaversion.libs.opennbt")
relocate("it.unimi.dsi.fastutil", "com.viaversion.viaversion.libs.fastutil")
+1 -1
View File
@@ -1,10 +1,10 @@
dependencies {
implementation(projects.viaversionBukkitLegacy)
implementation(projects.viaversionCommon)
implementation(libs.javassist)
compileOnly(libs.paper) {
exclude("junit", "junit")
exclude("com.google.code.gson", "gson")
exclude("javax.persistence", "persistence-api")
}
compileOnly(projects.compat.protocolsupportCompat)
}
@@ -26,16 +26,13 @@ import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.viaversion.api.platform.PlatformTask;
import com.viaversion.viaversion.api.platform.UnsupportedSoftware;
import com.viaversion.viaversion.api.platform.ViaPlatform;
import com.viaversion.viaversion.bukkit.classgenerator.ClassGenerator;
import com.viaversion.viaversion.bukkit.commands.BukkitCommandHandler;
import com.viaversion.viaversion.bukkit.commands.BukkitCommandSender;
import com.viaversion.viaversion.bukkit.listeners.ProtocolLibEnableListener;
import com.viaversion.viaversion.bukkit.platform.BukkitViaAPI;
import com.viaversion.viaversion.bukkit.platform.BukkitViaConfig;
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.util.NMSUtil;
import com.viaversion.viaversion.dump.PluginInfo;
import com.viaversion.viaversion.unsupported.UnsupportedPlugin;
import com.viaversion.viaversion.unsupported.UnsupportedServerSoftware;
@@ -60,8 +57,6 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
private final List<Runnable> queuedTasks = new ArrayList<>();
private final List<Runnable> asyncQueuedTasks = new ArrayList<>();
private final boolean protocolSupport;
private boolean compatSpigotBuild;
private boolean spigot = true;
private boolean lateBind;
public ViaVersionPlugin() {
@@ -89,37 +84,13 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
@Override
public void onLoad() {
// Via should load before PL, so we can't check for it in the constructor
Plugin protocolLib = Bukkit.getPluginManager().getPlugin("ProtocolLib");
ProtocolLibEnableListener.checkCompat(protocolLib);
// Spigot detector
try {
Class.forName("org.spigotmc.SpigotConfig");
} catch (ClassNotFoundException e) {
spigot = false;
}
// Check if it's a spigot build with a protocol mod
try {
NMSUtil.nms(
"PacketEncoder",
"net.minecraft.network.PacketEncoder"
).getDeclaredField("version");
compatSpigotBuild = true;
} catch (Exception e) {
compatSpigotBuild = false;
}
if (getServer().getPluginManager().getPlugin("ViaBackwards") != null) {
MappingDataLoader.enableMappingsCache();
}
// Generate classes needed (only works if it's compat or ps)
ClassGenerator.generate();
lateBind = !((BukkitViaInjector) Via.getManager().getInjector()).isBinded();
getLogger().info("ViaVersion " + getDescription().getVersion() + (compatSpigotBuild ? "compat" : "") + " is now loaded" + (lateBind ? ", waiting for boot. (late-bind)" : ", injecting!"));
getLogger().info("ViaVersion " + getDescription().getVersion() + " is now loaded" + (lateBind ? ", waiting for boot. (late-bind)" : ", injecting!"));
if (!lateBind) {
((ViaManagerImpl) Via.getManager()).init();
}
@@ -134,10 +105,8 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
getCommand("viaversion").setExecutor(commandHandler);
getCommand("viaversion").setTabCompleter(commandHandler);
getServer().getPluginManager().registerEvents(new ProtocolLibEnableListener(), this);
// Warn them if they have anti-xray on and they aren't using spigot
if (conf.isAntiXRay() && !spigot) {
if (conf.isAntiXRay() && !isSpigot()) {
getLogger().info("You have anti-xray on in your config, since you're not using spigot it won't fix xray!");
}
@@ -307,18 +276,19 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player>
return lateBind;
}
public boolean isCompatSpigotBuild() {
return compatSpigotBuild;
}
public boolean isSpigot() {
return this.spigot;
}
public boolean isProtocolSupport() {
return protocolSupport;
}
private boolean isSpigot() {
try {
Class.forName("org.spigotmc.SpigotConfig");
} catch (ClassNotFoundException e) {
return false;
}
return true;
}
public static ViaVersionPlugin getInstance() {
return instance;
}
@@ -1,363 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.bukkit.classgenerator;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.bukkit.handlers.BukkitDecodeHandler;
import com.viaversion.viaversion.bukkit.handlers.BukkitEncodeHandler;
import com.viaversion.viaversion.bukkit.util.NMSUtil;
import com.viaversion.viaversion.classgenerator.generated.BasicHandlerConstructor;
import com.viaversion.viaversion.classgenerator.generated.HandlerConstructor;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.LoaderClassPath;
import javassist.NotFoundException;
import javassist.expr.ConstructorCall;
import javassist.expr.ExprEditor;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.bukkit.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.lang.reflect.Method;
//TODO maybe clean this up a bit 👀
public final class ClassGenerator {
private static final boolean useModules = hasModuleMethod();
private static HandlerConstructor constructor = new BasicHandlerConstructor();
private static String psPackage;
private static Class psConnectListener;
public static HandlerConstructor getConstructor() {
return constructor;
}
public static void generate() {
if (ViaVersionPlugin.getInstance().isCompatSpigotBuild() || ViaVersionPlugin.getInstance().isProtocolSupport()) {
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new LoaderClassPath(Bukkit.class.getClassLoader()));
for (Plugin p : Bukkit.getPluginManager().getPlugins()) {
pool.insertClassPath(new LoaderClassPath(p.getClass().getClassLoader()));
}
if (ViaVersionPlugin.getInstance().isCompatSpigotBuild()) {
Class decodeSuper = NMSUtil.nms("PacketDecoder", "net.minecraft.network.PacketDecoder");
Class encodeSuper = NMSUtil.nms("PacketEncoder", "net.minecraft.network.PacketEncoder");
// Generate the classes
addSpigotCompatibility(pool, BukkitDecodeHandler.class, decodeSuper);
addSpigotCompatibility(pool, BukkitEncodeHandler.class, encodeSuper);
} else {
// ProtocolSupport compatibility
Class encodeSuper;
Class decodeSuper;
if (isMultiplatformPS()) {
psConnectListener = makePSConnectListener(pool);
return;
} else {
String psPackage = getOldPSPackage();
decodeSuper = Class.forName(psPackage.equals("unknown") ? "protocolsupport.protocol.pipeline.common.PacketDecoder" : psPackage + ".wrapped.WrappedDecoder");
encodeSuper = Class.forName(psPackage.equals("unknown") ? "protocolsupport.protocol.pipeline.common.PacketEncoder" : psPackage + ".wrapped.WrappedEncoder");
}
// Generate the classes
addPSCompatibility(pool, BukkitDecodeHandler.class, decodeSuper);
addPSCompatibility(pool, BukkitEncodeHandler.class, encodeSuper);
}
// Implement Constructor
CtClass generated = pool.makeClass("com.viaversion.viaversion.classgenerator.generated.GeneratedConstructor");
CtClass handlerInterface = pool.get(HandlerConstructor.class.getName());
generated.setInterfaces(new CtClass[]{handlerInterface});
// Import required classes
pool.importPackage("com.viaversion.viaversion.classgenerator.generated");
pool.importPackage("com.viaversion.viaversion.classgenerator");
pool.importPackage("com.viaversion.viaversion.api.connection");
pool.importPackage("io.netty.handler.codec");
// Implement Methods
generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" +
" return new BukkitEncodeHandler(info, minecraftEncoder);\n" +
" }", generated));
generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" +
" return new BukkitDecodeHandler(info, minecraftDecoder);\n" +
" }", generated));
constructor = (HandlerConstructor) toClass(generated).getConstructor().newInstance();
} catch (ReflectiveOperationException | CannotCompileException | NotFoundException e) {
e.printStackTrace();
}
}
}
private static void addSpigotCompatibility(ClassPool pool, Class input, Class superclass) {
String newName = "com.viaversion.viaversion.classgenerator.generated." + input.getSimpleName();
try {
CtClass generated = pool.getAndRename(input.getName(), newName);
if (superclass != null) {
CtClass toExtend = pool.get(superclass.getName());
generated.setSuperclass(toExtend);
// If it's NMS satisfy constructor.
if (superclass.getName().startsWith("net.minecraft")) {
// Modify constructor to call super
if (generated.getConstructors().length != 0) {
generated.getConstructors()[0].instrument(new ExprEditor() {
@Override
public void edit(ConstructorCall c) throws CannotCompileException {
if (c.isSuper()) {
// Constructor for both has a stats thing.
c.replace("super(null);");
}
super.edit(c);
}
});
}
}
}
toClass(generated);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
}
private static void addPSCompatibility(ClassPool pool, Class input, Class superclass) {
boolean newPS = getOldPSPackage().equals("unknown");
String newName = "com.viaversion.viaversion.classgenerator.generated." + input.getSimpleName();
try {
CtClass generated = pool.getAndRename(input.getName(), newName);
if (superclass != null) {
CtClass toExtend = pool.get(superclass.getName());
generated.setSuperclass(toExtend);
if (!newPS) {
// Override setRealEncoder / setRealDecoder
pool.importPackage(getOldPSPackage());
pool.importPackage(getOldPSPackage() + ".wrapped");
if (superclass.getName().endsWith("Decoder")) {
// Decoder
generated.addMethod(CtMethod.make("public void setRealDecoder(IPacketDecoder dec) {\n" +
" ((WrappedDecoder) this.minecraftDecoder).setRealDecoder(dec);\n" +
" }", generated));
} else {
// Encoder
pool.importPackage("protocolsupport.api");
pool.importPackage("java.lang.reflect");
generated.addMethod(CtMethod.make("public void setRealEncoder(IPacketEncoder enc) {\n" +
" try {\n" +
// Tell ProtocolSupport to decode MINECRAFT_FUTURE packets using the default decoder (for 1.9.4)
" Field field = enc.getClass().getDeclaredField(\"version\");\n" +
" field.setAccessible(true);\n" +
" ProtocolVersion version = (ProtocolVersion) field.get(enc);\n" +
" if (version == ProtocolVersion.MINECRAFT_FUTURE) enc = enc.getClass().getConstructor(\n" +
" new Class[]{ProtocolVersion.class}).newInstance(new Object[] {ProtocolVersion.getLatest()});\n" +
" } catch (Exception e) {\n" +
// I guess we're not on 1.9.4
" }\n" +
" ((WrappedEncoder) this.minecraftEncoder).setRealEncoder(enc);\n" +
" }", generated));
}
}
}
toClass(generated);
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
}
private static Class makePSConnectListener(ClassPool pool) {
HandshakeProtocolType type = handshakeVersionMethod();
try {
// Reference classes
CtClass toExtend = pool.get("protocolsupport.api.Connection$PacketListener");
CtClass connectListenerClazz = pool.makeClass("com.viaversion.viaversion.classgenerator.generated.ProtocolSupportConnectListener");
connectListenerClazz.setSuperclass(toExtend);
// Import packages
pool.importPackage("java.util.Arrays");
pool.importPackage("protocolsupport.api.ProtocolVersion");
pool.importPackage("protocolsupport.api.ProtocolType");
pool.importPackage("protocolsupport.api.Connection");
pool.importPackage("protocolsupport.api.Connection.PacketListener");
pool.importPackage("protocolsupport.api.Connection.PacketListener.PacketEvent");
pool.importPackage("protocolsupport.protocol.ConnectionImpl");
pool.importPackage(NMSUtil.nms(
"PacketHandshakingInSetProtocol",
"net.minecraft.network.protocol.handshake.PacketHandshakingInSetProtocol"
).getName());
// Add connection reference field
connectListenerClazz.addField(CtField.make("private ConnectionImpl connection;", connectListenerClazz));
// Bake constructor
connectListenerClazz.addConstructor(CtNewConstructor.make(
"public ProtocolSupportConnectListener (ConnectionImpl connection) {\n"
+ " this.connection = connection;\n"
+ "}", connectListenerClazz));
// Add the listening method
connectListenerClazz.addMethod(CtNewMethod.make(
// On packet receive
"public void onPacketReceiving(protocolsupport.api.Connection.PacketListener.PacketEvent event) {\n"
// Check if we are getting handshake packet.
+ " if (event.getPacket() instanceof PacketHandshakingInSetProtocol) {\n"
// Get protocol version.
+ " PacketHandshakingInSetProtocol packet = (PacketHandshakingInSetProtocol) event.getPacket();\n"
+ " int protoVersion = packet." + type.methodName() + "();\n"
// ViaVersion has at this point already spoofed the connectionversion. (Since it is higher up the pipeline)
// If via has put the protoVersion to the server we can spoof ProtocolSupport's version.
+ " if (connection.getVersion() == ProtocolVersion.MINECRAFT_FUTURE && protoVersion == com.viaversion.viaversion.api.Via.getAPI().getServerVersion().lowestSupportedVersion()) {\n"
+ " connection.setVersion(ProtocolVersion.getLatest(ProtocolType.PC));\n"
+ " }\n"
+ " }\n"
// Id version is not serverversion viaversion will not spoof. ProtocolSupport will handle the rest.
// In any case, remove the packet listener and wrap up.
+ " connection.removePacketListener(this);\n"
+ "}", connectListenerClazz));
return toClass(connectListenerClazz);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void registerPSConnectListener(ViaVersionPlugin plugin) {
if (psConnectListener != null) {
try {
Class<? extends Event> connectionOpenEvent = (Class<? extends Event>) Class.forName("protocolsupport.api.events.ConnectionOpenEvent");
Bukkit.getPluginManager().registerEvent(connectionOpenEvent, new Listener() {
}, EventPriority.HIGH, new EventExecutor() {
@Override
public void execute(@NonNull Listener listener, @NonNull Event event) throws EventException {
try {
Object connection = event.getClass().getMethod("getConnection").invoke(event);
Object connectListener = psConnectListener.getConstructor(connection.getClass()).newInstance(connection);
Method addConnectListener = connection.getClass().getMethod("addPacketListener", Class.forName("protocolsupport.api.Connection$PacketListener"));
addConnectListener.invoke(connection, connectListener);
} catch (Exception e) {
e.printStackTrace();
}
}
}, plugin);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static Class getPSConnectListener() {
return psConnectListener;
}
public static String getOldPSPackage() {
if (psPackage == null) {
try {
Class.forName("protocolsupport.protocol.core.IPacketDecoder");
psPackage = "protocolsupport.protocol.core";
} catch (ClassNotFoundException e) {
try {
Class.forName("protocolsupport.protocol.pipeline.IPacketDecoder");
psPackage = "protocolsupport.protocol.pipeline";
} catch (ClassNotFoundException e1) {
psPackage = "unknown";
}
}
}
return psPackage;
}
public static boolean isMultiplatformPS() {
try {
Class.forName("protocolsupport.zplatform.impl.spigot.network.pipeline.SpigotPacketEncoder");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
public static HandshakeProtocolType handshakeVersionMethod() {
Class<?> clazz = null;
// Check for the mapped method
try {
clazz = NMSUtil.nms(
"PacketHandshakingInSetProtocol",
"net.minecraft.network.protocol.handshake.PacketHandshakingInSetProtocol"
);
clazz.getMethod("getProtocolVersion");
return HandshakeProtocolType.MAPPED;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException ignored) {
}
// Check for obfusacted b/c methods
try {
if (clazz.getMethod("b").getReturnType() == int.class) {
return HandshakeProtocolType.OBFUSCATED_OLD;
} else if (clazz.getMethod("c").getReturnType() == int.class) {
return HandshakeProtocolType.OBFUSCATED_NEW;
}
throw new UnsupportedOperationException("Protocol version method not found in " + clazz.getSimpleName());
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("deprecation")
private static Class<?> toClass(CtClass ctClass) throws CannotCompileException {
return useModules ? ctClass.toClass(HandlerConstructor.class) : ctClass.toClass(HandlerConstructor.class.getClassLoader());
}
private static boolean hasModuleMethod() {
try {
Class.class.getDeclaredMethod("getModule");
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
private enum HandshakeProtocolType {
MAPPED("getProtocolVersion"),
OBFUSCATED_OLD("b"),
OBFUSCATED_NEW("c");
private final String methodName;
HandshakeProtocolType(String methodName) {
this.methodName = methodName;
}
public String methodName() {
return methodName;
}
}
}
@@ -0,0 +1,105 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.bukkit.compat;
import com.viaversion.viaversion.ViaVersionPlugin;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.bukkit.util.NMSUtil;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import java.util.logging.Level;
public final class ProtocolSupportCompat {
public static void registerPSConnectListener(ViaVersionPlugin plugin) {
Via.getPlatform().getLogger().info("Registering ProtocolSupport compat connection listener");
try {
//noinspection unchecked
Class<? extends Event> connectionOpenEvent = (Class<? extends Event>) Class.forName("protocolsupport.api.events.ConnectionOpenEvent");
Bukkit.getPluginManager().registerEvent(connectionOpenEvent, new Listener() {
}, EventPriority.HIGH, (listener, event) -> {
try {
Object connection = event.getClass().getMethod("getConnection").invoke(event);
ProtocolSupportConnectionListener connectListener = new ProtocolSupportConnectionListener(connection);
ProtocolSupportConnectionListener.ADD_PACKET_LISTENER_METHOD.invoke(connection, connectListener);
} catch (ReflectiveOperationException e) {
Via.getPlatform().getLogger().log(Level.WARNING, "Error when handling ProtocolSupport event", e);
}
}, plugin);
} catch (ClassNotFoundException e) {
Via.getPlatform().getLogger().log(Level.WARNING, "Unable to register ProtocolSupport listener", e);
}
}
public static boolean isMultiplatformPS() {
try {
Class.forName("protocolsupport.zplatform.impl.spigot.network.pipeline.SpigotPacketEncoder");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
static HandshakeProtocolType handshakeVersionMethod() {
Class<?> clazz = null;
// Check for the mapped method
try {
clazz = NMSUtil.nms(
"PacketHandshakingInSetProtocol",
"net.minecraft.network.protocol.handshake.PacketHandshakingInSetProtocol"
);
clazz.getMethod("getProtocolVersion");
return HandshakeProtocolType.MAPPED;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException ignored) {
}
// Check for obfusacted b/c methods
try {
if (clazz.getMethod("b").getReturnType() == int.class) {
return HandshakeProtocolType.OBFUSCATED_B;
} else if (clazz.getMethod("c").getReturnType() == int.class) {
return HandshakeProtocolType.OBFUSCATED_C;
}
throw new UnsupportedOperationException("Protocol version method not found in " + clazz.getSimpleName());
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
enum HandshakeProtocolType {
MAPPED("getProtocolVersion"),
OBFUSCATED_B("b"),
OBFUSCATED_C("c");
private final String methodName;
HandshakeProtocolType(String methodName) {
this.methodName = methodName;
}
public String methodName() {
return methodName;
}
}
}
@@ -0,0 +1,88 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.bukkit.compat;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.bukkit.util.NMSUtil;
import protocolsupport.api.Connection;
import java.lang.reflect.Method;
final class ProtocolSupportConnectionListener extends Connection.PacketListener {
static final Method ADD_PACKET_LISTENER_METHOD;
private static final Class<?> HANDSHAKE_PACKET_CLASS;
private static final Method GET_VERSION_METHOD;
private static final Method SET_VERSION_METHOD;
private static final Method REMOVE_PACKET_LISTENER_METHOD;
private static final Method GET_LATEST_METHOD;
private static final Object PROTOCOL_VERSION_MINECRAFT_FUTURE;
private static final Object PROTOCOL_TYPE_PC;
static {
try {
HANDSHAKE_PACKET_CLASS = NMSUtil.nms(
"PacketHandshakingInSetProtocol",
"net.minecraft.network.protocol.handshake.PacketHandshakingInSetProtocol"
);
final Class<?> connectionImplClass = Class.forName("protocolsupport.protocol.ConnectionImpl");
final Class<?> connectionClass = Class.forName("protocolsupport.api.Connection");
final Class<?> packetListenerClass = Class.forName("protocolsupport.api.Connection$PacketListener");
final Class<?> protocolVersionClass = Class.forName("protocolsupport.api.ProtocolVersion");
final Class<?> protocolTypeClass = Class.forName("protocolsupport.api.ProtocolType");
GET_VERSION_METHOD = connectionClass.getDeclaredMethod("getVersion");
SET_VERSION_METHOD = connectionImplClass.getDeclaredMethod("setVersion", protocolVersionClass);
PROTOCOL_VERSION_MINECRAFT_FUTURE = protocolVersionClass.getDeclaredField("MINECRAFT_FUTURE").get(null);
GET_LATEST_METHOD = protocolVersionClass.getDeclaredMethod("getLatest", protocolTypeClass);
PROTOCOL_TYPE_PC = protocolTypeClass.getDeclaredField("PC").get(null);
ADD_PACKET_LISTENER_METHOD = connectionClass.getDeclaredMethod("addPacketListener", packetListenerClass);
REMOVE_PACKET_LISTENER_METHOD = connectionClass.getDeclaredMethod("removePacketListener", packetListenerClass);
} catch (final ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
private final Object connection;
ProtocolSupportConnectionListener(final Object connection) {
this.connection = connection;
}
@Override
public void onPacketReceiving(final Connection.PacketListener.PacketEvent event) {
try {
// Check if we are getting handshake packet.
if (HANDSHAKE_PACKET_CLASS.isInstance(event.getPacket()) && GET_VERSION_METHOD.invoke(connection) == PROTOCOL_VERSION_MINECRAFT_FUTURE) {
final Object packet = event.getPacket();
final int protocolVersion = (int) HANDSHAKE_PACKET_CLASS.getDeclaredMethod(ProtocolSupportCompat.handshakeVersionMethod().methodName()).invoke(packet);
// ViaVersion has at this point already spoofed the connectionversion. (Since it is higher up the pipeline)
// If via has put the protoVersion to the server we can spoof ProtocolSupport's version.
if (protocolVersion == Via.getAPI().getServerVersion().lowestSupportedVersion()) {
SET_VERSION_METHOD.invoke(connection, GET_LATEST_METHOD.invoke(null, PROTOCOL_TYPE_PC));
}
}
// Id version is not serverversion viaversion will not spoof. ProtocolSupport will handle the rest.
// In any case, remove the packet listener and wrap up.
REMOVE_PACKET_LISTENER_METHOD.invoke(connection, this);
} catch (final ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
}
@@ -18,33 +18,48 @@
package com.viaversion.viaversion.bukkit.handlers;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.bukkit.classgenerator.ClassGenerator;
import com.viaversion.viaversion.bukkit.platform.PaperViaInjector;
import com.viaversion.viaversion.classgenerator.generated.HandlerConstructor;
import com.viaversion.viaversion.connection.UserConnectionImpl;
import com.viaversion.viaversion.platform.WrappedChannelInitializer;
import com.viaversion.viaversion.protocol.ProtocolPipelineImpl;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.channel.ChannelPipeline;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.lang.reflect.Method;
public class BukkitChannelInitializer extends ChannelInitializer<Channel> implements WrappedChannelInitializer {
public final class BukkitChannelInitializer extends ChannelInitializer<Channel> implements WrappedChannelInitializer {
public static final String VIA_ENCODER = "via-encoder";
public static final String VIA_DECODER = "via-decoder";
public static final String MINECRAFT_ENCODER = "encoder";
public static final String MINECRAFT_DECODER = "decoder";
public static final String MINECRAFT_COMPRESSOR = "compress";
public static final String MINECRAFT_DECOMPRESSOR = "decompress";
public static final Object COMPRESSION_ENABLED_EVENT = paperCompressionEnabledEvent();
private static final Method INIT_CHANNEL_METHOD;
private final ChannelInitializer<Channel> original;
static {
try {
INIT_CHANNEL_METHOD = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
INIT_CHANNEL_METHOD.setAccessible(true);
} catch (NoSuchMethodException e) {
} catch (final ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
private static @Nullable Object paperCompressionEnabledEvent() {
try {
final Class<?> eventClass = Class.forName("io.papermc.paper.network.ConnectionEvent");
return eventClass.getDeclaredField("COMPRESSION_THRESHOLD_SET").get(null);
} catch (final ReflectiveOperationException e) {
return null;
}
}
public BukkitChannelInitializer(ChannelInitializer<Channel> oldInit) {
this.original = oldInit;
}
@@ -62,7 +77,7 @@ public class BukkitChannelInitializer extends ChannelInitializer<Channel> implem
}
public static void afterChannelInitialize(Channel channel) {
UserConnection connection = new UserConnectionImpl(channel);
final UserConnection connection = new UserConnectionImpl(channel);
new ProtocolPipelineImpl(connection);
if (PaperViaInjector.PAPER_PACKET_LIMITER) {
@@ -70,12 +85,9 @@ public class BukkitChannelInitializer extends ChannelInitializer<Channel> implem
}
// Add our transformers
HandlerConstructor constructor = ClassGenerator.getConstructor();
MessageToByteEncoder encoder = constructor.newEncodeHandler(connection, (MessageToByteEncoder) channel.pipeline().get("encoder"));
ByteToMessageDecoder decoder = constructor.newDecodeHandler(connection, (ByteToMessageDecoder) channel.pipeline().get("decoder"));
channel.pipeline().replace("encoder", "encoder", encoder);
channel.pipeline().replace("decoder", "decoder", decoder);
final ChannelPipeline pipeline = channel.pipeline();
pipeline.addBefore(MINECRAFT_ENCODER, VIA_ENCODER, new BukkitEncodeHandler(connection));
pipeline.addBefore(MINECRAFT_DECODER, VIA_DECODER, new BukkitDecodeHandler(connection));
}
@Override
@@ -26,59 +26,64 @@ import com.viaversion.viaversion.exception.CancelDecoderException;
import com.viaversion.viaversion.exception.InformativeException;
import com.viaversion.viaversion.util.PipelineUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.MessageToMessageDecoder;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class BukkitDecodeHandler extends ByteToMessageDecoder {
private final ByteToMessageDecoder minecraftDecoder;
private final UserConnection info;
@ChannelHandler.Sharable
public final class BukkitDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
private final UserConnection connection;
public BukkitDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
this.info = info;
this.minecraftDecoder = minecraftDecoder;
public BukkitDecodeHandler(final UserConnection connection) {
this.connection = connection;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
if (!info.checkServerboundPacket()) {
bytebuf.clear(); // Don't accumulate
protected void decode(final ChannelHandlerContext ctx, final ByteBuf bytebuf, final List<Object> out) throws Exception {
if (!connection.checkServerboundPacket()) {
throw CancelDecoderException.generate(null);
}
if (!connection.shouldTransformPacket()) {
out.add(bytebuf.retain());
return;
}
ByteBuf transformedBuf = null;
final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
try {
if (info.shouldTransformPacket()) {
transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
info.transformServerbound(transformedBuf, CancelDecoderException::generate);
}
try {
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, transformedBuf == null ? bytebuf : transformedBuf));
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Exception) {
throw (Exception) e.getCause();
} else if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
}
}
connection.transformIncoming(transformedBuf, CancelDecoderException::generate);
out.add(transformedBuf.retain());
} finally {
if (transformedBuf != null) {
transformedBuf.release();
}
transformedBuf.release();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; // ProtocolLib compat
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) {
return;
}
super.exceptionCaught(ctx, cause);
if (!NMSUtil.isDebugPropertySet() && PipelineUtil.containsCause(cause, InformativeException.class)
&& (info.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
&& (connection.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
cause.printStackTrace(); // Print if CB doesn't already do it
}
}
@Override
public void userEventTriggered(final ChannelHandlerContext ctx, final Object event) throws Exception {
if (BukkitChannelInitializer.COMPRESSION_ENABLED_EVENT == null || event != BukkitChannelInitializer.COMPRESSION_ENABLED_EVENT) {
super.userEventTriggered(ctx, event);
return;
}
// When compression handlers are added, the order becomes Minecraft Encoder -> Compressor -> Via Encoder; fix the order again
final ChannelPipeline pipeline = ctx.pipeline();
pipeline.addAfter(BukkitChannelInitializer.MINECRAFT_COMPRESSOR, BukkitChannelInitializer.VIA_ENCODER, pipeline.remove(BukkitChannelInitializer.VIA_ENCODER));
pipeline.addAfter(BukkitChannelInitializer.MINECRAFT_DECOMPRESSOR, BukkitChannelInitializer.VIA_DECODER, pipeline.remove(BukkitChannelInitializer.VIA_DECODER));
super.userEventTriggered(ctx, event);
}
}
@@ -24,84 +24,99 @@ 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.handlers.ChannelHandlerContextWrapper;
import com.viaversion.viaversion.handlers.ViaCodecHandler;
import com.viaversion.viaversion.util.PipelineUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.MessageToMessageEncoder;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaCodecHandler {
private static Field versionField;
@ChannelHandler.Sharable
public final class BukkitEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
private final UserConnection connection;
private boolean handledCompression = BukkitChannelInitializer.COMPRESSION_ENABLED_EVENT != null;
static {
try {
// Attempt to get any version info from the handler
versionField = NMSUtil.nms(
"PacketEncoder",
"net.minecraft.network.PacketEncoder"
).getDeclaredField("version");
versionField.setAccessible(true);
} catch (Exception e) {
// Not compat version
}
}
private final UserConnection info;
private final MessageToByteEncoder minecraftEncoder;
public BukkitEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
this.info = info;
this.minecraftEncoder = minecraftEncoder;
public BukkitEncodeHandler(final UserConnection connection) {
this.connection = connection;
}
@Override
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
if (versionField != null) {
versionField.set(minecraftEncoder, versionField.get(this));
protected void encode(final ChannelHandlerContext ctx, final ByteBuf bytebuf, final List<Object> out) throws Exception {
if (!connection.checkClientboundPacket()) {
throw CancelEncoderException.generate(null);
}
// handle the packet type
if (!(o instanceof ByteBuf)) {
// call minecraft encoder
try {
PipelineUtil.callEncode(this.minecraftEncoder, new ChannelHandlerContextWrapper(ctx, this), o, bytebuf);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Exception) {
throw (Exception) e.getCause();
} else if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
}
if (!connection.shouldTransformPacket()) {
out.add(bytebuf.retain());
return;
}
final ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
try {
final boolean needsCompression = !handledCompression && handleCompressionOrder(ctx, transformedBuf);
connection.transformClientbound(transformedBuf, CancelEncoderException::generate);
if (needsCompression) {
recompress(ctx, transformedBuf);
}
} else {
bytebuf.writeBytes((ByteBuf) o);
out.add(transformedBuf.retain());
} finally {
transformedBuf.release();
}
}
private boolean handleCompressionOrder(final ChannelHandlerContext ctx, final ByteBuf buf) throws Exception {
final ChannelPipeline pipeline = ctx.pipeline();
final List<String> names = pipeline.names();
final int compressorIndex = names.indexOf(BukkitChannelInitializer.MINECRAFT_COMPRESSOR);
if (compressorIndex == -1) {
return false;
}
handledCompression = true;
if (compressorIndex > names.indexOf(BukkitChannelInitializer.VIA_ENCODER)) {
// Need to decompress this packet due to bad order
final ByteBuf decompressed = (ByteBuf) PipelineUtil.callDecode((ByteToMessageDecoder) pipeline.get(BukkitChannelInitializer.MINECRAFT_DECOMPRESSOR), ctx, buf).get(0);
try {
buf.clear().writeBytes(decompressed);
} finally {
decompressed.release();
}
pipeline.addAfter(BukkitChannelInitializer.MINECRAFT_COMPRESSOR, BukkitChannelInitializer.VIA_ENCODER, pipeline.remove(BukkitChannelInitializer.VIA_ENCODER));
pipeline.addAfter(BukkitChannelInitializer.MINECRAFT_DECOMPRESSOR, BukkitChannelInitializer.VIA_DECODER, pipeline.remove(BukkitChannelInitializer.VIA_DECODER));
return true;
}
return false;
}
private void recompress(final ChannelHandlerContext ctx, final ByteBuf buf) throws Exception {
final ByteBuf compressed = ctx.alloc().buffer();
try {
PipelineUtil.callEncode((MessageToByteEncoder<ByteBuf>) ctx.pipeline().get(BukkitChannelInitializer.MINECRAFT_COMPRESSOR), ctx, buf, compressed);
buf.clear().writeBytes(compressed);
} finally {
compressed.release();
}
transform(bytebuf);
}
@Override
public void transform(ByteBuf bytebuf) throws Exception {
if (!info.checkClientboundPacket()) throw CancelEncoderException.generate(null);
if (!info.shouldTransformPacket()) return;
info.transformClientbound(bytebuf, CancelEncoderException::generate);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; // ProtocolLib compat
public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) {
return;
}
super.exceptionCaught(ctx, cause);
if (!NMSUtil.isDebugPropertySet() && PipelineUtil.containsCause(cause, InformativeException.class)
&& (info.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
&& (connection.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
cause.printStackTrace(); // Print if CB doesn't already do it
}
}
public UserConnection getInfo() {
return info;
public UserConnection connection() {
return connection;
}
}
@@ -103,7 +103,7 @@ public class JoinListener implements Listener {
private @Nullable UserConnection getUserConnection(Channel channel) {
BukkitEncodeHandler encoder = channel.pipeline().get(BukkitEncodeHandler.class);
return encoder != null ? encoder.getInfo() : null;
return encoder != null ? encoder.connection() : null;
}
private Channel getChannel(Player player) throws Exception {
@@ -1,62 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.bukkit.listeners;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.bukkit.platform.BukkitViaInjector;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;
public class ProtocolLibEnableListener implements Listener {
@EventHandler
public void onPluginEnable(PluginEnableEvent e) {
// Will likely never happen, but try to account for hacky plugin loading systems anyways
if (e.getPlugin().getName().equals("ProtocolLib")) {
checkCompat(e.getPlugin());
}
}
@EventHandler
public void onPluginDisable(PluginDisableEvent e) {
if (e.getPlugin().getName().equals("ProtocolLib")) {
((BukkitViaInjector) Via.getManager().getInjector()).setProtocolLib(false);
}
}
public static void checkCompat(@Nullable Plugin protocolLib) {
if (protocolLib != null) {
String version = protocolLib.getDescription().getVersion();
String majorVersion = version.split("\\.", 2)[0];
try {
// Only need the compat check for version < 5
if (Integer.parseInt(majorVersion) < 5) {
((BukkitViaInjector) Via.getManager().getInjector()).setProtocolLib(true);
return;
}
} catch (NumberFormatException ignored) {
Via.getPlatform().getLogger().warning("ProtocolLib version check failed for version " + version);
}
}
((BukkitViaInjector) Via.getManager().getInjector()).setProtocolLib(false);
}
}
@@ -43,14 +43,17 @@ public class BukkitViaAPI extends ViaAPIBase<Player> {
@Override
public int getPlayerVersion(UUID uuid) {
UserConnection connection = Via.getManager().getConnectionManager().getConnectedClient(uuid);
if (connection == null) {
if (connection != null) {
return connection.getProtocolInfo().getProtocolVersion();
}
if (isProtocolSupport()) {
Player player = Bukkit.getPlayer(uuid);
if (player != null && isProtocolSupport()) {
if (player != null) {
return ProtocolSupportUtil.getProtocolVersion(player);
}
return -1;
}
return connection.getProtocolInfo().getProtocolVersion();
return -1;
}
@Override
@@ -58,16 +61,6 @@ public class BukkitViaAPI extends ViaAPIBase<Player> {
sendRawPacket(player.getUniqueId(), packet);
}
/**
* Returns if this version is a compatibility build for spigot.
* Eg. 1.9.1 / 1.9.2 allow certain versions to connect
*
* @return true if compat Spigot build
*/
public boolean isCompatSpigotBuild() {
return plugin.isCompatSpigotBuild();
}
/**
* Returns if ProtocolSupport is also being used.
*
@@ -76,5 +69,4 @@ public class BukkitViaAPI extends ViaAPIBase<Player> {
public boolean isProtocolSupport() {
return plugin.isProtocolSupport();
}
}
@@ -35,7 +35,6 @@ import java.lang.reflect.Method;
import java.util.List;
public class BukkitViaInjector extends LegacyViaInjector {
private boolean protocolLib;
@Override
public void inject() throws ReflectiveOperationException {
@@ -112,11 +111,6 @@ public class BukkitViaInjector extends LegacyViaInjector {
throw new RuntimeException("Failed to get server");
}
@Override
public String getDecoderName() {
return protocolLib ? "protocol_lib_decoder" : "decoder";
}
@Override
protected @Nullable Object getServerConnection() throws ReflectiveOperationException {
Class<?> serverClass = NMSUtil.nms(
@@ -189,8 +183,4 @@ public class BukkitViaInjector extends LegacyViaInjector {
}
return false;
}
public void setProtocolLib(boolean protocolLib) {
this.protocolLib = protocolLib;
}
}
@@ -23,7 +23,7 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.platform.ViaPlatformLoader;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.bukkit.classgenerator.ClassGenerator;
import com.viaversion.viaversion.bukkit.compat.ProtocolSupportCompat;
import com.viaversion.viaversion.bukkit.listeners.JoinListener;
import com.viaversion.viaversion.bukkit.listeners.UpdateListener;
import com.viaversion.viaversion.bukkit.listeners.multiversion.PlayerSneakListener;
@@ -88,7 +88,10 @@ public class BukkitViaLoader implements ViaPlatformLoader {
final ViaVersionPlugin plugin = (ViaVersionPlugin) Bukkit.getPluginManager().getPlugin("ViaVersion");
// Add ProtocolSupport ConnectListener if necessary.
ClassGenerator.registerPSConnectListener(plugin);
if (plugin.isProtocolSupport() && ProtocolSupportCompat.isMultiplatformPS()) {
ProtocolSupportCompat.registerPSConnectListener(plugin);
}
int serverProtocolVersion = Via.getAPI().getServerVersion().lowestSupportedVersion();
/* 1.9 client to 1.8 server */
@@ -69,7 +69,7 @@ public final class PaperViaInjector {
}
private static boolean hasPacketLimiter() {
return hasClass("com.destroystokyo.paper.PaperConfig$PacketLimit") || hasClass("io.papermc.paper.PaperConfig$PacketLimit");
return hasClass("com.destroystokyo.paper.PaperConfig$PacketLimit") || hasClass("io.papermc.paper.configuration.GlobalConfiguration$PacketLimiter");
}
private static boolean hasClass(final String className) {
@@ -19,7 +19,7 @@ package com.viaversion.viaversion.bukkit.util;
import org.bukkit.Bukkit;
public class NMSUtil {
public final class NMSUtil {
private static final String BASE = Bukkit.getServer().getClass().getPackage().getName();
private static final String NMS = BASE.replace("org.bukkit.craftbukkit", "net.minecraft.server");
private static final boolean DEBUG_PROPERTY = loadDebugProperty();
@@ -53,10 +53,6 @@ public class NMSUtil {
return Class.forName(BASE + "." + className);
}
public static String getVersion() {
return BASE.substring(BASE.lastIndexOf('.') + 1);
}
/**
* @return true if debug=true is set in the server.properties (added by CB)
*/
@@ -22,27 +22,31 @@ import org.bukkit.entity.Player;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ProtocolSupportUtil {
private static Method protocolVersionMethod = null;
private static Method getIdMethod = null;
public final class ProtocolSupportUtil {
private static final Method PROTOCOL_VERSION_METHOD;
private static final Method GET_ID_METHOD;
static {
Method protocolVersionMethod = null;
Method getIdMethod = null;
try {
protocolVersionMethod = Class.forName("protocolsupport.api.ProtocolSupportAPI").getMethod("getProtocolVersion", Player.class);
getIdMethod = Class.forName("protocolsupport.api.ProtocolVersion").getMethod("getId");
} catch (Exception e) {
} catch (ReflectiveOperationException e) {
// ProtocolSupport not installed.
}
PROTOCOL_VERSION_METHOD = protocolVersionMethod;
GET_ID_METHOD = getIdMethod;
}
public static int getProtocolVersion(Player player) {
if (protocolVersionMethod == null) return -1;
if (PROTOCOL_VERSION_METHOD == null) {
return -1;
}
try {
Object version = protocolVersionMethod.invoke(null, player);
return (int) getIdMethod.invoke(version);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
Object version = PROTOCOL_VERSION_METHOD.invoke(null, player);
return (int) GET_ID_METHOD.invoke(version);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return -1;
@@ -1,28 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.classgenerator.generated;
import com.viaversion.viaversion.api.connection.UserConnection;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
public interface HandlerConstructor {
public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder);
public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder);
}
@@ -20,17 +20,25 @@ package com.viaversion.viaversion.classgenerator.generated;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.bukkit.handlers.BukkitDecodeHandler;
import com.viaversion.viaversion.bukkit.handlers.BukkitEncodeHandler;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.MessageToMessageEncoder;
public class BasicHandlerConstructor implements HandlerConstructor {
@Override
public BukkitEncodeHandler newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
return new BukkitEncodeHandler(info, minecraftEncoder);
}
public interface HandlerSupplier {
@Override
public BukkitDecodeHandler newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
return new BukkitDecodeHandler(info, minecraftDecoder);
MessageToMessageEncoder<ByteBuf> newEncodeHandler(UserConnection connection);
MessageToMessageDecoder<ByteBuf> newDecodeHandler(UserConnection connection);
final class DefaultHandlerSupplier implements HandlerSupplier {
@Override
public MessageToMessageEncoder<ByteBuf> newEncodeHandler(final UserConnection connection) {
return new BukkitEncodeHandler(connection);
}
@Override
public MessageToMessageDecoder<ByteBuf> newDecodeHandler(final UserConnection connection) {
return new BukkitDecodeHandler(connection);
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
dependencies {
implementation(projects.viaversionCommon)
implementation(projects.javaCompat)
implementation(projects.compat)
compileOnly(libs.bungee)
}
@@ -235,16 +235,6 @@ public abstract class LegacyViaInjector implements ViaInjector {
return data;
}
@Override
public String getEncoderName() {
return "encoder";
}
@Override
public String getDecoderName() {
return "decoder";
}
/**
* Returns the Vanilla server connection object the channels to be injected should be searched in.
*
@@ -68,6 +68,7 @@ import com.viaversion.viaversion.protocols.protocol1_18_2to1_18.Protocol1_18_2To
import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.Protocol1_18To1_17_1;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.Protocol1_19_1To1_19;
import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.Protocol1_19To1_18_2;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.Protocol1_19_3To1_19_1;
import com.viaversion.viaversion.protocols.protocol1_9_1_2to1_9_3_4.Protocol1_9_1_2To1_9_3_4;
import com.viaversion.viaversion.protocols.protocol1_9_1to1_9.Protocol1_9_1To1_9;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.Protocol1_9_3To1_9_1_2;
@@ -176,6 +177,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
registerProtocol(new Protocol1_19To1_18_2(), ProtocolVersion.v1_19, ProtocolVersion.v1_18_2);
registerProtocol(new Protocol1_19_1To1_19(), ProtocolVersion.v1_19_1, ProtocolVersion.v1_19);
registerProtocol(new Protocol1_19_3To1_19_1(), ProtocolVersion.v1_19_3, ProtocolVersion.v1_19_1);
}
@Override
@@ -25,12 +25,15 @@ import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection;
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.entities.Entity1_12Types;
import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_12;
@@ -38,6 +41,8 @@ import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.metadata.MetadataRewriter1_12To1_11_1;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.packets.InventoryPackets;
import com.viaversion.viaversion.protocols.protocol1_12to1_11_1.providers.InventoryQuickMoveProvider;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
import com.viaversion.viaversion.protocols.protocol1_9_1_2to1_9_3_4.types.Chunk1_9_3_4Type;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ClientboundPackets1_9_3;
import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.ServerboundPackets1_9_3;
@@ -125,33 +130,28 @@ public class Protocol1_12To1_11_1 extends AbstractProtocol<ClientboundPackets1_9
Chunk1_9_3_4Type type = new Chunk1_9_3_4Type(clientWorld);
Chunk chunk = wrapper.passthrough(type);
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection section = chunk.getSections()[i];
if (section == null)
continue;
for (int s = 0; s < chunk.getSections().length; s++) {
ChunkSection section = chunk.getSections()[s];
if (section == null) continue;
DataPalette blocks = section.palette(PaletteType.BLOCKS);
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int block = section.getBlockWithoutData(x, y, z);
// Is this a bed?
if (block == 26) {
// NBT -> { color:14, x:132, y:64, z:222, id:"minecraft:bed" } (Debug output)
CompoundTag tag = new CompoundTag();
tag.put("color", new IntTag(14)); // Set color to red (Default in previous versions)
tag.put("x", new IntTag(x + (chunk.getX() << 4)));
tag.put("y", new IntTag(y + (i << 4)));
tag.put("z", new IntTag(z + (chunk.getZ() << 4)));
tag.put("id", new StringTag("minecraft:bed"));
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
int id = blocks.idAt(idx) >> 4;
// Is this a bed?
if (id != 26) continue;
// Add a fake block entity
chunk.getBlockEntities().add(tag);
}
}
}
// NBT -> { color:14, x:132, y:64, z:222, id:"minecraft:bed" } (Debug output)
CompoundTag tag = new CompoundTag();
tag.put("color", new IntTag(14)); // Set color to red (Default in previous versions)
tag.put("x", new IntTag(ChunkSection.xFromIndex(idx) + (chunk.getX() << 4)));
tag.put("y", new IntTag(ChunkSection.yFromIndex(idx) + (s << 4)));
tag.put("z", new IntTag(ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4)));
tag.put("id", new StringTag("minecraft:bed"));
// Add a fake block entity
chunk.getBlockEntities().add(tag);
}
}
}
});
}
@@ -167,9 +167,16 @@ public class Protocol1_12To1_11_1 extends AbstractProtocol<ClientboundPackets1_9
map(Type.UNSIGNED_BYTE);
map(Type.INT);
handler(wrapper -> {
ClientWorld clientChunks = wrapper.user().get(ClientWorld.class);
UserConnection user = wrapper.user();
ClientWorld clientChunks = user.get(ClientWorld.class);
int dimensionId = wrapper.get(Type.INT, 1);
clientChunks.setEnvironment(dimensionId);
// Reset recipes
if (user.getProtocolInfo().getProtocolVersion() >= ProtocolVersion.v1_13.getVersion()) {
wrapper.create(ClientboundPackets1_13.DECLARE_RECIPES, packetWrapper -> packetWrapper.write(Type.VAR_INT, 0))
.scheduleSend(Protocol1_13To1_12_2.class);
}
});
}
});
@@ -28,6 +28,8 @@ import com.viaversion.viaversion.api.minecraft.BlockFace;
import com.viaversion.viaversion.api.minecraft.Position;
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.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.ClientboundPackets1_13;
@@ -75,31 +77,25 @@ public class ConnectionData {
}
public static void updateChunkSectionNeighbours(UserConnection user, int chunkX, int chunkZ, int chunkSectionY) {
int chunkMinY = chunkSectionY << 4;
List<BlockChangeRecord1_8> updates = new ArrayList<>();
for (int chunkDeltaX = -1; chunkDeltaX <= 1; chunkDeltaX++) {
for (int chunkDeltaZ = -1; chunkDeltaZ <= 1; chunkDeltaZ++) {
if (Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ) == 0) continue;
int distance = Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ);
if (distance == 0) continue;
List<BlockChangeRecord1_8> updates = new ArrayList<>();
if (Math.abs(chunkDeltaX) + Math.abs(chunkDeltaZ) == 2) { // Corner
for (int blockY = chunkSectionY * 16; blockY < chunkSectionY * 16 + 16; blockY++) {
int chunkMinX = (chunkX + chunkDeltaX) << 4;
int chunkMinZ = (chunkZ + chunkDeltaZ) << 4;
if (distance == 2) { // Corner
for (int blockY = chunkMinY; blockY < chunkMinY + 16; blockY++) {
int blockPosX = chunkDeltaX == 1 ? 0 : 15;
int blockPosZ = chunkDeltaZ == 1 ? 0 : 15;
updateBlock(user,
new Position(
((chunkX + chunkDeltaX) << 4) + blockPosX,
(short) blockY,
((chunkZ + chunkDeltaZ) << 4) + blockPosZ
),
updates
);
updateBlock(user, new Position(chunkMinX + blockPosX, blockY, chunkMinZ + blockPosZ), updates);
}
} else {
for (int blockY = chunkSectionY * 16; blockY < chunkSectionY * 16 + 16; blockY++) {
int xStart;
int xEnd;
int zStart;
int zEnd;
for (int blockY = chunkMinY; blockY < chunkMinY + 16; blockY++) {
int xStart, xEnd;
int zStart, zEnd;
if (chunkDeltaX == 1) {
xStart = 0;
xEnd = 2;
@@ -123,13 +119,7 @@ public class ConnectionData {
}
for (int blockX = xStart; blockX < xEnd; blockX++) {
for (int blockZ = zStart; blockZ < zEnd; blockZ++) {
updateBlock(user,
new Position(
((chunkX + chunkDeltaX) << 4) + blockX,
(short) blockY,
((chunkZ + chunkDeltaZ) << 4) + blockZ),
updates
);
updateBlock(user, new Position(chunkMinX + blockX, blockY, chunkMinZ + blockZ), updates);
}
}
}
@@ -145,6 +135,7 @@ public class ConnectionData {
} catch (Exception e) {
e.printStackTrace();
}
updates.clear();
}
}
}
@@ -178,17 +169,17 @@ public class ConnectionData {
}
public static void connectBlocks(UserConnection user, Chunk chunk) {
long xOff = chunk.getX() << 4;
long zOff = chunk.getZ() << 4;
int xOff = chunk.getX() << 4;
int zOff = chunk.getZ() << 4;
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection section = chunk.getSections()[i];
for (int s = 0; s < chunk.getSections().length; s++) {
ChunkSection section = chunk.getSections()[s];
if (section == null) continue;
DataPalette blocks = section.palette(PaletteType.BLOCKS);
boolean willConnect = false;
for (int p = 0; p < section.getPaletteSize(); p++) {
int id = section.getPaletteEntry(p);
for (int p = 0; p < blocks.size(); p++) {
int id = blocks.idByIndex(p);
if (ConnectionData.connects(id)) {
willConnect = true;
break;
@@ -196,24 +187,14 @@ public class ConnectionData {
}
if (!willConnect) continue;
long yOff = i << 4;
int yOff = s << 4;
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int block = section.getFlatBlock(x, y, z);
ConnectionHandler handler = ConnectionData.getConnectionHandler(block);
if (handler != null) {
block = handler.connect(user, new Position(
(int) (xOff + x),
(short) (yOff + y),
(int) (zOff + z)
), block);
section.setFlatBlock(x, y, z, block);
}
}
}
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
int id = blocks.idAt(idx);
ConnectionHandler handler = ConnectionData.getConnectionHandler(id);
if (handler == null) continue;
id = handler.connect(user, new Position(xOff + ChunkSection.xFromIndex(idx), yOff + ChunkSection.yFromIndex(idx), zOff + ChunkSection.zFromIndex(idx)), id);
blocks.setIdAt(idx, id);
}
}
}
@@ -17,6 +17,7 @@
*/
package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.packets;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.minecraft.entities.Entity1_13Types;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
@@ -146,6 +147,25 @@ public class EntityPackets {
}
});
protocol.registerClientbound(ClientboundPackets1_12_1.ENTITY_EFFECT, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // Entity id
map(Type.BYTE); // Effect id
map(Type.BYTE); // Amplifier
map(Type.VAR_INT); // Duration
handler(packetWrapper -> {
byte flags = packetWrapper.read(Type.BYTE); // Input Flags
if (Via.getConfig().isNewEffectIndicator())
flags |= 0x04;
packetWrapper.write(Type.BYTE, flags);
});
}
});
metadataRewriter.registerRemoveEntities(ClientboundPackets1_12_1.DESTROY_ENTITIES);
metadataRewriter.registerMetadataRewriter(ClientboundPackets1_12_1.ENTITY_METADATA, Types1_12.METADATA_LIST, Types1_13.METADATA_LIST);
}
@@ -309,8 +309,12 @@ public class InventoryPackets extends ItemRewriter<Protocol1_13To1_12_2> {
if (blockEntityTag.get("Patterns") instanceof ListTag) {
for (Tag pattern : (ListTag) blockEntityTag.get("Patterns")) {
if (pattern instanceof CompoundTag) {
IntTag c = ((CompoundTag) pattern).get("Color");
c.setValue(15 - c.asInt()); // Invert color id
Tag c = ((CompoundTag) pattern).get("Color");
if (c instanceof NumberTag) {
// Invert color id
((CompoundTag) pattern).put("Color",
new IntTag(15 - ((NumberTag) c).asInt()));
}
}
}
}
@@ -27,6 +27,8 @@ import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.Position;
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.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
@@ -334,77 +336,62 @@ public class WorldPackets {
Chunk chunk = wrapper.read(type);
wrapper.write(type1_13, chunk);
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection section = chunk.getSections()[i];
if (section == null)
continue;
for (int s = 0; s < chunk.getSections().length; s++) {
ChunkSection section = chunk.getSections()[s];
if (section == null) continue;
DataPalette blocks = section.palette(PaletteType.BLOCKS);
for (int p = 0; p < section.getPaletteSize(); p++) {
int old = section.getPaletteEntry(p);
for (int p = 0; p < blocks.size(); p++) {
int old = blocks.idByIndex(p);
int newId = toNewId(old);
section.setPaletteEntry(p, newId);
blocks.setIdByIndex(p, newId);
}
storage:
{
if (chunk.isFullChunk()) {
boolean willSave = false;
for (int j = 0; j < section.getPaletteSize(); j++) {
if (storage.isWelcome(section.getPaletteEntry(j))) {
for (int p = 0; p < blocks.size(); p++) {
if (storage.isWelcome(blocks.idByIndex(p))) {
willSave = true;
break;
}
}
if (!willSave) break storage;
}
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int block = section.getFlatBlock(x, y, z);
Position pos = new Position(
(x + (chunk.getX() << 4)),
(y + (i << 4)),
(z + (chunk.getZ() << 4))
);
if (storage.isWelcome(block)) {
storage.store(pos, block);
} else if (!chunk.isFullChunk()) { // Update
storage.remove(pos);
}
}
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
int id = blocks.idAt(idx);
if (storage.isWelcome(id)) {
storage.store(new Position(ChunkSection.xFromIndex(idx) + (chunk.getX() << 4), ChunkSection.yFromIndex(idx) + (s << 4), ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4)), id);
} else if (!chunk.isFullChunk()) { // Update
storage.remove(new Position(ChunkSection.xFromIndex(idx) + (chunk.getX() << 4), ChunkSection.yFromIndex(idx) + (s << 4), ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4)));
}
}
}
save_connections:
{
if (!Via.getConfig().isServersideBlockConnections()
|| !ConnectionData.needStoreBlocks()) break save_connections;
if (!Via.getConfig().isServersideBlockConnections() || !ConnectionData.needStoreBlocks()) break save_connections;
if (!chunk.isFullChunk()) { // Update
ConnectionData.blockConnectionProvider.unloadChunkSection(wrapper.user(), chunk.getX(), i, chunk.getZ());
ConnectionData.blockConnectionProvider.unloadChunkSection(wrapper.user(), chunk.getX(), s, chunk.getZ());
}
boolean willSave = false;
for (int j = 0; j < section.getPaletteSize(); j++) {
if (ConnectionData.isWelcome(section.getPaletteEntry(j))) {
for (int p = 0; p < blocks.size(); p++) {
if (ConnectionData.isWelcome(blocks.idByIndex(p))) {
willSave = true;
break;
}
}
if (!willSave) break save_connections;
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int block = section.getFlatBlock(x, y, z);
if (ConnectionData.isWelcome(block)) {
int globalX = x + (chunk.getX() << 4);
int globalY = y + (i << 4);
int globalZ = z + (chunk.getZ() << 4);
ConnectionData.blockConnectionProvider.storeBlock(wrapper.user(), globalX,
globalY, globalZ, block);
}
}
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
int id = blocks.idAt(idx);
if (ConnectionData.isWelcome(id)) {
int globalX = ChunkSection.xFromIndex(idx) + (chunk.getX() << 4);
int globalY = ChunkSection.yFromIndex(idx) + (s << 4);
int globalZ = ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4);
ConnectionData.blockConnectionProvider.storeBlock(wrapper.user(), globalX, globalY, globalZ, id);
}
}
}
@@ -51,8 +51,8 @@ public class BannerHandler implements BlockEntityProvider.BlockEntityHandler {
Tag base = tag.get("Base");
int color = 0;
if (base != null) {
color = ((NumberTag) tag.get("Base")).asInt();
if (base instanceof NumberTag) {
color = ((NumberTag) base).asInt();
}
// Standing banner
if (blockId >= BANNER_START && blockId <= BANNER_STOP) {
@@ -64,8 +64,9 @@ public class BannerHandler implements BlockEntityProvider.BlockEntityHandler {
Via.getPlatform().getLogger().warning("Why does this block have the banner block entity? :(" + tag);
}
if (tag.get("Patterns") instanceof ListTag) {
for (Tag pattern : (ListTag) tag.get("Patterns")) {
Tag patterns = tag.get("Patterns");
if (patterns instanceof ListTag) {
for (Tag pattern : (ListTag) patterns) {
if (pattern instanceof CompoundTag) {
Tag c = ((CompoundTag) pattern).get("Color");
if (c instanceof IntTag) {
@@ -42,7 +42,7 @@ public class BedHandler implements BlockEntityProvider.BlockEntityHandler {
int blockId = storage.get(position).getOriginal() - 972 + 748;
Tag color = tag.get("color");
if (color != null) {
if (color instanceof NumberTag) {
blockId += (((NumberTag) color).asInt() * 16);
}
@@ -43,11 +43,12 @@ public class SkullHandler implements BlockEntityProvider.BlockEntityHandler {
int id = storage.get(position).getOriginal();
if (id >= SKULL_WALL_START && id <= SKULL_END) {
Tag skullType = tag.get("SkullType");
if (skullType != null) {
id += ((NumberTag) tag.get("SkullType")).asInt() * 20;
if (skullType instanceof NumberTag) {
id += ((NumberTag) skullType).asInt() * 20;
}
if (tag.contains("Rot")) {
id += ((NumberTag) tag.get("Rot")).asInt();
Tag rot = tag.get("Rot");
if (rot instanceof NumberTag) {
id += ((NumberTag) rot).asInt();
}
} else {
Via.getPlatform().getLogger().warning("Why does this block have the skull block entity? " + tag);
@@ -19,6 +19,7 @@ package com.viaversion.viaversion.protocols.protocol1_13to1_12_2.providers.block
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.data.EntityNameRewriter;
import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.providers.BlockEntityProvider;
@@ -26,11 +27,11 @@ import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.providers.BlockE
public class SpawnerHandler implements BlockEntityProvider.BlockEntityHandler {
@Override
public int transform(UserConnection user, CompoundTag tag) {
if (tag.contains("SpawnData") && tag.get("SpawnData") instanceof CompoundTag) {
CompoundTag data = tag.get("SpawnData");
if (data.contains("id") && data.get("id") instanceof StringTag) {
StringTag s = data.get("id");
s.setValue(EntityNameRewriter.rewrite(s.getValue()));
Tag data = tag.get("SpawnData");
if (data instanceof CompoundTag) {
Tag id = ((CompoundTag) data).get("id");
if (id instanceof StringTag) {
((StringTag) id).setValue(EntityNameRewriter.rewrite(((StringTag) id).getValue()));
}
}
@@ -24,7 +24,9 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.BlockFace;
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.NibbleArray;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
@@ -154,15 +156,16 @@ public class WorldPackets {
for (int s = 0; s < chunk.getSections().length; s++) {
ChunkSection section = chunk.getSections()[s];
if (section == null) continue;
DataPalette blocks = section.palette(PaletteType.BLOCKS);
boolean hasBlock = false;
for (int i = 0; i < section.getPaletteSize(); i++) {
int old = section.getPaletteEntry(i);
for (int i = 0; i < blocks.size(); i++) {
int old = blocks.idByIndex(i);
int newId = protocol.getMappingData().getNewBlockStateId(old);
if (!hasBlock && newId != air && newId != voidAir && newId != caveAir) { // air, void_air, cave_air
hasBlock = true;
}
section.setPaletteEntry(i, newId);
blocks.setIdByIndex(i, newId);
}
if (!hasBlock) {
section.setNonAirBlocksCount(0);
@@ -170,23 +173,25 @@ public class WorldPackets {
}
int nonAirBlockCount = 0;
for (int x = 0; x < 16; x++) {
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
int id = section.getFlatBlock(x, y, z);
if (id != air && id != voidAir && id != caveAir) {
nonAirBlockCount++;
worldSurface[x + z * 16] = y + s * 16 + 1; // +1 (top of the block)
}
if (protocol.getMappingData().getMotionBlocking().contains(id)) {
motionBlocking[x + z * 16] = y + s * 16 + 1; // +1 (top of the block)
}
int sy = s << 4;
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
int id = blocks.idAt(idx);
if (id == air || id == voidAir || id == caveAir) continue;
nonAirBlockCount++;
// Manually update light for non full blocks (block light must not be sent)
if (Via.getConfig().isNonFullBlockLightFix() && protocol.getMappingData().getNonFullBlocks().contains(id)) {
setNonFullLight(chunk, section, s, x, y, z);
}
}
int xz = idx & 0xFF;
int y = ChunkSection.yFromIndex(idx);
worldSurface[xz] = sy + y + 1; // +1 (top of the block)
if (protocol.getMappingData().getMotionBlocking().contains(id)) {
motionBlocking[xz] = sy + y + 1; // +1 (top of the block)
}
// Manually update light for non-full blocks (block light must not be sent)
if (Via.getConfig().isNonFullBlockLightFix() && protocol.getMappingData().getNonFullBlocks().contains(id)) {
int x = ChunkSection.xFromIndex(idx);
int z = ChunkSection.zFromIndex(idx);
setNonFullLight(chunk, section, s, x, y, z);
}
}
@@ -377,7 +382,7 @@ public class WorldPackets {
neighbourY = 15;
}
if (ySection == 16 || ySection == -1) continue;
if (ySection == chunk.getSections().length || ySection == -1) continue;
ChunkSection newSection = chunk.getSections()[ySection];
if (newSection == null) continue;
@@ -34,7 +34,7 @@ public class InventoryPackets extends ItemRewriter<Protocol1_15To1_14_4> {
public void registerPackets() {
registerSetCooldown(ClientboundPackets1_14.COOLDOWN);
registerWindowItems(ClientboundPackets1_14.WINDOW_ITEMS, Type.FLAT_VAR_INT_ITEM_ARRAY);
registerTradeList(ClientboundPackets1_14.TRADE_LIST, Type.FLAT_VAR_INT_ITEM);
registerTradeList(ClientboundPackets1_14.TRADE_LIST);
registerSetSlot(ClientboundPackets1_14.SET_SLOT, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipment(ClientboundPackets1_14.ENTITY_EQUIPMENT, Type.FLAT_VAR_INT_ITEM);
registerAdvancements(ClientboundPackets1_14.ADVANCEMENTS, Type.FLAT_VAR_INT_ITEM);
@@ -35,9 +35,9 @@ public class InventoryPackets extends ItemRewriter<Protocol1_16_2To1_16_1> {
public void registerPackets() {
registerSetCooldown(ClientboundPackets1_16.COOLDOWN);
registerWindowItems(ClientboundPackets1_16.WINDOW_ITEMS, Type.FLAT_VAR_INT_ITEM_ARRAY);
registerTradeList(ClientboundPackets1_16.TRADE_LIST, Type.FLAT_VAR_INT_ITEM);
registerTradeList(ClientboundPackets1_16.TRADE_LIST);
registerSetSlot(ClientboundPackets1_16.SET_SLOT, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_16.ENTITY_EQUIPMENT, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_16.ENTITY_EQUIPMENT);
registerAdvancements(ClientboundPackets1_16.ADVANCEMENTS, Type.FLAT_VAR_INT_ITEM);
protocol.registerClientbound(ClientboundPackets1_16.UNLOCK_RECIPES, new PacketRemapper() {
@@ -60,6 +60,7 @@ public class Protocol1_16To1_15_2 extends AbstractProtocol<ClientboundPackets1_1
public static final MappingData MAPPINGS = new MappingData();
private final EntityRewriter metadataRewriter = new MetadataRewriter1_16To1_15_2(this);
private final ItemRewriter itemRewriter = new InventoryPackets(this);
private final ComponentRewriter componentRewriter = new TranslationMappings(this);
private TagRewriter tagRewriter;
public Protocol1_16To1_15_2() {
@@ -131,7 +132,6 @@ public class Protocol1_16To1_15_2 extends AbstractProtocol<ClientboundPackets1_1
}
});
ComponentRewriter componentRewriter = new TranslationMappings(this);
// Handle (relevant) component cases for translatable and score changes
registerClientbound(ClientboundPackets1_15.CHAT_MESSAGE, new PacketRemapper() {
@Override
@@ -301,4 +301,8 @@ public class Protocol1_16To1_15_2 extends AbstractProtocol<ClientboundPackets1_1
public ItemRewriter getItemRewriter() {
return itemRewriter;
}
public ComponentRewriter getComponentRewriter() {
return componentRewriter;
}
}
@@ -109,7 +109,7 @@ public class InventoryPackets extends ItemRewriter<Protocol1_16To1_15_2> {
registerSetCooldown(ClientboundPackets1_15.COOLDOWN);
registerWindowItems(ClientboundPackets1_15.WINDOW_ITEMS, Type.FLAT_VAR_INT_ITEM_ARRAY);
registerTradeList(ClientboundPackets1_15.TRADE_LIST, Type.FLAT_VAR_INT_ITEM);
registerTradeList(ClientboundPackets1_15.TRADE_LIST);
registerSetSlot(ClientboundPackets1_15.SET_SLOT, Type.FLAT_VAR_INT_ITEM);
registerAdvancements(ClientboundPackets1_15.ADVANCEMENTS, Type.FLAT_VAR_INT_ITEM);
@@ -155,8 +155,9 @@ public class InventoryPackets extends ItemRewriter<Protocol1_16To1_15_2> {
public Item handleItemToClient(Item item) {
if (item == null) return null;
if (item.identifier() == 771 && item.tag() != null) {
CompoundTag tag = item.tag();
CompoundTag tag = item.tag();
if (item.identifier() == 771 && tag != null) {
Tag ownerTag = tag.get("SkullOwner");
if (ownerTag instanceof CompoundTag) {
CompoundTag ownerCompundTag = (CompoundTag) ownerTag;
@@ -166,6 +167,17 @@ public class InventoryPackets extends ItemRewriter<Protocol1_16To1_15_2> {
ownerCompundTag.put("Id", new IntArrayTag(UUIDIntArrayType.uuidToIntArray(id)));
}
}
} else if (item.identifier() == 759 && tag != null) {
Tag pages = tag.get("pages");
if (pages instanceof ListTag) {
for (Tag pageTag : (ListTag) pages) {
if (!(pageTag instanceof StringTag)) {
continue;
}
StringTag page = (StringTag) pageTag;
page.setValue(protocol.getComponentRewriter().processText(page.getValue()).toString());
}
}
}
oldToNewAttributes(item);
@@ -22,6 +22,7 @@ import com.github.steveice10.opennbt.tag.builtin.IntArrayTag;
import com.github.steveice10.opennbt.tag.builtin.LongArrayTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
@@ -85,7 +86,7 @@ public class WorldPackets {
if (chunk.getBlockEntities() == null) return;
for (CompoundTag blockEntity : chunk.getBlockEntities()) {
handleBlockEntity(blockEntity);
handleBlockEntity(protocol, blockEntity);
}
});
}
@@ -98,7 +99,7 @@ public class WorldPackets {
Position position = wrapper.passthrough(Type.POSITION1_14);
short action = wrapper.passthrough(Type.UNSIGNED_BYTE);
CompoundTag tag = wrapper.passthrough(Type.NBT);
handleBlockEntity(tag);
handleBlockEntity(protocol, tag);
});
}
});
@@ -106,7 +107,7 @@ public class WorldPackets {
blockRewriter.registerEffect(ClientboundPackets1_15.EFFECT, 1010, 2001);
}
private static void handleBlockEntity(CompoundTag compoundTag) {
private static void handleBlockEntity(Protocol1_16To1_15_2 protocol, CompoundTag compoundTag) {
StringTag idTag = compoundTag.get("id");
if (idTag == null) return;
@@ -132,6 +133,25 @@ public class WorldPackets {
skullOwnerTag.put(entry.getKey(), entry.getValue());
}
compoundTag.put("SkullOwner", skullOwnerTag);
} else if (id.equals("minecraft:sign")) {
for (int i = 1; i <= 4; i++) {
Tag line = compoundTag.get("Text" + i);
if (line instanceof StringTag) {
JsonElement text = protocol.getComponentRewriter().processText(((StringTag) line).getValue());
compoundTag.put("Text" + i, new StringTag(text.toString()));
}
}
} else if (id.equals("minecraft:mob_spawner")) {
Tag spawnDataTag = compoundTag.get("SpawnData");
if (spawnDataTag instanceof CompoundTag) {
Tag spawnDataIdTag = ((CompoundTag) spawnDataTag).get("id");
if (spawnDataIdTag instanceof StringTag) {
StringTag spawnDataIdStringTag = ((StringTag) spawnDataIdTag);
if (spawnDataIdStringTag.getValue().equals("minecraft:zombie_pigman")) {
spawnDataIdStringTag.setValue("minecraft:zombified_piglin");
}
}
}
}
}
}
@@ -40,10 +40,10 @@ public final class InventoryPackets extends ItemRewriter<Protocol1_17To1_16_4> {
public void registerPackets() {
registerSetCooldown(ClientboundPackets1_16_2.COOLDOWN);
registerWindowItems(ClientboundPackets1_16_2.WINDOW_ITEMS, Type.FLAT_VAR_INT_ITEM_ARRAY);
registerTradeList(ClientboundPackets1_16_2.TRADE_LIST, Type.FLAT_VAR_INT_ITEM);
registerTradeList(ClientboundPackets1_16_2.TRADE_LIST);
registerSetSlot(ClientboundPackets1_16_2.SET_SLOT, Type.FLAT_VAR_INT_ITEM);
registerAdvancements(ClientboundPackets1_16_2.ADVANCEMENTS, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_16_2.ENTITY_EQUIPMENT, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_16_2.ENTITY_EQUIPMENT);
registerSpawnParticle(ClientboundPackets1_16_2.SPAWN_PARTICLE, Type.FLAT_VAR_INT_ITEM, Type.DOUBLE);
new RecipeRewriter1_16(protocol).registerDefaultHandler(ClientboundPackets1_16_2.DECLARE_RECIPES);
@@ -35,11 +35,11 @@ public final class InventoryPackets extends ItemRewriter<Protocol1_18To1_17_1> {
@Override
public void registerPackets() {
registerSetCooldown(ClientboundPackets1_17_1.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_17_1.WINDOW_ITEMS, Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT, Type.FLAT_VAR_INT_ITEM);
registerTradeList(ClientboundPackets1_17_1.TRADE_LIST, Type.FLAT_VAR_INT_ITEM);
registerSetSlot1_17_1(ClientboundPackets1_17_1.SET_SLOT, Type.FLAT_VAR_INT_ITEM);
registerWindowItems1_17_1(ClientboundPackets1_17_1.WINDOW_ITEMS);
registerTradeList(ClientboundPackets1_17_1.TRADE_LIST);
registerSetSlot1_17_1(ClientboundPackets1_17_1.SET_SLOT);
registerAdvancements(ClientboundPackets1_17_1.ADVANCEMENTS, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_17_1.ENTITY_EQUIPMENT, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_17_1.ENTITY_EQUIPMENT);
protocol.registerClientbound(ClientboundPackets1_17_1.EFFECT, new PacketRemapper() {
@Override
@@ -99,7 +99,7 @@ public final class InventoryPackets extends ItemRewriter<Protocol1_18To1_17_1> {
new RecipeRewriter1_16(protocol).registerDefaultHandler(ClientboundPackets1_17_1.DECLARE_RECIPES);
registerClickWindow1_17_1(ServerboundPackets1_17.CLICK_WINDOW, Type.FLAT_VAR_INT_ITEM);
registerClickWindow1_17_1(ServerboundPackets1_17.CLICK_WINDOW);
registerCreativeInvAction(ServerboundPackets1_17.CREATIVE_INVENTORY_ACTION, Type.FLAT_VAR_INT_ITEM);
}
}
@@ -20,6 +20,7 @@ package com.viaversion.viaversion.protocols.protocol1_18to1_17_1.packets;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.NumberTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity;
@@ -212,8 +213,8 @@ public final class WorldPackets {
private static void handleSpawners(int typeId, final CompoundTag tag) {
if (typeId == 8) {
final CompoundTag entity = tag.get("SpawnData");
if (entity != null) {
final Tag entity = tag.get("SpawnData");
if (entity instanceof CompoundTag) {
final CompoundTag spawnData = new CompoundTag();
tag.put("SpawnData", spawnData);
spawnData.put("entity", entity);
@@ -0,0 +1,141 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
public enum ClientboundPackets1_19_3 implements ClientboundPacketType {
SPAWN_ENTITY, // 0x00
SPAWN_EXPERIENCE_ORB, // 0x01
SPAWN_PLAYER, // 0x02
ENTITY_ANIMATION, // 0x03
STATISTICS, // 0x04
BLOCK_CHANGED_ACK, // 0x05
BLOCK_BREAK_ANIMATION, // 0x06
BLOCK_ENTITY_DATA, // 0x07
BLOCK_ACTION, // 0x08
BLOCK_CHANGE, // 0x09
BOSSBAR, // 0x0A
SERVER_DIFFICULTY, // 0x0B
CLEAR_TITLES, // 0x0C
TAB_COMPLETE, // 0x0D
DECLARE_COMMANDS, // 0x0E
CLOSE_WINDOW, // 0x0F
WINDOW_ITEMS, // 0x10
WINDOW_PROPERTY, // 0x11
SET_SLOT, // 0x12
COOLDOWN, // 0x13
CUSTOM_CHAT_COMPLETIONS, // 0x14
PLUGIN_MESSAGE, // 0x15
DELETE_CHAT_MESSAGE, // 0x16
DISCONNECT, // 0x17
DISGUISED_CHAT, // 0x18
ENTITY_STATUS, // 0x19
EXPLOSION, // 0x1A
UNLOAD_CHUNK, // 0x1B
GAME_EVENT, // 0x1C
OPEN_HORSE_WINDOW, // 0x1D
WORLD_BORDER_INIT, // 0x1E
KEEP_ALIVE, // 0x1F
CHUNK_DATA, // 0x20
EFFECT, // 0x21
SPAWN_PARTICLE, // 0x22
UPDATE_LIGHT, // 0x23
JOIN_GAME, // 0x24
MAP_DATA, // 0x25
TRADE_LIST, // 0x26
ENTITY_POSITION, // 0x27
ENTITY_POSITION_AND_ROTATION, // 0x28
ENTITY_ROTATION, // 0x29
VEHICLE_MOVE, // 0x2A
OPEN_BOOK, // 0x2B
OPEN_WINDOW, // 0x2C
OPEN_SIGN_EDITOR, // 0x2D
PING, // 0x2E
CRAFT_RECIPE_RESPONSE, // 0x2F
PLAYER_ABILITIES, // 0x30
PLAYER_CHAT, // 0x31
COMBAT_END, // 0x32
COMBAT_ENTER, // 0x33
COMBAT_KILL, // 0x34
PLAYER_INFO_REMOVE, // 0x35
PLAYER_INFO_UPDATE, // 0x36
FACE_PLAYER, // 0x37
PLAYER_POSITION, // 0x38
UNLOCK_RECIPES, // 0x39
REMOVE_ENTITIES, // 0x3A
REMOVE_ENTITY_EFFECT, // 0x3B
RESOURCE_PACK, // 0x3C
RESPAWN, // 0x3D
ENTITY_HEAD_LOOK, // 0x3E
MULTI_BLOCK_CHANGE, // 0x3F
SELECT_ADVANCEMENTS_TAB, // 0x40
SERVER_DATA, // 0x41
ACTIONBAR, // 0x42
WORLD_BORDER_CENTER, // 0x43
WORLD_BORDER_LERP_SIZE, // 0x44
WORLD_BORDER_SIZE, // 0x45
WORLD_BORDER_WARNING_DELAY, // 0x46
WORLD_BORDER_WARNING_DISTANCE, // 0x47
CAMERA, // 0x48
HELD_ITEM_CHANGE, // 0x49
UPDATE_VIEW_POSITION, // 0x4A
UPDATE_VIEW_DISTANCE, // 0x4B
SPAWN_POSITION, // 0x4C
DISPLAY_SCOREBOARD, // 0x4D
ENTITY_METADATA, // 0x4E
ATTACH_ENTITY, // 0x4F
ENTITY_VELOCITY, // 0x50
ENTITY_EQUIPMENT, // 0x51
SET_EXPERIENCE, // 0x52
UPDATE_HEALTH, // 0x53
SCOREBOARD_OBJECTIVE, // 0x54
SET_PASSENGERS, // 0x55
TEAMS, // 0x56
UPDATE_SCORE, // 0x57
SET_SIMULATION_DISTANCE, // 0x58
TITLE_SUBTITLE, // 0x59
TIME_UPDATE, // 0x5A
TITLE_TEXT, // 0x5B
TITLE_TIMES, // 0x5C
ENTITY_SOUND, // 0x5D
SOUND, // 0x5E
STOP_SOUND, // 0x5F
SYSTEM_CHAT, // 0x60
TAB_LIST, // 0x61
NBT_QUERY, // 0x62
COLLECT_ITEM, // 0x63
ENTITY_TELEPORT, // 0x64
ADVANCEMENTS, // 0x65
ENTITY_PROPERTIES, // 0x66
UPDATE_ENABLED_FEATURES, // 0x67
ENTITY_EFFECT, // 0x68
DECLARE_RECIPES, // 0x69
TAGS; // 0x6A
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
@@ -0,0 +1,320 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1;
import com.google.gson.JsonElement;
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.PlayerMessageSignature;
import com.viaversion.viaversion.api.minecraft.RegistryType;
import com.viaversion.viaversion.api.minecraft.entities.Entity1_19_3Types;
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.remapper.PacketRemapper;
import com.viaversion.viaversion.api.rewriter.EntityRewriter;
import com.viaversion.viaversion.api.rewriter.ItemRewriter;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.BitSetType;
import com.viaversion.viaversion.api.type.types.ByteArrayType;
import com.viaversion.viaversion.api.type.types.minecraft.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_19_3;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.libs.kyori.adventure.text.Component;
import com.viaversion.viaversion.libs.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.ClientboundPackets1_19_1;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.ServerboundPackets1_19_1;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.packets.EntityPackets;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.packets.InventoryPackets;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.storage.ReceivedMessagesStorage;
import com.viaversion.viaversion.rewriter.CommandRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import java.util.UUID;
public final class Protocol1_19_3To1_19_1 extends AbstractProtocol<ClientboundPackets1_19_1, ClientboundPackets1_19_3, ServerboundPackets1_19_1, ServerboundPackets1_19_3> {
public static final MappingData MAPPINGS = new MappingDataBase("1.19", "1.19.3", true);
private static final ByteArrayType.OptionalByteArrayType OPTIONAL_MESSAGE_SIGNATURE_BYTES_TYPE = new ByteArrayType.OptionalByteArrayType(256);
private static final UUID ZERO_UUID = new UUID(0, 0);
private static final byte[] EMPTY_BYTES = new byte[0];
private final EntityPackets entityRewriter = new EntityPackets(this);
private final InventoryPackets itemRewriter = new InventoryPackets(this);
public Protocol1_19_3To1_19_1() {
super(ClientboundPackets1_19_1.class, ClientboundPackets1_19_3.class, ServerboundPackets1_19_1.class, ServerboundPackets1_19_3.class);
}
@Override
protected void registerPackets() {
final TagRewriter tagRewriter = new TagRewriter(this);
tagRewriter.addEmptyTags(RegistryType.ITEM, "minecraft:bookshelf_books", "minecraft:hanging_signs", "minecraft:stripped_logs");
tagRewriter.addEmptyTags(RegistryType.BLOCK, "minecraft:all_hanging_signs", "minecraft:ceiling_hanging_signs", "minecraft:invalid_spawn_inside",
"minecraft:stripped_logs", "minecraft:wall_hanging_signs");
tagRewriter.registerGeneric(ClientboundPackets1_19_1.TAGS);
entityRewriter.register();
itemRewriter.register();
final SoundRewriter soundRewriter = new SoundRewriter(this);
registerClientbound(ClientboundPackets1_19_1.ENTITY_SOUND, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // Sound id
handler(soundRewriter.getSoundHandler());
handler(wrapper -> {
// 0 means a resource location will be written
final int soundId = wrapper.get(Type.VAR_INT, 0);
wrapper.set(Type.VAR_INT, 0, soundId + 1);
});
}
});
registerClientbound(ClientboundPackets1_19_1.SOUND, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // Sound id
handler(soundRewriter.getSoundHandler());
handler(wrapper -> {
// 0 means a resource location will be written
final int soundId = wrapper.get(Type.VAR_INT, 0);
wrapper.set(Type.VAR_INT, 0, soundId + 1);
});
}
});
registerClientbound(ClientboundPackets1_19_1.NAMED_SOUND, ClientboundPackets1_19_3.SOUND, new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
wrapper.write(Type.VAR_INT, 0);
wrapper.passthrough(Type.STRING); // Sound identifier
wrapper.write(Type.OPTIONAL_FLOAT, null); // No fixed range
});
}
});
new StatisticsRewriter(this).register(ClientboundPackets1_19_1.STATISTICS);
final CommandRewriter commandRewriter = new CommandRewriter(this) {
@Override
public void handleArgument(final PacketWrapper wrapper, final String argumentType) throws Exception {
switch (argumentType) {
case "minecraft:item_enchantment":
wrapper.write(Type.STRING, "minecraft:enchantment");
break;
case "minecraft:mob_effect":
wrapper.write(Type.STRING, "minecraft:mob_effect");
break;
case "minecraft:entity_summon":
wrapper.write(Type.STRING, "minecraft:entity_type");
break;
default:
super.handleArgument(wrapper, argumentType);
break;
}
}
@Override
public String handleArgumentType(final String argumentType) {
switch (argumentType) {
case "minecraft:resource":
return "minecraft:resource_key";
case "minecraft:resource_or_tag":
return "minecraft:resource_or_tag_key";
case "minecraft:entity_summon":
case "minecraft:item_enchantment":
case "minecraft:mob_effect":
return "minecraft:resource";
}
return argumentType;
}
};
commandRewriter.registerDeclareCommands1_19(ClientboundPackets1_19_1.DECLARE_COMMANDS);
registerClientbound(ClientboundPackets1_19_1.SERVER_DATA, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.OPTIONAL_COMPONENT); // Motd
map(Type.OPTIONAL_STRING); // Encoded icon
read(Type.BOOLEAN); // Remove previews chat
}
});
// Aaaaand once more
registerClientbound(ClientboundPackets1_19_1.PLAYER_CHAT, ClientboundPackets1_19_3.DISGUISED_CHAT, new PacketRemapper() {
@Override
public void registerMap() {
read(Type.OPTIONAL_BYTE_ARRAY_PRIMITIVE); // Previous signature
handler(wrapper -> {
final PlayerMessageSignature signature = wrapper.read(Type.PLAYER_MESSAGE_SIGNATURE);
// Store message signature for last seen
if (!signature.uuid().equals(ZERO_UUID) && signature.signatureBytes().length != 0) {
final ReceivedMessagesStorage messagesStorage = wrapper.user().get(ReceivedMessagesStorage.class);
messagesStorage.add(signature);
if (messagesStorage.tickUnacknowledged() > 64) {
messagesStorage.resetUnacknowledgedCount();
// Send chat acknowledgement
final PacketWrapper chatAckPacket = wrapper.create(ServerboundPackets1_19_1.CHAT_ACK);
chatAckPacket.write(Type.PLAYER_MESSAGE_SIGNATURE_ARRAY, messagesStorage.lastSignatures());
chatAckPacket.write(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE, null);
chatAckPacket.sendToServer(Protocol1_19_3To1_19_1.class);
}
}
final String plainMessage = wrapper.read(Type.STRING);
JsonElement decoratedMessage = wrapper.read(Type.OPTIONAL_COMPONENT);
wrapper.read(Type.LONG); // Timestamp
wrapper.read(Type.LONG); // Salt
wrapper.read(Type.PLAYER_MESSAGE_SIGNATURE_ARRAY); // Last seen
final JsonElement unsignedMessage = wrapper.read(Type.OPTIONAL_COMPONENT);
if (unsignedMessage != null) {
decoratedMessage = unsignedMessage;
}
if (decoratedMessage == null) {
decoratedMessage = GsonComponentSerializer.gson().serializeToTree(Component.text(plainMessage));
}
final int filterMaskType = wrapper.read(Type.VAR_INT);
if (filterMaskType == 2) { // Partially filtered
wrapper.read(Type.LONG_ARRAY_PRIMITIVE); // Mask
}
wrapper.write(Type.COMPONENT, decoratedMessage);
// Keep chat type at the end
});
}
});
registerServerbound(ServerboundPackets1_19_3.CHAT_COMMAND, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // Command
map(Type.LONG); // Timestamp
map(Type.LONG); // Salt
handler(wrapper -> {
final int signatures = wrapper.read(Type.VAR_INT);
wrapper.write(Type.VAR_INT, 0);
for (int i = 0; i < signatures; i++) {
wrapper.read(Type.STRING); // Argument name
wrapper.read(OPTIONAL_MESSAGE_SIGNATURE_BYTES_TYPE); // Signature
}
wrapper.write(Type.BOOLEAN, false); // No signed preview
final ReceivedMessagesStorage messagesStorage = wrapper.user().get(ReceivedMessagesStorage.class);
messagesStorage.resetUnacknowledgedCount();
wrapper.write(Type.PLAYER_MESSAGE_SIGNATURE_ARRAY, messagesStorage.lastSignatures());
wrapper.write(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE, null); // No last unacknowledged
});
read(Type.VAR_INT); // Offset
read(new BitSetType(20)); // Acknowledged
}
});
registerServerbound(ServerboundPackets1_19_3.CHAT_MESSAGE, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // Command
map(Type.LONG); // Timestamp
// Salt
read(Type.LONG);
create(Type.LONG, 0L);
handler(wrapper -> {
// Remove signature
final byte[] signature = wrapper.read(OPTIONAL_MESSAGE_SIGNATURE_BYTES_TYPE);
wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, EMPTY_BYTES);
wrapper.write(Type.BOOLEAN, false); // No signed preview
final ReceivedMessagesStorage messagesStorage = wrapper.user().get(ReceivedMessagesStorage.class);
messagesStorage.resetUnacknowledgedCount();
wrapper.write(Type.PLAYER_MESSAGE_SIGNATURE_ARRAY, messagesStorage.lastSignatures());
wrapper.write(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE, null); // No last unacknowledged
});
read(Type.VAR_INT); // Offset
read(new BitSetType(20)); // Acknowledged
}
});
// Remove the key once again
registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO.getId(), ServerboundLoginPackets.HELLO.getId(), new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // Name
create(Type.OPTIONAL_PROFILE_KEY, null);
}
});
registerServerbound(State.LOGIN, ServerboundLoginPackets.ENCRYPTION_KEY.getId(), ServerboundLoginPackets.ENCRYPTION_KEY.getId(), new PacketRemapper() {
@Override
public void registerMap() {
map(Type.BYTE_ARRAY_PRIMITIVE); // Keys
create(Type.BOOLEAN, true); // Is nonce
map(Type.BYTE_ARRAY_PRIMITIVE); // Encrypted challenge
}
});
cancelServerbound(ServerboundPackets1_19_3.CHAT_SESSION_UPDATE);
cancelClientbound(ClientboundPackets1_19_1.DELETE_CHAT_MESSAGE);
cancelClientbound(ClientboundPackets1_19_1.PLAYER_CHAT_HEADER);
cancelClientbound(ClientboundPackets1_19_1.CHAT_PREVIEW);
cancelClientbound(ClientboundPackets1_19_1.SET_DISPLAY_CHAT_PREVIEW);
cancelServerbound(ServerboundPackets1_19_3.CHAT_ACK);
}
@Override
protected void onMappingDataLoaded() {
entityRewriter.onMappingDataLoaded();
Types1_19_3.PARTICLE.filler(this)
.reader("block", ParticleType.Readers.BLOCK)
.reader("block_marker", ParticleType.Readers.BLOCK)
.reader("dust", ParticleType.Readers.DUST)
.reader("falling_dust", ParticleType.Readers.BLOCK)
.reader("dust_color_transition", ParticleType.Readers.DUST_TRANSITION)
.reader("item", ParticleType.Readers.VAR_INT_ITEM)
.reader("vibration", ParticleType.Readers.VIBRATION)
.reader("sculk_charge", ParticleType.Readers.SCULK_CHARGE)
.reader("shriek", ParticleType.Readers.SHRIEK);
Entity1_19_3Types.initialize(this);
}
@Override
public void init(final UserConnection user) {
user.put(new ReceivedMessagesStorage());
addEntityTracker(user, new EntityTrackerBase(user, Entity1_19_3Types.PLAYER));
}
@Override
public MappingData getMappingData() {
return MAPPINGS;
}
@Override
public EntityRewriter getEntityRewriter() {
return entityRewriter;
}
@Override
public ItemRewriter getItemRewriter() {
return itemRewriter;
}
}
@@ -0,0 +1,85 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
public enum ServerboundPackets1_19_3 implements ServerboundPacketType {
TELEPORT_CONFIRM, // 0x00
QUERY_BLOCK_NBT, // 0x01
SET_DIFFICULTY, // 0x02
CHAT_ACK, // 0x03
CHAT_COMMAND, // 0x04
CHAT_MESSAGE, // 0x05
CLIENT_STATUS, // 0x06
CLIENT_SETTINGS, // 0x07
TAB_COMPLETE, // 0x08
CLICK_WINDOW_BUTTON, // 0x09
CLICK_WINDOW, // 0x0A
CLOSE_WINDOW, // 0x0B
PLUGIN_MESSAGE, // 0x0C
EDIT_BOOK, // 0x0D
ENTITY_NBT_REQUEST, // 0x0E
INTERACT_ENTITY, // 0x0F
GENERATE_JIGSAW, // 0x10
KEEP_ALIVE, // 0x11
LOCK_DIFFICULTY, // 0x12
PLAYER_POSITION, // 0x13
PLAYER_POSITION_AND_ROTATION, // 0x14
PLAYER_ROTATION, // 0x15
PLAYER_MOVEMENT, // 0x16
VEHICLE_MOVE, // 0x17
STEER_BOAT, // 0x18
PICK_ITEM, // 0x19
CRAFT_RECIPE_REQUEST, // 0x1A
PLAYER_ABILITIES, // 0x1B
PLAYER_DIGGING, // 0x1C
ENTITY_ACTION, // 0x1D
STEER_VEHICLE, // 0x1E
PONG, // 0x1F
CHAT_SESSION_UPDATE,
RECIPE_BOOK_DATA, // 0x20
SEEN_RECIPE, // 0x21
RENAME_ITEM, // 0x22
RESOURCE_PACK_STATUS, // 0x23
ADVANCEMENT_TAB, // 0x24
SELECT_TRADE, // 0x25
SET_BEACON_EFFECT, // 0x26
HELD_ITEM_CHANGE, // 0x27
UPDATE_COMMAND_BLOCK, // 0x28
UPDATE_COMMAND_BLOCK_MINECART, // 0x29
CREATIVE_INVENTORY_ACTION, // 0x2A
UPDATE_JIGSAW_BLOCK, // 0x2B
UPDATE_STRUCTURE_BLOCK, // 0x2C
UPDATE_SIGN, // 0x2D
ANIMATION, // 0x2E
SPECTATE, // 0x2F
PLAYER_BLOCK_PLACEMENT, // 0x30
USE_ITEM; // 0x31
@Override
public int getId() {
return ordinal();
}
@Override
public String getName() {
return name();
}
}
@@ -0,0 +1,89 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.data;
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.Type;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.data.RecipeRewriter1_16;
public class RecipeRewriter1_19_3 extends RecipeRewriter1_16 {
public RecipeRewriter1_19_3(final Protocol protocol) {
super(protocol);
recipeHandlers.put("crafting_special_armordye", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_bookcloning", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_mapcloning", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_mapextending", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_firework_rocket", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_firework_star", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_firework_star_fade", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_tippedarrow", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_bannerduplicate", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_shielddecoration", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_shulkerboxcoloring", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_suspiciousstew", this::handleSimpleRecipe);
recipeHandlers.put("crafting_special_repairitem", this::handleSimpleRecipe);
}
@Override
public void handleCraftingShapeless(final PacketWrapper wrapper) throws Exception {
wrapper.passthrough(Type.STRING); // Group
wrapper.passthrough(Type.VAR_INT); // Crafting book category
final int ingredients = wrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < ingredients; j++) {
final Item[] items = wrapper.passthrough(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT); // Ingredients
for (final Item item : items) {
rewrite(item);
}
}
rewrite(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Result
}
@Override
public void handleCraftingShaped(final PacketWrapper wrapper) throws Exception {
final int ingredients = wrapper.passthrough(Type.VAR_INT) * wrapper.passthrough(Type.VAR_INT);
wrapper.passthrough(Type.STRING); // Group
wrapper.passthrough(Type.VAR_INT); // Crafting book category
for (int j = 0; j < ingredients; j++) {
final Item[] items = wrapper.passthrough(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT); // Ingredients
for (final Item item : items) {
rewrite(item);
}
}
rewrite(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Result
}
@Override
public void handleSmelting(final PacketWrapper wrapper) throws Exception {
wrapper.passthrough(Type.STRING); // Group
wrapper.passthrough(Type.VAR_INT); // Crafting book category
final Item[] items = wrapper.passthrough(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT); // Ingredients
for (final Item item : items) {
rewrite(item);
}
rewrite(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Result
wrapper.passthrough(Type.FLOAT); // EXP
wrapper.passthrough(Type.VAR_INT); // Cooking time
}
public void handleSimpleRecipe(final PacketWrapper wrapper) throws Exception {
wrapper.passthrough(Type.VAR_INT); // Crafting book category
}
}
@@ -0,0 +1,182 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.packets;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.minecraft.entities.Entity1_19_3Types;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.BitSetType;
import com.viaversion.viaversion.api.type.types.version.Types1_19;
import com.viaversion.viaversion.api.type.types.version.Types1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.ClientboundPackets1_19_1;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ClientboundPackets1_19_3;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.Protocol1_19_3To1_19_1;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import java.util.BitSet;
import java.util.UUID;
public final class EntityPackets extends EntityRewriter<Protocol1_19_3To1_19_1> {
private static final BitSetType PROFILE_ACTIONS_ENUM_TYPE = new BitSetType(6);
public EntityPackets(final Protocol1_19_3To1_19_1 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
registerTrackerWithData1_19(ClientboundPackets1_19_1.SPAWN_ENTITY, Entity1_19_3Types.FALLING_BLOCK);
registerMetadataRewriter(ClientboundPackets1_19_1.ENTITY_METADATA, Types1_19.METADATA_LIST, Types1_19_3.METADATA_LIST);
registerRemoveEntities(ClientboundPackets1_19_1.REMOVE_ENTITIES);
protocol.registerClientbound(ClientboundPackets1_19_1.JOIN_GAME, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // Entity id
map(Type.BOOLEAN); // Hardcore
map(Type.UNSIGNED_BYTE); // Gamemode
map(Type.BYTE); // Previous Gamemode
map(Type.STRING_ARRAY); // World List
map(Type.NBT); // Dimension registry
map(Type.STRING); // Dimension key
map(Type.STRING); // World
handler(dimensionDataHandler());
handler(biomeSizeTracker());
handler(worldDataTrackerHandlerByKey());
handler(wrapper -> {
// Also enable vanilla features
final PacketWrapper enableFeaturesPacket = wrapper.create(ClientboundPackets1_19_3.UPDATE_ENABLED_FEATURES);
enableFeaturesPacket.write(Type.VAR_INT, 1);
enableFeaturesPacket.write(Type.STRING, "minecraft:vanilla");
enableFeaturesPacket.send(Protocol1_19_3To1_19_1.class);
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_1.RESPAWN, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.STRING); // Dimension
map(Type.STRING); // World
map(Type.LONG); // Seed
map(Type.UNSIGNED_BYTE); // Gamemode
map(Type.BYTE); // Previous gamemode
map(Type.BOOLEAN); // Debug
map(Type.BOOLEAN); // Flat
handler(worldDataTrackerHandlerByKey());
handler(wrapper -> {
final boolean keepAttributes = wrapper.read(Type.BOOLEAN);
byte keepDataMask = 0x02; // Always keep entity data
if (keepAttributes) {
keepDataMask |= 0x01;
}
wrapper.write(Type.BYTE, keepDataMask);
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_1.PLAYER_INFO, ClientboundPackets1_19_3.PLAYER_INFO_UPDATE, new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
final int action = wrapper.read(Type.VAR_INT);
if (action == 4) { // Remove player
// Write into new packet type
final int entries = wrapper.read(Type.VAR_INT);
final UUID[] uuidsToRemove = new UUID[entries];
for (int i = 0; i < entries; i++) {
uuidsToRemove[i] = wrapper.read(Type.UUID);
}
wrapper.write(Type.UUID_ARRAY, uuidsToRemove);
wrapper.setPacketType(ClientboundPackets1_19_3.PLAYER_INFO_REMOVE);
return;
}
final BitSet set = new BitSet(6);
if (action == 0) {
// Includes add player, profile key, gamemode, listed status, latency, and display name
set.set(0, 6);
} else {
// Update listed added at 3, initialize chat added at index 1
set.set(action == 1 ? action + 1 : action + 2);
}
wrapper.write(PROFILE_ACTIONS_ENUM_TYPE, set);
final int entries = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < entries; i++) {
wrapper.passthrough(Type.UUID); // UUID
if (action == 0) { // Add player
wrapper.passthrough(Type.STRING); // Player Name
final int properties = wrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < properties; j++) {
wrapper.passthrough(Type.STRING); // Name
wrapper.passthrough(Type.STRING); // Value
wrapper.passthrough(Type.OPTIONAL_STRING); // Signature
}
final int gamemode = wrapper.read(Type.VAR_INT);
final int ping = wrapper.read(Type.VAR_INT);
final JsonElement displayName = wrapper.read(Type.OPTIONAL_COMPONENT);
wrapper.read(Type.OPTIONAL_PROFILE_KEY);
wrapper.write(Type.BOOLEAN, false); // No chat session data
wrapper.write(Type.VAR_INT, gamemode);
wrapper.write(Type.BOOLEAN, true); // Also update listed
wrapper.write(Type.VAR_INT, ping);
wrapper.write(Type.OPTIONAL_COMPONENT, displayName);
} else if (action == 1 || action == 2) { // Update gamemode/update latency
wrapper.passthrough(Type.VAR_INT);
} else if (action == 3) { // Update display name
wrapper.passthrough(Type.OPTIONAL_COMPONENT);
}
}
});
}
});
}
@Override
protected void registerRewrites() {
filter().handler((event, meta) -> {
final int id = meta.metaType().typeId();
meta.setMetaType(Types1_19_3.META_TYPES.byId(id >= 2 ? id + 1 : id)); // long added
});
registerMetaTypeHandler(Types1_19_3.META_TYPES.itemType, Types1_19_3.META_TYPES.blockStateType, Types1_19_3.META_TYPES.particleType);
filter().filterFamily(Entity1_19_3Types.MINECART_ABSTRACT).index(11).handler((event, meta) -> {
// Convert to new block id
final int data = (int) meta.getValue();
meta.setValue(protocol.getMappingData().getNewBlockStateId(data));
});
}
@Override
public void onMappingDataLoaded() {
mapTypes();
}
@Override
public EntityType typeFromId(final int type) {
return Entity1_19_3Types.getTypeFromId(type);
}
}
@@ -0,0 +1,143 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.packets;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.data.RecipeRewriter1_16;
import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.types.Chunk1_18Type;
import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.ClientboundPackets1_19_1;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.Protocol1_19_3To1_19_1;
import com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.ServerboundPackets1_19_3;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.ItemRewriter;
public final class InventoryPackets extends ItemRewriter<Protocol1_19_3To1_19_1> {
private static final int MISC_CRAFTING_BOOK_CATEGORY = 0;
public InventoryPackets(final Protocol1_19_3To1_19_1 protocol) {
super(protocol);
}
@Override
public void registerPackets() {
final BlockRewriter blockRewriter = new BlockRewriter(protocol, Type.POSITION1_14);
blockRewriter.registerBlockAction(ClientboundPackets1_19_1.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_19_1.BLOCK_CHANGE);
blockRewriter.registerVarLongMultiBlockChange(ClientboundPackets1_19_1.MULTI_BLOCK_CHANGE);
blockRewriter.registerEffect(ClientboundPackets1_19_1.EFFECT, 1010, 2001);
blockRewriter.registerChunkData1_19(ClientboundPackets1_19_1.CHUNK_DATA, Chunk1_18Type::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_19_1.BLOCK_ENTITY_DATA);
registerSetCooldown(ClientboundPackets1_19_1.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_19_1.WINDOW_ITEMS);
registerSetSlot1_17_1(ClientboundPackets1_19_1.SET_SLOT);
registerAdvancements(ClientboundPackets1_19_1.ADVANCEMENTS, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_19_1.ENTITY_EQUIPMENT);
registerClickWindow1_17_1(ServerboundPackets1_19_3.CLICK_WINDOW);
registerTradeList1_19(ClientboundPackets1_19_1.TRADE_LIST);
registerCreativeInvAction(ServerboundPackets1_19_3.CREATIVE_INVENTORY_ACTION, Type.FLAT_VAR_INT_ITEM);
registerWindowPropertyEnchantmentHandler(ClientboundPackets1_19_1.WINDOW_PROPERTY);
registerSpawnParticle1_19(ClientboundPackets1_19_1.SPAWN_PARTICLE);
final RecipeRewriter1_16 recipeRewriter = new RecipeRewriter1_16(protocol);
protocol.registerClientbound(ClientboundPackets1_19_1.DECLARE_RECIPES, new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
final int size = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < size; i++) {
final String type = wrapper.passthrough(Type.STRING).replace("minecraft:", "");
wrapper.passthrough(Type.STRING); // Recipe Identifier
switch (type) {
case "crafting_shapeless": {
wrapper.passthrough(Type.STRING); // Group
wrapper.write(Type.VAR_INT, MISC_CRAFTING_BOOK_CATEGORY);
final int ingredients = wrapper.passthrough(Type.VAR_INT);
for (int j = 0; j < ingredients; j++) {
final Item[] items = wrapper.passthrough(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT); // Ingredients
for (final Item item : items) {
handleItemToClient(item);
}
}
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Result
break;
}
case "crafting_shaped": {
final int ingredients = wrapper.passthrough(Type.VAR_INT) * wrapper.passthrough(Type.VAR_INT);
wrapper.passthrough(Type.STRING); // Group
wrapper.write(Type.VAR_INT, MISC_CRAFTING_BOOK_CATEGORY);
for (int j = 0; j < ingredients; j++) {
final Item[] items = wrapper.passthrough(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT); // Ingredients
for (final Item item : items) {
handleItemToClient(item);
}
}
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Result
break;
}
case "smelting":
case "campfire_cooking":
case "blasting":
case "smoking":
wrapper.passthrough(Type.STRING); // Group
wrapper.write(Type.VAR_INT, MISC_CRAFTING_BOOK_CATEGORY);
final Item[] items = wrapper.passthrough(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT); // Ingredients
for (final Item item : items) {
handleItemToClient(item);
}
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Result
wrapper.passthrough(Type.FLOAT); // EXP
wrapper.passthrough(Type.VAR_INT); // Cooking time
break;
case "crafting_special_armordye":
case "crafting_special_bookcloning":
case "crafting_special_mapcloning":
case "crafting_special_mapextending":
case "crafting_special_firework_rocket":
case "crafting_special_firework_star":
case "crafting_special_firework_star_fade":
case "crafting_special_tippedarrow":
case "crafting_special_bannerduplicate":
case "crafting_special_shielddecoration":
case "crafting_special_shulkerboxcoloring":
case "crafting_special_suspiciousstew":
case "crafting_special_repairitem":
wrapper.write(Type.VAR_INT, MISC_CRAFTING_BOOK_CATEGORY);
break;
default:
recipeRewriter.handle(wrapper, type);
break;
}
}
});
}
});
protocol.registerClientbound(ClientboundPackets1_19_1.EXPLOSION, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.FLOAT, Type.DOUBLE); // X
map(Type.FLOAT, Type.DOUBLE); // Y
map(Type.FLOAT, Type.DOUBLE); // Z
}
});
}
}
@@ -0,0 +1,64 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2022 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature;
import java.util.Arrays;
public final class ReceivedMessagesStorage implements StorableObject {
private final PlayerMessageSignature[] signatures = new PlayerMessageSignature[5];
private PlayerMessageSignature lastSignature;
private int size;
private int unacknowledged;
public boolean add(final PlayerMessageSignature signature) {
if (signature.equals(this.lastSignature)) {
return false;
}
this.lastSignature = signature;
PlayerMessageSignature toPush = signature;
for (int i = 0; i < this.size; ++i) {
final PlayerMessageSignature entry = this.signatures[i];
this.signatures[i] = toPush;
toPush = entry;
if (entry.uuid().equals(signature.uuid())) {
return true;
}
}
if (this.size < this.signatures.length) {
this.signatures[this.size++] = toPush;
}
return true;
}
public PlayerMessageSignature[] lastSignatures() {
return Arrays.copyOf(this.signatures, size);
}
public int tickUnacknowledged() {
return unacknowledged++;
}
public void resetUnacknowledgedCount() {
unacknowledged = 0;
}
}
@@ -64,6 +64,10 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
super(ClientboundPackets1_18.class, ClientboundPackets1_19.class, ServerboundPackets1_17.class, ServerboundPackets1_19.class);
}
public static boolean isTextComponentNull(final JsonElement element) {
return element == null || element.isJsonNull() || (element.isJsonArray() && element.getAsJsonArray().size() == 0);
}
@Override
protected void registerPackets() {
final TagRewriter tagRewriter = new TagRewriter(this);
@@ -86,7 +90,7 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
map(Type.INT); // Z
map(Type.FLOAT); // Volume
map(Type.FLOAT); // Pitch
create(Type.LONG, randomLong()); // Seed
handler(wrapper -> wrapper.write(Type.LONG, randomLong())); // Seed
handler(soundRewriter.getSoundHandler());
}
});
@@ -98,7 +102,7 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
map(Type.VAR_INT); // Entity id
map(Type.FLOAT); // Volume
map(Type.FLOAT); // Pitch
create(Type.LONG, randomLong()); // Seed
handler(wrapper -> wrapper.write(Type.LONG, randomLong())); // Seed
handler(soundRewriter.getSoundHandler());
}
});
@@ -112,7 +116,7 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
map(Type.INT); // Z
map(Type.FLOAT); // Volume
map(Type.FLOAT); // Pitch
create(Type.LONG, randomLong()); // Seed
handler(wrapper -> wrapper.write(Type.LONG, randomLong())); // Seed
}
});
@@ -120,7 +124,7 @@ public final class Protocol1_19To1_18_2 extends AbstractProtocol<ClientboundPack
final PacketHandler titleHandler = wrapper -> {
final JsonElement component = wrapper.read(Type.COMPONENT);
if (!component.isJsonNull()) {
if (!isTextComponentNull(component)) {
wrapper.write(Type.COMPONENT, component);
} else {
wrapper.write(Type.COMPONENT, GsonComponentSerializer.gson().serializeToTree(Component.empty()));
@@ -22,6 +22,7 @@ import com.github.steveice10.opennbt.tag.builtin.IntTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.google.common.collect.Maps;
import com.google.gson.JsonElement;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.data.entity.DimensionData;
import com.viaversion.viaversion.api.minecraft.Position;
@@ -280,15 +281,16 @@ public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
for (int j = 0; j < properties; j++) {
wrapper.passthrough(Type.STRING); // Name
wrapper.passthrough(Type.STRING); // Value
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.STRING); // Signature
}
wrapper.passthrough(Type.OPTIONAL_STRING); // Signature
}
wrapper.passthrough(Type.VAR_INT); // Gamemode
wrapper.passthrough(Type.VAR_INT); // Ping
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.COMPONENT); // Display name
final JsonElement displayName = wrapper.read(Type.OPTIONAL_COMPONENT); // Display name
if (!Protocol1_19To1_18_2.isTextComponentNull(displayName)) {
wrapper.write(Type.OPTIONAL_COMPONENT, displayName);
} else {
wrapper.write(Type.OPTIONAL_COMPONENT, null);
}
// No public profile signature
@@ -296,8 +298,11 @@ public final class EntityPackets extends EntityRewriter<Protocol1_19To1_18_2> {
} else if (action == 1 || action == 2) { // Update gamemode/update latency
wrapper.passthrough(Type.VAR_INT);
} else if (action == 3) { // Update display name
if (wrapper.passthrough(Type.BOOLEAN)) {
wrapper.passthrough(Type.COMPONENT);
final JsonElement displayName = wrapper.read(Type.OPTIONAL_COMPONENT); // Display name
if (!Protocol1_19To1_18_2.isTextComponentNull(displayName)) {
wrapper.write(Type.OPTIONAL_COMPONENT, displayName);
} else {
wrapper.write(Type.OPTIONAL_COMPONENT, null);
}
}
}
@@ -37,10 +37,10 @@ public final class InventoryPackets extends ItemRewriter<Protocol1_19To1_18_2> {
@Override
public void registerPackets() {
registerSetCooldown(ClientboundPackets1_18.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_18.WINDOW_ITEMS, Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT, Type.FLAT_VAR_INT_ITEM);
registerSetSlot1_17_1(ClientboundPackets1_18.SET_SLOT, Type.FLAT_VAR_INT_ITEM);
registerWindowItems1_17_1(ClientboundPackets1_18.WINDOW_ITEMS);
registerSetSlot1_17_1(ClientboundPackets1_18.SET_SLOT);
registerAdvancements(ClientboundPackets1_18.ADVANCEMENTS, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_18.ENTITY_EQUIPMENT, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_18.ENTITY_EQUIPMENT);
protocol.registerClientbound(ClientboundPackets1_18.SPAWN_PARTICLE, new PacketRemapper() {
@Override
public void registerMap() {
@@ -58,7 +58,7 @@ public final class InventoryPackets extends ItemRewriter<Protocol1_19To1_18_2> {
}
});
registerClickWindow1_17_1(ServerboundPackets1_19.CLICK_WINDOW, Type.FLAT_VAR_INT_ITEM);
registerClickWindow1_17_1(ServerboundPackets1_19.CLICK_WINDOW);
registerCreativeInvAction(ServerboundPackets1_19.CREATIVE_INVENTORY_ACTION, Type.FLAT_VAR_INT_ITEM);
registerWindowPropertyEnchantmentHandler(ClientboundPackets1_18.WINDOW_PROPERTY);
@@ -18,6 +18,8 @@
package com.viaversion.viaversion.protocols.protocol1_9_1_2to1_9_3_4;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Position;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
@@ -63,7 +65,9 @@ public class Protocol1_9_1_2To1_9_3_4 extends AbstractProtocol<ClientboundPacket
wrapper.write(Type.POSITION, position); // Position
for (int i = 1; i < 5; i++) {
// Should technically be written as COMPONENT, but left as String for simplification/to remove redundant wrapping for VR
wrapper.write(Type.STRING, (String) tag.get("Text" + i).getValue()); // Sign line
Tag textTag = tag.get("Text" + i);
String line = textTag instanceof StringTag ? ((StringTag) textTag).getValue() : "";
wrapper.write(Type.STRING, line); // Sign line
}
}
}
@@ -25,6 +25,8 @@ import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.Position;
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.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandler;
@@ -104,18 +106,20 @@ public class Protocol1_9_3To1_9_1_2 extends AbstractProtocol<ClientboundPackets1
wrapper.write(new Chunk1_9_3_4Type(clientWorld), chunk);
List<CompoundTag> tags = chunk.getBlockEntities();
for (int i = 0; i < chunk.getSections().length; i++) {
ChunkSection section = chunk.getSections()[i];
for (int s = 0; s < chunk.getSections().length; s++) {
ChunkSection section = chunk.getSections()[s];
if (section == null) continue;
DataPalette blocks = section.palette(PaletteType.BLOCKS);
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int block = section.getBlockWithoutData(x, y, z);
if (FakeTileEntity.isTileEntity(block)) {
tags.add(FakeTileEntity.createTileEntity(x + (chunk.getX() << 4), y + (i << 4), z + (chunk.getZ() << 4), block));
}
}
for (int idx = 0; idx < ChunkSection.SIZE; idx++) {
int id = blocks.idAt(idx) >> 4;
if (FakeTileEntity.isTileEntity(id)) {
tags.add(FakeTileEntity.createTileEntity(
ChunkSection.xFromIndex(idx) + (chunk.getX() << 4),
ChunkSection.yFromIndex(idx) + (s << 4),
ChunkSection.zFromIndex(idx) + (chunk.getZ() << 4),
id
));
}
}
}
@@ -61,12 +61,12 @@ public class EntityPackets {
map(Type.INT); // 0 - Entity ID
map(Type.INT); // 1 - Vehicle
// Leash boolean is removed in new versions
map(Type.BOOLEAN, new ValueTransformer<Boolean, Void>(Type.NOTHING) {
// Leash state is removed in new versions
map(Type.UNSIGNED_BYTE, new ValueTransformer<Short, Void>(Type.NOTHING) {
@Override
public Void transform(PacketWrapper wrapper, Boolean inputValue) throws Exception {
public Void transform(PacketWrapper wrapper, Short inputValue) throws Exception {
EntityTracker1_9 tracker = wrapper.user().getEntityTracker(Protocol1_9To1_8.class);
if (!inputValue) {
if (inputValue == 0) {
int passenger = wrapper.get(Type.INT, 0);
int vehicle = wrapper.get(Type.INT, 1);
@@ -241,25 +241,20 @@ public class PlayerPackets {
for (int j = 0; j < properties; j++) {
wrapper.passthrough(Type.STRING); // name
wrapper.passthrough(Type.STRING); // value
boolean isSigned = wrapper.passthrough(Type.BOOLEAN);
if (isSigned) {
wrapper.passthrough(Type.STRING); // signature
}
wrapper.passthrough(Type.OPTIONAL_STRING); // signature
}
wrapper.passthrough(Type.VAR_INT); // gamemode
wrapper.passthrough(Type.VAR_INT); // ping
boolean hasDisplayName = wrapper.passthrough(Type.BOOLEAN);
if (hasDisplayName) {
Protocol1_9To1_8.FIX_JSON.write(wrapper, wrapper.read(Type.STRING)); // display name
}
String displayName = wrapper.read(Type.OPTIONAL_STRING);
wrapper.write(Type.OPTIONAL_COMPONENT, displayName != null ?
Protocol1_9To1_8.FIX_JSON.transform(wrapper, displayName) : null);
} else if ((action == 1) || (action == 2)) { // update gamemode || update latency
wrapper.passthrough(Type.VAR_INT);
} else if (action == 3) { // update display name
boolean hasDisplayName = wrapper.passthrough(Type.BOOLEAN);
if (hasDisplayName) {
Protocol1_9To1_8.FIX_JSON.write(wrapper, wrapper.read(Type.STRING)); // display name
}
String displayName = wrapper.read(Type.OPTIONAL_STRING);
wrapper.write(Type.OPTIONAL_COMPONENT, displayName != null ?
Protocol1_9To1_8.FIX_JSON.transform(wrapper, displayName) : null);
} else if (action == 4) { // remove player
// no fields
}
@@ -17,12 +17,23 @@
*/
package com.viaversion.viaversion.rewriter;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.Mappings;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.BlockChangeRecord;
import com.viaversion.viaversion.api.minecraft.Position;
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.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.util.MathUtil;
import java.util.List;
public class BlockRewriter {
private final Protocol protocol;
@@ -121,4 +132,56 @@ public class BlockRewriter {
}
});
}
public void registerChunkData1_19(ClientboundPacketType packetType, ChunkTypeSupplier chunkTypeSupplier) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
final EntityTracker tracker = protocol.getEntityRewriter().tracker(wrapper.user());
Preconditions.checkArgument(tracker.biomesSent() != 0, "Biome count not set");
Preconditions.checkArgument(tracker.currentWorldSectionHeight() != 0, "Section height not set");
final Type<Chunk> chunkType = chunkTypeSupplier.supply(tracker.currentWorldSectionHeight(),
MathUtil.ceilLog2(protocol.getMappingData().getBlockStateMappings().mappedSize()),
MathUtil.ceilLog2(tracker.biomesSent()));
final Chunk chunk = wrapper.passthrough(chunkType);
for (final ChunkSection section : chunk.getSections()) {
final DataPalette blockPalette = section.palette(PaletteType.BLOCKS);
for (int i = 0; i < blockPalette.size(); i++) {
final int id = blockPalette.idByIndex(i);
blockPalette.setIdByIndex(i, protocol.getMappingData().getNewBlockStateId(id));
}
}
final Mappings blockEntityMappings = protocol.getMappingData().getBlockEntityMappings();
if (blockEntityMappings != null) {
List<BlockEntity> blockEntities = chunk.blockEntities();
for (int i = 0; i < blockEntities.size(); i++) {
final BlockEntity blockEntity = blockEntities.get(i);
blockEntities.set(i, blockEntity.withTypeId(protocol.getMappingData().getBlockEntityMappings().getNewIdOrDefault(blockEntity.typeId(), blockEntity.typeId())));
}
}
});
}
});
}
public void registerBlockEntityData(ClientboundPacketType packetType) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.POSITION1_14);
handler(wrapper -> {
final int blockEntityId = wrapper.read(Type.VAR_INT);
wrapper.write(Type.VAR_INT, protocol.getMappingData().getBlockEntityMappings().getNewIdOrDefault(blockEntityId, blockEntityId));
});
}
});
}
@FunctionalInterface
public interface ChunkTypeSupplier {
Type<Chunk> supply(int ySectionCount, int globalPaletteBlockBits, int globalPaletteBiomeBits);
}
}
@@ -17,6 +17,7 @@
*/
package com.viaversion.viaversion.rewriter;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
@@ -73,6 +74,12 @@ public class CommandRewriter {
this.parserHandlers.put("minecraft:resource_or_tag", wrapper -> {
wrapper.passthrough(Type.STRING); // Resource location/tag
});
this.parserHandlers.put("minecraft:resource_or_tag_key", wrapper -> {
wrapper.passthrough(Type.STRING); // Resource location
});
this.parserHandlers.put("minecraft:resource_key", wrapper -> {
wrapper.passthrough(Type.STRING); // Resource location/tag
});
}
public void handleArgument(PacketWrapper wrapper, String argumentType) throws Exception {
@@ -144,9 +151,8 @@ public class CommandRewriter {
int argumentTypeId = wrapper.read(Type.VAR_INT);
String argumentType = protocol.getMappingData().getArgumentTypeMappings().identifier(argumentTypeId);
String newArgumentType = handleArgumentType(argumentType);
if (newArgumentType != null) {
wrapper.write(Type.VAR_INT, protocol.getMappingData().getArgumentTypeMappings().mappedId(newArgumentType));
}
Preconditions.checkArgument(newArgumentType != null, "No mapping for argument type " + argumentType);
wrapper.write(Type.VAR_INT, protocol.getMappingData().getArgumentTypeMappings().mappedId(newArgumentType));
// Always call the handler using the previous name
handleArgument(wrapper, argumentType);
@@ -40,6 +40,7 @@ import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.rewriter.RewriterBase;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.Particle;
import com.viaversion.viaversion.data.entity.DimensionDataImpl;
import com.viaversion.viaversion.rewriter.meta.MetaFilter;
import com.viaversion.viaversion.rewriter.meta.MetaHandlerEvent;
import com.viaversion.viaversion.rewriter.meta.MetaHandlerEventImpl;
@@ -47,7 +48,9 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@@ -475,6 +478,26 @@ public abstract class EntityRewriter<T extends Protocol> extends RewriterBase<T>
};
}
/**
* Returns a handler to cache dimension data, later used to get height values and other important info.
*
* @return handler to cache dimension data
*/
public PacketHandler dimensionDataHandler() {
return wrapper -> {
final CompoundTag tag = wrapper.get(Type.NBT, 0);
final ListTag dimensions = ((CompoundTag) tag.get("minecraft:dimension_type")).get("value");
final Map<String, DimensionData> dimensionDataMap = new HashMap<>(dimensions.size());
for (final Tag dimension : dimensions) {
final CompoundTag dimensionCompound = (CompoundTag) dimension;
final CompoundTag element = dimensionCompound.get("element");
final String name = (String) dimensionCompound.get("name").getValue();
dimensionDataMap.put(name, new DimensionDataImpl(element));
}
tracker(wrapper.user()).setDimensions(dimensionDataMap);
};
}
// ---------------------------------------------------------------------------
// Sub 1.14.1 methods
@@ -66,21 +66,19 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
});
}
public void registerWindowItems1_17_1(ClientboundPacketType packetType, Type<Item[]> itemsType, Type<Item> carriedItemType) {
public void registerWindowItems1_17_1(ClientboundPacketType packetType) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.UNSIGNED_BYTE); // Window id
map(Type.VAR_INT); // State id
map(itemsType); // Items
map(carriedItemType); // Carried item
handler(wrapper -> {
Item[] items = wrapper.get(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT, 0);
Item[] items = wrapper.passthrough(Type.FLAT_VAR_INT_ITEM_ARRAY_VAR_INT);
for (Item item : items) {
handleItemToClient(item);
}
handleItemToClient(wrapper.get(Type.FLAT_VAR_INT_ITEM, 0));
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Carried item
});
}
});
@@ -98,15 +96,15 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
});
}
public void registerSetSlot1_17_1(ClientboundPacketType packetType, Type<Item> type) {
public void registerSetSlot1_17_1(ClientboundPacketType packetType) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.UNSIGNED_BYTE); // Window id
map(Type.VAR_INT); // State id
map(Type.SHORT); // Slot id
map(type); // Item
handler(itemToClientHandler(type));
map(Type.FLAT_VAR_INT_ITEM); // Item
handler(itemToClientHandler(Type.FLAT_VAR_INT_ITEM));
}
});
}
@@ -126,7 +124,7 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
}
// 1.16+
public void registerEntityEquipmentArray(ClientboundPacketType packetType, Type<Item> type) {
public void registerEntityEquipmentArray(ClientboundPacketType packetType) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
@@ -137,7 +135,7 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
do {
slot = wrapper.passthrough(Type.BYTE);
// & 0x7F into an extra variable if slot is needed
handleItemToClient(wrapper.passthrough(type));
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM));
} while ((slot & 0xFFFFFF80) != 0);
});
}
@@ -172,7 +170,7 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
});
}
public void registerClickWindow1_17_1(ServerboundPacketType packetType, Type<Item> type) {
public void registerClickWindow1_17_1(ServerboundPacketType packetType) {
protocol.registerServerbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
@@ -187,11 +185,11 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
int length = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < length; i++) {
wrapper.passthrough(Type.SHORT); // Slot
handleItemToServer(wrapper.passthrough(type));
handleItemToServer(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM));
}
// Carried item
handleItemToServer(wrapper.passthrough(type));
handleItemToServer(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM));
});
}
});
@@ -210,7 +208,7 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
}
// 1.14.4+
public void registerTradeList(ClientboundPacketType packetType, Type<Item> type) {
public void registerTradeList(ClientboundPacketType packetType) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
@@ -218,11 +216,11 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
wrapper.passthrough(Type.VAR_INT);
int size = wrapper.passthrough(Type.UNSIGNED_BYTE);
for (int i = 0; i < size; i++) {
handleItemToClient(wrapper.passthrough(type)); // Input
handleItemToClient(wrapper.passthrough(type)); // Output
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Input
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Output
if (wrapper.passthrough(Type.BOOLEAN)) { // Has second item
handleItemToClient(wrapper.passthrough(type)); // Second Item
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Second Item
}
wrapper.passthrough(Type.BOOLEAN); // Trade disabled
@@ -240,7 +238,7 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
});
}
public void registerTradeList1_19(ClientboundPacketType packetType, Type<Item> type) {
public void registerTradeList1_19(ClientboundPacketType packetType) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
@@ -248,9 +246,9 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
wrapper.passthrough(Type.VAR_INT); // Container id
int size = wrapper.passthrough(Type.VAR_INT);
for (int i = 0; i < size; i++) {
handleItemToClient(wrapper.passthrough(type)); // Input
handleItemToClient(wrapper.passthrough(type)); // Output
handleItemToClient(wrapper.passthrough(type)); // Second Item
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Input
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Output
handleItemToClient(wrapper.passthrough(Type.FLAT_VAR_INT_ITEM)); // Second Item
wrapper.passthrough(Type.BOOLEAN); // Trade disabled
wrapper.passthrough(Type.INT); // Number of tools uses
@@ -343,21 +341,21 @@ public abstract class ItemRewriter<T extends Protocol> extends RewriterBase<T> i
});
}
public void registerSpawnParticle1_19(ClientboundPacketType packetType, Type<Item> itemType, Type<?> coordType) {
public void registerSpawnParticle1_19(ClientboundPacketType packetType) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Particle ID
map(Type.BOOLEAN); // 1 - Long Distance
map(coordType); // 2 - X
map(coordType); // 3 - Y
map(coordType); // 4 - Z
map(Type.DOUBLE); // 2 - X
map(Type.DOUBLE); // 3 - Y
map(Type.DOUBLE); // 4 - Z
map(Type.FLOAT); // 5 - Offset X
map(Type.FLOAT); // 6 - Offset Y
map(Type.FLOAT); // 7 - Offset Z
map(Type.FLOAT); // 8 - Particle Data
map(Type.INT); // 9 - Particle Count
handler(getSpawnParticleHandler(Type.VAR_INT, itemType));
handler(getSpawnParticleHandler(Type.VAR_INT, Type.FLAT_VAR_INT_ITEM));
}
});
}
@@ -48,6 +48,32 @@ public class SoundRewriter {
});
}
public void register1_19_3Sound(ClientboundPacketType packetType) {
protocol.registerClientbound(packetType, new PacketRemapper() {
@Override
public void registerMap() {
handler(wrapper -> {
int soundId = wrapper.read(Type.VAR_INT);
if (soundId == 0) {
// Is followed by the resource loation
wrapper.write(Type.VAR_INT, 0);
return;
}
// The id needs to be normalized
soundId--;
final int mappedId = idRewriter.rewrite(soundId);
if (mappedId == -1) {
wrapper.cancel();
return;
}
wrapper.write(Type.VAR_INT, mappedId + 1);
});
}
});
}
public PacketHandler getSoundHandler() {
return wrapper -> {
int soundId = wrapper.get(Type.VAR_INT, 0);
@@ -17,7 +17,6 @@
*/
package com.viaversion.viaversion.util;
import com.google.common.base.Joiner;
import com.google.common.io.CharStreams;
import com.google.common.io.Files;
@@ -85,6 +84,9 @@ public class CommentStore {
}
public void storeComments(final InputStream inputStream) throws IOException {
mainHeader.clear();
headers.clear();
final String data;
try (final InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
data = CharStreams.toString(reader);
@@ -219,20 +221,6 @@ public class CommentStore {
Files.write(fileData.toString(), output, StandardCharsets.UTF_8);
}
private String addHeaderTags(final List<String> header, final String indent) {
final StringBuilder builder = new StringBuilder();
for (final String line : header) {
builder.append(indent).append("# ").append(line).append('\n');
}
return builder.toString();
}
private String join(final String[] array, final char joinChar, final int start, final int length) {
final String[] copy = new String[length - start];
System.arraycopy(array, start, copy, 0, length - start);
return Joiner.on(joinChar).join(copy);
}
private int getIndents(final String line) {
int count = 0;
for (int i = 0; i < line.length(); i++) {
@@ -250,16 +238,4 @@ public class CommentStore {
System.arraycopy(array, 0, copy, 0, length);
return String.join(this.pathSeparator, copy);
}
private int getSuccessiveSpaces(final String text) {
int count = 0;
for (int i = 0; i < text.length(); i++) {
if (text.charAt(i) == ' ') {
count += 1;
} else {
break;
}
}
return count;
}
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,7 @@
{
"argumenttypes": {
"minecraft:item_enchantment": "minecraft:resource",
"minecraft:mob_effect": "minecraft:resource",
"minecraft:entity_summon": "minecraft:resource"
}
}
+4
View File
@@ -0,0 +1,4 @@
dependencies {
api(projects.compat.javaCompatCommon)
api(projects.compat.javaCompatUnsafe)
}
@@ -0,0 +1,3 @@
dependencies {
api(projects.compat.javaCompatCommon)
}
@@ -0,0 +1,2 @@
dependencies {
}
@@ -0,0 +1,18 @@
package protocolsupport.api;
public abstract class Connection {
public abstract static class PacketListener {
public void onPacketReceiving(PacketEvent event) {
throw new UnsupportedOperationException();
}
public static class PacketEvent {
public Object getPacket() {
throw new UnsupportedOperationException();
}
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=4.4.2
projectVersion=4.5.0
# Gradle properties
org.gradle.daemon=true
+4 -6
View File
@@ -2,12 +2,11 @@ metadata.format.version = "1.1"
[versions]
adventure = "4.9.3"
gson = "2.8.8"
adventure = "4.12.0"
gson = "2.10"
fastutil = "8.5.6"
flare = "2.0.0"
flare = "2.0.1"
openNBT = "2.1"
javassist = "3.28.0-GA"
# Common provided
netty = "4.0.20.Final"
@@ -15,7 +14,7 @@ guava = "17.0"
snakeYaml = "1.18"
junit = "5.7.2"
checkerQual = "3.18.0"
checkerQual = "3.27.0"
# Platforms
paper = "1.16.5-R0.1-SNAPSHOT"
@@ -38,7 +37,6 @@ fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil"
flare = { group = "space.vectrix.flare", name = "flare", version.ref = "flare" }
flareFastutil = { group = "space.vectrix.flare", name = "flare-fastutil", version.ref = "flare" }
openNBT = { group = "com.viaversion", name = "opennbt", version.ref = "openNBT" }
javassist = { group = "org.javassist", name = "javassist", version.ref = "javassist" }
netty = { group = "io.netty", name = "netty-all", version.ref = "netty" }
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+6
View File
@@ -205,6 +205,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
Vendored
+8 -6
View File
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
-4
View File
@@ -1,4 +0,0 @@
dependencies {
api(projects.javaCompat.javaCompatCommon)
api(projects.javaCompat.javaCompatUnsafe)
}
@@ -1,3 +0,0 @@
dependencies {
api(projects.javaCompat.javaCompatCommon)
}
+1 -1
View File
@@ -27,7 +27,7 @@ rootProject.name = "viaversion-parent"
includeBuild("build-logic")
include("adventure")
include("java-compat", "java-compat:java-compat-common", "java-compat:java-compat-unsafe")
include("compat", "compat:java-compat-common", "compat:java-compat-unsafe", "compat:protocolsupport-compat")
setupViaSubproject("api")
setupViaSubproject("api-legacy")
@@ -50,4 +50,14 @@ public class SpongeViaInjector extends LegacyViaInjector {
protected void blame(ChannelHandler bootstrapAcceptor) {
throw new RuntimeException("Unable to find core component 'childHandler', please check your plugins. Issue: " + bootstrapAcceptor.getClass().getName());
}
@Override
public String getEncoderName() {
return "encoder";
}
@Override
public String getDecoderName() {
return "decoder";
}
}