diff --git a/sp-server/src/main/java/net/lax1dude/eaglercraft/sp/IntegratedServer.java b/sp-server/src/main/java/net/lax1dude/eaglercraft/sp/IntegratedServer.java index b6e10bc..49ae437 100644 --- a/sp-server/src/main/java/net/lax1dude/eaglercraft/sp/IntegratedServer.java +++ b/sp-server/src/main/java/net/lax1dude/eaglercraft/sp/IntegratedServer.java @@ -711,6 +711,7 @@ public class IntegratedServer { if(currentProcess != null) { currentProcess.mainLoop(); if(currentProcess.isServerStopped()) { + sendIPCPacket(new IPCPacketFFProcessKeepAlive(IPCPacket01StopServer.ID)); currentProcess = null; } } diff --git a/sp-server/src/main/java/net/lax1dude/eaglercraft/sp/WorkerListenThread.java b/sp-server/src/main/java/net/lax1dude/eaglercraft/sp/WorkerListenThread.java index f93ddeb..7f4da52 100644 --- a/sp-server/src/main/java/net/lax1dude/eaglercraft/sp/WorkerListenThread.java +++ b/sp-server/src/main/java/net/lax1dude/eaglercraft/sp/WorkerListenThread.java @@ -32,6 +32,11 @@ public class WorkerListenThread { public void stopListening() { this.isListening = false; + List names = new ArrayList(); + names.addAll(channels.keySet()); + for(int i = 0, l = names.size(); i < l; ++i) { + closeChannel(names.get(i)); + } } public boolean openChannel(String player) { diff --git a/sp-server/src/main/java/net/minecraft/server/MinecraftServer.java b/sp-server/src/main/java/net/minecraft/server/MinecraftServer.java index ecef25d..4573b9b 100644 --- a/sp-server/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/sp-server/src/main/java/net/minecraft/server/MinecraftServer.java @@ -396,6 +396,7 @@ public abstract class MinecraftServer implements ICommandSender, Runnable { this.getLogAgent().logSevereException( "Encountered an unexpected exception " + var48.getClass().getSimpleName(), var48); var48.printStackTrace(); + IntegratedServer.throwExceptionToClient("Encountered an unexpected exception", var48); } finally { try { this.stopServer(); diff --git a/src/main/java/net/lax1dude/eaglercraft/IntegratedServer.java b/src/main/java/net/lax1dude/eaglercraft/IntegratedServer.java index fe0b360..a0c3815 100644 --- a/src/main/java/net/lax1dude/eaglercraft/IntegratedServer.java +++ b/src/main/java/net/lax1dude/eaglercraft/IntegratedServer.java @@ -61,7 +61,12 @@ public class IntegratedServer { } public static boolean isWorldRunning() { - return statusState == IntegratedState.WORLD_LOADED || statusState == IntegratedState.WORLD_PAUSED; + return statusState == IntegratedState.WORLD_LOADED || statusState == IntegratedState.WORLD_PAUSED || + statusState == IntegratedState.WORLD_LOADING || statusState == IntegratedState.WORLD_SAVING; + } + + public static boolean isWorldReady() { + return statusState == IntegratedState.WORLD_LOADED || statusState == IntegratedState.WORLD_LOADING; } private static void ensureReady() { @@ -72,7 +77,7 @@ public class IntegratedServer { } private static void ensureWorldReady() { - if(!isWorldRunning()) { + if(!isWorldReady()) { String msg = "Server is in state " + statusState + " '" + IntegratedState.getStateName(statusState) + "' which is not the 'WORLD_LOADED' state for the requested IPC operation"; throw new IllegalStateException(msg); } @@ -131,6 +136,7 @@ public class IntegratedServer { } public static void requestWorldList() { + ensureReady(); statusState = IntegratedState.WORLD_LISTING; worlds.clear(); sendIPCPacket(new IPCPacket0EListWorlds()); @@ -282,6 +288,8 @@ public class IntegratedServer { callFailed = true; break; case IPCPacket01StopServer.ID: + statusState = IntegratedState.WORLD_NONE; + break; case IPCPacket03DeleteWorld.ID: case IPCPacket04RenameWorld.ID: case IPCPacket07ImportWorld.ID: diff --git a/src/main/java/net/minecraft/client/Minecraft.java b/src/main/java/net/minecraft/client/Minecraft.java index 6205b26..addead9 100644 --- a/src/main/java/net/minecraft/client/Minecraft.java +++ b/src/main/java/net/minecraft/client/Minecraft.java @@ -590,7 +590,7 @@ public class Minecraft implements Runnable { } public void stopServerAndDisplayGuiScreen(GuiScreen par1GuiScreen) { - if(IntegratedServer.isWorldRunning()) { + if(!IntegratedServer.isReady()) { IntegratedServer.unloadWorld(); displayGuiScreen(new GuiScreenSingleplayerLoading(par1GuiScreen, "saving world", () -> IntegratedServer.isReady())); }else { diff --git a/src/main/java/net/minecraft/src/GuiSelectWorld.java b/src/main/java/net/minecraft/src/GuiSelectWorld.java index 81f3bce..df580f4 100644 --- a/src/main/java/net/minecraft/src/GuiSelectWorld.java +++ b/src/main/java/net/minecraft/src/GuiSelectWorld.java @@ -57,7 +57,8 @@ public class GuiSelectWorld extends GuiScreen { /** The rename button in the world selection GUI */ private GuiButton buttonRename; private GuiButton buttonBackup; - + + private boolean hasRequestedWorlds = false; private boolean waitingForWorlds = false; public GuiSelectWorld(GuiScreen par1GuiScreen) { @@ -72,8 +73,14 @@ public class GuiSelectWorld extends GuiScreen { this.screenTitle = var1.translateKey("selectWorld.title"); this.saveList = new LinkedList(); - waitingForWorlds = true; - IntegratedServer.requestWorldList(); + if(IntegratedServer.isReady()) { + hasRequestedWorlds = true; + waitingForWorlds = true; + IntegratedServer.requestWorldList(); + }else { + IntegratedServer.unloadWorld(); + hasRequestedWorlds = false; + } this.localizedWorldText = var1.translateKey("selectWorld.world"); this.localizedMustConvertText = var1.translateKey("selectWorld.conversion"); @@ -86,7 +93,11 @@ public class GuiSelectWorld extends GuiScreen { } public void updateScreen() { - if(waitingForWorlds && IntegratedServer.getWorldList() != null) { + if(!hasRequestedWorlds && IntegratedServer.isReady()) { + hasRequestedWorlds = true; + waitingForWorlds = true; + IntegratedServer.requestWorldList(); + }else if(waitingForWorlds && IntegratedServer.getWorldList() != null) { waitingForWorlds = false; this.loadSaves(); } diff --git a/src/main/java/net/minecraft/src/NetClientHandler.java b/src/main/java/net/minecraft/src/NetClientHandler.java index 626c320..36aea32 100644 --- a/src/main/java/net/minecraft/src/NetClientHandler.java +++ b/src/main/java/net/minecraft/src/NetClientHandler.java @@ -14,6 +14,8 @@ import net.lax1dude.eaglercraft.DefaultSkinRenderer; import net.lax1dude.eaglercraft.EaglerAdapter; import net.lax1dude.eaglercraft.IntegratedServer; import net.lax1dude.eaglercraft.EaglercraftRandom; +import net.lax1dude.eaglercraft.GuiScreenSingleplayerException; +import net.lax1dude.eaglercraft.GuiScreenSingleplayerLoading; import net.lax1dude.eaglercraft.Voice; import net.lax1dude.eaglercraft.WebsocketNetworkManager; import net.lax1dude.eaglercraft.WorkerNetworkManager; @@ -123,8 +125,9 @@ public class NetClientHandler extends NetHandler { this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.disconnected", "RateLimit." + r.name(), null)); } }else { - if(!(this.mc.currentScreen instanceof GuiDisconnected)) { - this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.disconnected", "disconnect.endOfStream", null)); + if(!(this.mc.currentScreen instanceof GuiDisconnected) && !(this.mc.currentScreen instanceof GuiScreenSingleplayerException) && + !(this.mc.currentScreen instanceof GuiScreenSingleplayerLoading)) { + this.mc.stopServerAndDisplayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.disconnected", "disconnect.endOfStream", null)); } } this.disconnected = true; @@ -505,10 +508,10 @@ public class NetClientHandler extends NetHandler { this.mc.loadWorld((WorldClient) null); if(par1Packet255KickDisconnect.reason.equalsIgnoreCase("BLOCKED")) { EaglerAdapter.logRateLimit(netManager.getServerURI(), RateLimit.BLOCKED); - this.mc.stopServerAndDisplayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.kickBlocked", "disconnect.endOfStream", (Object[])null)); + this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.kickBlocked", "disconnect.endOfStream", (Object[])null)); }else if(par1Packet255KickDisconnect.reason.equalsIgnoreCase("LOCKED")) { EaglerAdapter.logRateLimit(netManager.getServerURI(), RateLimit.LOCKED); - this.mc.stopServerAndDisplayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.kickLocked", "disconnect.endOfStream", (Object[])null)); + this.mc.displayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.ratelimit.kickLocked", "disconnect.endOfStream", (Object[])null)); }else { this.mc.stopServerAndDisplayGuiScreen(new GuiDisconnected(backToMenu(), "disconnect.disconnected", "disconnect.genericReason", new Object[] { par1Packet255KickDisconnect.reason })); }