More work on the snapshot

This commit is contained in:
Nassim Jahnke 2023-08-03 18:36:30 +10:00
parent 6dfd4747ee
commit 6586fc1436
13 changed files with 306 additions and 99 deletions

View File

@ -77,6 +77,7 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
/** /**
* Creates a protocol with automated id mapping if the respective packet type classes are not null. * Creates a protocol with automated id mapping if the respective packet type classes are not null.
* They are also required to track the CONFIGURATION state.
*/ */
protected AbstractProtocol(@Nullable Class<CU> unmappedClientboundPacketType, @Nullable Class<CM> mappedClientboundPacketType, protected AbstractProtocol(@Nullable Class<CU> unmappedClientboundPacketType, @Nullable Class<CM> mappedClientboundPacketType,
@Nullable Class<SM> mappedServerboundPacketType, @Nullable Class<SU> unmappedServerboundPacketType) { @Nullable Class<SM> mappedServerboundPacketType, @Nullable Class<SU> unmappedServerboundPacketType) {
@ -97,6 +98,12 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
registerPackets(); registerPackets();
// Register the rest of the ids with no handlers if necessary // Register the rest of the ids with no handlers if necessary
final SU configurationAcknowledgedPacket = configurationAcknowledgedPacket();
if (configurationAcknowledgedPacket != null) {
// TODO Only register one of those handlers, possibly somehow in the base protocol
registerServerbound(configurationAcknowledgedPacket, wrapper -> wrapper.user().getProtocolInfo().setState(State.CONFIGURATION));
}
if (unmappedClientboundPacketType != null && mappedClientboundPacketType != null if (unmappedClientboundPacketType != null && mappedClientboundPacketType != null
&& unmappedClientboundPacketType != mappedClientboundPacketType) { && unmappedClientboundPacketType != mappedClientboundPacketType) {
registerPacketIdChanges( registerPacketIdChanges(
@ -208,6 +215,12 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
return Collections.emptyMap(); return Collections.emptyMap();
} }
protected @Nullable SU configurationAcknowledgedPacket() {
final Map<State, PacketTypeMap<SU>> packetTypes = packetTypesProvider.unmappedServerboundPacketTypes();
final PacketTypeMap<SU> packetTypeMap = packetTypes.get(State.PLAY);
return packetTypeMap != null ? packetTypeMap.typeByName("CONFIGURATION_ACKNOWLEDGED") : null;
}
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
@Override @Override
@ -361,7 +374,7 @@ public abstract class AbstractProtocol<CU extends ClientboundPacketType, CM exte
} }
} }
private void throwRemapError(Direction direction, State state, int unmappedPacketId, int mappedPacketId, InformativeException e) throws InformativeException { protected void throwRemapError(Direction direction, State state, int unmappedPacketId, int mappedPacketId, InformativeException e) throws InformativeException {
// Don't print errors during handshake/login/status // Don't print errors during handshake/login/status
if (state != State.PLAY && direction == Direction.SERVERBOUND && !Via.getManager().debugHandler().enabled()) { if (state != State.PLAY && direction == Direction.SERVERBOUND && !Via.getManager().debugHandler().enabled()) {
e.setShouldBePrinted(false); e.setShouldBePrinted(false);

View File

@ -59,6 +59,7 @@ import com.viaversion.viaversion.api.type.types.VarIntArrayType;
import com.viaversion.viaversion.api.type.types.VarIntType; import com.viaversion.viaversion.api.type.types.VarIntType;
import com.viaversion.viaversion.api.type.types.VarLongType; import com.viaversion.viaversion.api.type.types.VarLongType;
import com.viaversion.viaversion.api.type.types.VoidType; import com.viaversion.viaversion.api.type.types.VoidType;
import com.viaversion.viaversion.api.type.types.minecraft.NamelessNBTType;
import com.viaversion.viaversion.api.type.types.minecraft.BlockChangeRecordType; import com.viaversion.viaversion.api.type.types.minecraft.BlockChangeRecordType;
import com.viaversion.viaversion.api.type.types.minecraft.ChunkPositionType; import com.viaversion.viaversion.api.type.types.minecraft.ChunkPositionType;
import com.viaversion.viaversion.api.type.types.minecraft.EulerAngleType; import com.viaversion.viaversion.api.type.types.minecraft.EulerAngleType;
@ -165,6 +166,7 @@ public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
public static final Type<Vector3f> VECTOR3F = new Vector3fType(); public static final Type<Vector3f> VECTOR3F = new Vector3fType();
public static final Type<Quaternion> QUATERNION = new QuaternionType(); public static final Type<Quaternion> QUATERNION = new QuaternionType();
public static final Type<CompoundTag> NBT = new NBTType(); public static final Type<CompoundTag> NBT = new NBTType();
public static final Type<CompoundTag> NAMELESS_NBT = new NamelessNBTType();
public static final Type<CompoundTag[]> NBT_ARRAY = new ArrayType<>(Type.NBT); public static final Type<CompoundTag[]> NBT_ARRAY = new ArrayType<>(Type.NBT);
public static final Type<GlobalPosition> GLOBAL_POSITION = new GlobalPositionType(); public static final Type<GlobalPosition> GLOBAL_POSITION = new GlobalPositionType();
public static final Type<GlobalPosition> OPTIONAL_GLOBAL_POSITION = new GlobalPositionType.OptionalGlobalPositionType(); public static final Type<GlobalPosition> OPTIONAL_GLOBAL_POSITION = new GlobalPositionType.OptionalGlobalPositionType();

View File

@ -22,15 +22,15 @@
*/ */
package com.viaversion.viaversion.api.type.types.minecraft; package com.viaversion.viaversion.api.type.types.minecraft;
import com.github.steveice10.opennbt.NBTIO;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.limiter.TagLimiter; import com.github.steveice10.opennbt.tag.limiter.TagLimiter;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.ByteBufOutputStream;
import java.io.DataInput; import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.DataOutput;
import java.io.IOException;
public class NBTType extends Type<CompoundTag> { public class NBTType extends Type<CompoundTag> {
@ -43,23 +43,50 @@ public class NBTType extends Type<CompoundTag> {
@Override @Override
public CompoundTag read(ByteBuf buffer) throws Exception { public CompoundTag read(ByteBuf buffer) throws Exception {
int readerIndex = buffer.readerIndex(); return read(buffer, true);
byte b = buffer.readByte();
if (b == 0) {
return null;
} else {
buffer.readerIndex(readerIndex);
return NBTIO.readTag((DataInput) new ByteBufInputStream(buffer), TagLimiter.create(MAX_NBT_BYTES, MAX_NESTING_LEVEL));
}
} }
@Override @Override
public void write(ByteBuf buffer, CompoundTag object) throws Exception { public void write(ByteBuf buffer, CompoundTag object) throws Exception {
if (object == null) { write(buffer, object, "");
buffer.writeByte(0); }
} else {
ByteBufOutputStream bytebufStream = new ByteBufOutputStream(buffer); public static CompoundTag read(final ByteBuf buffer, final boolean readName) throws Exception {
NBTIO.writeTag((DataOutput) bytebufStream, object); final int readerIndex = buffer.readerIndex();
final byte b = buffer.readByte();
if (b == 0) {
return null;
} }
buffer.readerIndex(readerIndex);
final ByteBufInputStream in = new ByteBufInputStream(buffer);
final int id = in.readByte();
if (id != CompoundTag.ID) {
throw new IOException(String.format("Expected root tag to be a CompoundTag, was %s", id));
}
if (readName) {
in.skipBytes(in.readUnsignedShort());
}
final TagLimiter tagLimiter = TagLimiter.create(MAX_NBT_BYTES, MAX_NESTING_LEVEL);
final CompoundTag tag = new CompoundTag();
tag.read(in, tagLimiter);
return tag;
}
public static void write(final ByteBuf buffer, final CompoundTag tag, final @Nullable String name) throws Exception {
if (tag == null) {
buffer.writeByte(0);
return;
}
final ByteBufOutputStream out = new ByteBufOutputStream(buffer);
out.writeByte(CompoundTag.ID);
if (name != null) {
out.writeUTF(name);
}
tag.write(out);
} }
} }

View File

@ -0,0 +1,44 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2023 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.minecraft;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.api.type.Type;
import io.netty.buffer.ByteBuf;
public class NamelessNBTType extends Type<CompoundTag> {
public NamelessNBTType() {
super(CompoundTag.class);
}
@Override
public CompoundTag read(final ByteBuf buffer) throws Exception {
return NBTType.read(buffer, false);
}
@Override
public void write(final ByteBuf buffer, final CompoundTag tag) throws Exception {
NBTType.write(buffer, tag, null);
}
}

View File

@ -23,6 +23,11 @@ import java.util.UUID;
public class BaseProtocol1_16 extends BaseProtocol1_7 { public class BaseProtocol1_16 extends BaseProtocol1_7 {
@Override
protected boolean finishLoginAfterGameprofile() {
return false; // Start CONFIGURATION phase after the serverbound ack
}
@Override @Override
protected UUID passthroughLoginUUID(final PacketWrapper wrapper) throws Exception { protected UUID passthroughLoginUUID(final PacketWrapper wrapper) throws Exception {
return wrapper.passthrough(Type.UUID); return wrapper.passthrough(Type.UUID);

View File

@ -33,10 +33,12 @@ import com.viaversion.viaversion.api.protocol.version.VersionProvider;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocol.ProtocolManagerImpl; import com.viaversion.viaversion.protocol.ProtocolManagerImpl;
import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton; import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.Protocol1_9To1_8; import com.viaversion.viaversion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
import com.viaversion.viaversion.util.ChatColorUtil; import com.viaversion.viaversion.util.ChatColorUtil;
import com.viaversion.viaversion.util.GsonUtil; import com.viaversion.viaversion.util.GsonUtil;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
@ -45,9 +47,6 @@ public class BaseProtocol1_7 extends AbstractProtocol {
@Override @Override
protected void registerPackets() { protected void registerPackets() {
/* Outgoing Packets */
// Status Response Packet
registerClientbound(ClientboundStatusPackets.STATUS_RESPONSE, new PacketHandlers() { // Status Response Packet registerClientbound(ClientboundStatusPackets.STATUS_RESPONSE, new PacketHandlers() { // Status Response Packet
@Override @Override
public void register() { public void register() {
@ -122,7 +121,9 @@ public class BaseProtocol1_7 extends AbstractProtocol {
// Login Success Packet // Login Success Packet
registerClientbound(ClientboundLoginPackets.GAME_PROFILE, wrapper -> { registerClientbound(ClientboundLoginPackets.GAME_PROFILE, wrapper -> {
ProtocolInfo info = wrapper.user().getProtocolInfo(); ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setState(State.PLAY); if (finishLoginAfterGameprofile()) {
info.setState(State.PLAY);
}
UUID uuid = passthroughLoginUUID(wrapper); UUID uuid = passthroughLoginUUID(wrapper);
info.setUuid(uuid); info.setUuid(uuid);
@ -147,7 +148,6 @@ public class BaseProtocol1_7 extends AbstractProtocol {
} }
}); });
/* Incoming Packets */
// Login Start Packet // Login Start Packet
registerServerbound(ServerboundLoginPackets.HELLO, wrapper -> { registerServerbound(ServerboundLoginPackets.HELLO, wrapper -> {
int protocol = wrapper.user().getProtocolInfo().getProtocolVersion(); int protocol = wrapper.user().getProtocolInfo().getProtocolVersion();
@ -164,6 +164,10 @@ public class BaseProtocol1_7 extends AbstractProtocol {
future.addListener(f -> wrapper.user().getChannel().close()); future.addListener(f -> wrapper.user().getChannel().close());
} }
}); });
registerServerbound(ServerboundLoginPackets.LOGIN_ACKNOWLEDGED, wrapper -> wrapper.user().getProtocolInfo().setState(State.CONFIGURATION));
// TODO AAAAAAAAAAAAAAAAA
registerServerbound(ServerboundConfigurationPackets1_20_2.FINISH_CONFIGURATION, wrapper -> wrapper.user().getProtocolInfo().setState(State.PLAY));
} }
@Override @Override
@ -188,4 +192,8 @@ public class BaseProtocol1_7 extends AbstractProtocol {
} }
return UUID.fromString(uuidString); return UUID.fromString(uuidString);
} }
protected boolean finishLoginAfterGameprofile() {
return true;
}
} }

View File

@ -17,24 +17,31 @@
*/ */
package com.viaversion.viaversion.protocols.protocol1_20_2to1_20; package com.viaversion.viaversion.protocols.protocol1_20_2to1_20;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.Entity1_19_4Types; import com.viaversion.viaversion.api.minecraft.entities.Entity1_19_4Types;
import com.viaversion.viaversion.api.protocol.AbstractProtocol; import com.viaversion.viaversion.api.protocol.AbstractProtocol;
import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.State; import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.rewriter.EntityRewriter; import com.viaversion.viaversion.api.rewriter.EntityRewriter;
import com.viaversion.viaversion.api.rewriter.ItemRewriter; import com.viaversion.viaversion.api.rewriter.ItemRewriter;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.data.entity.EntityTrackerBase; import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets; import com.viaversion.viaversion.protocols.base.ServerboundLoginPackets;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4; import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ServerboundPackets1_19_4; import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ServerboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.handler.BlockItemPacketHandler1_20_2; import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.handler.BlockItemPacketHandler1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.handler.EntityPacketHandler1_20_2; import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.handler.EntityPacketHandler1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundPackets1_20_2; import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundPackets1_20_2; import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundPackets1_20_2;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.storage.FakeProtocolState;
import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter;
import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter;
import com.viaversion.viaversion.rewriter.TagRewriter; import com.viaversion.viaversion.rewriter.TagRewriter;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.UUID; import java.util.UUID;
@ -50,12 +57,9 @@ public final class Protocol1_20_2To1_20 extends AbstractProtocol<ClientboundPack
@Override @Override
protected void registerPackets() { protected void registerPackets() {
// TODO Stopped at ForgetLevelChunk // TODO Updated NBT type used in: block entity, chunk, tag query, entity metadata data, item type, mob effect
// TODO New login packets (custom query answer, login ack)
// TODO Handle move from and to configuration state // TODO Handle Enabled features and tags before configuration phase end
// Game profile/serverbound ack -> configuration
// Client/serverbound config finish -> play
// TODO New helper methods for: join game, respawn,
// TODO Make sure Paper/Velocity handle a 0,0 uuid fine during login // TODO Make sure Paper/Velocity handle a 0,0 uuid fine during login
// Lesser: // Lesser:
@ -77,15 +81,96 @@ public final class Protocol1_20_2To1_20 extends AbstractProtocol<ClientboundPack
wrapper.write(Type.VAR_INT, (int) slot); wrapper.write(Type.VAR_INT, (int) slot);
}); });
registerClientbound(State.LOGIN, ClientboundLoginPackets.HELLO.getId(), ClientboundLoginPackets.HELLO.getId(), wrapper -> { registerServerbound(State.LOGIN, ServerboundLoginPackets.HELLO.getId(), ServerboundLoginPackets.HELLO.getId(), wrapper -> {
wrapper.passthrough(Type.STRING); // Name wrapper.passthrough(Type.STRING); // Name
final UUID uuid = wrapper.read(Type.OPTIONAL_UUID);
wrapper.write(Type.UUID, uuid != null ? uuid : new UUID(0, 0)); final UUID uuid = wrapper.read(Type.UUID);
wrapper.write(Type.OPTIONAL_UUID, uuid);
}); });
// Deal with the new CONFIGURATION protocol state the client expects
registerServerbound(State.LOGIN, ServerboundLoginPackets.LOGIN_ACKNOWLEDGED.getId(), -1, wrapper -> {
wrapper.user().get(FakeProtocolState.class).setConfigurationState(true);
wrapper.cancel();
});
registerServerbound(State.CONFIGURATION, ServerboundConfigurationPackets1_20_2.FINISH_CONFIGURATION.getId(), -1, wrapper -> {
wrapper.user().get(FakeProtocolState.class).setConfigurationState(false);
wrapper.cancel();
});
registerServerbound(State.CONFIGURATION, ServerboundConfigurationPackets1_20_2.CUSTOM_PAYLOAD.getId(), ServerboundPackets1_19_4.PLUGIN_MESSAGE.getId(), wrapper -> {
});
registerServerbound(State.CONFIGURATION, ServerboundConfigurationPackets1_20_2.KEEP_ALIVE.getId(), ServerboundPackets1_19_4.KEEP_ALIVE.getId(), wrapper -> {
});
registerServerbound(State.CONFIGURATION, ServerboundConfigurationPackets1_20_2.PONG.getId(), ServerboundPackets1_19_4.PONG.getId(), wrapper -> {
});
registerServerbound(State.CONFIGURATION, ServerboundConfigurationPackets1_20_2.RESOURCE_PACK.getId(), ServerboundPackets1_19_4.RESOURCE_PACK_STATUS.getId(), wrapper -> {
});
// Sad emoji
cancelClientbound(ClientboundPackets1_19_4.UPDATE_ENABLED_FEATURES);
registerServerbound(ServerboundPackets1_20_2.CONFIGURATION_ACKNOWLEDGED, null, wrapper -> {
wrapper.user().get(FakeProtocolState.class).setConfigurationState(false);
wrapper.cancel();
});
// TODO Check if we can just not send batches (probably fine like this)
cancelServerbound(ServerboundPackets1_20_2.CHUNK_BATCH_RECEIVED);
}
@Override
public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception {
final boolean configurationState = packetWrapper.user().get(FakeProtocolState.class).isConfigurationState();
if (direction == Direction.SERVERBOUND) {
// Redirect packets during the fake configuration phase
// This might mess up people using Via API/other protocols down the line, but such is life. We can't have different states for server and client
final State newState = configurationState ? State.CONFIGURATION : state;
super.transform(direction, newState, packetWrapper);
return;
}
// Make sure we don't send the client any packets from another protocol state
if (configurationState) {
// TODO Queue these packets to send them later
Via.getPlatform().getLogger().warning("Cancelled packet " + packetWrapper.getId() + " sent during configuration state");
packetWrapper.cancel();
super.transform(direction, state, packetWrapper);
return;
}
// Map some of them to their configuration state counterparts
final int unmappedId = packetWrapper.getId();
if (state == State.PLAY && unmappedId != ClientboundPackets1_19_4.JOIN_GAME.getId()) {
if (unmappedId == ClientboundPackets1_19_4.PLUGIN_MESSAGE.getId()) {
packetWrapper.setPacketType(ClientboundConfigurationPackets1_20_2.CUSTOM_PAYLOAD);
} else if (unmappedId == ClientboundPackets1_19_4.DISCONNECT.getId()) {
packetWrapper.setPacketType(ClientboundConfigurationPackets1_20_2.DISCONNECT);
} else if (unmappedId == ClientboundPackets1_19_4.KEEP_ALIVE.getId()) {
packetWrapper.setPacketType(ClientboundConfigurationPackets1_20_2.KEEP_ALIVE);
} else if (unmappedId == ClientboundPackets1_19_4.PING.getId()) {
packetWrapper.setPacketType(ClientboundConfigurationPackets1_20_2.PING);
} else if (unmappedId == ClientboundPackets1_19_4.RESOURCE_PACK.getId()) {
packetWrapper.setPacketType(ClientboundConfigurationPackets1_20_2.RESOURCE_PACK);
} else if (unmappedId == ClientboundPackets1_19_4.UPDATE_ENABLED_FEATURES.getId()) {
packetWrapper.setPacketType(ClientboundConfigurationPackets1_20_2.UPDATE_ENABLED_FEATURES);
} else if (unmappedId == ClientboundPackets1_19_4.TAGS.getId()) {
packetWrapper.setPacketType(ClientboundConfigurationPackets1_20_2.UPDATE_TAGS);
}
return;
}
super.transform(direction, state, packetWrapper);
}
@Override
protected @Nullable ServerboundPackets1_20_2 configurationAcknowledgedPacket() {
return null; // Don't handle it in the transitioning protocol
} }
@Override @Override
public void init(final UserConnection user) { public void init(final UserConnection user) {
user.put(new FakeProtocolState());
addEntityTracker(user, new EntityTrackerBase(user, Entity1_19_4Types.PLAYER)); addEntityTracker(user, new EntityTrackerBase(user, Entity1_19_4Types.PLAYER));
} }

View File

@ -19,12 +19,9 @@ package com.viaversion.viaversion.protocols.protocol1_20_2to1_20.handler;
import com.viaversion.viaversion.api.minecraft.metadata.ChunkPosition; import com.viaversion.viaversion.api.minecraft.metadata.ChunkPosition;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.types.Chunk1_18Type;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4; import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.rewriter.RecipeRewriter1_19_4;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.Protocol1_20_2To1_20; import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.Protocol1_20_2To1_20;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundPackets1_20_2; import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ServerboundPackets1_20_2;
import com.viaversion.viaversion.rewriter.BlockRewriter;
import com.viaversion.viaversion.rewriter.ItemRewriter; import com.viaversion.viaversion.rewriter.ItemRewriter;
public final class BlockItemPacketHandler1_20_2 extends ItemRewriter<ClientboundPackets1_19_4, ServerboundPackets1_20_2, Protocol1_20_2To1_20> { public final class BlockItemPacketHandler1_20_2 extends ItemRewriter<ClientboundPackets1_19_4, ServerboundPackets1_20_2, Protocol1_20_2To1_20> {
@ -35,27 +32,6 @@ public final class BlockItemPacketHandler1_20_2 extends ItemRewriter<Clientbound
@Override @Override
public void registerPackets() { public void registerPackets() {
final BlockRewriter<ClientboundPackets1_19_4> blockRewriter = new BlockRewriter<>(protocol, Type.POSITION1_14);
blockRewriter.registerBlockAction(ClientboundPackets1_19_4.BLOCK_ACTION);
blockRewriter.registerBlockChange(ClientboundPackets1_19_4.BLOCK_CHANGE);
blockRewriter.registerVarLongMultiBlockChange1_20(ClientboundPackets1_19_4.MULTI_BLOCK_CHANGE);
blockRewriter.registerEffect(ClientboundPackets1_19_4.EFFECT, 1010, 2001);
blockRewriter.registerChunkData1_19(ClientboundPackets1_19_4.CHUNK_DATA, Chunk1_18Type::new);
blockRewriter.registerBlockEntityData(ClientboundPackets1_19_4.BLOCK_ENTITY_DATA);
registerSetCooldown(ClientboundPackets1_19_4.COOLDOWN);
registerWindowItems1_17_1(ClientboundPackets1_19_4.WINDOW_ITEMS);
registerSetSlot1_17_1(ClientboundPackets1_19_4.SET_SLOT);
registerAdvancements1_20(ClientboundPackets1_19_4.ADVANCEMENTS, Type.FLAT_VAR_INT_ITEM);
registerEntityEquipmentArray(ClientboundPackets1_19_4.ENTITY_EQUIPMENT);
registerClickWindow1_17_1(ServerboundPackets1_20_2.CLICK_WINDOW);
registerTradeList1_19(ClientboundPackets1_19_4.TRADE_LIST);
registerCreativeInvAction(ServerboundPackets1_20_2.CREATIVE_INVENTORY_ACTION, Type.FLAT_VAR_INT_ITEM);
registerWindowPropertyEnchantmentHandler(ClientboundPackets1_19_4.WINDOW_PROPERTY);
registerSpawnParticle1_19(ClientboundPackets1_19_4.SPAWN_PARTICLE);
new RecipeRewriter1_19_4<>(protocol).register(ClientboundPackets1_19_4.DECLARE_RECIPES);
protocol.registerClientbound(ClientboundPackets1_19_4.UNLOAD_CHUNK, wrapper -> { protocol.registerClientbound(ClientboundPackets1_19_4.UNLOAD_CHUNK, wrapper -> {
final int x = wrapper.read(Type.INT); final int x = wrapper.read(Type.INT);
final int z = wrapper.read(Type.INT); final int z = wrapper.read(Type.INT);

View File

@ -20,11 +20,13 @@ package com.viaversion.viaversion.protocols.protocol1_20_2to1_20.handler;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.viaversion.viaversion.api.minecraft.entities.Entity1_19_4Types; import com.viaversion.viaversion.api.minecraft.entities.Entity1_19_4Types;
import com.viaversion.viaversion.api.minecraft.entities.EntityType; import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers; import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.types.version.Types1_20; import com.viaversion.viaversion.api.type.types.version.Types1_20;
import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4; import com.viaversion.viaversion.protocols.protocol1_19_4to1_19_3.ClientboundPackets1_19_4;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.Protocol1_20_2To1_20; import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.Protocol1_20_2To1_20;
import com.viaversion.viaversion.protocols.protocol1_20_2to1_20.packet.ClientboundConfigurationPackets1_20_2;
import com.viaversion.viaversion.rewriter.EntityRewriter; import com.viaversion.viaversion.rewriter.EntityRewriter;
public final class EntityPacketHandler1_20_2 extends EntityRewriter<ClientboundPackets1_19_4, Protocol1_20_2To1_20> { public final class EntityPacketHandler1_20_2 extends EntityRewriter<ClientboundPackets1_19_4, Protocol1_20_2To1_20> {
@ -52,10 +54,12 @@ public final class EntityPacketHandler1_20_2 extends EntityRewriter<ClientboundP
wrapper.passthrough(Type.STRING_ARRAY); // World List wrapper.passthrough(Type.STRING_ARRAY); // World List
final CompoundTag dimensionRegistry = wrapper.read(Type.NBT); // TODO AAAAAAAAAAAAAAAAAAAAA final CompoundTag dimensionRegistry = wrapper.read(Type.NBT);
final String dimensionType = wrapper.read(Type.STRING); final String dimensionType = wrapper.read(Type.STRING);
final String world = wrapper.read(Type.STRING); final String world = wrapper.read(Type.STRING);
final long seed = wrapper.read(Type.LONG); final long seed = wrapper.read(Type.LONG);
trackBiomeSize(wrapper.user(), dimensionRegistry); // Caches dimensions to access data like height later
cacheDimensionData(wrapper.user(), dimensionRegistry); // Tracks the amount of biomes sent for chunk data
wrapper.passthrough(Type.VAR_INT); // Max players wrapper.passthrough(Type.VAR_INT); // Max players
wrapper.passthrough(Type.VAR_INT); // View distance wrapper.passthrough(Type.VAR_INT); // View distance
@ -73,9 +77,23 @@ public final class EntityPacketHandler1_20_2 extends EntityRewriter<ClientboundP
wrapper.passthrough(Type.BOOLEAN); // Flat wrapper.passthrough(Type.BOOLEAN); // Flat
wrapper.passthrough(Type.OPTIONAL_GLOBAL_POSITION); // Last death position wrapper.passthrough(Type.OPTIONAL_GLOBAL_POSITION); // Last death position
wrapper.passthrough(Type.VAR_INT); // Portal cooldown wrapper.passthrough(Type.VAR_INT); // Portal cooldown
// Send configuration packets first before going into the play protocol state
final PacketWrapper registryDataPacket = wrapper.create(ClientboundConfigurationPackets1_20_2.REGISTRY_DATA);
registryDataPacket.write(Type.NAMELESS_NBT, dimensionRegistry);
registryDataPacket.send(Protocol1_20_2To1_20.class);
// Enabling features is only possible during the configuraton phase
// TODO Capture more packets after login to send them later
final PacketWrapper enableFeaturesPacket = wrapper.create(ClientboundConfigurationPackets1_20_2.UPDATE_ENABLED_FEATURES);
enableFeaturesPacket.write(Type.VAR_INT, 1);
enableFeaturesPacket.write(Type.STRING, "minecraft:vanilla");
enableFeaturesPacket.scheduleSend(Protocol1_20_2To1_20.class);
// Manually send it at the end and hope nothing breaks
wrapper.send(Protocol1_20_2To1_20.class);
wrapper.cancel();
}); });
handler(dimensionDataHandler()); // Caches dimensions to access data like height later
handler(biomeSizeTracker()); // Tracks the amount of biomes sent for chunk data
handler(worldDataTrackerHandlerByKey()); // Tracks world height and name for chunk data and entity (un)tracking handler(worldDataTrackerHandlerByKey()); // Tracks world height and name for chunk data and entity (un)tracking
} }
}); });
@ -105,16 +123,6 @@ public final class EntityPacketHandler1_20_2 extends EntityRewriter<ClientboundP
}); });
} }
@Override
protected void registerRewrites() {
registerMetaTypeHandler(Types1_20.META_TYPES.itemType, Types1_20.META_TYPES.blockStateType, Types1_20.META_TYPES.optionalBlockStateType, Types1_20.META_TYPES.particleType);
filter().filterFamily(Entity1_19_4Types.MINECART_ABSTRACT).index(11).handler((event, meta) -> {
final int blockState = meta.value();
meta.setValue(protocol.getMappingData().getNewBlockStateId(blockState));
});
}
@Override @Override
public EntityType typeFromId(final int type) { public EntityType typeFromId(final int type) {
return Entity1_19_4Types.getTypeFromId(type); return Entity1_19_4Types.getTypeFromId(type);

View File

@ -34,8 +34,8 @@ public enum ClientboundPackets1_20_2 implements ClientboundPacketType {
BLOCK_CHANGE, // 0x0A BLOCK_CHANGE, // 0x0A
BOSSBAR, // 0x0B BOSSBAR, // 0x0B
SERVER_DIFFICULTY, // 0x0C SERVER_DIFFICULTY, // 0x0C
CHUNK_BATCH_FINISHED, // 0x0D // TODO AAAAAAAAAAAAAAAAAAAAAAAAA CHUNK_BATCH_FINISHED, // 0x0D
CHUNK_BATCH_START, // 0x0E // TODO AAAAAAAAAAAAAAAAAAAAAAAAA CHUNK_BATCH_START, // 0x0E
CHUNK_BIOMES, // 0x0F CHUNK_BIOMES, // 0x0F
CLEAR_TITLES, // 0x10 CLEAR_TITLES, // 0x10
TAB_COMPLETE, // 0x11 TAB_COMPLETE, // 0x11
@ -46,7 +46,7 @@ public enum ClientboundPackets1_20_2 implements ClientboundPacketType {
SET_SLOT, // 0x16 SET_SLOT, // 0x16
COOLDOWN, // 0x17 COOLDOWN, // 0x17
CUSTOM_CHAT_COMPLETIONS, // 0x18 CUSTOM_CHAT_COMPLETIONS, // 0x18
PLUGIN_MESSAGE, // 0x19 // TODO AAAAAAAAAAAAAAAAAAAAAAAAA PLUGIN_MESSAGE, // 0x19
DAMAGE_EVENT, // 0x1A DAMAGE_EVENT, // 0x1A
DELETE_CHAT_MESSAGE, // 0x1B DELETE_CHAT_MESSAGE, // 0x1B
DISCONNECT, // 0x1C DISCONNECT, // 0x1C
@ -122,7 +122,7 @@ public enum ClientboundPackets1_20_2 implements ClientboundPacketType {
TITLE_TIMES, // 0x62 TITLE_TIMES, // 0x62
ENTITY_SOUND, // 0x63 ENTITY_SOUND, // 0x63
SOUND, // 0x64 SOUND, // 0x64
START_CONFIGURATION, // 0x65 // TODO AAAAAAAAAAAAAAAAAAAAAAAAA START_CONFIGURATION, // 0x65
STOP_SOUND, // 0x66 STOP_SOUND, // 0x66
SYSTEM_CHAT, // 0x67 SYSTEM_CHAT, // 0x67
TAB_LIST, // 0x68 TAB_LIST, // 0x68

View File

@ -28,15 +28,15 @@ public enum ServerboundPackets1_20_2 implements ServerboundPacketType {
CHAT_COMMAND, // 0x04 CHAT_COMMAND, // 0x04
CHAT_MESSAGE, // 0x05 CHAT_MESSAGE, // 0x05
CHAT_SESSION_UPDATE, // 0x06 CHAT_SESSION_UPDATE, // 0x06
CHUNK_BATCH_RECEIVED, // 0x07 // TODO AAAAAAAAAAAAAAAAAAAAAAAAA CHUNK_BATCH_RECEIVED, // 0x07
CLIENT_STATUS, // 0x08 CLIENT_STATUS, // 0x08
CLIENT_SETTINGS, // 0x09 CLIENT_SETTINGS, // 0x09
TAB_COMPLETE, // 0x0A TAB_COMPLETE, // 0x0A
CONFIGURATION_ACKNOWLEDGED, // 0x0B // TODO AAAAAAAAAAAAAAAAAAAAAAAAA CONFIGURATION_ACKNOWLEDGED, // 0x0B
CLICK_WINDOW_BUTTON, // 0x0C CLICK_WINDOW_BUTTON, // 0x0C
CLICK_WINDOW, // 0x0D CLICK_WINDOW, // 0x0D
CLOSE_WINDOW, // 0x0E CLOSE_WINDOW, // 0x0E
PLUGIN_MESSAGE, // 0x0F // TODO AAAAAAAAAAAAAAAAAAAAAAAAA PLUGIN_MESSAGE, // 0x0F
EDIT_BOOK, // 0x10 EDIT_BOOK, // 0x10
ENTITY_NBT_REQUEST, // 0x11 ENTITY_NBT_REQUEST, // 0x11
INTERACT_ENTITY, // 0x12 INTERACT_ENTITY, // 0x12

View File

@ -0,0 +1,38 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2023 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_20_2to1_20.storage;
import com.viaversion.viaversion.api.connection.StorableObject;
public class FakeProtocolState implements StorableObject {
private boolean configurationState;
public boolean isConfigurationState() {
return configurationState;
}
public void setConfigurationState(final boolean configurationState) {
this.configurationState = configurationState;
}
@Override
public boolean clearOnServerSwitch() {
return false;
}
}

View File

@ -45,6 +45,8 @@ import com.viaversion.viaversion.data.entity.DimensionDataImpl;
import com.viaversion.viaversion.rewriter.meta.MetaFilter; import com.viaversion.viaversion.rewriter.meta.MetaFilter;
import com.viaversion.viaversion.rewriter.meta.MetaHandlerEvent; import com.viaversion.viaversion.rewriter.meta.MetaHandlerEvent;
import com.viaversion.viaversion.rewriter.meta.MetaHandlerEventImpl; import com.viaversion.viaversion.rewriter.meta.MetaHandlerEventImpl;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
@ -52,7 +54,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.Nullable;
public abstract class EntityRewriter<C extends ClientboundPacketType, T extends Protocol<C, ?, ?, ?>> public abstract class EntityRewriter<C extends ClientboundPacketType, T extends Protocol<C, ?, ?, ?>>
extends RewriterBase<T> implements com.viaversion.viaversion.api.rewriter.EntityRewriter<T> { extends RewriterBase<T> implements com.viaversion.viaversion.api.rewriter.EntityRewriter<T> {
@ -468,32 +469,32 @@ public abstract class EntityRewriter<C extends ClientboundPacketType, T extends
} }
public PacketHandler biomeSizeTracker() { public PacketHandler biomeSizeTracker() {
return wrapper -> { return wrapper -> trackBiomeSize(wrapper.user(), wrapper.get(Type.NBT, 0));
final CompoundTag registry = wrapper.get(Type.NBT, 0); }
final CompoundTag biomeRegistry = registry.get("minecraft:worldgen/biome");
final ListTag biomes = biomeRegistry.get("value"); public void trackBiomeSize(final UserConnection connection, final CompoundTag registry) {
tracker(wrapper.user()).setBiomesSent(biomes.size()); final CompoundTag biomeRegistry = registry.get("minecraft:worldgen/biome");
}; final ListTag biomes = biomeRegistry.get("value");
tracker(connection).setBiomesSent(biomes.size());
}
public PacketHandler dimensionDataHandler() {
return wrapper -> cacheDimensionData(wrapper.user(), wrapper.get(Type.NBT, 0));
} }
/** /**
* Returns a handler to cache dimension data, later used to get height values and other important info. * Caches dimension data, later used to get height values and other important info.
*
* @return handler to cache dimension data
*/ */
public PacketHandler dimensionDataHandler() { public void cacheDimensionData(final UserConnection connection, final CompoundTag registry) {
return wrapper -> { final ListTag dimensions = ((CompoundTag) registry.get("minecraft:dimension_type")).get("value");
final CompoundTag tag = wrapper.get(Type.NBT, 0); final Map<String, DimensionData> dimensionDataMap = new HashMap<>(dimensions.size());
final ListTag dimensions = ((CompoundTag) tag.get("minecraft:dimension_type")).get("value"); for (final Tag dimension : dimensions) {
final Map<String, DimensionData> dimensionDataMap = new HashMap<>(dimensions.size()); final CompoundTag dimensionCompound = (CompoundTag) dimension;
for (final Tag dimension : dimensions) { final CompoundTag element = dimensionCompound.get("element");
final CompoundTag dimensionCompound = (CompoundTag) dimension; final String name = (String) dimensionCompound.get("name").getValue();
final CompoundTag element = dimensionCompound.get("element"); dimensionDataMap.put(name, new DimensionDataImpl(element));
final String name = (String) dimensionCompound.get("name").getValue(); }
dimensionDataMap.put(name, new DimensionDataImpl(element)); tracker(connection).setDimensions(dimensionDataMap);
}
tracker(wrapper.user()).setDimensions(dimensionDataMap);
};
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------