From 74fd9e78fceedb2b8b8d909a9d5ed15acf585f7a Mon Sep 17 00:00:00 2001
From: Adrian Siekierka <kontakt@asie.pl>
Date: Sat, 27 Apr 2019 01:53:03 +0200
Subject: [PATCH] fix handling (sending and receiving) of register-type packets

---
 .../network/ClientSidePacketRegistryImpl.java |  4 +-
 .../impl/network/PacketRegistryImpl.java      | 17 ++++----
 .../MixinClientPlayNetworkHandler.java        |  8 +++-
 .../mixin/network/MixinPlayerManager.java     | 42 +++++++++++++++++++
 .../resources/fabric-networking.mixins.json   |  1 +
 .../mixin/registry/MixinPlayerManager.java    |  1 -
 6 files changed, 62 insertions(+), 11 deletions(-)
 create mode 100644 fabric-networking/src/main/java/net/fabricmc/fabric/mixin/network/MixinPlayerManager.java

diff --git a/fabric-networking/src/main/java/net/fabricmc/fabric/impl/network/ClientSidePacketRegistryImpl.java b/fabric-networking/src/main/java/net/fabricmc/fabric/impl/network/ClientSidePacketRegistryImpl.java
index f7e3275ed..3b8d4754b 100644
--- a/fabric-networking/src/main/java/net/fabricmc/fabric/impl/network/ClientSidePacketRegistryImpl.java
+++ b/fabric-networking/src/main/java/net/fabricmc/fabric/impl/network/ClientSidePacketRegistryImpl.java
@@ -69,7 +69,7 @@ public class ClientSidePacketRegistryImpl extends PacketRegistryImpl implements
 	protected void onRegister(Identifier id) {
 		ClientPlayNetworkHandler handler = MinecraftClient.getInstance().getNetworkHandler();
 		if (handler != null) {
-			handler.sendPacket(createRegisterTypePacket(PacketTypes.REGISTER, Collections.singleton(id)));
+			createRegisterTypePacket(PacketTypes.REGISTER, Collections.singleton(id)).ifPresent(handler::sendPacket);
 		}
 	}
 
@@ -77,7 +77,7 @@ public class ClientSidePacketRegistryImpl extends PacketRegistryImpl implements
 	protected void onUnregister(Identifier id) {
 		ClientPlayNetworkHandler handler = MinecraftClient.getInstance().getNetworkHandler();
 		if (handler != null) {
-			handler.sendPacket(createRegisterTypePacket(PacketTypes.UNREGISTER, Collections.singleton(id)));
+			createRegisterTypePacket(PacketTypes.UNREGISTER, Collections.singleton(id)).ifPresent(handler::sendPacket);
 		}
 	}
 
diff --git a/fabric-networking/src/main/java/net/fabricmc/fabric/impl/network/PacketRegistryImpl.java b/fabric-networking/src/main/java/net/fabricmc/fabric/impl/network/PacketRegistryImpl.java
index 86c0d8cd0..3ce9bca5a 100644
--- a/fabric-networking/src/main/java/net/fabricmc/fabric/impl/network/PacketRegistryImpl.java
+++ b/fabric-networking/src/main/java/net/fabricmc/fabric/impl/network/PacketRegistryImpl.java
@@ -27,10 +27,7 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
 import java.nio.charset.StandardCharsets;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
 
 public abstract class PacketRegistryImpl implements PacketRegistry {
 	protected static final Logger LOGGER = LogManager.getLogger();
@@ -40,7 +37,7 @@ public abstract class PacketRegistryImpl implements PacketRegistry {
 		consumerMap = new LinkedHashMap<>();
 	}
 
-	public static Packet<?> createInitialRegisterPacket(PacketRegistry registry) {
+	public static Optional<Packet<?>> createInitialRegisterPacket(PacketRegistry registry) {
 		PacketRegistryImpl impl = (PacketRegistryImpl) registry;
 		return impl.createRegisterTypePacket(PacketTypes.REGISTER, impl.consumerMap.keySet());
 	}
@@ -75,7 +72,11 @@ public abstract class PacketRegistryImpl implements PacketRegistry {
 
 	protected abstract void onReceivedUnregisterPacket(PacketContext context, Collection<Identifier> ids);
 
-	protected Packet<?> createRegisterTypePacket(Identifier id, Collection<Identifier> ids) {
+	protected Optional<Packet<?>> createRegisterTypePacket(Identifier id, Collection<Identifier> ids) {
+		if (ids.isEmpty()) {
+			return Optional.empty();
+		}
+
 		PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
 		boolean first = true;
 		for (Identifier a : ids) {
@@ -86,7 +87,7 @@ public abstract class PacketRegistryImpl implements PacketRegistry {
 			}
 			buf.writeBytes(a.toString().getBytes(StandardCharsets.US_ASCII));
 		}
-		return toPacket(id, buf);
+		return Optional.of(toPacket(id, buf));
 	}
 
 	private boolean acceptRegisterType(Identifier id, PacketContext context, PacketByteBuf buf) {
@@ -96,6 +97,7 @@ public abstract class PacketRegistryImpl implements PacketRegistry {
 			StringBuilder sb = new StringBuilder();
 			char c;
 
+			int oldIndex = buf.readerIndex();
 			while (buf.readerIndex() < buf.writerIndex()) {
 				c = (char) buf.readByte();
 				if (c == 0) {
@@ -108,6 +110,7 @@ public abstract class PacketRegistryImpl implements PacketRegistry {
 					sb.append(c);
 				}
 			}
+			buf.readerIndex(oldIndex);
 
 			String s = sb.toString();
 			if (!s.isEmpty()) {
diff --git a/fabric-networking/src/main/java/net/fabricmc/fabric/mixin/network/MixinClientPlayNetworkHandler.java b/fabric-networking/src/main/java/net/fabricmc/fabric/mixin/network/MixinClientPlayNetworkHandler.java
index 1f78e65d3..d37925fb7 100644
--- a/fabric-networking/src/main/java/net/fabricmc/fabric/mixin/network/MixinClientPlayNetworkHandler.java
+++ b/fabric-networking/src/main/java/net/fabricmc/fabric/mixin/network/MixinClientPlayNetworkHandler.java
@@ -35,6 +35,8 @@ import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
 
+import java.util.Optional;
+
 @Mixin(ClientPlayNetworkHandler.class)
 public abstract class MixinClientPlayNetworkHandler implements PacketContext {
 	@Shadow
@@ -45,7 +47,11 @@ public abstract class MixinClientPlayNetworkHandler implements PacketContext {
 
 	@Inject(at = @At("RETURN"), method = "onGameJoin")
 	public void onGameJoin(GameJoinS2CPacket packet, CallbackInfo info) {
-		sendPacket(PacketRegistryImpl.createInitialRegisterPacket(ClientSidePacketRegistry.INSTANCE));
+		Optional<Packet<?>> optionalPacket = PacketRegistryImpl.createInitialRegisterPacket(ClientSidePacketRegistry.INSTANCE);
+		//noinspection OptionalIsPresent
+		if (optionalPacket.isPresent()) {
+			sendPacket(optionalPacket.get());
+		}
 	}
 
 	// Optional hook: it only removes a warning message.
diff --git a/fabric-networking/src/main/java/net/fabricmc/fabric/mixin/network/MixinPlayerManager.java b/fabric-networking/src/main/java/net/fabricmc/fabric/mixin/network/MixinPlayerManager.java
new file mode 100644
index 000000000..6199eb71a
--- /dev/null
+++ b/fabric-networking/src/main/java/net/fabricmc/fabric/mixin/network/MixinPlayerManager.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 2017, 2018, 2019 FabricMC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.fabricmc.fabric.mixin.network;
+
+import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
+import net.fabricmc.fabric.impl.network.PacketRegistryImpl;
+import net.minecraft.network.ClientConnection;
+import net.minecraft.network.Packet;
+import net.minecraft.server.PlayerManager;
+import net.minecraft.server.network.ServerPlayerEntity;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import java.util.Optional;
+
+@Mixin(priority = 500, value = PlayerManager.class)
+public abstract class MixinPlayerManager {
+	@Inject(method = "onPlayerConnect", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/packet/DifficultyS2CPacket;<init>(Lnet/minecraft/world/Difficulty;Z)V"))
+	public void onPlayerConnect(ClientConnection lvt1, ServerPlayerEntity lvt2, CallbackInfo info) {
+		Optional<Packet<?>> optionalPacket = PacketRegistryImpl.createInitialRegisterPacket(ServerSidePacketRegistry.INSTANCE);
+		//noinspection OptionalIsPresent
+		if (optionalPacket.isPresent()) {
+			lvt2.networkHandler.sendPacket(optionalPacket.get());
+		}
+	}
+}
diff --git a/fabric-networking/src/main/resources/fabric-networking.mixins.json b/fabric-networking/src/main/resources/fabric-networking.mixins.json
index 12a261327..ab9bd3d52 100644
--- a/fabric-networking/src/main/resources/fabric-networking.mixins.json
+++ b/fabric-networking/src/main/resources/fabric-networking.mixins.json
@@ -5,6 +5,7 @@
   "mixins": [
     "MixinCustomPayloadC2SPacket",
     "MixinEntityTracker",
+    "MixinPlayerManager",
     "MixinServerPlayNetworkHandler",
     "MixinThreadedAnvilChunkStorage"
   ],
diff --git a/fabric-registry-sync/src/main/java/net/fabricmc/fabric/mixin/registry/MixinPlayerManager.java b/fabric-registry-sync/src/main/java/net/fabricmc/fabric/mixin/registry/MixinPlayerManager.java
index 1a25d7164..7583431ff 100644
--- a/fabric-registry-sync/src/main/java/net/fabricmc/fabric/mixin/registry/MixinPlayerManager.java
+++ b/fabric-registry-sync/src/main/java/net/fabricmc/fabric/mixin/registry/MixinPlayerManager.java
@@ -33,7 +33,6 @@ public abstract class MixinPlayerManager {
 	public void onPlayerConnect(ClientConnection lvt1, ServerPlayerEntity lvt2, CallbackInfo info) {
 		// TODO: If integrated and local, don't send the packet (it's ignored)
 		// TODO: Refactor out into network + move registry hook to event
-		lvt2.networkHandler.sendPacket(PacketRegistryImpl.createInitialRegisterPacket(ServerSidePacketRegistry.INSTANCE));
 		lvt2.networkHandler.sendPacket(RegistrySyncManager.createPacket());
 	}
 }