From 4da5176b893baca3e4600b9763da999c183f19ff Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Sun, 11 Nov 2018 21:01:09 +0000 Subject: [PATCH] Don't allow digging into unloaded chunks --- .../level/ServerPlayerGameMode.java.patch | 75 +++++++++---- .../ServerGamePacketListenerImpl.java.patch | 105 ++++++++++-------- 2 files changed, 116 insertions(+), 64 deletions(-) diff --git a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch index 9a2f656dc2..7a7a9fe2a4 100644 --- a/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/level/ServerPlayerGameMode.java.patch @@ -57,7 +57,7 @@ this.level.updateSleepingPlayerList(); if (gameMode == GameType.CREATIVE) { this.player.resetCurrentImpulseContext(); -@@ -92,7 +118,7 @@ +@@ -92,12 +118,12 @@ } public void tick() { @@ -66,7 +66,37 @@ BlockState iblockdata; if (this.hasDelayedDestroy) { -@@ -146,15 +172,45 @@ +- iblockdata = this.level.getBlockState(this.delayedDestroyPos); +- if (iblockdata.isAir()) { ++ iblockdata = this.level.getBlockStateIfLoaded(this.delayedDestroyPos); // Paper - Don't allow digging into unloaded chunks ++ if (iblockdata == null || iblockdata.isAir()) { // Paper - Don't allow digging into unloaded chunks + this.hasDelayedDestroy = false; + } else { + float f = this.incrementDestroyProgress(iblockdata, this.delayedDestroyPos, this.delayedTickStart); +@@ -108,7 +134,13 @@ + } + } + } else if (this.isDestroyingBlock) { +- iblockdata = this.level.getBlockState(this.destroyPos); ++ // Paper start - Don't allow digging into unloaded chunks; don't want to do same logic as above, return instead ++ iblockdata = this.level.getBlockStateIfLoaded(this.destroyPos); ++ if (iblockdata == null) { ++ this.isDestroyingBlock = false; ++ return; ++ } ++ // Paper end - Don't allow digging into unloaded chunks + if (iblockdata.isAir()) { + this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1); + this.lastSentState = -1; +@@ -137,6 +169,7 @@ + + public void handleBlockBreakAction(BlockPos pos, ServerboundPlayerActionPacket.Action action, Direction direction, int worldHeight, int sequence) { + if (!this.player.canInteractWithBlock(pos, 1.0D)) { ++ if (true) return; // Paper - Don't allow digging into unloaded chunks; Don't notify if unreasonably far away + this.debugLogging(pos, false, sequence, "too far"); + } else if (pos.getY() > worldHeight) { + this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos))); +@@ -146,16 +179,46 @@ if (action == ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK) { if (!this.level.mayInteract(this.player, pos)) { @@ -99,20 +129,21 @@ + if (this.isCreative()) { this.destroyAndAck(pos, sequence, "creative destroy"); -+ return; -+ } -+ + return; + } + + // Spigot start - handle debug stick left click for non-creative + if (this.player.getMainHandItem().is(net.minecraft.world.item.Items.DEBUG_STICK) + && ((net.minecraft.world.item.DebugStickItem) net.minecraft.world.item.Items.DEBUG_STICK).handleInteraction(this.player, this.level.getBlockState(pos), this.level, pos, false, this.player.getMainHandItem())) { + this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos)); - return; - } ++ return; ++ } + // Spigot end - ++ if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) { this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos))); -@@ -166,7 +222,19 @@ + this.debugLogging(pos, false, sequence, "block action restricted"); +@@ -166,7 +229,19 @@ float f = 1.0F; iblockdata = this.level.getBlockState(pos); @@ -133,7 +164,7 @@ EnchantmentHelper.onHitBlock(this.level, this.player.getMainHandItem(), this.player, this.player, EquipmentSlot.MAINHAND, Vec3.atCenterOf(pos), iblockdata, (item) -> { this.player.onEquippedItemBroken(item, EquipmentSlot.MAINHAND); }); -@@ -174,6 +242,26 @@ +@@ -174,6 +249,26 @@ f = iblockdata.getDestroyProgress(this.player, this.player.level(), pos); } @@ -160,14 +191,20 @@ if (!iblockdata.isAir() && f >= 1.0F) { this.destroyAndAck(pos, sequence, "insta mine"); } else { -@@ -218,13 +306,15 @@ +@@ -217,14 +312,18 @@ + this.debugLogging(pos, true, sequence, "stopped destroying"); } else if (action == ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK) { this.isDestroyingBlock = false; - if (!Objects.equals(this.destroyPos, pos)) { +- if (!Objects.equals(this.destroyPos, pos)) { - ServerPlayerGameMode.LOGGER.warn("Mismatch in destroy block pos: {} {}", this.destroyPos, pos); +- this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1); +- this.debugLogging(pos, true, sequence, "aborted mismatched destroying"); ++ if (!Objects.equals(this.destroyPos, pos) && !BlockPos.ZERO.equals(this.destroyPos)) { // Paper + ServerPlayerGameMode.LOGGER.debug("Mismatch in destroy block pos: {} {}", this.destroyPos, pos); // CraftBukkit - SPIGOT-5457 sent by client when interact event cancelled - this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1); - this.debugLogging(pos, true, sequence, "aborted mismatched destroying"); ++ BlockState type = this.level.getBlockStateIfLoaded(this.destroyPos); // Paper - don't load unloaded chunks for stale records here ++ if (type != null) this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1); ++ if (type != null) this.debugLogging(pos, true, sequence, "aborted mismatched destroying"); ++ this.destroyPos = BlockPos.ZERO; // Paper } this.level.destroyBlockProgress(this.player.getId(), pos, -1); @@ -177,7 +214,7 @@ } } -@@ -242,10 +332,65 @@ +@@ -242,10 +341,65 @@ public boolean destroyBlock(BlockPos pos) { BlockState iblockdata = this.level.getBlockState(pos); @@ -244,7 +281,7 @@ BlockEntity tileentity = this.level.getBlockEntity(pos); Block block = iblockdata.getBlock(); -@@ -255,6 +400,10 @@ +@@ -255,6 +409,10 @@ } else if (this.player.blockActionRestricted(this.level, pos, this.gameModeForPlayer)) { return false; } else { @@ -255,7 +292,7 @@ BlockState iblockdata1 = block.playerWillDestroy(this.level, pos, iblockdata, this.player); boolean flag = this.level.removeBlock(pos, false); -@@ -263,19 +412,32 @@ +@@ -263,19 +421,32 @@ } if (this.isCreative()) { @@ -291,7 +328,7 @@ } } } -@@ -321,15 +483,58 @@ +@@ -321,15 +492,58 @@ } } @@ -350,7 +387,7 @@ if (itileinventory != null) { player.openMenu(itileinventory); return InteractionResult.CONSUME; -@@ -359,7 +564,7 @@ +@@ -359,7 +573,7 @@ } } diff --git a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch index 6fd066cb99..977f0178f8 100644 --- a/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ b/paper-server/patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch @@ -48,7 +48,7 @@ import net.minecraft.world.level.GameRules; import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; -@@ -192,11 +196,71 @@ +@@ -192,12 +196,72 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; @@ -58,7 +58,7 @@ import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import org.slf4j.Logger; -+ + +// CraftBukkit start +import io.papermc.paper.adventure.ChatProcessor; // Paper +import io.papermc.paper.adventure.PaperAdventure; // Paper @@ -117,9 +117,10 @@ +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.SmithingInventory; +// CraftBukkit end - ++ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl implements ServerGamePacketListener, ServerPlayerConnection, TickablePacketListener { + static final Logger LOGGER = LogUtils.getLogger(); @@ -212,6 +276,7 @@ private int tickCount; private int ackBlockChangesUpTo = -1; @@ -137,14 +138,14 @@ this.chunkSender = new PlayerChunkSender(connection.isMemoryConnection()); this.player = player; player.connection = this; -@@ -256,8 +321,24 @@ +@@ -256,9 +321,25 @@ Objects.requireNonNull(server); this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(uuid, server::enforceSecureProfile); - this.chatMessageChain = new FutureChain(server); + this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat } -+ + + // CraftBukkit start - add fields and methods + private int lastTick = MinecraftServer.currentTick; + private int allowedPlayerTicks = 1; @@ -160,9 +161,10 @@ + private float lastYaw = Float.MAX_VALUE; + private boolean justTeleported = false; + // CraftBukkit end - ++ @Override public void tick() { + if (this.ackBlockChangesUpTo > -1) { @@ -277,7 +358,7 @@ if (this.clientIsFloating && !this.player.isSleeping() && !this.player.isPassenger() && !this.player.isDeadOrDying()) { if (++this.aboveGroundTickCount > this.getMaximumFlyingTicks(this.player)) { @@ -846,7 +848,20 @@ this.player.drop(false); } -@@ -1218,9 +1687,31 @@ +@@ -1199,6 +1668,12 @@ + case START_DESTROY_BLOCK: + case ABORT_DESTROY_BLOCK: + case STOP_DESTROY_BLOCK: ++ // Paper start - Don't allow digging into unloaded chunks ++ if (this.player.level().getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) == null) { ++ this.player.connection.ackBlockChangesUpTo(packet.getSequence()); ++ return; ++ } ++ // Paper end - Don't allow digging into unloaded chunks + this.player.gameMode.handleBlockBreakAction(blockposition, packetplayinblockdig_enumplayerdigtype, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence()); + this.player.connection.ackBlockChangesUpTo(packet.getSequence()); + return; +@@ -1218,9 +1693,31 @@ } } @@ -878,7 +893,7 @@ if (this.player.hasClientLoaded()) { this.player.connection.ackBlockChangesUpTo(packet.getSequence()); ServerLevel worldserver = this.player.serverLevel(); -@@ -1244,6 +1735,7 @@ +@@ -1244,6 +1741,7 @@ if (blockposition.getY() <= i) { if (this.awaitingPositionFromClient == null && worldserver.mayInteract(this.player, blockposition)) { @@ -886,7 +901,7 @@ InteractionResult enuminteractionresult = this.player.gameMode.useItemOn(this.player, worldserver, itemstack, enumhand, movingobjectpositionblock); if (enuminteractionresult.consumesAction()) { -@@ -1281,6 +1773,8 @@ +@@ -1281,6 +1779,8 @@ @Override public void handleUseItem(ServerboundUseItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -895,7 +910,7 @@ if (this.player.hasClientLoaded()) { this.ackBlockChangesUpTo(packet.getSequence()); ServerLevel worldserver = this.player.serverLevel(); -@@ -1296,6 +1790,47 @@ +@@ -1296,6 +1796,47 @@ this.player.absRotateTo(f, f1); } @@ -943,7 +958,7 @@ InteractionResult enuminteractionresult = this.player.gameMode.useItem(this.player, worldserver, itemstack, enumhand); if (enuminteractionresult instanceof InteractionResult.Success) { -@@ -1321,7 +1856,7 @@ +@@ -1321,7 +1862,7 @@ Entity entity = packet.getEntity(worldserver); if (entity != null) { @@ -952,7 +967,7 @@ return; } } -@@ -1342,6 +1877,13 @@ +@@ -1342,6 +1883,13 @@ @Override public void onDisconnect(DisconnectionDetails info) { @@ -966,7 +981,7 @@ ServerGamePacketListenerImpl.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), info.reason().getString()); this.removePlayerFromWorld(); super.onDisconnect(info); -@@ -1349,10 +1891,20 @@ +@@ -1349,10 +1897,20 @@ private void removePlayerFromWorld() { this.chatMessageChain.close(); @@ -989,7 +1004,7 @@ this.player.getTextFilter().leave(); } -@@ -1367,7 +1919,16 @@ +@@ -1367,7 +1925,16 @@ @Override public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1006,7 +1021,7 @@ if (this.player.getInventory().selected != packet.getSlot() && this.player.getUsedItemHand() == InteractionHand.MAIN_HAND) { this.player.stopUsingItem(); } -@@ -1376,11 +1937,18 @@ +@@ -1376,11 +1943,18 @@ this.player.resetLastActionTime(); } else { ServerGamePacketListenerImpl.LOGGER.warn("{} tried to set an invalid carried item", this.player.getName().getString()); @@ -1025,7 +1040,7 @@ Optional optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages()); if (!optional.isEmpty()) { -@@ -1394,27 +1962,44 @@ +@@ -1394,27 +1968,44 @@ return; } @@ -1077,7 +1092,7 @@ ParseResults parseresults = this.parseCommand(command); if (this.server.enforceSecureProfile() && SignableCommand.hasSignableArguments(parseresults)) { -@@ -1431,19 +2016,37 @@ +@@ -1431,19 +2022,37 @@ if (!optional.isEmpty()) { this.tryHandleChat(packet.command(), () -> { @@ -1119,7 +1134,7 @@ } catch (SignedMessageChain.DecodeException signedmessagechain_a) { this.handleMessageDecodeFailure(signedmessagechain_a); return; -@@ -1451,10 +2054,10 @@ +@@ -1451,10 +2060,10 @@ CommandSigningContext.SignedArguments commandsigningcontext_a = new CommandSigningContext.SignedArguments(map); @@ -1132,7 +1147,7 @@ } private void handleMessageDecodeFailure(SignedMessageChain.DecodeException exception) { -@@ -1530,14 +2133,20 @@ +@@ -1530,14 +2139,20 @@ return com_mojang_brigadier_commanddispatcher.parse(command, this.player.createCommandSourceStack()); } @@ -1157,7 +1172,7 @@ } } -@@ -1566,6 +2175,127 @@ +@@ -1566,6 +2181,127 @@ return false; } @@ -1285,7 +1300,7 @@ private PlayerChatMessage getSignedMessage(ServerboundChatPacket packet, LastSeenMessages lastSeenMessages) throws SignedMessageChain.DecodeException { SignedMessageBody signedmessagebody = new SignedMessageBody(packet.message(), packet.timeStamp(), packet.salt(), lastSeenMessages); -@@ -1573,13 +2303,42 @@ +@@ -1573,13 +2309,42 @@ } private void broadcastChatMessage(PlayerChatMessage message) { @@ -1333,7 +1348,7 @@ this.disconnect((Component) Component.translatable("disconnect.spam")); } -@@ -1601,7 +2360,33 @@ +@@ -1601,7 +2366,33 @@ @Override public void handleAnimate(ServerboundSwingPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1367,7 +1382,7 @@ this.player.swing(packet.getHand()); } -@@ -1609,6 +2394,29 @@ +@@ -1609,6 +2400,29 @@ public void handlePlayerCommand(ServerboundPlayerCommandPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); if (this.player.hasClientLoaded()) { @@ -1397,7 +1412,7 @@ this.player.resetLastActionTime(); Entity entity; PlayerRideableJumping ijumpable; -@@ -1616,6 +2424,11 @@ +@@ -1616,6 +2430,11 @@ switch (packet.getAction()) { case PRESS_SHIFT_KEY: this.player.setShiftKeyDown(true); @@ -1409,7 +1424,7 @@ break; case RELEASE_SHIFT_KEY: this.player.setShiftKeyDown(false); -@@ -1691,6 +2504,12 @@ +@@ -1691,6 +2510,12 @@ } public void sendPlayerChatMessage(PlayerChatMessage message, ChatType.Bound params) { @@ -1422,7 +1437,7 @@ this.send(new ClientboundPlayerChatPacket(message.link().sender(), message.link().index(), message.signature(), message.signedBody().pack(this.messageSignatureCache), message.unsignedContent(), message.filterMask(), params)); this.addPendingMessage(message); } -@@ -1703,6 +2522,13 @@ +@@ -1703,6 +2528,13 @@ return this.connection.getRemoteAddress(); } @@ -1436,7 +1451,7 @@ public void switchToConfig() { this.waitingForSwitchToConfig = true; this.removePlayerFromWorld(); -@@ -1718,9 +2544,17 @@ +@@ -1718,9 +2550,17 @@ @Override public void handleInteract(ServerboundInteractPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1454,7 +1469,7 @@ this.player.resetLastActionTime(); this.player.setShiftKeyDown(packet.isUsingSecondaryAction()); -@@ -1733,20 +2567,58 @@ +@@ -1733,20 +2573,58 @@ if (this.player.canInteractWithEntity(axisalignedbb, 3.0D)) { packet.dispatch(new ServerboundInteractPacket.Handler() { @@ -1478,12 +1493,12 @@ + entity.getBukkitEntity().update(ServerGamePacketListenerImpl.this.player); + ServerGamePacketListenerImpl.this.player.containerMenu.sendAllDataToRemote(); + } -+ + + if (triggerLeashUpdate && (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem)) { + // Refresh the current leash state + ServerGamePacketListenerImpl.this.send(new ClientboundSetEntityLinkPacket(entity, ((Mob) entity).getLeashHolder())); + } - ++ + if (event.isCancelled() || ServerGamePacketListenerImpl.this.player.getInventory().getSelected() == null || ServerGamePacketListenerImpl.this.player.getInventory().getSelected().getItem() != origItem) { + // Refresh the current entity metadata + entity.refreshEntityData(ServerGamePacketListenerImpl.this.player); @@ -1517,7 +1532,7 @@ } } -@@ -1755,19 +2627,20 @@ +@@ -1755,19 +2633,20 @@ @Override public void onInteraction(InteractionHand hand) { @@ -1541,7 +1556,7 @@ label23: { if (entity instanceof AbstractArrow) { -@@ -1785,6 +2658,11 @@ +@@ -1785,6 +2664,11 @@ } ServerGamePacketListenerImpl.this.player.attack(entity); @@ -1553,7 +1568,7 @@ return; } } -@@ -1795,7 +2673,26 @@ +@@ -1795,7 +2679,26 @@ }); } } @@ -1580,7 +1595,7 @@ } } -@@ -1809,7 +2706,7 @@ +@@ -1809,7 +2712,7 @@ case PERFORM_RESPAWN: if (this.player.wonGame) { this.player.wonGame = false; @@ -1589,7 +1604,7 @@ this.resetPosition(); CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, Level.END, Level.OVERWORLD); } else { -@@ -1817,11 +2714,11 @@ +@@ -1817,11 +2720,11 @@ return; } @@ -1603,7 +1618,7 @@ } } break; -@@ -1833,16 +2730,27 @@ +@@ -1833,16 +2736,27 @@ @Override public void handleContainerClose(ServerboundContainerClosePacket packet) { @@ -1633,7 +1648,7 @@ this.player.containerMenu.sendAllDataToRemote(); } else if (!this.player.containerMenu.stillValid(this.player)) { ServerGamePacketListenerImpl.LOGGER.debug("Player {} interacted with invalid menu {}", this.player, this.player.containerMenu); -@@ -1855,7 +2763,284 @@ +@@ -1855,7 +2769,284 @@ boolean flag = packet.getStateId() != this.player.containerMenu.getStateId(); this.player.containerMenu.suppressRemoteUpdates(); @@ -1919,7 +1934,7 @@ ObjectIterator objectiterator = Int2ObjectMaps.fastIterable(packet.getChangedSlots()).iterator(); while (objectiterator.hasNext()) { -@@ -1901,8 +3086,22 @@ +@@ -1901,8 +3092,22 @@ return; } @@ -1943,7 +1958,7 @@ if (containerrecipebook_a == RecipeBookMenu.PostPlaceAction.PLACE_GHOST_RECIPE) { this.player.connection.send(new ClientboundPlaceGhostRecipePacket(this.player.containerMenu.containerId, craftingmanager_d.display().display())); } -@@ -1917,6 +3116,7 @@ +@@ -1917,6 +3122,7 @@ @Override public void handleContainerButtonClick(ServerboundContainerButtonClickPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -1951,7 +1966,7 @@ this.player.resetLastActionTime(); if (this.player.containerMenu.containerId == packet.containerId() && !this.player.isSpectator()) { if (!this.player.containerMenu.stillValid(this.player)) { -@@ -1945,7 +3145,44 @@ +@@ -1945,7 +3151,44 @@ boolean flag1 = packet.slotNum() >= 1 && packet.slotNum() <= 45; boolean flag2 = itemstack.isEmpty() || itemstack.getCount() <= itemstack.getMaxStackSize(); @@ -1996,7 +2011,7 @@ if (flag1 && flag2) { this.player.inventoryMenu.getSlot(packet.slotNum()).setByPlayer(itemstack); this.player.inventoryMenu.setRemoteSlot(packet.slotNum(), itemstack); -@@ -1972,6 +3209,7 @@ +@@ -1972,6 +3215,7 @@ } private void updateSignText(ServerboundSignUpdatePacket packet, List signText) { @@ -2004,7 +2019,7 @@ this.player.resetLastActionTime(); ServerLevel worldserver = this.player.serverLevel(); BlockPos blockposition = packet.getPos(); -@@ -1993,7 +3231,17 @@ +@@ -1993,7 +3237,17 @@ @Override public void handlePlayerAbilities(ServerboundPlayerAbilitiesPacket packet) { PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); @@ -2023,7 +2038,7 @@ } @Override -@@ -2002,6 +3250,7 @@ +@@ -2002,6 +3256,7 @@ boolean flag = this.player.isModelPartShown(PlayerModelPart.HAT); this.player.updateOptions(packet.information()); @@ -2031,7 +2046,7 @@ if (this.player.isModelPartShown(PlayerModelPart.HAT) != flag) { this.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_HAT, this.player)); } -@@ -2058,7 +3307,7 @@ +@@ -2058,7 +3313,7 @@ if (!this.waitingForSwitchToConfig) { throw new IllegalStateException("Client acknowledged config, but none was requested"); } else { @@ -2040,7 +2055,7 @@ } } -@@ -2083,8 +3332,10 @@ +@@ -2083,8 +3338,10 @@ }); }