From 4e1d4a75b2b3d5a215f10b340559bc599b8b37ab Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Mon, 19 Feb 2024 22:37:51 +0100 Subject: [PATCH] Small refactors around ProtocolPipeline and concurrent collections Make concurrency handling in ProtocolPipelineImpl more defensive, as generally the pipeline is expected to never be called from multiple threads. The only case to look out for is pipeline additions during protocol transformation in a base protocol --- api/build.gradle.kts | 2 - .../com/viaversion/viaversion/api/ViaAPI.java | 2 +- .../api/protocol/ProtocolPipeline.java | 18 ++- .../api/protocol/packet/PacketWrapper.java | 23 ++- .../kotlin/via.shadow-conventions.gradle.kts | 6 - .../bungee/handlers/BungeeServerHandler.java | 19 +-- .../data/entity/EntityTrackerBase.java | 4 +- .../protocol/ProtocolPipelineImpl.java | 141 ++++++++++++------ .../protocol/packet/PacketWrapperImpl.java | 116 ++++++-------- .../VersionedPacketTransformerImpl.java | 41 ++--- .../protocols/base/BaseProtocol.java | 19 ++- .../protocols/base/BaseProtocol1_7.java | 2 +- .../storage/EntityTracker1_11.java | 4 +- .../storage/BlockStorage.java | 4 +- .../storage/EntityTracker1_14.java | 8 +- .../storage/EntityTracker1_9.java | 30 ++-- gradle/libs.versions.toml | 3 - 17 files changed, 235 insertions(+), 207 deletions(-) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 8a1a3cd88..13551a9cd 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -16,8 +16,6 @@ sourceSets { dependencies { api(libs.fastutil) - api(libs.flare) - api(libs.flareFastutil) api(libs.vianbt) api(libs.gson) implementation(rootProject.libs.text) { diff --git a/api/src/main/java/com/viaversion/viaversion/api/ViaAPI.java b/api/src/main/java/com/viaversion/viaversion/api/ViaAPI.java index 5b7c2b89c..c69d01d20 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/ViaAPI.java +++ b/api/src/main/java/com/viaversion/viaversion/api/ViaAPI.java @@ -66,7 +66,7 @@ public interface ViaAPI { * @return API version incremented with meaningful API changes */ default int apiVersion() { - return 24; + return 25; } /** diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPipeline.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPipeline.java index 3876a65a0..926a6ca97 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPipeline.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPipeline.java @@ -23,6 +23,7 @@ package com.viaversion.viaversion.api.protocol; import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.packet.Direction; import java.util.Collection; import java.util.List; import org.checkerframework.checker.nullness.qual.Nullable; @@ -61,25 +62,34 @@ public interface ProtocolPipeline extends SimpleProtocol { * @param pipeClass protocol class * @param

protocol * @return protocol from class - * @see #contains(Class) - * @see ProtocolManager#getProtocol(Class) for a faster implementation + * @deprecated use {@link ProtocolManager#getProtocol(Class)} and/or {@link #contains(Class)} */ + @Deprecated @Nullable

P getProtocol(Class

pipeClass); + List pipes(@Nullable Class protocolClass, boolean skipCurrentPipeline, Direction direction); + /** - * Returns the list of protocols this pipeline contains. + * Returns the list of protocols this pipeline contains, lead by base protocols. * * @return immutable list of protocols in this pipe */ List pipes(); /** - * Returns the list of protocols this pipeline contains in reversed order. + * Returns the list of protocols this pipeline contains in reversed order, although still lead by base protocols. * * @return immutable list of protocols in reversed direction */ List reversedPipes(); + /** + * Returns the number of base protocols in this pipeline. + * + * @return the number of base protocols in this pipeline + */ + int baseProtocolCount(); + /** * Returns whether this pipe has protocols that are not base protocols, as given by {@link Protocol#isBaseProtocol()}. * diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/packet/PacketWrapper.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/packet/PacketWrapper.java index e10b131e5..23f02713a 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/packet/PacketWrapper.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/packet/PacketWrapper.java @@ -92,6 +92,7 @@ public interface PacketWrapper { * @param index The index of the part (relative to the type) * @return True if the type is at the index */ + @Deprecated boolean is(Type type, int index); /** @@ -212,11 +213,11 @@ public interface PacketWrapper { * (Sends it after current) * Also returns the packets ChannelFuture * - * @param packetProtocol The protocol version of the packet. - * @return The packets ChannelFuture + * @param protocolClass the protocol class to start from in the pipeline + * @return new ChannelFuture for the write operation * @throws Exception if it fails to write */ - ChannelFuture sendFuture(Class packetProtocol) throws Exception; + ChannelFuture sendFuture(Class protocolClass) throws Exception; /** * @deprecated misleading; use {@link #sendRaw()}. This method will be removed in 5.0.0 @@ -287,18 +288,24 @@ public interface PacketWrapper { * * @param direction protocol direction * @param state protocol state - * @param index index to start from, will be reversed depending on the reverse parameter * @param pipeline protocol pipeline - * @param reverse whether the array should be looped in reverse, will also reverse the given index - * @return The current packetwrapper * @throws Exception If it fails to transform a packet, exception will be thrown */ + void apply(Direction direction, State state, List pipeline) throws Exception; + + /** + * @deprecated use {@link #apply(Direction, State, List)} + */ + @Deprecated PacketWrapper apply(Direction direction, State state, int index, List pipeline, boolean reverse) throws Exception; /** - * @see #apply(Direction, State, int, List, boolean) + * @deprecated use {@link #apply(Direction, State, List)} */ - PacketWrapper apply(Direction direction, State state, int index, List pipeline) throws Exception; + @Deprecated + default PacketWrapper apply(Direction direction, State state, int index, List pipeline) throws Exception { + return apply(direction, state, index, pipeline, false); + } /** * Check if this packet is cancelled. diff --git a/build-logic/src/main/kotlin/via.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/via.shadow-conventions.gradle.kts index 15ee2df92..eb9926d0b 100644 --- a/build-logic/src/main/kotlin/via.shadow-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/via.shadow-conventions.gradle.kts @@ -25,7 +25,6 @@ fun ShadowJar.configureRelocations() { 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") - relocate("space.vectrix.flare", "com.viaversion.viaversion.libs.flare") relocate("net.lenni0451.mcstructs", "com.viaversion.viaversion.libs.mcstructs") } @@ -49,9 +48,4 @@ fun ShadowJar.configureExcludes() { exclude("it/unimi/dsi/fastutil/*/*Big*") exclude("it/unimi/dsi/fastutil/*/*Synchronized*") exclude("it/unimi/dsi/fastutil/*/*Unmodifiable*") - // Flare - only need int maps - exclude("space/vectrix/flare/fastutil/*Double*") - exclude("space/vectrix/flare/fastutil/*Float*") - exclude("space/vectrix/flare/fastutil/*Long*") - exclude("space/vectrix/flare/fastutil/*Short*") } diff --git a/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeServerHandler.java b/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeServerHandler.java index 25b039ae2..4ebe2350d 100644 --- a/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeServerHandler.java +++ b/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeServerHandler.java @@ -44,6 +44,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.event.ServerConnectEvent; @@ -194,18 +195,15 @@ public class BungeeServerHandler implements Listener { ProtocolPipeline pipeline = user.getProtocolInfo().getPipeline(); user.clearStoredObjects(true); pipeline.cleanPipes(); - if (protocolPath == null) { + if (protocolPath != null) { + info.setServerProtocolVersion(serverProtocolVersion); + pipeline.add(protocolPath.stream().map(ProtocolPathEntry::protocol).collect(Collectors.toList())); + } else { // TODO Check Bungee Supported Protocols? *shrugs* serverProtocolVersion = info.protocolVersion(); - } else { - List protocols = new ArrayList<>(protocolPath.size()); - for (ProtocolPathEntry entry : protocolPath) { - protocols.add(entry.protocol()); - } - pipeline.add(protocols); + info.setServerProtocolVersion(serverProtocolVersion); } - info.setServerProtocolVersion(serverProtocolVersion); // Add version-specific base Protocol pipeline.add(Via.getManager().getProtocolManager().getBaseProtocol(serverProtocolVersion)); @@ -254,11 +252,6 @@ public class BungeeServerHandler implements Listener { user.setActive(protocolPath != null); - // Init all protocols TODO check if this can get moved up to the previous for loop, and doesn't require the pipeline to already exist. - for (Protocol protocol : pipeline.pipes()) { - protocol.init(user); - } - ProxiedPlayer player = storage.getPlayer(); EntityTracker1_9 newTracker = user.getEntityTracker(Protocol1_9To1_8.class); if (newTracker != null && Via.getConfig().isAutoTeam()) { diff --git a/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java b/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java index 3d7548e8c..bcaaf0a94 100644 --- a/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java +++ b/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java @@ -28,13 +28,13 @@ import com.viaversion.viaversion.api.data.entity.TrackedEntity; import com.viaversion.viaversion.api.minecraft.entities.EntityType; import com.viaversion.viaversion.util.Key; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import java.util.Collections; import java.util.Map; import org.checkerframework.checker.nullness.qual.Nullable; -import space.vectrix.flare.fastutil.Int2ObjectSyncMap; public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeListener { - private final Int2ObjectMap entities = Int2ObjectSyncMap.hashmap(); + private final Int2ObjectMap entities = new Int2ObjectOpenHashMap<>(); private final UserConnection connection; private final EntityType playerType; private int clientEntityId = -1; diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPipelineImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPipelineImpl.java index 9b014d2a7..97bce8082 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPipelineImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPipelineImpl.java @@ -18,6 +18,7 @@ package com.viaversion.viaversion.protocol; import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.ProtocolInfo; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.debug.DebugHandler; import com.viaversion.viaversion.api.protocol.AbstractSimpleProtocol; @@ -31,19 +32,16 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.NoSuchElementException; import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.logging.Level; import org.checkerframework.checker.nullness.qual.Nullable; public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements ProtocolPipeline { - private final UserConnection userConnection; - /** - * Protocol list ordered from client to server transformation with the base protocols at the end. - */ - private final List protocolList = new CopyOnWriteArrayList<>(); + private final List protocolList = new ArrayList<>(); private final Set> protocolSet = new HashSet<>(); - private List reversedProtocolList = new CopyOnWriteArrayList<>(); + private final UserConnection userConnection; + private List reversedProtocolList = new ArrayList<>(); private int baseProtocols; public ProtocolPipelineImpl(UserConnection userConnection) { @@ -53,13 +51,9 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot } @Override - protected synchronized void registerPackets() { + protected void registerPackets() { // This is a pipeline so we register basic pipes - final Protocol baseProtocol = Via.getManager().getProtocolManager().getBaseProtocol(); - protocolList.add(baseProtocol); - reversedProtocolList.add(baseProtocol); - protocolSet.add(baseProtocol.getClass()); - baseProtocols++; + this.add(Via.getManager().getProtocolManager().getBaseProtocol()); } @Override @@ -68,15 +62,14 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot } @Override - public synchronized void add(final Protocol protocol) { + public void add(final Protocol protocol) { + reversedProtocolList.add(baseProtocols, protocol); if (protocol.isBaseProtocol()) { // Add base protocol on top of previous ones protocolList.add(baseProtocols, protocol); - reversedProtocolList.add(baseProtocols, protocol); baseProtocols++; } else { protocolList.add(protocol); - reversedProtocolList.add(0, protocol); } protocolSet.add(protocol.getClass()); @@ -84,22 +77,32 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot } @Override - public synchronized void add(final Collection protocols) { - protocolList.addAll(protocols); + public void add(final Collection protocols) { for (final Protocol protocol : protocols) { + if (protocol.isBaseProtocol()) { + throw new UnsupportedOperationException("Base protocols cannot be added in bulk"); + } + protocol.init(userConnection); protocolSet.add(protocol.getClass()); } + protocolList.addAll(protocols); refreshReversedList(); } - private synchronized void refreshReversedList() { - final List protocols = new ArrayList<>(protocolList.subList(0, this.baseProtocols)); - final List additionalProtocols = new ArrayList<>(protocolList.subList(this.baseProtocols, protocolList.size())); - Collections.reverse(additionalProtocols); - protocols.addAll(additionalProtocols); - reversedProtocolList = new CopyOnWriteArrayList<>(protocols); + private void refreshReversedList() { + final List reversedProtocols = new ArrayList<>(protocolList.size()); + // Add base protocols in regular order first + for (int i = 0; i < baseProtocols; i++) { + reversedProtocols.add(protocolList.get(i)); + } + + // Add non-base protocols in reverse order + for (int i = protocolList.size() - 1; i >= baseProtocols; i--) { + reversedProtocols.add(protocolList.get(i)); + } + reversedProtocolList = reversedProtocols; } @Override @@ -113,7 +116,7 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot } // Apply protocols - packetWrapper.apply(direction, state, 0, protocolListFor(direction)); + packetWrapper.apply(direction, state, protocolListFor(direction)); super.transform(direction, state, packetWrapper); if (debug && debugHandler.logPostPacketTransform() && debugHandler.shouldLog(packetWrapper, direction)) { @@ -126,20 +129,21 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot } private void logPacket(Direction direction, State state, PacketWrapper packetWrapper, int originalID) { - String actualUsername = packetWrapper.user().getProtocolInfo().getUsername(); + ProtocolInfo protocolInfo = userConnection.getProtocolInfo(); + String actualUsername = protocolInfo.getUsername(); String username = actualUsername != null ? actualUsername + " " : ""; Via.getPlatform().getLogger().log(Level.INFO, "{0}{1} {2}: {3} ({4}) -> {5} ({6}) [{7}] {8}", - new Object[]{ - username, - direction, - state, - originalID, - AbstractSimpleProtocol.toNiceHex(originalID), - packetWrapper.getId(), - AbstractSimpleProtocol.toNiceHex(packetWrapper.getId()), - userConnection.getProtocolInfo().protocolVersion().getName(), - packetWrapper - }); + new Object[]{ + username, + direction, + state, + originalID, + AbstractSimpleProtocol.toNiceHex(originalID), + packetWrapper.getId(), + AbstractSimpleProtocol.toNiceHex(packetWrapper.getId()), + protocolInfo.protocolVersion().getName(), + packetWrapper + }); } @Override @@ -157,6 +161,49 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot return null; } + @Override + public List pipes(@Nullable final Class protocolClass, final boolean skipCurrentPipeline, final Direction direction) { + final List protocolList = this.protocolListFor(direction); + final int index = indexOf(protocolClass, skipCurrentPipeline, protocolList); + + final List pipes = new ArrayList<>(baseProtocols + protocolList.size() - index); + // Always add base protocols to the head + for (int i = 0, size = Math.min(index, baseProtocols); i < size; i++) { + pipes.add(protocolList.get(i)); + } + + // Add remaining protocols on top + for (int i = index, size = protocolList.size(); i < size; i++) { + pipes.add(protocolList.get(i)); + } + return pipes; + } + + private int indexOf(@Nullable Class protocolClass, boolean skipCurrentPipeline, List protocolList) { + if (protocolClass == null) { + return 0; + } + + // Find the index of the given protocol + int index = -1; + for (int i = 0; i < protocolList.size(); i++) { + if (protocolList.get(i).getClass() == protocolClass) { + index = i; + break; + } + } + + if (index == -1) { + // The given protocol is not in the pipeline + throw new NoSuchElementException(protocolClass.getCanonicalName()); + } + + if (skipCurrentPipeline) { + index = Math.min(index + 1, protocolList.size()); + } + return index; + } + @Override public List pipes() { return Collections.unmodifiableList(protocolList); @@ -168,17 +215,17 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot } @Override - public boolean hasNonBaseProtocols() { - for (Protocol protocol : protocolList) { - if (!protocol.isBaseProtocol()) { - return true; - } - } - return false; + public int baseProtocolCount() { + return baseProtocols; } @Override - public synchronized void cleanPipes() { + public boolean hasNonBaseProtocols() { + return protocolList.size() > baseProtocols; + } + + @Override + public void cleanPipes() { protocolList.clear(); reversedProtocolList.clear(); protocolSet.clear(); @@ -190,7 +237,7 @@ public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements Prot @Override public String toString() { return "ProtocolPipelineImpl{" + - "protocolList=" + protocolList + - '}'; + "protocolList=" + protocolList + + '}'; } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java index 322473924..aab6945e5 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java @@ -39,13 +39,10 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; -import java.util.NoSuchElementException; import java.util.Objects; import org.checkerframework.checker.nullness.qual.Nullable; public class PacketWrapperImpl implements PacketWrapper { - private static final Protocol[] PROTOCOL_ARRAY = new Protocol[0]; - private final Deque> readableObjects = new ArrayDeque<>(); private final List> packetValues = new ArrayList<>(); private final ByteBuf inputBuffer; @@ -148,8 +145,8 @@ public class PacketWrapperImpl implements PacketWrapper { PacketValue readValue = readableObjects.poll(); Type readType = readValue.type(); if (readType == type - || (type.getBaseClass() == readType.getBaseClass() - && type.getOutputClass() == readType.getOutputClass())) { + || (type.getBaseClass() == readType.getBaseClass() + && type.getOutputClass() == readType.getOutputClass())) { //noinspection unchecked return (T) readValue.value(); } else { @@ -210,25 +207,24 @@ public class PacketWrapperImpl implements PacketWrapper { readableObjects.clear(); } - int index = 0; - for (final PacketValue packetValue : packetValues) { + for (int i = 0; i < packetValues.size(); i++) { + PacketValue packetValue = packetValues.get(i); try { packetValue.write(buffer); } catch (final Exception e) { - throw createInformativeException(e, packetValue.type(), index); + throw createInformativeException(e, packetValue.type(), i); } - index++; } writeRemaining(buffer); } private InformativeException createInformativeException(final Exception cause, final Type type, final int index) { return new InformativeException(cause) - .set("Index", index) - .set("Type", type.getTypeName()) - .set("Packet ID", this.id) - .set("Packet Type", this.packetType) - .set("Data", this.packetValues); + .set("Index", index) + .set("Type", type.getTypeName()) + .set("Packet ID", this.id) + .set("Packet Type", this.packetType) + .set("Data", this.packetValues); } @Override @@ -298,46 +294,17 @@ public class PacketWrapperImpl implements PacketWrapper { /** * Let the packet go through the protocol pipes and write it to ByteBuf * - * @param packetProtocol The protocol version of the packet. - * @param skipCurrentPipeline Skip the current pipeline - * @return Packet buffer + * @param protocolClass protocol class to send the packet from, or null to go through the full pipeline + * @param skipCurrentPipeline whether to start from the next protocol in the pipeline, or the provided one + * @return created packet buffer * @throws Exception if it fails to write */ - private ByteBuf constructPacket(Class packetProtocol, boolean skipCurrentPipeline, Direction direction) throws Exception { + private ByteBuf constructPacket(@Nullable Class protocolClass, boolean skipCurrentPipeline, Direction direction) throws Exception { + resetReader(); // Reset reader before we start + final ProtocolInfo protocolInfo = user().getProtocolInfo(); - final List pipes = direction == Direction.SERVERBOUND ? protocolInfo.getPipeline().pipes() : protocolInfo.getPipeline().reversedPipes(); - final List protocols = new ArrayList<>(); - int index = -1; - for (int i = 0; i < pipes.size(); i++) { - // Always add base protocols to the head - final Protocol protocol = pipes.get(i); - if (protocol.isBaseProtocol()) { - protocols.add(protocol); - } - - if (protocol.getClass() == packetProtocol) { - index = i; - break; - } - } - - if (index == -1) { - // The given protocol is not in the pipeline - throw new NoSuchElementException(packetProtocol.getCanonicalName()); - } - - if (skipCurrentPipeline) { - index = Math.min(index + 1, pipes.size()); - } - - // Add remaining protocols on top - protocols.addAll(pipes.subList(index, pipes.size())); - - // Reset reader before we start - resetReader(); - - // Apply other protocols - apply(direction, protocolInfo.getState(direction), 0, protocols); + final List protocols = protocolInfo.getPipeline().pipes(protocolClass, skipCurrentPipeline, direction); + apply(direction, protocolInfo.getState(direction), protocols); final ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); try { writeToBuffer(output); @@ -348,9 +315,9 @@ public class PacketWrapperImpl implements PacketWrapper { } @Override - public ChannelFuture sendFuture(Class packetProtocol) throws Exception { + public ChannelFuture sendFuture(Class protocolClass) throws Exception { if (!isCancelled()) { - ByteBuf output = constructPacket(packetProtocol, true, Direction.CLIENTBOUND); + ByteBuf output = constructPacket(protocolClass, true, Direction.CLIENTBOUND); return user().sendRawPacketFuture(output); } return user().getChannel().newFailedFuture(new Exception("Cancelled packet")); @@ -397,33 +364,36 @@ public class PacketWrapperImpl implements PacketWrapper { } @Override - public PacketWrapperImpl apply(Direction direction, State state, int index, List pipeline, boolean reverse) throws Exception { - Protocol[] array = pipeline.toArray(PROTOCOL_ARRAY); - return apply(direction, state, reverse ? array.length - 1 : index, array, reverse); // Copy to prevent from removal + public void apply(Direction direction, State state, List pipeline) throws Exception { + // Indexed loop to allow additions to the tail + for (int i = 0, size = pipeline.size(); i < size; i++) { + Protocol protocol = pipeline.get(i); + protocol.transform(direction, state, this); + resetReader(); + if (this.packetType != null) { + state = this.packetType.state(); + } + } } @Override - public PacketWrapperImpl apply(Direction direction, State state, int index, List pipeline) throws Exception { - return apply(direction, state, index, pipeline.toArray(PROTOCOL_ARRAY), false); - } - - private PacketWrapperImpl apply(Direction direction, State state, int index, Protocol[] pipeline, boolean reverse) throws Exception { + @Deprecated + public PacketWrapperImpl apply(Direction direction, State state, int index, List pipeline, boolean reverse) throws Exception { // Reset the reader after every transformation for the packetWrapper, so it can be recycled across packets - State updatedState = state; // The state might change while transforming, so we need to check for that if (reverse) { for (int i = index; i >= 0; i--) { - pipeline[i].transform(direction, updatedState, this); + pipeline.get(i).transform(direction, state, this); resetReader(); if (this.packetType != null) { - updatedState = this.packetType.state(); + state = this.packetType.state(); } } } else { - for (int i = index; i < pipeline.length; i++) { - pipeline[i].transform(direction, updatedState, this); + for (int i = index; i < pipeline.size(); i++) { + pipeline.get(i).transform(direction, state, this); resetReader(); if (this.packetType != null) { - updatedState = this.packetType.state(); + state = this.packetType.state(); } } } @@ -447,7 +417,7 @@ public class PacketWrapperImpl implements PacketWrapper { @Override public void resetReader() { - // Move all packet values to the readable for next packet. + // Move all packet values to the readable for next Protocol for (int i = packetValues.size() - 1; i >= 0; i--) { this.readableObjects.addFirst(this.packetValues.get(i)); } @@ -557,11 +527,11 @@ public class PacketWrapperImpl implements PacketWrapper { @Override public String toString() { return "PacketWrapper{" + - "type=" + packetType + - ", id=" + id + - ", values=" + packetValues + - ", readable=" + readableObjects + - '}'; + "type=" + packetType + + ", id=" + id + + ", values=" + packetValues + + ", readable=" + readableObjects + + '}'; } public static final class PacketValue { diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/packet/VersionedPacketTransformerImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/packet/VersionedPacketTransformerImpl.java index 81cbe7954..f9d544309 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocol/packet/VersionedPacketTransformerImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/protocol/packet/VersionedPacketTransformerImpl.java @@ -33,6 +33,7 @@ import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; +import java.util.stream.Collectors; import org.checkerframework.checker.nullness.qual.Nullable; public class VersionedPacketTransformerImpl implements VersionedPacketTransformer { @@ -44,7 +45,7 @@ public class VersionedPacketTransformerImpl clientboundPacketsClass, @Nullable Class serverboundPacketsClass) { Preconditions.checkNotNull(inputVersion); Preconditions.checkArgument(clientboundPacketsClass != null || serverboundPacketsClass != null, - "Either the clientbound or serverbound packets class has to be non-null"); + "Either the clientbound or serverbound packets class has to be non-null"); this.inputProtocolVersion = inputVersion; this.clientboundPacketsClass = clientboundPacketsClass; this.serverboundPacketsClass = serverboundPacketsClass; @@ -108,7 +109,7 @@ public class VersionedPacketTransformerImpl expectedPacketClass = - packet.getPacketType().direction() == Direction.CLIENTBOUND ? clientboundPacketsClass : serverboundPacketsClass; + packet.getPacketType().direction() == Direction.CLIENTBOUND ? clientboundPacketsClass : serverboundPacketsClass; if (packet.getPacketType().getClass() != expectedPacketClass) { throw new IllegalArgumentException("PacketWrapper packet type is of the wrong packet class"); } @@ -139,34 +140,40 @@ public class VersionedPacketTransformerImpl path = Via.getManager().getProtocolManager().getProtocolPath(clientProtocolVersion, serverProtocolVersion); - List protocolList = null; - if (path != null) { - protocolList = new ArrayList<>(path.size()); + if (path == null) { + if (serverProtocolVersion != clientProtocolVersion) { + throw new RuntimeException("No protocol path between client version " + clientProtocolVersion + " and server version " + serverProtocolVersion); + } + return; + } + + final List protocolList = new ArrayList<>(path.size()); + if (clientbound) { + for (int i = path.size() - 1; i >= 0; i--) { + protocolList.add(path.get(i).protocol()); + } + } else { for (ProtocolPathEntry entry : path) { protocolList.add(entry.protocol()); } - } else if (serverProtocolVersion != clientProtocolVersion) { - throw new RuntimeException("No protocol path between client version " + clientProtocolVersion + " and server version " + serverProtocolVersion); } - if (protocolList != null) { - // Reset reader and apply pipeline - packet.resetReader(); + // Reset reader and apply pipeline + packet.resetReader(); - try { - packet.apply(packetType.direction(), State.PLAY, 0, protocolList, clientbound); - } catch (Exception e) { - throw new Exception("Exception trying to transform packet between client version " + clientProtocolVersion - + " and server version " + serverProtocolVersion + ". Are you sure you used the correct input version and packet write types?", e); - } + try { + packet.apply(packetType.direction(), packetType.state(), protocolList); + } catch (Exception e) { + throw new Exception("Exception trying to transform packet between client version " + clientProtocolVersion + + " and server version " + serverProtocolVersion + ". Are you sure you used the correct input version and packet write types?", e); } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol.java b/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol.java index d33ef3c18..626bd2d72 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol.java @@ -22,6 +22,7 @@ import com.viaversion.viaversion.api.connection.ProtocolInfo; import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.protocol.AbstractProtocol; import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.protocol.ProtocolManager; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.ProtocolPipeline; import com.viaversion.viaversion.api.protocol.packet.Direction; @@ -72,18 +73,25 @@ public class BaseProtocol extends AbstractProtocol protocolPath = null; // Only allow newer clients (or 1.9.2 on 1.9.4 server if the server supports it) + ProtocolManager protocolManager = Via.getManager().getProtocolManager(); if (info.protocolVersion().newerThanOrEqualTo(serverProtocol) || Via.getPlatform().isOldClientsAllowed()) { - protocolPath = Via.getManager().getProtocolManager().getProtocolPath(info.protocolVersion(), serverProtocol); + protocolPath = protocolManager.getProtocolPath(info.protocolVersion(), serverProtocol); } - ProtocolPipeline pipeline = wrapper.user().getProtocolInfo().getPipeline(); + // Add Base Protocol + ProtocolPipeline pipeline = info.getPipeline(); + if (serverProtocol.getVersionType() != VersionType.SPECIAL) { + pipeline.add(protocolManager.getBaseProtocol(serverProtocol)); + } + + // Add other protocols if (protocolPath != null) { List protocols = new ArrayList<>(protocolPath.size()); for (ProtocolPathEntry entry : protocolPath) { protocols.add(entry.protocol()); // Ensure mapping data has already been loaded - Via.getManager().getProtocolManager().completeMappingDataLoading(entry.protocol().getClass()); + protocolManager.completeMappingDataLoading(entry.protocol().getClass()); } // Add protocols to pipeline @@ -93,11 +101,6 @@ public class BaseProtocol extends AbstractProtocol wrapper.user().getChannel().close()); } }); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_11to1_10/storage/EntityTracker1_11.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_11to1_10/storage/EntityTracker1_11.java index c9152f60f..c68cb21a0 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_11to1_10/storage/EntityTracker1_11.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_11to1_10/storage/EntityTracker1_11.java @@ -20,11 +20,11 @@ package com.viaversion.viaversion.protocols.protocol1_11to1_10.storage; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_11.EntityType; import com.viaversion.viaversion.data.entity.EntityTrackerBase; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; -import space.vectrix.flare.fastutil.Int2ObjectSyncMap; public class EntityTracker1_11 extends EntityTrackerBase { - private final IntSet holograms = Int2ObjectSyncMap.hashset(); + private final IntSet holograms = new IntOpenHashSet(); public EntityTracker1_11(UserConnection user) { super(user, EntityType.PLAYER); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/storage/BlockStorage.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/storage/BlockStorage.java index f37631f9e..7ee968213 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/storage/BlockStorage.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/storage/BlockStorage.java @@ -21,13 +21,13 @@ import com.viaversion.viaversion.api.connection.StorableObject; import com.viaversion.viaversion.api.minecraft.Position; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; +import java.util.HashMap; import java.util.Map; -import space.vectrix.flare.SyncMap; // TODO Fix memory leak lolz (only a smol one tho) public class BlockStorage implements StorableObject { private static final IntSet WHITELIST = new IntOpenHashSet(46, .99F); - private final Map blocks = SyncMap.hashmap(); + private final Map blocks = new HashMap<>(); static { // Flower pots diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/storage/EntityTracker1_14.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/storage/EntityTracker1_14.java index f7e48b85a..9dd412b68 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/storage/EntityTracker1_14.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/storage/EntityTracker1_14.java @@ -21,13 +21,13 @@ import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_14; import com.viaversion.viaversion.data.entity.EntityTrackerBase; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import space.vectrix.flare.fastutil.Int2ObjectSyncMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class EntityTracker1_14 extends EntityTrackerBase { - private final Int2ObjectMap insentientData = Int2ObjectSyncMap.hashmap(); + private final Int2ObjectMap insentientData = new Int2ObjectOpenHashMap<>(); // 0x1 = sleeping, 0x2 = riptide - private final Int2ObjectMap sleepingAndRiptideData = Int2ObjectSyncMap.hashmap(); - private final Int2ObjectMap playerEntityFlags = Int2ObjectSyncMap.hashmap(); + private final Int2ObjectMap sleepingAndRiptideData = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap playerEntityFlags = new Int2ObjectOpenHashMap<>(); private int latestTradeWindowId; private boolean forceSendCenterChunk = true; private int chunkCenterX; diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java index 29f7b34d6..924c11392 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java @@ -39,26 +39,28 @@ import com.viaversion.viaversion.protocols.protocol1_9to1_8.chat.GameMode; import com.viaversion.viaversion.protocols.protocol1_9to1_8.metadata.MetadataRewriter1_9To1_8; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.BossBarProvider; import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.EntityIdProvider; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; -import space.vectrix.flare.fastutil.Int2ObjectSyncMap; public class EntityTracker1_9 extends EntityTrackerBase { public static final String WITHER_TRANSLATABLE = "{\"translate\":\"entity.WitherBoss.name\"}"; public static final String DRAGON_TRANSLATABLE = "{\"translate\":\"entity.EnderDragon.name\"}"; - private final Int2ObjectMap uuidMap = Int2ObjectSyncMap.hashmap(); - private final Int2ObjectMap> metadataBuffer = Int2ObjectSyncMap.hashmap(); - private final Int2ObjectMap vehicleMap = Int2ObjectSyncMap.hashmap(); - private final Int2ObjectMap bossBarMap = Int2ObjectSyncMap.hashmap(); - private final IntSet validBlocking = Int2ObjectSyncMap.hashset(); - private final Set knownHolograms = Int2ObjectSyncMap.hashset(); + private final Int2ObjectMap uuidMap = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap> metadataBuffer = new Int2ObjectOpenHashMap<>(); + private final Int2IntMap vehicleMap = new Int2IntOpenHashMap(); + private final Int2ObjectMap bossBarMap = new Int2ObjectOpenHashMap<>(); + private final IntSet validBlocking = new IntOpenHashSet(); + private final IntSet knownHolograms = new IntOpenHashSet(); private final Set blockInteractions = Collections.newSetFromMap(CacheBuilder.newBuilder() .maximumSize(1000) .expireAfterAccess(250, TimeUnit.MILLISECONDS) @@ -368,27 +370,27 @@ public class EntityTracker1_9 extends EntityTrackerBase { } } - public Map getUuidMap() { + public Int2ObjectMap getUuidMap() { return uuidMap; } - public Map> getMetadataBuffer() { + public Int2ObjectMap> getMetadataBuffer() { return metadataBuffer; } - public Map getVehicleMap() { + public Int2IntMap getVehicleMap() { return vehicleMap; } - public Map getBossBarMap() { + public Int2ObjectMap getBossBarMap() { return bossBarMap; } - public Set getValidBlocking() { + public IntSet getValidBlocking() { return validBlocking; } - public Set getKnownHolograms() { + public IntSet getKnownHolograms() { return knownHolograms; } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d9eb3ce36..ca515d782 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,7 +4,6 @@ metadata.format.version = "1.1" gson = "2.10.1" fastutil = "8.5.12" -flare = "2.0.1" vianbt = "4.2.0" mcstructs = "2.4.2-SNAPSHOT" @@ -29,8 +28,6 @@ velocity = "3.1.1" gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } 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" } vianbt = { group = "com.viaversion", name = "nbt", version.ref = "vianbt" } # Custom version that uses ViaNBT instead of its own inbuilt NBT library text = { group = "com.viaversion.mcstructs", name = "text", version.ref = "mcstructs" }