Files
AkarinMC/patches/server/0011-Optimizations-for-network.patch
ㄗㄠˋ ㄑㄧˊ 504eb37c5e Updated Upstream (Paper)
Upstream has released updates that appears to apply and compile correctly

Paper Changes:
bc8fafb20 Updated Upstream (CraftBukkit/Spigot)
ebbca5ced Drowned is a RangedEntity (fixes API for Drowned to support Ranged)
83b03eee0 Don't move existing players to world spawn
3b3e38fd0 Fix issue with loading chunk during ticking chunks issue
78431dcae Update test server startup script
ab74bb451 Speed up processing of chunk loads and generation
f5dd491fc Increase Light Queue Size
9ab693487 Don't load chunks when attempting to unload a chunk
38c626229 Improve Optimize Memory use logic to make iterator safer and fix bad plugins like P2
d33ba160a Fix incorrect keyword use on visibleChunksClone
2f3430158 Updated Upstream (Bukkit/CraftBukkit)
a65831bd6 Optimize PlayerChunkMap memory use for visibleChunks
2020-04-10 11:02:20 +08:00

406 lines
24 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=84=97=E3=84=A0=CB=8B=20=E3=84=91=E3=84=A7=CB=8A?=
<tsao-chi@the-lingo.org>
Date: Sun, 5 Apr 2020 14:59:10 +0800
Subject: [PATCH] Optimizations for network
diff --git a/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
index a85466bc7e0a8aa54b9eff14077fe6c992ae2902..324af1a12a5780170f8cd6e060ff2f2f9d152c3d 100644
--- a/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
+++ b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
@@ -106,7 +106,7 @@ public final class StandardPaperServerListPingEventImpl extends PaperServerListP
}
// Send response
- networkManager.sendPacket(new PacketStatusOutServerInfo(ping));
+ networkManager.sendPacketAsync(new PacketStatusOutServerInfo(ping)); // Akarin - Async Sending packets
}
}
diff --git a/src/main/java/net/minecraft/server/HandshakeListener.java b/src/main/java/net/minecraft/server/HandshakeListener.java
index 0532f975b7af5b3f2916c26141221cd3701765d0..e7be1074b1b8fde3590b1323508965961824e671 100644
--- a/src/main/java/net/minecraft/server/HandshakeListener.java
+++ b/src/main/java/net/minecraft/server/HandshakeListener.java
@@ -39,7 +39,7 @@ public class HandshakeListener implements PacketHandshakingInListener {
if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.get(address) < connectionThrottle) {
throttleTracker.put(address, currentTime);
chatmessage = new ChatMessage(com.destroystokyo.paper.PaperConfig.connectionThrottleKickMessage); // Paper - Configurable connection throttle kick message
- this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
+ this.b.sendPacketAsync(new PacketLoginOutDisconnect(chatmessage)); // Akarin - Async Sending packets
this.b.close(chatmessage);
return;
}
@@ -66,11 +66,11 @@ public class HandshakeListener implements PacketHandshakingInListener {
if (packethandshakinginsetprotocol.c() > SharedConstants.getGameVersion().getProtocolVersion()) {
chatmessage = new ChatMessage( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedServerMessage.replaceAll("'", "''"), SharedConstants.getGameVersion().getName() ) ); // Spigot
- this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
+ this.b.sendPacketAsync(new PacketLoginOutDisconnect(chatmessage));
this.b.close(chatmessage);
} else if (packethandshakinginsetprotocol.c() < SharedConstants.getGameVersion().getProtocolVersion()) {
chatmessage = new ChatMessage( java.text.MessageFormat.format( org.spigotmc.SpigotConfig.outdatedClientMessage.replaceAll("'", "''"), SharedConstants.getGameVersion().getName() ) ); // Spigot
- this.b.sendPacket(new PacketLoginOutDisconnect(chatmessage));
+ this.b.sendPacketAsync(new PacketLoginOutDisconnect(chatmessage));
this.b.close(chatmessage);
} else {
this.b.setPacketListener(new LoginListener(this.a, this.b));
diff --git a/src/main/java/net/minecraft/server/LoginListener.java b/src/main/java/net/minecraft/server/LoginListener.java
index f1222fcb2bd52b8781d0f92c94e1472fa7b1e493..522cfed4cb09bc9ecc48b6313da47f9af7a5e1d8 100644
--- a/src/main/java/net/minecraft/server/LoginListener.java
+++ b/src/main/java/net/minecraft/server/LoginListener.java
@@ -111,6 +111,19 @@ public class LoginListener implements PacketLoginInListener {
}
+ // Akarin Start - Async Sending packets
+ public void disconnectAsync(IChatBaseComponent ichatbasecomponent) {
+ try {
+ LoginListener.LOGGER.info("Disconnecting {}: {}", this.d(), ichatbasecomponent.getString());
+ this.networkManager.sendPacketAsync(new PacketLoginOutDisconnect(ichatbasecomponent));
+ this.networkManager.close(ichatbasecomponent);
+ } catch (Exception exception) {
+ LoginListener.LOGGER.error("Error whilst disconnecting player", exception);
+ }
+
+ }
+ // Akarin End - Async Sending packets
+
// Paper start - Cache authenticator threads
private static final AtomicInteger threadId = new AtomicInteger(0);
private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newCachedThreadPool(
@@ -192,7 +205,7 @@ public class LoginListener implements PacketLoginInListener {
this.i = packetlogininstart.b();
if (this.server.getOnlineMode() && !this.networkManager.isLocal()) {
this.g = LoginListener.EnumProtocolState.KEY;
- this.networkManager.sendPacket(new PacketLoginOutEncryptionBegin("", this.server.getKeyPair().getPublic(), this.e));
+ this.networkManager.sendPacketAsync(new PacketLoginOutEncryptionBegin("", this.server.getKeyPair().getPublic(), this.e)); // Akarin - Async Sending packets
} else {
// Paper start - Velocity support
if (com.destroystokyo.paper.PaperConfig.velocitySupport) {
@@ -254,7 +267,7 @@ public class LoginListener implements PacketLoginInListener {
LoginListener.this.i = LoginListener.this.a(gameprofile);
LoginListener.this.g = LoginListener.EnumProtocolState.READY_TO_ACCEPT;
} else {
- LoginListener.this.disconnect(new ChatMessage("multiplayer.disconnect.unverified_username", new Object[0]));
+ LoginListener.this.disconnectAsync(new ChatMessage("multiplayer.disconnect.unverified_username", new Object[0])); // Akarin - Async Sending packets
LoginListener.LOGGER.error("Username '{}' tried to join with an invalid session", gameprofile.getName());
}
} catch (AuthenticationUnavailableException authenticationunavailableexception) {
@@ -267,7 +280,7 @@ public class LoginListener implements PacketLoginInListener {
if (com.destroystokyo.paper.PaperConfig.authenticationServersDownKickMessage != null) {
LoginListener.this.disconnect(new ChatComponentText(com.destroystokyo.paper.PaperConfig.authenticationServersDownKickMessage));
} else // Paper end
- LoginListener.this.disconnect(new ChatMessage("multiplayer.disconnect.authservers_down", new Object[0]));
+ LoginListener.this.disconnectAsync(new ChatMessage("multiplayer.disconnect.authservers_down", new Object[0])); // Akarin - Async Sending packets
LoginListener.LOGGER.error("Couldn't verify username because servers are unavailable");
}
// CraftBukkit start - catch all exceptions
@@ -376,7 +389,7 @@ public class LoginListener implements PacketLoginInListener {
return;
}
// Paper end
- this.disconnect(new ChatMessage("multiplayer.disconnect.unexpected_query_response", new Object[0]));
+ this.disconnectAsync(new ChatMessage("multiplayer.disconnect.unexpected_query_response", new Object[0])); // Akarin - Async Sending packets
}
protected GameProfile a(GameProfile gameprofile) {
diff --git a/src/main/java/net/minecraft/server/NetworkManager.java b/src/main/java/net/minecraft/server/NetworkManager.java
index 96a785af27e1924b0cc1959254d4ae3cdd0385a1..c5e32e42465aece552f09bc5c73d6e0d51735c91 100644
--- a/src/main/java/net/minecraft/server/NetworkManager.java
+++ b/src/main/java/net/minecraft/server/NetworkManager.java
@@ -43,6 +43,8 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
});
private final EnumProtocolDirection h;
private final Queue<NetworkManager.QueuedPacket> packetQueue = Queues.newConcurrentLinkedQueue(); private final Queue<NetworkManager.QueuedPacket> getPacketQueue() { return this.packetQueue; } // Paper - OBFHELPER
+ private boolean handled = false; // Akarin - free packet queue
+ private EnumProtocol protocol; // Akarin - avoid map lookup
public Channel channel;
public SocketAddress socketAddress; public void setSpoofedRemoteAddress(SocketAddress address) { this.socketAddress = address; } // Paper - OBFHELPER
// Spigot Start
@@ -88,6 +90,7 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
public void setProtocol(EnumProtocol enumprotocol) {
this.channel.attr(NetworkManager.c).set(enumprotocol);
+ protocol = enumprotocol; // Akarin - avoid map lookup
this.channel.config().setAutoRead(true);
NetworkManager.LOGGER.debug("Enabled auto read");
}
@@ -175,8 +178,8 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
private void dispatchPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> genericFutureListener) { this.b(packet, genericFutureListener); } // Paper - OBFHELPER
private void b(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> genericfuturelistener) {
- EnumProtocol enumprotocol = EnumProtocol.a(packet);
- EnumProtocol enumprotocol1 = (EnumProtocol) this.channel.attr(NetworkManager.c).get();
+ EnumProtocol enumprotocol = packet.protocol();//EnumProtocol.a(packet); // Akarin - avoid map lookup
+ EnumProtocol enumprotocol1 = protocol;//(EnumProtocol) this.channel.attr(NetworkManager.c).get(); // Akarin - avoid map lookup
++this.q;
if (enumprotocol1 != enumprotocol) {
@@ -184,7 +187,7 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
this.channel.config().setAutoRead(false);
}
- if (this.channel.eventLoop().inEventLoop()) {
+ if (false && this.channel.eventLoop().inEventLoop()) { // Akarin - Async Sending packets
if (enumprotocol != enumprotocol1) {
this.setProtocol(enumprotocol);
}
@@ -223,9 +226,51 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
}
+ // Akarin Start - Async Sending packets - multiple packets, copied from above
+ public void sendPacketAsync(Packet<?> packet) {
+ EnumProtocol enumprotocol = packet.protocol();
+ EnumProtocol enumprotocol1 = protocol;
+
+ ++this.q;
+ if (enumprotocol1 != enumprotocol) {
+ NetworkManager.LOGGER.debug("Disabled auto read");
+ this.channel.config().setAutoRead(false);
+ this.setProtocol(enumprotocol);
+ }
+
+ ChannelFuture channelfuture = this.channel.writeAndFlush(packet);
+
+ channelfuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
+
+ }
+
+ public void sendPackets(Packet<?> packet, Packet<?> ...packets) {
+ EnumProtocol enumprotocol = packet.protocol();
+
+ ++this.q;
+ if (protocol != enumprotocol) {
+ NetworkManager.LOGGER.debug("Disabled auto read");
+ this.channel.config().setAutoRead(false);
+ }
+
+ this.channel.eventLoop().execute(() -> {
+ if (enumprotocol != protocol) {
+ this.setProtocol(enumprotocol);
+ }
+
+ this.channel.write(packet).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
+ for (Packet<?> pkt : packets) {
+ this.channel.write(pkt).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
+ }
+ this.channel.flush();
+ });
+ }
+ // Akarin End
+
// Paper start - Async-Anti-Xray - Stop dispatching further packets and return false if the peeked packet is a chunk packet which is not ready
private boolean sendPacketQueue() { return this.o(); } // OBFHELPER // void -> boolean
private boolean o() { // void -> boolean
+ if (!handled) { // Akarin - free packet queue
if (this.channel != null && this.channel.isOpen()) {
Queue queue = this.packetQueue;
@@ -245,6 +290,8 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
}
}
+ handled = true; // Akarin - free packet queue
+ } // Akarin - free packet queue
return true; // Return true if all packets were dispatched
}
@@ -260,9 +307,9 @@ public class NetworkManager extends SimpleChannelInboundHandler<Packet<?>> {
((PlayerConnection) this.packetListener).tick();
}
- if (this.channel != null) {
- if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - we don't need to explicit flush here, but allow opt in incase issues are found to a better version
- }
+ //if (this.channel != null) { // Akarin - already did
+ //if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - we don't need to explicit flush here, but allow opt in incase issues are found to a better version
+ //}
if (this.t++ % 20 == 0) {
this.s = this.s * 0.75F + (float) this.q * 0.25F;
diff --git a/src/main/java/net/minecraft/server/Packet.java b/src/main/java/net/minecraft/server/Packet.java
index 8d0965a0535b16f19eda21b97a44464b85b05460..7e27cd280fa889f6178d46aa9f9d3a613d9702e6 100644
--- a/src/main/java/net/minecraft/server/Packet.java
+++ b/src/main/java/net/minecraft/server/Packet.java
@@ -20,4 +20,10 @@ public interface Packet<T extends PacketListener> {
default boolean a() {
return false;
}
+
+ // Akarin start - add protocol
+ default EnumProtocol protocol() {
+ return EnumProtocol.PLAY;
+ }
+ // Akarin end
}
diff --git a/src/main/java/net/minecraft/server/PacketLoginOutCustomPayload.java b/src/main/java/net/minecraft/server/PacketLoginOutCustomPayload.java
index 7eb230f1b27eddf48f1b12fc78877a3678d802df..d01cac0bd40a11d82fa0d6874d87ad3f576a4e20 100644
--- a/src/main/java/net/minecraft/server/PacketLoginOutCustomPayload.java
+++ b/src/main/java/net/minecraft/server/PacketLoginOutCustomPayload.java
@@ -41,4 +41,11 @@ public class PacketLoginOutCustomPayload implements Packet<PacketLoginOutListene
public void a(PacketLoginOutListener packetloginoutlistener) {
packetloginoutlistener.a(this);
}
+
+ // Akarin start - add protocol
+ @Override
+ public EnumProtocol protocol() {
+ return EnumProtocol.LOGIN;
+ }
+ // Akarin end
}
diff --git a/src/main/java/net/minecraft/server/PacketLoginOutDisconnect.java b/src/main/java/net/minecraft/server/PacketLoginOutDisconnect.java
index e5094f55f1472c9b74f7f9394aec448237e87149..a5d9b6d94c386f05659f10d69cb84b150610138e 100644
--- a/src/main/java/net/minecraft/server/PacketLoginOutDisconnect.java
+++ b/src/main/java/net/minecraft/server/PacketLoginOutDisconnect.java
@@ -25,4 +25,11 @@ public class PacketLoginOutDisconnect implements Packet<PacketLoginOutListener>
public void a(PacketLoginOutListener packetloginoutlistener) {
packetloginoutlistener.a(this);
}
+
+ // Akarin start - add protocol
+ @Override
+ public EnumProtocol protocol() {
+ return EnumProtocol.LOGIN;
+ }
+ // Akarin end
}
diff --git a/src/main/java/net/minecraft/server/PacketLoginOutEncryptionBegin.java b/src/main/java/net/minecraft/server/PacketLoginOutEncryptionBegin.java
index b0d6342c319a48290fd8bf6aa07a16d108feae18..eeabb54c44d39197f34a7171884cc7e885bce453 100644
--- a/src/main/java/net/minecraft/server/PacketLoginOutEncryptionBegin.java
+++ b/src/main/java/net/minecraft/server/PacketLoginOutEncryptionBegin.java
@@ -34,4 +34,11 @@ public class PacketLoginOutEncryptionBegin implements Packet<PacketLoginOutListe
public void a(PacketLoginOutListener packetloginoutlistener) {
packetloginoutlistener.a(this);
}
+
+ // Akarin start - add protocol
+ @Override
+ public EnumProtocol protocol() {
+ return EnumProtocol.LOGIN;
+ }
+ // Akarin end
}
diff --git a/src/main/java/net/minecraft/server/PacketLoginOutSetCompression.java b/src/main/java/net/minecraft/server/PacketLoginOutSetCompression.java
index fa0653a7e4a21445fa5c2221a73e9ea419ae157c..d3b5f83d5659322360c89e379db9aef4c623159a 100644
--- a/src/main/java/net/minecraft/server/PacketLoginOutSetCompression.java
+++ b/src/main/java/net/minecraft/server/PacketLoginOutSetCompression.java
@@ -25,4 +25,11 @@ public class PacketLoginOutSetCompression implements Packet<PacketLoginOutListen
public void a(PacketLoginOutListener packetloginoutlistener) {
packetloginoutlistener.a(this);
}
+
+ // Akarin start - add protocol
+ @Override
+ public EnumProtocol protocol() {
+ return EnumProtocol.LOGIN;
+ }
+ // Akarin end
}
diff --git a/src/main/java/net/minecraft/server/PacketLoginOutSuccess.java b/src/main/java/net/minecraft/server/PacketLoginOutSuccess.java
index 54c29047180794a9802b4f1d79fbd35478870226..75d7bc19683a6c411af5f381a4809267a4cadaaa 100644
--- a/src/main/java/net/minecraft/server/PacketLoginOutSuccess.java
+++ b/src/main/java/net/minecraft/server/PacketLoginOutSuccess.java
@@ -34,4 +34,11 @@ public class PacketLoginOutSuccess implements Packet<PacketLoginOutListener> {
public void a(PacketLoginOutListener packetloginoutlistener) {
packetloginoutlistener.a(this);
}
+
+ // Akarin start - add protocol
+ @Override
+ public EnumProtocol protocol() {
+ return EnumProtocol.LOGIN;
+ }
+ // Akarin end
}
diff --git a/src/main/java/net/minecraft/server/PacketStatusListener.java b/src/main/java/net/minecraft/server/PacketStatusListener.java
index 4bb21c48bd50353370ec3c3546a00a5d20e4b9d8..06af567fc1fb3a2053eb4e8af6d93dbb2391616a 100644
--- a/src/main/java/net/minecraft/server/PacketStatusListener.java
+++ b/src/main/java/net/minecraft/server/PacketStatusListener.java
@@ -143,7 +143,7 @@ public class PacketStatusListener implements PacketStatusInListener {
@Override
public void a(PacketStatusInPing packetstatusinping) {
- this.networkManager.sendPacket(new PacketStatusOutPong(packetstatusinping.b()));
+ this.networkManager.sendPacketAsync(new PacketStatusOutPong(packetstatusinping.b())); // Akarin - Async Sending packets
this.networkManager.close(PacketStatusListener.a);
}
}
diff --git a/src/main/java/net/minecraft/server/PacketStatusOutPong.java b/src/main/java/net/minecraft/server/PacketStatusOutPong.java
index 94a0da87db34ee5131686e4fa813500794ffc30d..577c6ef9cfe26d38783cd38353720b0fe457d7f5 100644
--- a/src/main/java/net/minecraft/server/PacketStatusOutPong.java
+++ b/src/main/java/net/minecraft/server/PacketStatusOutPong.java
@@ -25,4 +25,11 @@ public class PacketStatusOutPong implements Packet<PacketStatusOutListener> {
public void a(PacketStatusOutListener packetstatusoutlistener) {
packetstatusoutlistener.a(this);
}
+
+ // Akarin start - add protocol
+ @Override
+ public EnumProtocol protocol() {
+ return EnumProtocol.STATUS;
+ }
+ // Akarin end
}
diff --git a/src/main/java/net/minecraft/server/PacketStatusOutServerInfo.java b/src/main/java/net/minecraft/server/PacketStatusOutServerInfo.java
index 50d5fb62efa7c89c7a73ccf072a0e7e433bcc650..4da7a2c1a4f84661e1018c7233b7a52449532d5b 100644
--- a/src/main/java/net/minecraft/server/PacketStatusOutServerInfo.java
+++ b/src/main/java/net/minecraft/server/PacketStatusOutServerInfo.java
@@ -28,4 +28,11 @@ public class PacketStatusOutServerInfo implements Packet<PacketStatusOutListener
public void a(PacketStatusOutListener packetstatusoutlistener) {
packetstatusoutlistener.a(this);
}
+
+ // Akarin start - add protocol
+ @Override
+ public EnumProtocol protocol() {
+ return EnumProtocol.STATUS;
+ }
+ // Akarin end
}
diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java
index e1225d5017cc0b65a4fd5ac753a705a11679cf2b..3d0397620392043c196cdcf59986ef8a8af17c1c 100644
--- a/src/main/java/net/minecraft/server/PlayerConnection.java
+++ b/src/main/java/net/minecraft/server/PlayerConnection.java
@@ -284,9 +284,9 @@ public class PlayerConnection implements PacketListenerPlayIn {
MinecraftServer minecraftserver = this.minecraftServer;
NetworkManager networkmanager = this.networkManager;
- this.networkManager.getClass();
+ //this.networkManager.getClass(); // Akarin - decompile fixes
// CraftBukkit - Don't wait
- minecraftserver.scheduleOnMain(networkmanager::handleDisconnection); // Paper
+ //minecraftserver.scheduleOnMain(networkmanager::handleDisconnection); // Paper // Akarin - Async Sending packets - already did
}
@Override
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
index 6d6fbf2f50159846267199f74575bedeb54c1473..4b549ccc4137f95167458ead0115e461e47c478f 100644
--- a/src/main/java/net/minecraft/server/PlayerList.java
+++ b/src/main/java/net/minecraft/server/PlayerList.java
@@ -159,13 +159,15 @@ public abstract class PlayerList {
// Spigot - view distance
playerconnection.sendPacket(new PacketPlayOutLogin(entityplayer.getId(), entityplayer.playerInteractManager.getGameMode(), WorldData.c(worlddata.getSeed()), worlddata.isHardcore(), worldserver.worldProvider.getDimensionManager().getType(), this.getMaxPlayers(), worlddata.getType(), worldserver.spigotConfig.viewDistance, flag1, !flag));
entityplayer.getBukkitEntity().sendSupportedChannels(); // CraftBukkit
- playerconnection.sendPacket(new PacketPlayOutCustomPayload(PacketPlayOutCustomPayload.a, (new PacketDataSerializer(Unpooled.buffer())).a(this.getServer().getServerModName())));
- playerconnection.sendPacket(new PacketPlayOutServerDifficulty(worlddata.getDifficulty(), worlddata.isDifficultyLocked()));
- playerconnection.sendPacket(new PacketPlayOutAbilities(entityplayer.abilities));
- playerconnection.sendPacket(new PacketPlayOutHeldItemSlot(entityplayer.inventory.itemInHandIndex));
- playerconnection.sendPacket(new PacketPlayOutRecipeUpdate(this.server.getCraftingManager().b()));
- playerconnection.sendPacket(new PacketPlayOutTags(this.server.getTagRegistry()));
- playerconnection.sendPacket(new PacketPlayOutEntityStatus(entityplayer, (byte) (worldserver.getGameRules().getBoolean(GameRules.REDUCED_DEBUG_INFO) ? 22 : 23))); // Paper - fix this rule not being initialized on the client
+ // Akarin Start
+ playerconnection.networkManager.sendPackets(new PacketPlayOutCustomPayload(PacketPlayOutCustomPayload.a, (new PacketDataSerializer(Unpooled.buffer())).a(this.getServer().getServerModName())),
+ new PacketPlayOutServerDifficulty(worlddata.getDifficulty(), worlddata.isDifficultyLocked()),
+ new PacketPlayOutAbilities(entityplayer.abilities),
+ new PacketPlayOutHeldItemSlot(entityplayer.inventory.itemInHandIndex),
+ new PacketPlayOutRecipeUpdate(this.server.getCraftingManager().b()),
+ new PacketPlayOutTags(this.server.getTagRegistry()),
+ new PacketPlayOutEntityStatus(entityplayer, (byte) (worldserver.getGameRules().getBoolean(GameRules.REDUCED_DEBUG_INFO) ? 22 : 23))); // Paper - fix this rule not being initialized on the client
+ // Akarin End
this.d(entityplayer);
entityplayer.getStatisticManager().c();
entityplayer.B().a(entityplayer);