initial attempt at a better way to ask the user in case of startup issues

This commit is contained in:
Player 2014-04-01 14:30:47 +02:00
parent e013f1514d
commit 11ab034638
16 changed files with 482 additions and 191 deletions

View file

@ -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())

View file

@ -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;

View file

@ -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()
{

View file

@ -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)
{

View file

@ -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,40 +635,8 @@ public class FMLClientHandler implements IFMLSidedHandler
}
else
{
launchIntegratedServerCallback(dirName, saveName);
}
}
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)
@ -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<Void>()
{
// 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()
{

View file

@ -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();
}
}
}

View file

@ -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;
}

View file

@ -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);
}
}
}

View file

@ -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();
@ -380,17 +390,9 @@ 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;
}
}
}
}
}

View file

@ -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<String> 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<String> 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<String> 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();
}
}

View file

@ -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();
}

View file

@ -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();
}
}
}

View file

@ -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;

View file

@ -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<String> items;
public GameRegistryException(String message, List<String> items)
{
super(message);
this.items = items;
}
public List<String> getItems()
{
return this.items;
}
}

View file

@ -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<ServerCommand> 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()

View file

@ -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