Compare commits

...
8 changed files with 145 additions and 111 deletions

No files matched your search

@@ -24,6 +24,7 @@ import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_20_5;
import com.viaversion.viaversion.api.minecraft.item.data.ChatType;
import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.provider.PacketTypesProvider;
import com.viaversion.viaversion.api.protocol.packet.provider.SimplePacketTypesProvider;
import com.viaversion.viaversion.api.type.Types;
@@ -139,6 +140,29 @@ public final class Protocol1_20_5To1_21 extends AbstractProtocol<ClientboundPack
final double accelerationPower = Math.sqrt(xPower * xPower + yPower * yPower + zPower * zPower);
wrapper.write(Types.DOUBLE, accelerationPower);
});
// Servers up to 1.20.6 resend the win game event with a value of 0 to players that already saw the credits,
// telling the client to skip the end poem and to confirm the credits right away.
// 1.21+ clients ignore the value and always open the full end poem screen instead
appendClientbound(ClientboundPackets1_20_5.GAME_EVENT, wrapper -> {
wrapper.resetReader();
final short event = wrapper.passthrough(Types.UNSIGNED_BYTE);
if (event != 4) { // Win game
return;
}
final float value = wrapper.passthrough(Types.FLOAT);
if (value >= 0.5F) { // Rounded by clients, meaning the end poem is being shown for the first time
return;
}
wrapper.cancel();
// The server only teleports the player out of the end once the client confirms the credits being over
final PacketWrapper clientCommandPacket = wrapper.create(ServerboundPackets1_20_5.CLIENT_COMMAND);
clientCommandPacket.write(Types.VAR_INT, 0); // Perform respawn
clientCommandPacket.sendToServer(Protocol1_20_5To1_21.class);
});
}
public static String mapAttributeUUID(final UUID uuid, final String name) {
@@ -17,12 +17,10 @@
*/
package com.viaversion.viaversion.protocols.v26_2to26_3;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.nbt.tag.StringTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.MappingData;
import com.viaversion.viaversion.api.minecraft.HolderSet;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.data.StructuredDataKey;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys26_2;
import com.viaversion.viaversion.api.minecraft.data.version.StructuredDataKeys26_3;
@@ -62,7 +60,6 @@ import com.viaversion.viaversion.rewriter.RecipeDisplayRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter;
import com.viaversion.viaversion.rewriter.text.NBTComponentRewriter;
import java.util.BitSet;
import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
@@ -70,32 +67,6 @@ import static com.viaversion.viaversion.util.ProtocolUtil.packetTypeMap;
public final class Protocol26_2To26_3 extends AbstractProtocol<ClientboundPacket26_1, ClientboundPacket26_3, ServerboundPacket26_1, ServerboundPacket26_3> {
public static final MappingData26_3 MAPPINGS = new MappingData26_3();
private static final String[] POT_PATTERNS = {
"angler",
"archer",
"arms_up",
"blade",
"brewer",
"burn",
"danger",
"explorer",
"flow",
"friend",
"guster",
"heart",
"heartbreak",
"howl",
"miner",
"mourner",
"plenty",
"prize",
"scrape",
"sheaf",
"shelter",
"skull",
"snort"
};
private final EntityPacketRewriter26_3 entityRewriter = new EntityPacketRewriter26_3(this);
private final BlockItemPacketRewriter26_3 itemRewriter = new BlockItemPacketRewriter26_3(this);
private final BlockRewriter<ClientboundPacket26_1> blockRewriter = new BlockPacketRewriter26_3(this);
@@ -127,14 +98,7 @@ public final class Protocol26_2To26_3 extends AbstractProtocol<ClientboundPacket
appendClientbound(ClientboundConfigurationPackets1_21_9.FINISH_CONFIGURATION, wrapper -> {
final PacketWrapper clocksPacket = wrapper.create(ClientboundConfigurationPackets26_3.REGISTRY_DATA);
clocksPacket.write(Types.STRING, "decorated_pot_pattern");
final RegistryEntry[] entries = new RegistryEntry[POT_PATTERNS.length];
for (int i = 0; i < POT_PATTERNS.length; i++) {
final String key = POT_PATTERNS[i];
final CompoundTag tag = new CompoundTag();
tag.putString("asset_id", key + "_pottery_pattern");
entries[i] = new RegistryEntry(key, tag);
}
clocksPacket.write(Types.REGISTRY_ENTRY_ARRAY, entries);
clocksPacket.write(Types.REGISTRY_ENTRY_ARRAY, MAPPINGS.potPatterns());
clocksPacket.send(Protocol26_2To26_3.class);
final PacketWrapper blockTransformersPacket = wrapper.create(ClientboundConfigurationPackets26_3.REGISTRY_DATA);
@@ -172,6 +136,19 @@ public final class Protocol26_2To26_3 extends AbstractProtocol<ClientboundPacket
componentRewriter.processTag(wrapper.user(), wrapper.passthrough(Types.TRUSTED_TAG)); // Name
componentRewriter.processTag(wrapper.user(), wrapper.passthrough(Types.TRUSTED_OPTIONAL_TAG)); // Target Name
});
// 26.3 reads the items the brewing stand slots accept from the server, older clients have them hardcoded
appendClientbound(ClientboundPackets26_1.UPDATE_RECIPES, wrapper -> {
wrapper.resetReader();
final int size = wrapper.read(Types.VAR_INT);
wrapper.write(Types.VAR_INT, size + 2);
// Copies, as later protocols rewrite the ids in place
wrapper.write(Types.STRING, "minecraft:brewing_input");
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, MAPPINGS.brewingInputIds().clone());
wrapper.write(Types.STRING, "minecraft:brewing_reagent");
wrapper.write(Types.VAR_INT_ARRAY_PRIMITIVE, MAPPINGS.brewingReagentIds().clone());
});
}
@Override
@@ -20,10 +20,68 @@ package com.viaversion.viaversion.protocols.v26_2to26_3.data;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.data.MappingDataBase;
import com.viaversion.viaversion.api.data.MappingDataLoader;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import java.util.Arrays;
public final class MappingData26_3 extends MappingDataBase {
private static final String[] BREWING_INPUTS = {
"potion",
"splash_potion",
"lingering_potion"
};
private static final String[] BREWING_REAGENTS = {
"blaze_powder",
"breeze_rod",
"cobweb",
"dragon_breath",
"fermented_spider_eye",
"ghast_tear",
"glistering_melon_slice",
"glowstone_dust",
"golden_carrot",
"gunpowder",
"magma_cream",
"nether_wart",
"phantom_membrane",
"pufferfish",
"rabbit_foot",
"redstone",
"slime_block",
"spider_eye",
"stone",
"sugar",
"turtle_helmet"
};
private static final String[] POT_PATTERNS = {
"angler",
"archer",
"arms_up",
"blade",
"brewer",
"burn",
"danger",
"explorer",
"flow",
"friend",
"guster",
"heart",
"heartbreak",
"howl",
"miner",
"mourner",
"plenty",
"prize",
"scrape",
"sheaf",
"shelter",
"skull",
"snort"
};
private CompoundTag blockTransformerRegistry;
private int[] brewingInputIds;
private int[] brewingReagentIds;
public MappingData26_3() {
super("26.2", "26.3");
@@ -32,9 +90,31 @@ public final class MappingData26_3 extends MappingDataBase {
@Override
protected void loadExtras(final CompoundTag data) {
blockTransformerRegistry = MappingDataLoader.INSTANCE.loadNBTFromFile("block-transformer-registry-26.3.nbt");
brewingInputIds = Arrays.stream(BREWING_INPUTS).mapToInt(identifier -> this.getFullItemMappings().mappedId(identifier)).toArray();
brewingReagentIds = Arrays.stream(BREWING_REAGENTS).mapToInt(identifier -> this.getFullItemMappings().mappedId(identifier)).toArray();
}
public CompoundTag blockTransformerRegistry() {
return blockTransformerRegistry;
}
public RegistryEntry[] potPatterns() {
final RegistryEntry[] entries = new RegistryEntry[POT_PATTERNS.length];
for (int i = 0; i < POT_PATTERNS.length; i++) {
final String key = POT_PATTERNS[i];
final CompoundTag tag = new CompoundTag();
tag.putString("asset_id", key + "_pottery_pattern");
entries[i] = new RegistryEntry(key, tag);
}
return entries;
}
public int[] brewingInputIds() {
return brewingInputIds;
}
public int[] brewingReagentIds() {
return brewingReagentIds;
}
}
@@ -17,8 +17,6 @@
*/
package com.viaversion.viaversion.protocols.v26_2to26_3.rewriter;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.TrackedEntity;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes26_3;
import com.viaversion.viaversion.api.minecraft.entitydata.types.EntityDataTypes26_3;
@@ -32,13 +30,14 @@ import com.viaversion.viaversion.protocols.v1_21_11to26_1.packet.ServerboundPack
import com.viaversion.viaversion.protocols.v26_2to26_3.Protocol26_2To26_3;
import com.viaversion.viaversion.protocols.v26_2to26_3.packet.ClientboundPackets26_3;
import com.viaversion.viaversion.protocols.v26_2to26_3.packet.ServerboundPackets26_3;
import com.viaversion.viaversion.protocols.v26_2to26_3.storage.LastMovement;
import com.viaversion.viaversion.rewriter.EntityRewriter;
public final class EntityPacketRewriter26_3 extends EntityRewriter<ClientboundPacket26_1, Protocol26_2To26_3> {
private static final int SINGLE_STEP = 1 << 1;
private static final int MAX_TICK_OFFSET = 5;
// All entities that care about steps use 3 steps in 26.2. 26.3 still lerps every tick within each step, so this
// is equivalent
private static final int INTERPOLATION_STEP_TICKS = 3;
private static final int MAIN_HAND = 0;
private static final int OFF_HAND = 1;
private static final int CHANGE_DESTROY_DIRECTION_ACTION = 1;
@@ -51,20 +50,20 @@ public final class EntityPacketRewriter26_3 extends EntityRewriter<ClientboundPa
@Override
public void registerPackets() {
protocol.registerClientbound(ClientboundPackets26_1.MOVE_ENTITY_POS, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.VAR_INT); // Entity id
final short xa = wrapper.read(Types.SHORT);
final short ya = wrapper.read(Types.SHORT);
final short za = wrapper.read(Types.SHORT);
final boolean onGround = wrapper.read(Types.BOOLEAN);
wrapper.write(Types.VAR_INT, (onGround ? 1 : 0) | SINGLE_STEP); // Only the first bit set, otherwise empty = no step count
wrapper.write(Types.VAR_INT, tickOffset(wrapper.user(), entityId));
wrapper.write(Types.VAR_INT, INTERPOLATION_STEP_TICKS);
wrapper.write(Types.SHORT, xa);
wrapper.write(Types.SHORT, ya);
wrapper.write(Types.SHORT, za);
});
protocol.registerClientbound(ClientboundPackets26_1.MOVE_ENTITY_POS_ROT, wrapper -> {
final int entityId = wrapper.passthrough(Types.VAR_INT);
wrapper.passthrough(Types.VAR_INT); // Entity id
final short xa = wrapper.read(Types.SHORT);
final short ya = wrapper.read(Types.SHORT);
final short za = wrapper.read(Types.SHORT);
@@ -72,7 +71,7 @@ public final class EntityPacketRewriter26_3 extends EntityRewriter<ClientboundPa
final byte xRot = wrapper.read(Types.BYTE);
final boolean onGround = wrapper.read(Types.BOOLEAN);
wrapper.write(Types.VAR_INT, (onGround ? 1 : 0) | SINGLE_STEP); // Only the first bit set, otherwise empty = no extra steps
wrapper.write(Types.VAR_INT, tickOffset(wrapper.user(), entityId));
wrapper.write(Types.VAR_INT, INTERPOLATION_STEP_TICKS);
wrapper.write(Types.SHORT, xa);
wrapper.write(Types.SHORT, ya);
wrapper.write(Types.SHORT, za);
@@ -92,10 +91,13 @@ public final class EntityPacketRewriter26_3 extends EntityRewriter<ClientboundPa
protocol.registerClientbound(ClientboundPackets26_1.ENTITY_POSITION_SYNC, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
wrapper.write(Types.VAR_INT, 0); // Linear
wrapper.write(Types.VAR_INT, 1); // Stepped
wrapper.write(Types.VAR_INT, 1); // 1 step
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
wrapper.write(Types.VAR_INT, INTERPOLATION_STEP_TICKS);
wrapper.read(Types.DOUBLE); // Delta x
wrapper.read(Types.DOUBLE); // Delta y
@@ -177,30 +179,6 @@ public final class EntityPacketRewriter26_3 extends EntityRewriter<ClientboundPa
wrapper.write(Types.OPTIONAL_VAR_INT, previousGamemode == -1 ? null : (int) previousGamemode);
}
// To make the stepped interpolation handler work properly, the offset has to match the server's actual updateInterval (e.g. 2 for players).
// An offset that's too small makes the client snap, a too large one makes it queue up steps and fall behind - this makes it match the actual rate.
// Estimate it from the time between move packets; errors cancel out across consecutive packets as the timestamps telescope.
private int tickOffset(final UserConnection connection, final int entityId) {
final TrackedEntity entity = tracker(connection).entity(entityId);
if (entity == null) {
return 1;
}
final long now = System.nanoTime();
final LastMovement timestamp = entity.get(LastMovement.class);
if (timestamp == null) {
entity.put(new LastMovement(now));
return 1;
}
final long deltaMillis = (now - timestamp.lastMovementTime()) / 1_000_000L;
timestamp.setLastMovementTime(now);
if (deltaMillis > MAX_TICK_OFFSET * 50L) {
return 1; // No recent movement. Don't stretch the first step of a new movement burst
}
return (int) Math.max(1, (deltaMillis + 25) / 50); // Round to the nearest tick count
}
@Override
protected void registerRewrites() {
final EntityDataTypes26_3 entityDataTypes = protocol.mappedTypes().entityDataTypes();
@@ -1,36 +0,0 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2026 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.v26_2to26_3.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public final class LastMovement implements StorableObject {
private long lastMovementTime;
public LastMovement(final long lastMovementTime) {
this.lastMovementTime = lastMovementTime;
}
public long lastMovementTime() {
return lastMovementTime;
}
public void setLastMovementTime(final long lastMovementTime) {
this.lastMovementTime = lastMovementTime;
}
}
+2 -2
View File
@@ -1,10 +1,10 @@
# Project properties - we put these here so they can be modified without causing a recompile of the build scripts
projectVersion=5.12.0
projectVersion=5.12.1-SNAPSHOT
# Smile emoji (note that modrinth may not have added the version on release yet)
mcVersions=26.3, 26.2, 26.1.2, 26.1.1, 26.1, 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.2, 1.21.1, 1.21, 1.20.6, 1.20.5, 1.20.4, 1.20.3, 1.20.2, 1.20.1, 1.20, 1.19.4, 1.19.3, 1.19.2, 1.19.1, 1.19, 1.18.2, 1.18.1, 1.18, 1.17.1, 1.17, 1.16.5, 1.16.4, 1.16.3, 1.16.2, 1.16.1, 1.16, 1.15.2, 1.15.1, 1.15, 1.14.4, 1.14.3, 1.14.2, 1.14.1, 1.14, 1.13.2, 1.13.1, 1.13, 1.12.2, 1.12.1, 1.12, 1.11.2, 1.11.1, 1.11, 1.10.2, 1.10.1, 1.10, 1.9.4, 1.9.3, 1.9.2, 1.9.1, 1.9, 1.8.9
mcVersionRange=1.8-26.3
velocityVersion=3.4-3.5
velocityVersion=3.4-4.2.0
# Gradle properties
org.gradle.daemon=true
@@ -17,6 +17,8 @@
*/
package com.viaversion.viaversion.velocity.listeners;
import java.util.UUID;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.PluginMessageEvent;
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
@@ -24,6 +26,7 @@ import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.viaversion.viaversion.VelocityPlugin;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.ConnectionManager;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.connection.ConnectionDetails;
@@ -32,9 +35,17 @@ public class ConnectionDetailsListener {
@Subscribe
public void onPostServerJoin(final ServerPostConnectEvent event) {
final UserConnection connection = Via.getManager().getConnectionManager().getClientConnection(event.getPlayer().getUniqueId());
if (connection != null) {
ConnectionDetails.sendConnectionDetails(connection, ConnectionDetails.PROXY_CHANNEL);
ConnectionManager manager = Via.getManager().getConnectionManager();
UUID uuid = event.getPlayer().getUniqueId();
UserConnection frontend = manager.getServerConnection(uuid);
if (frontend != null) {
ConnectionDetails.sendPlayerDetails(frontend, ConnectionDetails.PROXY_CHANNEL);
}
UserConnection backend = manager.getClientConnection(uuid);
if (backend != null) {
ConnectionDetails.sendServerDetails(backend, ConnectionDetails.PROXY_CHANNEL);
}
}