From e9dbc713620ae751bf8399fdb7b841c9cc374c99 Mon Sep 17 00:00:00 2001 From: Lex Manos Date: Sat, 13 Dec 2014 17:45:38 -0800 Subject: [PATCH] Ensure that EntitySpawn and OpenGUI packets are handled in the world thread. Also log all errors that are thrown in FutureTasks. --- .../net/minecraft/client/Minecraft.java.patch | 9 +++++++ .../server/MinecraftServer.java.patch | 9 +++++++ .../integrated/IntegratedServer.java.patch | 9 +++++++ .../fml/client/FMLClientHandler.java | 21 ++++++++++++++++ .../fml/common/FMLCommonHandler.java | 25 +++++++++++++++++++ .../fml/common/IFMLSidedHandler.java | 3 +++ .../network/internal/EntitySpawnHandler.java | 25 +++++++++++++++++-- .../network/internal/OpenGuiHandler.java | 24 +++++++++++++++++- .../fml/server/FMLServerHandler.java | 8 ++++++ 9 files changed, 130 insertions(+), 3 deletions(-) diff --git a/fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch index e2c272a11a..da90e830c6 100644 --- a/fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/fml/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -59,6 +59,15 @@ } public boolean func_152349_b() +@@ -1000,7 +1004,7 @@ + { + while (!this.field_152351_aB.isEmpty()) + { +- ((FutureTask)this.field_152351_aB.poll()).run(); ++ net.minecraftforge.fml.common.FMLCommonHandler.callFuture(((FutureTask)this.field_152351_aB.poll())); + } + } + @@ -1035,9 +1039,11 @@ if (!this.field_71454_w) diff --git a/fml/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch b/fml/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch index 450fde291b..55f72e5d59 100644 --- a/fml/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch +++ b/fml/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch @@ -71,6 +71,15 @@ } public void func_71190_q() +@@ -657,7 +671,7 @@ + { + try + { +- ((FutureTask)this.field_175589_i.poll()).run(); ++ net.minecraftforge.fml.common.FMLCommonHandler.callFuture(((FutureTask)this.field_175589_i.poll())); + } + catch (Throwable throwable2) + { @@ -686,6 +700,7 @@ } diff --git a/fml/patches/minecraft/net/minecraft/server/integrated/IntegratedServer.java.patch b/fml/patches/minecraft/net/minecraft/server/integrated/IntegratedServer.java.patch index d08b9dada3..4f0ce861c5 100644 --- a/fml/patches/minecraft/net/minecraft/server/integrated/IntegratedServer.java.patch +++ b/fml/patches/minecraft/net/minecraft/server/integrated/IntegratedServer.java.patch @@ -12,3 +12,12 @@ } public void func_71217_p() +@@ -171,7 +172,7 @@ + { + try + { +- ((FutureTask)this.field_175589_i.poll()).run(); ++ net.minecraftforge.fml.common.FMLCommonHandler.callFuture(((FutureTask)this.field_175589_i.poll())); + } + catch (Throwable throwable) + { diff --git a/fml/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java b/fml/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java index a5f39e9e87..b680df20e0 100644 --- a/fml/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java +++ b/fml/src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java @@ -53,7 +53,15 @@ import net.minecraft.network.INetHandler; import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.NetworkManager; import net.minecraft.network.ServerStatusResponse; +import net.minecraft.network.handshake.INetHandlerHandshakeServer; +import net.minecraft.network.login.INetHandlerLoginClient; +import net.minecraft.network.login.INetHandlerLoginServer; +import net.minecraft.network.play.INetHandlerPlayClient; +import net.minecraft.network.play.INetHandlerPlayServer; +import net.minecraft.network.status.INetHandlerStatusClient; +import net.minecraft.network.status.INetHandlerStatusServer; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.IThreadListener; import net.minecraft.util.ResourceLocation; import net.minecraft.world.WorldSettings; import net.minecraft.world.storage.SaveFormatOld; @@ -842,4 +850,17 @@ public class FMLClientHandler implements IFMLSidedHandler public void allowLogins() { // NOOP for integrated server } + + @Override + public IThreadListener getWorldThread(INetHandler net) + { + if (net instanceof INetHandlerPlayClient || + net instanceof INetHandlerLoginClient || + net instanceof INetHandlerStatusClient) return getClient(); + if (net instanceof INetHandlerHandshakeServer || + net instanceof INetHandlerLoginServer || + net instanceof INetHandlerPlayServer || + net instanceof INetHandlerStatusServer) return getServer(); + throw new RuntimeException("Unknown INetHandler: " + net); + } } diff --git a/fml/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java b/fml/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java index 6689a23d70..521f2f1feb 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/FMLCommonHandler.java @@ -18,6 +18,8 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import net.minecraft.crash.CrashReport; @@ -35,6 +37,7 @@ import net.minecraft.network.handshake.client.C00Handshake; import net.minecraft.network.login.server.S00PacketDisconnect; import net.minecraft.server.MinecraftServer; import net.minecraft.util.ChatComponentText; +import net.minecraft.util.IThreadListener; import net.minecraft.world.World; import net.minecraft.world.storage.SaveHandler; import net.minecraft.world.storage.WorldInfo; @@ -660,4 +663,26 @@ public class FMLCommonHandler Runtime.getRuntime().exit(exitCode); } } + + public IThreadListener getWorldThread(INetHandler net) + { + return sidedDelegate.getWorldThread(net); + } + + public static void callFuture(FutureTask task) + { + try + { + task.run(); + task.get(); // Forces the exception to be thrown if any + } + catch (InterruptedException e) + { + FMLLog.log(Level.FATAL, e, "Exception caught executing FutureTask: " + e.toString()); + } + catch (ExecutionException e) + { + FMLLog.log(Level.FATAL, e, "Exception caught executing FutureTask: " + e.toString()); + } + } } diff --git a/fml/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java b/fml/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java index 6b2614a378..0c94391dec 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/IFMLSidedHandler.java @@ -19,6 +19,7 @@ import java.util.Set; import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.IThreadListener; import net.minecraftforge.fml.common.eventhandler.EventBus; import net.minecraftforge.fml.relauncher.Side; @@ -59,4 +60,6 @@ public interface IFMLSidedHandler boolean shouldAllowPlayerLogins(); void allowLogins(); + + IThreadListener getWorldThread(INetHandler net); } diff --git a/fml/src/main/java/net/minecraftforge/fml/common/network/internal/EntitySpawnHandler.java b/fml/src/main/java/net/minecraftforge/fml/common/network/internal/EntitySpawnHandler.java index ad9f348e0c..bf5eb7b4be 100644 --- a/fml/src/main/java/net/minecraftforge/fml/common/network/internal/EntitySpawnHandler.java +++ b/fml/src/main/java/net/minecraftforge/fml/common/network/internal/EntitySpawnHandler.java @@ -11,11 +11,14 @@ import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; +import net.minecraft.util.IThreadListener; import net.minecraft.world.World; import net.minecraftforge.fml.client.FMLClientHandler; +import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.FMLLog; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.network.internal.FMLMessage.EntityAdjustMessage; import net.minecraftforge.fml.common.network.internal.FMLMessage.EntityMessage; import net.minecraftforge.fml.common.registry.EntityRegistry; @@ -27,7 +30,26 @@ import com.google.common.base.Throwables; public class EntitySpawnHandler extends SimpleChannelInboundHandler { @Override - protected void channelRead0(ChannelHandlerContext ctx, EntityMessage msg) throws Exception + protected void channelRead0(ChannelHandlerContext ctx, final EntityMessage msg) throws Exception + { + IThreadListener thread = FMLCommonHandler.instance().getWorldThread(ctx.channel().attr(NetworkRegistry.NET_HANDLER).get()); + if (thread.isCallingFromMinecraftThread()) + { + process(msg); + } + else + { + thread.addScheduledTask(new Runnable() + { + public void run() + { + EntitySpawnHandler.this.process(msg); + } + }); + } + } + + private void process(EntityMessage msg) { if (msg.getClass().equals(FMLMessage.EntitySpawnMessage.class)) { @@ -52,7 +74,6 @@ public class EntitySpawnHandler extends SimpleChannelInboundHandler { @Override - protected void channelRead0(ChannelHandlerContext ctx, OpenGui msg) throws Exception + protected void channelRead0(ChannelHandlerContext ctx, final OpenGui msg) throws Exception + { + IThreadListener thread = FMLCommonHandler.instance().getWorldThread(ctx.channel().attr(NetworkRegistry.NET_HANDLER).get()); + if (thread.isCallingFromMinecraftThread()) + { + process(msg); + } + else + { + thread.addScheduledTask(new Runnable() + { + public void run() + { + OpenGuiHandler.this.process(msg); + } + }); + } + } + + private void process(OpenGui msg) { EntityPlayer player = FMLClientHandler.instance().getClient().thePlayer; player.openGui(msg.modId, msg.modGuiId, player.worldObj, msg.x, msg.y, msg.z); diff --git a/fml/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java b/fml/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java index bbb64e0557..11e2ac2255 100644 --- a/fml/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java +++ b/fml/src/main/java/net/minecraftforge/fml/server/FMLServerHandler.java @@ -23,6 +23,7 @@ import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.NetworkManager; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.util.IThreadListener; import net.minecraft.world.storage.SaveFormatOld; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.FMLLog; @@ -258,4 +259,11 @@ public class FMLServerHandler implements IFMLSidedHandler public void allowLogins() { DedicatedServer.allowPlayerLogins = true; } + + @Override + public IThreadListener getWorldThread(INetHandler net) + { + // Always the server on the dedicated server, eventually add Per-World if Mojang adds world stuff. + return getServer(); + } }