diff --git a/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.java.patch b/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.java.patch new file mode 100644 index 0000000000..fe5853480d --- /dev/null +++ b/patches/minecraft/net/minecraft/client/LoadingScreenRenderer.java.patch @@ -0,0 +1,26 @@ +--- ../src-base/minecraft/net/minecraft/client/LoadingScreenRenderer.java ++++ ../src-work/minecraft/net/minecraft/client/LoadingScreenRenderer.java +@@ -1,5 +1,6 @@ + package net.minecraft.client; + ++import cpw.mods.fml.client.FMLClientHandler; + import cpw.mods.fml.relauncher.Side; + import cpw.mods.fml.relauncher.SideOnly; + import net.minecraft.client.gui.Gui; +@@ -147,6 +148,8 @@ + GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); + } + ++ if (!FMLClientHandler.instance().handleLoadingScreen(scaledresolution)) ++ { + Tessellator tessellator = Tessellator.field_78398_a; + this.field_73725_b.func_110434_K().func_110577_a(Gui.field_110325_k); + float f = 32.0F; +@@ -184,6 +187,7 @@ + OpenGlHelper.func_148821_a(770, 771, 1, 0); + this.field_73725_b.field_71466_p.func_78261_a(this.field_73726_c, (l - this.field_73725_b.field_71466_p.func_78256_a(this.field_73726_c)) / 2, i1 / 2 - 4 - 16, 16777215); + this.field_73725_b.field_71466_p.func_78261_a(this.field_73727_a, (l - this.field_73725_b.field_71466_p.func_78256_a(this.field_73727_a)) / 2, i1 / 2 - 4 + 8, 16777215); ++ } + this.field_146588_g.func_147609_e(); + + if (OpenGlHelper.func_148822_b()) diff --git a/patches/minecraft/net/minecraft/client/Minecraft.java.patch b/patches/minecraft/net/minecraft/client/Minecraft.java.patch index 00d133e9ba..9739784ef8 100644 --- a/patches/minecraft/net/minecraft/client/Minecraft.java.patch +++ b/patches/minecraft/net/minecraft/client/Minecraft.java.patch @@ -1,16 +1,17 @@ --- ../src-base/minecraft/net/minecraft/client/Minecraft.java +++ ../src-work/minecraft/net/minecraft/client/Minecraft.java -@@ -1,6 +1,9 @@ +@@ -1,6 +1,10 @@ package net.minecraft.client; import com.google.common.collect.Lists; + +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.common.FMLCommonHandler; ++import cpw.mods.fml.common.StartupQuery; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.util.concurrent.GenericFutureListener; -@@ -146,6 +149,8 @@ +@@ -146,6 +150,8 @@ import org.lwjgl.opengl.PixelFormat; import org.lwjgl.util.glu.GLU; @@ -19,21 +20,7 @@ @SideOnly(Side.CLIENT) public class Minecraft implements IPlayerUsage { -@@ -323,8 +328,11 @@ - - public void func_71404_a(CrashReport p_71404_1_) - { -- this.field_71434_R = true; -- this.field_71433_S = p_71404_1_; -+ if (!FMLClientHandler.instance().handlingCrash(p_71404_1_)) -+ { -+ this.field_71434_R = true; -+ this.field_71433_S = p_71404_1_; -+ } - } - - public void func_71377_b(CrashReport p_71377_1_) -@@ -448,7 +456,7 @@ +@@ -448,7 +454,7 @@ this.field_110451_am = new SimpleReloadableResourceManager(this.field_110452_an); this.field_135017_as = new LanguageManager(this.field_110452_an, this.field_71474_y.field_74363_ab); this.field_110451_am.func_110542_a(this.field_135017_as); @@ -42,7 +29,7 @@ this.field_71446_o = new TextureManager(this.field_110451_am); this.field_110451_am.func_110542_a(this.field_71446_o); this.field_147127_av = new SoundHandler(this.field_110451_am, this.field_71474_y); -@@ -508,12 +516,13 @@ +@@ -508,12 +514,13 @@ this.field_71446_o.func_130088_a(TextureMap.field_110576_c, new TextureMap(1, "textures/items")); GL11.glViewport(0, 0, this.field_71443_c, this.field_71440_d); this.field_71452_i = new EffectRenderer(this.field_71441_e, this.field_71446_o); @@ -57,7 +44,7 @@ } else { -@@ -527,6 +536,7 @@ +@@ -527,6 +534,7 @@ this.func_71352_k(); } @@ -65,7 +52,7 @@ Display.setVSyncEnabled(this.field_71474_y.field_74352_v); } -@@ -916,9 +926,11 @@ +@@ -916,9 +924,11 @@ if (!this.field_71454_w) { @@ -77,7 +64,7 @@ } GL11.glFlush(); -@@ -1496,6 +1508,8 @@ +@@ -1496,6 +1506,8 @@ --this.field_71467_ac; } @@ -86,7 +73,7 @@ this.field_71424_I.func_76320_a("gui"); if (!this.field_71445_n) -@@ -1646,6 +1660,7 @@ +@@ -1646,6 +1658,7 @@ this.field_71462_r.func_146274_d(); } } @@ -94,7 +81,7 @@ } if (this.field_71429_W > 0) -@@ -1787,6 +1802,7 @@ +@@ -1787,6 +1800,7 @@ } } } @@ -102,7 +89,7 @@ } } -@@ -1978,12 +1994,15 @@ +@@ -1978,12 +1992,15 @@ this.field_71453_ak.func_74428_b(); } @@ -118,7 +105,20 @@ this.func_71403_a((WorldClient)null); System.gc(); ISaveHandler isavehandler = this.field_71469_aa.func_75804_a(p_71371_1_, false); -@@ -2094,6 +2113,7 @@ +@@ -2019,6 +2036,12 @@ + + while (!this.field_71437_Z.func_71200_ad()) + { ++ if (!StartupQuery.check()) ++ { ++ func_71403_a(null); ++ func_147108_a(null); ++ return; ++ } + String s2 = this.field_71437_Z.func_71195_b_(); + + if (s2 != null) +@@ -2094,6 +2117,7 @@ this.field_110448_aq.func_148529_f(); this.func_71351_a((ServerData)null); this.field_71455_al = false; diff --git a/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch b/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch index 5970b575f5..94f0a0c80c 100644 --- a/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch +++ b/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch @@ -1,6 +1,6 @@ --- ../src-base/minecraft/net/minecraft/server/MinecraftServer.java +++ ../src-work/minecraft/net/minecraft/server/MinecraftServer.java -@@ -4,6 +4,10 @@ +@@ -4,6 +4,11 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; @@ -8,10 +8,20 @@ +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.LoaderState; ++import cpw.mods.fml.common.StartupQuery; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; -@@ -381,6 +385,7 @@ +@@ -333,7 +338,7 @@ + + public void func_71260_j() + { +- if (!this.field_71290_O) ++ if (!this.field_71290_O && Loader.instance().hasReachedState(LoaderState.SERVER_STARTED)) + { + field_147145_h.info("Stopping server"); + +@@ -381,6 +386,7 @@ { if (this.func_71197_b()) { @@ -19,7 +29,7 @@ long i = func_130071_aq(); long l = 0L; this.field_147147_p.func_151315_a(new ChatComponentText(this.field_71286_C)); -@@ -425,6 +430,7 @@ +@@ -425,12 +431,17 @@ Thread.sleep(1L); this.field_71296_Q = true; } @@ -27,18 +37,17 @@ } else { -@@ -462,7 +468,10 @@ - { - try - { -+ if (Loader.instance().hasReachedState(LoaderState.SERVER_STARTED)) -+ { - this.func_71260_j(); -+ } - this.field_71316_v = true; + this.func_71228_a((CrashReport)null); } - catch (Throwable throwable) -@@ -471,6 +480,8 @@ + } ++ catch (StartupQuery.AbortedException e) ++ { ++ // ignore silently ++ } + catch (Throwable throwable1) + { + field_147145_h.error("Encountered an unexpected exception", throwable1); +@@ -471,6 +482,8 @@ } finally { @@ -47,7 +56,7 @@ this.func_71240_o(); } } -@@ -513,6 +524,7 @@ +@@ -513,6 +526,7 @@ { long i = System.nanoTime(); AxisAlignedBB.func_72332_a().func_72298_a(); @@ -55,7 +64,7 @@ ++this.field_71315_w; if (this.field_71295_T) -@@ -566,6 +578,7 @@ +@@ -566,6 +580,7 @@ this.field_71304_b.func_76319_b(); this.field_71304_b.func_76319_b(); @@ -63,7 +72,7 @@ } public void func_71190_q() -@@ -593,6 +606,7 @@ +@@ -593,6 +608,7 @@ } this.field_71304_b.func_76320_a("tick"); @@ -71,7 +80,7 @@ CrashReport crashreport; try -@@ -617,6 +631,7 @@ +@@ -617,6 +633,7 @@ throw new ReportedException(crashreport); } @@ -79,7 +88,15 @@ this.field_71304_b.func_76319_b(); this.field_71304_b.func_76320_a("tracker"); worldserver.func_73039_n().func_72788_a(); -@@ -695,7 +710,7 @@ +@@ -648,6 +665,7 @@ + + public void func_71256_s() + { ++ StartupQuery.reset(); + (new Thread("Server thread") + { + private static final String __OBFID = "CL_00001418"; +@@ -695,7 +713,7 @@ public String getServerModName() { diff --git a/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch b/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch index 38007f857c..11c0322320 100644 --- a/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch +++ b/patches/minecraft/net/minecraft/world/storage/SaveHandler.java.patch @@ -6,7 +6,7 @@ import java.io.IOException; + +import cpw.mods.fml.common.FMLCommonHandler; -+import cpw.mods.fml.common.registry.GameRegistryException; ++import cpw.mods.fml.common.StartupQuery; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; @@ -27,9 +27,9 @@ + FMLCommonHandler.instance().handleWorldDataLoad(this, worldInfo, nbttagcompound); + return worldInfo; } -+ catch (GameRegistryException gre) ++ catch (StartupQuery.AbortedException e) + { -+ throw gre; ++ throw e; + } catch (Exception exception1) { @@ -43,9 +43,9 @@ + FMLCommonHandler.instance().handleWorldDataLoad(this, worldInfo, nbttagcompound); + return worldInfo; } -+ catch (GameRegistryException gre) ++ catch (StartupQuery.AbortedException e) + { -+ throw gre; ++ throw e; + } catch (Exception exception) { diff --git a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java index 4d98ee4e98..c8265df13c 100644 --- a/src/main/java/cpw/mods/fml/client/FMLClientHandler.java +++ b/src/main/java/cpw/mods/fml/client/FMLClientHandler.java @@ -25,6 +25,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; + import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityClientPlayerMP; import net.minecraft.client.gui.Gui; @@ -32,6 +33,7 @@ import net.minecraft.client.gui.GuiIngameMenu; import net.minecraft.client.gui.GuiMainMenu; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiSelectWorld; +import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.gui.ServerListEntryNormal; import net.minecraft.client.multiplayer.GuiConnecting; import net.minecraft.client.multiplayer.ServerData; @@ -55,7 +57,10 @@ import net.minecraft.network.ServerStatusResponse; import net.minecraft.server.MinecraftServer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.WorldSettings; + import org.apache.logging.log4j.Level; +import org.lwjgl.input.Mouse; + import com.google.common.base.Strings; import com.google.common.base.Throwables; import com.google.common.collect.BiMap; @@ -67,6 +72,7 @@ import com.google.common.collect.Maps; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; + import cpw.mods.fml.client.registry.RenderingRegistry; import cpw.mods.fml.common.DummyModContainer; import cpw.mods.fml.common.DuplicateModsFoundException; @@ -81,6 +87,7 @@ import cpw.mods.fml.common.MissingModsException; import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.ModMetadata; import cpw.mods.fml.common.ObfuscationReflectionHelper; +import cpw.mods.fml.common.StartupQuery; import cpw.mods.fml.common.WorldAccessContainer; import cpw.mods.fml.common.WrongMinecraftVersionException; import cpw.mods.fml.common.event.FMLMissingMappingsEvent; @@ -88,7 +95,6 @@ import cpw.mods.fml.common.event.FMLMissingMappingsEvent.Action; import cpw.mods.fml.common.eventhandler.EventBus; import cpw.mods.fml.common.network.FMLNetworkEvent; import cpw.mods.fml.common.registry.GameData; -import cpw.mods.fml.common.registry.GameRegistryException; import cpw.mods.fml.common.registry.LanguageRegistry; import cpw.mods.fml.common.toposort.ModSortingException; import cpw.mods.fml.relauncher.Side; @@ -424,6 +430,39 @@ public class FMLClientHandler implements IFMLSidedHandler client.displayGuiScreen(gui); } + @Override + public void queryUser(StartupQuery query) throws InterruptedException + { + if (query.getResult() == null) + { + client.displayGuiScreen(new GuiNotification(query)); + } + else + { + client.displayGuiScreen(new GuiConfirmation(query)); + } + } + + public boolean handleLoadingScreen(ScaledResolution scaledResolution) + { + if (client.currentScreen instanceof GuiMainMenu) + { + return false; + } + else + { + int width = scaledResolution.getScaledWidth(); + int height = scaledResolution.getScaledHeight(); + int mouseX = Mouse.getX() * width / client.displayWidth; + int mouseZ = height - Mouse.getY() * height / client.displayHeight - 1; + + client.currentScreen.drawScreen(mouseX, mouseZ, 0); + client.currentScreen.handleInput(); + + return true; + } + } + public WorldClient getWorldClient() { return client.theWorld; @@ -596,42 +635,10 @@ public class FMLClientHandler implements IFMLSidedHandler } else { - - launchIntegratedServerCallback(dirName, saveName); + client.launchIntegratedServer(dirName, saveName, (WorldSettings)null); } } - private CountDownLatch gameReleaseLatch; - private Thread clientWaiter; - private GameRegistryException gre; - - public void launchIntegratedServerCallback(String dirName, String saveName) - { - try - { - try - { - Thread.interrupted(); - gameReleaseLatch = new CountDownLatch(1); - clientWaiter = Thread.currentThread(); - client.launchIntegratedServer(dirName, saveName, (WorldSettings)null); - System.out.printf("POKEE %b\n", Thread.currentThread().isInterrupted()); - gameReleaseLatch.await(); - } - catch (InterruptedException ie) - { - Thread.interrupted(); - throw gre; - } - } - catch (GameRegistryException gre) - { - client.loadWorld(null); - showGuiScreen(new GuiModItemsMissing(gre.getItems())); - } - Thread.interrupted(); - } - public void showInGameModOptions(GuiIngameMenu guiIngameMenu) { showGuiScreen(new GuiIngameModOptions(guiIngameMenu)); @@ -826,57 +833,6 @@ public class FMLClientHandler implements IFMLSidedHandler return defaultMissingAction; } - @Override - public void serverLoadedSuccessfully() - { - if (gameReleaseLatch!=null) - { - gameReleaseLatch.countDown(); - } - } - - @Override - public void failedServerLoading(RuntimeException ex, WorldAccessContainer wac) - { - if (wac instanceof FMLContainer && ex instanceof GameRegistryException) - { - try - { - gre = (GameRegistryException) ex; - Executors.newSingleThreadExecutor().submit(new Callable() - { - // This needs to happen in a separate thread so that the server can "crash" - // The three pokes are for the client - it's in a sleep loop, and needs to get - // out of it - @Override - public Void call() throws Exception - { - System.err.println("POKE"); - clientWaiter.interrupt(); - Thread.sleep(50); - System.err.println("POKE"); - clientWaiter.interrupt(); - Thread.sleep(50); - System.err.println("POKE"); - clientWaiter.interrupt(); - return null; - } - - }); - - } - catch (Throwable t) - { - FMLLog.log(Level.ERROR, t, "stuff"); - } - } - } - - public boolean handlingCrash(CrashReport report) - { - return report.getCrashCause() instanceof GameRegistryException; - } - @Override public boolean shouldAllowPlayerLogins() { diff --git a/src/main/java/cpw/mods/fml/client/GuiConfirmation.java b/src/main/java/cpw/mods/fml/client/GuiConfirmation.java new file mode 100644 index 0000000000..6f3e1fa622 --- /dev/null +++ b/src/main/java/cpw/mods/fml/client/GuiConfirmation.java @@ -0,0 +1,33 @@ +package cpw.mods.fml.client; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiOptionButton; +import net.minecraft.client.resources.I18n; +import cpw.mods.fml.common.StartupQuery; + +public class GuiConfirmation extends GuiNotification +{ + public GuiConfirmation(StartupQuery query) + { + super(query); + } + + @SuppressWarnings("unchecked") + @Override + public void initGui() + { + this.buttonList.add(new GuiOptionButton(0, this.width / 2 - 155, this.height - 38, I18n.format("gui.yes"))); + this.buttonList.add(new GuiOptionButton(1, this.width / 2 - 155 + 160, this.height - 38, I18n.format("gui.no"))); + } + + @Override + protected void actionPerformed(GuiButton button) + { + if (button.enabled && (button.id == 0 || button.id == 1)) + { + FMLClientHandler.instance().showGuiScreen(null); + query.setResult(button.id == 0); + query.finish(); + } + } +} diff --git a/src/main/java/cpw/mods/fml/client/GuiNotification.java b/src/main/java/cpw/mods/fml/client/GuiNotification.java new file mode 100644 index 0000000000..ffbcc6bc1e --- /dev/null +++ b/src/main/java/cpw/mods/fml/client/GuiNotification.java @@ -0,0 +1,62 @@ +package cpw.mods.fml.client; + +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.resources.I18n; +import cpw.mods.fml.common.StartupQuery; + +public class GuiNotification extends GuiScreen +{ + public GuiNotification(StartupQuery query) + { + this.query = query; + } + + @SuppressWarnings("unchecked") + @Override + public void initGui() + { + this.buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height - 38, I18n.format("gui.done"))); + } + + @Override + protected void actionPerformed(GuiButton button) + { + if (button.enabled && button.id == 0) + { + FMLClientHandler.instance().showGuiScreen(null); + query.finish(); + } + } + + @Override + public void drawScreen(int p_73863_1_, int p_73863_2_, float p_73863_3_) + { + this.drawDefaultBackground(); + + String[] lines = query.getText().split("\n"); + + int spaceAvailable = this.height - 38 - 20; + int spaceRequired = Math.min(spaceAvailable, 10 + 10 * lines.length); + + int offset = 10 + (spaceAvailable - spaceRequired) / 2; // vertically centered + + for (String line : lines) + { + if (offset >= spaceAvailable) + { + this.drawCenteredString(this.fontRendererObj, "...", this.width / 2, offset, 0xFFFFFF); + break; + } + else + { + if (!line.isEmpty()) this.drawCenteredString(this.fontRendererObj, line, this.width / 2, offset, 0xFFFFFF); + offset += 10; + } + } + + super.drawScreen(p_73863_1_, p_73863_2_, p_73863_3_); + } + + protected final StartupQuery query; +} diff --git a/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java b/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java index 922a554b53..3b0d900f75 100644 --- a/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java +++ b/src/main/java/cpw/mods/fml/client/GuiOldSaveLoadConfirm.java @@ -2,12 +2,16 @@ package cpw.mods.fml.client; import java.io.File; import java.io.IOException; + import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiLabel; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiSelectWorld; import net.minecraft.client.gui.GuiYesNo; +import net.minecraft.world.WorldSettings; + import org.apache.logging.log4j.Level; + import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.ObfuscationReflectionHelper; import cpw.mods.fml.common.ZipperUtil; @@ -65,9 +69,7 @@ public class GuiOldSaveLoadConfirm extends GuiYesNo { return; } FMLClientHandler.instance().showGuiScreen(null); - FMLClientHandler.instance().launchIntegratedServerCallback(dirName, saveName); + mc.launchIntegratedServer(dirName, saveName, (WorldSettings)null); } - } - } diff --git a/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java b/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java index 2c57a4eca7..5573c0d6cc 100644 --- a/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java +++ b/src/main/java/cpw/mods/fml/common/FMLCommonHandler.java @@ -15,6 +15,9 @@ package cpw.mods.fml.common; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; + import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.minecraft.entity.item.EntityItem; @@ -29,8 +32,10 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.world.World; import net.minecraft.world.storage.SaveHandler; import net.minecraft.world.storage.WorldInfo; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Logger; + import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; @@ -39,6 +44,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.MapMaker; import com.google.common.collect.Maps; import com.google.common.collect.Sets; + import cpw.mods.fml.common.event.FMLMissingMappingsEvent; import cpw.mods.fml.common.eventhandler.EventBus; import cpw.mods.fml.common.gameevent.InputEvent; @@ -266,7 +272,6 @@ public class FMLCommonHandler public boolean handleServerStarting(MinecraftServer server) { - sidedDelegate.serverLoadedSuccessfully(); return Loader.instance().serverStarting(server); } @@ -290,6 +295,11 @@ public class FMLCommonHandler sidedDelegate.showGuiScreen(clientGuiElement); } + public void queryUser(StartupQuery query) throws InterruptedException + { + sidedDelegate.queryUser(query); + } + public void onServerStart(MinecraftServer dedicatedServer) { FMLServerHandler.instance(); @@ -381,15 +391,7 @@ public class FMLCommonHandler WorldAccessContainer wac = ((InjectedModContainer)mc).getWrappedWorldAccessContainer(); if (wac != null) { - try - { - wac.readData(handler, worldInfo, additionalProperties, tagCompound.getCompoundTag(mc.getModId())); - } - catch (RuntimeException ex) - { - sidedDelegate.failedServerLoading(ex, wac); - throw ex; - } + wac.readData(handler, worldInfo, additionalProperties, tagCompound.getCompoundTag(mc.getModId())); } } } diff --git a/src/main/java/cpw/mods/fml/common/FMLContainer.java b/src/main/java/cpw/mods/fml/common/FMLContainer.java index 73302cabc0..8e699e26ce 100644 --- a/src/main/java/cpw/mods/fml/common/FMLContainer.java +++ b/src/main/java/cpw/mods/fml/common/FMLContainer.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; + import net.minecraft.item.Item; import net.minecraft.nbt.NBTBase; import net.minecraft.nbt.NBTTagCompound; @@ -40,7 +41,6 @@ import cpw.mods.fml.common.network.NetworkCheckHandler; import cpw.mods.fml.common.network.NetworkRegistry; import cpw.mods.fml.common.network.internal.FMLNetworkHandler; import cpw.mods.fml.common.registry.GameData; -import cpw.mods.fml.common.registry.GameRegistryException; import cpw.mods.fml.relauncher.Side; /** @@ -160,6 +160,9 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai } } } + + List failedElements = null; + if (tag.hasKey("ModItemData")) { FMLLog.info("Attempting to convert old world data to new system. This may be trouble!"); @@ -200,11 +203,8 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai dataList.put(itemLabel, itemId); } } - List failedElements = GameData.injectWorldIDMap(dataList, true, true); - if (!failedElements.isEmpty()) - { - throw new GameRegistryException("Failed to load the world - there are fatal block and item id issues", failedElements); - } + failedElements = GameData.injectWorldIDMap(dataList, true, true); + } else if (tag.hasKey("ItemData")) { @@ -243,11 +243,20 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai itemAliases.put(dataTag.getString("K"), dataTag.getString("V")); } - List failedElements = GameData.injectWorldIDMap(dataList, blockedIds, blockAliases, itemAliases, true, true); - if (!failedElements.isEmpty()) - { - throw new GameRegistryException("Failed to load the world - there are fatal block and item id issues", failedElements); - } + failedElements = GameData.injectWorldIDMap(dataList, blockedIds, blockAliases, itemAliases, true, true); + } + + if (failedElements != null && !failedElements.isEmpty()) + { + String text = "Forge Mod Loader could not load this save\n\n" + + "There are "+failedElements.size()+" unassigned blocks and items in this save\n"+ + "You will not be able to load until they are present again\n\n"+ + "Missing Blocks/Items:\n"; + + for (String s : failedElements) text += s + "\n"; + + StartupQuery.notify(text); + StartupQuery.abort(); } } diff --git a/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java b/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java index 4a3e86aefe..c11ac23063 100644 --- a/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java +++ b/src/main/java/cpw/mods/fml/common/IFMLSidedHandler.java @@ -14,6 +14,8 @@ package cpw.mods.fml.common; import java.util.List; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; import net.minecraft.network.INetHandler; import net.minecraft.network.NetworkManager; @@ -32,6 +34,8 @@ public interface IFMLSidedHandler void showGuiScreen(Object clientGuiElement); + void queryUser(StartupQuery query) throws InterruptedException; + void beginServerLoading(MinecraftServer server); void finishServerLoading(); @@ -58,9 +62,5 @@ public interface IFMLSidedHandler FMLMissingMappingsEvent.Action getDefaultMissingAction(); - void serverLoadedSuccessfully(); - - void failedServerLoading(RuntimeException ex, WorldAccessContainer wac); - boolean shouldAllowPlayerLogins(); } diff --git a/src/main/java/cpw/mods/fml/common/StartupQuery.java b/src/main/java/cpw/mods/fml/common/StartupQuery.java new file mode 100644 index 0000000000..64668e6bca --- /dev/null +++ b/src/main/java/cpw/mods/fml/common/StartupQuery.java @@ -0,0 +1,142 @@ +package cpw.mods.fml.common; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; + +public class StartupQuery { + // internal class/functionality, do not use + + public static boolean confirm(String text) + { + StartupQuery query = new StartupQuery(text, new AtomicBoolean()); + query.execute(); + return query.getResult(); + } + + public static void notify(String text) + { + StartupQuery query = new StartupQuery(text, null); + query.execute(); + } + + public static void abort() + { + FMLCommonHandler.instance().getMinecraftServerInstance().initiateShutdown(); + aborted = true; // to abort loading and go back to the main menu + throw new AbortedException(); // to halt the server + } + + + public static void reset() + { + pending = null; + aborted = false; + } + + public static boolean check() + { + if (pending != null) + { + try + { + FMLCommonHandler.instance().queryUser(pending); + } + catch (InterruptedException e) + { + FMLLog.warning("query interrupted"); + abort(); + } + + pending = null; + } + + return !aborted; + } + + private static volatile StartupQuery pending; + private static volatile boolean aborted = false; + + + private StartupQuery(String text, AtomicBoolean result) + { + this.text = text; + this.result = result; + } + + public Boolean getResult() + { + return result == null ? null : result.get(); + } + + public void setResult(boolean result) + { + this.result.set(result); + } + + public String getText() + { + return text; + } + + public void finish() + { + signal.countDown(); + } + + private void execute() + { + String prop = System.getProperty("fml.queryResult"); + + if (result != null && prop != null) + { + FMLLog.info("Using fml.queryResult %s to answer the following query:\n%s", prop, text); + + if (prop.equalsIgnoreCase("confirm")) + { + setResult(true); + return; + } + else if (prop.equalsIgnoreCase("cancel")) + { + setResult(false); + return; + } + + FMLLog.warning("Invalid value for fml.queryResult: %s, expected confirm or cancel", prop); + } + + pending = this; // let the other thread start the query + + // the client will eventually check pending and execute the query + // command handling in mc is synchronous, execute the server-side query directly + if (FMLCommonHandler.instance().getSide().isServer()) check(); + + try + { + signal.await(); + } + catch (InterruptedException e) + { + FMLLog.warning("query interrupted"); + abort(); + } + } + + private String text; + private AtomicBoolean result; + private CountDownLatch signal = new CountDownLatch(1); + + + /** + * Exception not being caught by the crash report generation logic. + */ + public static class AbortedException extends RuntimeException + { + private static final long serialVersionUID = -5933665223696833921L; + + private AbortedException() + { + super(); + } + } +} diff --git a/src/main/java/cpw/mods/fml/common/registry/GameData.java b/src/main/java/cpw/mods/fml/common/registry/GameData.java index 551115c7c0..2a15292443 100644 --- a/src/main/java/cpw/mods/fml/common/registry/GameData.java +++ b/src/main/java/cpw/mods/fml/common/registry/GameData.java @@ -45,6 +45,7 @@ import cpw.mods.fml.common.FMLCommonHandler; import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.StartupQuery; import cpw.mods.fml.common.event.FMLMissingMappingsEvent; import cpw.mods.fml.common.event.FMLMissingMappingsEvent.MissingMapping; import cpw.mods.fml.common.registry.GameRegistry.Type; diff --git a/src/main/java/cpw/mods/fml/common/registry/GameRegistryException.java b/src/main/java/cpw/mods/fml/common/registry/GameRegistryException.java deleted file mode 100644 index 9b02969d93..0000000000 --- a/src/main/java/cpw/mods/fml/common/registry/GameRegistryException.java +++ /dev/null @@ -1,19 +0,0 @@ -package cpw.mods.fml.common.registry; - -import java.util.List; - -public class GameRegistryException extends RuntimeException { - private static final long serialVersionUID = 1L; - private List items; - - public GameRegistryException(String message, List items) - { - super(message); - this.items = items; - } - - public List getItems() - { - return this.items; - } -} diff --git a/src/main/java/cpw/mods/fml/server/FMLServerHandler.java b/src/main/java/cpw/mods/fml/server/FMLServerHandler.java index 92712eb239..7b72c34c58 100644 --- a/src/main/java/cpw/mods/fml/server/FMLServerHandler.java +++ b/src/main/java/cpw/mods/fml/server/FMLServerHandler.java @@ -12,18 +12,27 @@ */ package cpw.mods.fml.server; +import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicBoolean; + +import net.minecraft.command.ServerCommand; import net.minecraft.network.INetHandler; import net.minecraft.network.NetHandlerPlayServer; import net.minecraft.network.NetworkManager; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; + import com.google.common.collect.ImmutableList; + import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.IFMLSidedHandler; import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.ModContainer; +import cpw.mods.fml.common.StartupQuery; import cpw.mods.fml.common.WorldAccessContainer; import cpw.mods.fml.common.event.FMLMissingMappingsEvent; import cpw.mods.fml.common.eventhandler.EventBus; @@ -134,6 +143,65 @@ public class FMLServerHandler implements IFMLSidedHandler { } + + @Override + public void queryUser(StartupQuery query) throws InterruptedException + { + if (query.getResult() == null) + { + FMLLog.warning("%s", query.getText()); + query.finish(); + } + else + { + String text = query.getText() + + "\n\nRun the command /fml confirm or or /fml cancel to proceed." + + "\nAlternatively start the server with -Dfml.queryResult=confirm or -Dfml.queryResult=cancel to preselect the answer."; + FMLLog.warning("%s", text); + + boolean done = false; + + while (!done && server.isServerRunning()) + { + if (Thread.interrupted()) throw new InterruptedException(); + + DedicatedServer dedServer = (DedicatedServer) server; + + // rudimentary command processing, check for fml confirm/cancel and stop commands + synchronized (dedServer.pendingCommandList) + { + for (Iterator it = dedServer.pendingCommandList.iterator(); it.hasNext(); ) + { + String cmd = it.next().command.trim().toLowerCase(); + + if (cmd.equals("/fml confirm")) + { + FMLLog.info("confirmed"); + query.setResult(true); + done = true; + it.remove(); + } + else if (cmd.equals("/fml cancel")) + { + FMLLog.info("cancelled"); + query.setResult(false); + done = true; + it.remove(); + } + else if (cmd.equals("/stop")) + { + StartupQuery.abort(); + } + } + } + + Thread.sleep(10L); + } + + query.finish(); + } + } + @Override public boolean shouldServerShouldBeKilledQuietly() { @@ -186,16 +254,6 @@ public class FMLServerHandler implements IFMLSidedHandler public FMLMissingMappingsEvent.Action getDefaultMissingAction() { return FMLMissingMappingsEvent.Action.valueOf(System.getProperty("fml.missingBlockAction", "FAIL")); - } - @Override - public void serverLoadedSuccessfully() - { - - } - @Override - public void failedServerLoading(RuntimeException ex, WorldAccessContainer wac) - { - } @Override public boolean shouldAllowPlayerLogins() diff --git a/src/main/resources/fml_at.cfg b/src/main/resources/fml_at.cfg index b775c517a1..f92942df24 100644 --- a/src/main/resources/fml_at.cfg +++ b/src/main/resources/fml_at.cfg @@ -76,6 +76,8 @@ public net.minecraft.client.gui.GuiScreen field_146297_k # minecraft instance - public net.minecraft.client.Minecraft field_71446_o # textureManager ## ItemBlock public net.minecraft.item.ItemBlock field_150939_a +## DedicatedServer +public net.minecraft.server.dedicated.DedicatedServer field_71341_l # pendingCommandList protected net.minecraft.util.ObjectIntIdentityMap field_148749_a # internal map protected net.minecraft.util.ObjectIntIdentityMap field_148748_b # internal index list