package net.minecraftforge.fml.common;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import net.minecraft.server.MinecraftServer;
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()
{
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
if (server != null) server.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 boolean isSynchronous()
{
return synchronous;
}
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);
}
synchronous = false;
pending = this; // let the other thread start the query
// from the integrated server thread: the client will eventually check pending and execute the query
// from the client thread: synchronous execution
// dedicated server: command handling in mc is synchronous, execute the server-side query directly
if (FMLCommonHandler.instance().getSide().isServer() ||
FMLCommonHandler.instance().getEffectiveSide().isClient())
{
synchronous = true;
check();
}
try
{
signal.await();
reset();
}
catch (InterruptedException e)
{
FMLLog.warning("query interrupted");
abort();
}
}
private String text;
private AtomicBoolean result;
private CountDownLatch signal = new CountDownLatch(1);
private volatile boolean synchronous;
/**
* 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();
}
}
}