Add a java version detection and nag system for users on Java 7 or below.

Added detection of mods that rely on Java 8 and a graceful error screen.
The nag screen will be shown once a day. It can be disabled by editing the forge.cfg.
However it is HIGHLY recomended that user update to Java 8.
This commit is contained in:
LexManos 2016-05-03 18:26:52 -07:00
parent 4d27393c91
commit d8249b7886
15 changed files with 416 additions and 18 deletions

View file

@ -38,7 +38,16 @@
if (p_146284_1_.field_146127_k == 11)
{
this.field_146297_k.func_71371_a("Demo_World", "Demo_World", DemoWorldServer.field_73071_a);
@@ -512,7 +521,16 @@
@@ -493,6 +502,8 @@
this.func_73729_b(j + 155, k + 0, 0, 45, 155, 44);
}
+ this.field_73975_c = net.minecraftforge.client.ForgeHooksClient.renderMainMenu(this, this.field_146289_q, this.field_146294_l, this.field_146295_m, this.field_73975_c);
+
GlStateManager.func_179094_E();
GlStateManager.func_179109_b((float)(this.field_146294_l / 2 + 90), 70.0F, 0.0F);
GlStateManager.func_179114_b(-20.0F, 0.0F, 0.0F, 1.0F);
@@ -512,7 +523,15 @@
s = s + ("release".equalsIgnoreCase(this.field_146297_k.func_184123_d()) ? "" : "/" + this.field_146297_k.func_184123_d());
}
@ -52,11 +61,10 @@
+ this.func_73731_b(this.field_146289_q, brd, 2, this.field_146295_m - ( 10 + brdline * (this.field_146289_q.field_78288_b + 1)), 16777215);
+ }
+ }
+ net.minecraftforge.client.ForgeHooksClient.renderMainMenu(this, this.field_146289_q, this.field_146294_l, this.field_146295_m);
String s1 = "Copyright Mojang AB. Do not distribute!";
this.func_73731_b(this.field_146289_q, s1, this.field_146294_l - this.field_146289_q.func_78256_a(s1) - 2, this.field_146295_m - 10, -1);
@@ -529,6 +547,7 @@
@@ -529,6 +548,7 @@
{
this.field_183503_M.func_73863_a(p_73863_1_, p_73863_2_, p_73863_3_);
}
@ -64,3 +72,12 @@
}
protected void func_73864_a(int p_73864_1_, int p_73864_2_, int p_73864_3_) throws IOException
@@ -549,6 +569,8 @@
{
this.field_183503_M.func_73864_a(p_73864_1_, p_73864_2_, p_73864_3_);
}
+
+ net.minecraftforge.client.ForgeHooksClient.mainMenuMouseClick(p_73864_1_, p_73864_2_, p_73864_3_, this.field_146289_q, this.field_146294_l);
}
public void func_146281_b()

View file

@ -8,6 +8,7 @@ import static org.lwjgl.opengl.GL20.*;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.util.Collections;
import java.util.Map;
import javax.vecmath.Matrix3f;
@ -89,8 +90,12 @@ import net.minecraftforge.common.model.IModelPart;
import net.minecraftforge.common.model.ITransformation;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.client.GuiJava8Error;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Java8VersionException;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.BufferUtils;
@ -266,7 +271,8 @@ public class ForgeHooksClient
//RenderingRegistry.registerBlockHandler(RenderBlockFluid.instance);
}
public static void renderMainMenu(GuiMainMenu gui, FontRenderer font, int width, int height)
private static int updatescrollcounter = 0;
public static String renderMainMenu(GuiMainMenu gui, FontRenderer font, int width, int height, String splashText)
{
Status status = ForgeVersion.getStatus();
if (status == BETA || status == BETA_OUTDATED)
@ -278,6 +284,17 @@ public class ForgeHooksClient
gui.drawString(font, line, (width - font.getStringWidth(line)) / 2, 4 + (1 * (font.FONT_HEIGHT + 1)), -1);
}
if (!Loader.instance().java8)
{
String line = I18n.format("fml.messages.java8warning.1", TextFormatting.RED, TextFormatting.RESET);
gui.drawString(font, line, (width - font.getStringWidth(line)) / 2, 4 + (8 * (font.FONT_HEIGHT + 1)), -1);
line = I18n.format("fml.messages.java8warning.2");
gui.drawString(font, line, (width - font.getStringWidth(line)) / 2, 4 + (9 * (font.FONT_HEIGHT + 1)), -1);
splashText = updatescrollcounter < 50 ? "UPDATE!" : "JAVA!";
updatescrollcounter+=1;
updatescrollcounter%=100;
}
String line = null;
switch(status)
{
@ -294,6 +311,24 @@ public class ForgeHooksClient
// if we have a line, render it in the bottom right, above Mojang's copyright line
gui.drawString(font, line, width - font.getStringWidth(line) - 2, height - (2 * (font.FONT_HEIGHT + 1)), -1);
}
return splashText;
}
public static void mainMenuMouseClick(int mouseX, int mouseY, int mouseButton, FontRenderer font, int width)
{
if (!Loader.instance().java8)
{
if (mouseY >= (4 + (8 * 10)) && mouseY < (4 + (10 * 10)))
{
int w = font.getStringWidth(I18n.format("fml.messages.java8warning.1", TextFormatting.RED, TextFormatting.RESET));
w = Math.max(w, font.getStringWidth(I18n.format("fml.messages.java8warning.2")));
if (mouseX >= ((width - w) / 2) && mouseX <= ((width + w) / 2))
{
FMLClientHandler.instance().showGuiScreen(new GuiJava8Error(new Java8VersionException(Collections.<ModContainer>emptyList())));
}
}
}
}
public static ISound playSound(SoundManager manager, ISound sound)

View file

@ -14,6 +14,7 @@ import java.net.URL;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -74,6 +75,7 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
public static boolean defaultHasSpawnFuzz = true;
public static boolean forgeLightPipelineEnabled = true;
public static boolean replaceVanillaBucketModel = true;
public static long java8Reminder = 0;
private static Configuration config;
private static ForgeModContainer INSTANCE;
@ -259,6 +261,11 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
replaceVanillaBucketModel = prop.getBoolean(Boolean.FALSE);
propOrder.add(prop.getName());
prop = config.get(Configuration.CATEGORY_CLIENT, "java8Reminder", java8Reminder,
"The timestamp of the last reminder to update to Java 8 in number of milliseconds since January 1, 1970, 00:00:00 GMT. Nag will show only once every 24 hours. To disable it set this to some really high number.");
java8Reminder = prop.getLong(java8Reminder);
propOrder.add(prop.getName());
config.setCategoryPropertyOrder(CATEGORY_CLIENT, propOrder);
if (config.hasChanged())
@ -267,6 +274,13 @@ public class ForgeModContainer extends DummyModContainer implements WorldAccessC
}
}
public static void updateNag()
{
Property prop = config.get(Configuration.CATEGORY_CLIENT, "java8Reminder", java8Reminder);
prop.set((new Date()).getTime());
config.save();
}
/**
* By subscribing to the OnConfigChangedEvent we are able to execute code when our config screens are closed.
* This implementation uses the optional configID string to handle multiple Configurations using one event handler.

View file

@ -680,14 +680,7 @@ public class Property
*/
public int getInt()
{
try
{
return Integer.parseInt(value);
}
catch (NumberFormatException e)
{
return Integer.parseInt(defaultValue);
}
return getInt(Integer.parseInt(defaultValue));
}
/**
@ -727,6 +720,54 @@ public class Property
}
}
/**
* Returns the value in this property as a long,
* if the value is not a valid long, it will return the initially provided default.
*
* @return The value
*/
public long getLong()
{
return getLong(Long.parseLong(defaultValue));
}
/**
* Returns the value in this property as a long,
* if the value is not a valid long, it will return the
* provided default.
*
* @param _default The default to provide if the current value is not a validlong
* @return The value
*/
public long getLong(long _default)
{
try
{
return Long.parseLong(value);
}
catch (NumberFormatException e)
{
return _default;
}
}
/**
* Checks if the current value stored in this property can be converted to a long.
* @return True if the type of the Property is an Long
*/
public boolean isLongValue()
{
try
{
Long.parseLong(value);
return true;
}
catch (NumberFormatException e)
{
return false;
}
}
/**
* Returns the value in this property as a boolean,
* if the value is not a valid boolean, it will return the
@ -1148,6 +1189,7 @@ public class Property
this.setValues(values);
}
public void set(int value){ set(Integer.toString(value)); }
public void set(long value){ set(Long.toString(value)); }
public void set(boolean value){ set(Boolean.toString(value)); }
public void set(double value){ set(Double.toString(value)); }
}

View file

@ -19,6 +19,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@ -69,6 +70,7 @@ import net.minecraft.util.StringUtils;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.storage.SaveFormatComparator;
import net.minecraft.world.storage.SaveFormatOld;
import net.minecraftforge.common.ForgeModContainer;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
import net.minecraftforge.fml.common.DummyModContainer;
import net.minecraftforge.fml.common.DuplicateModsFoundException;
@ -76,6 +78,7 @@ import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.FMLContainerHolder;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.IFMLSidedHandler;
import net.minecraftforge.fml.common.Java8VersionException;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.LoaderException;
import net.minecraftforge.fml.common.MetadataCollection;
@ -158,6 +161,8 @@ public class FMLClientHandler implements IFMLSidedHandler
private boolean loading = true;
private Java8VersionException j8onlymods;
private WrongMinecraftVersionException wrongMC;
private CustomModLoadingErrorDisplayException customError;
@ -212,6 +217,10 @@ public class FMLClientHandler implements IFMLSidedHandler
{
dupesFound = dupes;
}
catch (Java8VersionException j8mods)
{
j8onlymods = j8mods;
}
catch (MissingModsException missing)
{
modsMissing = missing;
@ -297,7 +306,7 @@ public class FMLClientHandler implements IFMLSidedHandler
*/
public void finishMinecraftLoading()
{
if (modsMissing != null || wrongMC != null || customError!=null || dupesFound!=null || modSorting!=null)
if (modsMissing != null || wrongMC != null || customError!=null || dupesFound!=null || modSorting!=null || j8onlymods!=null)
{
SplashProgress.finish();
return;
@ -344,6 +353,8 @@ public class FMLClientHandler implements IFMLSidedHandler
}
loading = false;
client.gameSettings.loadOptions(); //Reload options to load any mod added keybindings.
Loader.instance().loadingComplete();
SplashProgress.finish();
}
public void extendModList()
@ -383,6 +394,10 @@ public class FMLClientHandler implements IFMLSidedHandler
{
showGuiScreen(new GuiWrongMinecraft(wrongMC));
}
else if (j8onlymods != null)
{
showGuiScreen(new GuiJava8Error(j8onlymods));
}
else if (modsMissing != null)
{
showGuiScreen(new GuiModsMissing(modsMissing));
@ -401,10 +416,16 @@ public class FMLClientHandler implements IFMLSidedHandler
}
else
{
Loader.instance().loadingComplete();
SplashProgress.finish();
logMissingTextureErrors();
if (!Loader.instance().java8)
{
if ((new Date()).getTime() >= ForgeModContainer.java8Reminder + (1000 * 60 * 60 * 24))
{
showGuiScreen(new GuiJava8Error(new Java8VersionException(Collections.<ModContainer>emptyList())));
ForgeModContainer.updateNag();
}
}
}
logMissingTextureErrors();
}
/**
* Get the server instance

View file

@ -0,0 +1,140 @@
/*
* Forge Mod Loader
* Copyright (c) 2012-2013 cpw.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* cpw - implementation
*/
package net.minecraftforge.fml.client;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Java8VersionException;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.ModContainer;
import org.apache.logging.log4j.Level;
import com.google.common.collect.Lists;
import java.awt.*;
import java.io.IOException;
import java.net.URI;
import java.util.List;
public class GuiJava8Error extends GuiErrorScreen
{
private Java8VersionException java8VersionException;
public GuiJava8Error(Java8VersionException java8VersionException)
{
super(null,null);
this.java8VersionException = java8VersionException;
}
@Override
public void initGui()
{
this.buttonList.clear();
this.buttonList.add(new GuiButton(1, 50, this.height - 38, this.width/2 -55, 20, I18n.format("fml.button.visitjavadownloads")));
if (java8VersionException.getMods().isEmpty())
{
this.buttonList.add(new GuiButton(3, this.width / 2 + 5, this.height - 38, this.width / 2 - 55, 20, I18n.format("fml.button.continue")));
}
else
{
this.buttonList.add(new GuiButton(2, this.width / 2 + 5, this.height - 38, this.width / 2 - 55, 20, I18n.format("menu.quit")));
}
}
@Override
protected void actionPerformed(GuiButton button) throws IOException
{
if (button.id == 1)
{
try
{
Desktop.getDesktop().browse(new URI("http://www.oracle.com/technetwork/java/javase/downloads/index.html"));
}
catch (Exception e)
{
FMLLog.log(Level.ERROR, e, "Problem launching browser");
}
}
else if (button.id == 2)
{
FMLCommonHandler.instance().exitJava(1,true);
}
else if (button.id == 3)
{
FMLClientHandler.instance().showGuiScreen(null);
}
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks)
{
this.drawDefaultBackground();
int offset = 25;
if (!java8VersionException.getMods().isEmpty())
{
this.drawCenteredString(this.fontRendererObj, I18n.format("fml.messages.java8problem", TextFormatting.RED, TextFormatting.BOLD, TextFormatting.RESET), this.width / 2, offset, 0xFFFFFF);
}
else
{
this.drawCenteredString(this.fontRendererObj, I18n.format("fml.messages.java8recommended", TextFormatting.RED, TextFormatting.BOLD, TextFormatting.RESET), this.width / 2, offset, 0xFFFFFF);
}
offset+=15;
this.drawCenteredString(this.fontRendererObj, I18n.format("fml.messages.javaversion", System.getProperty("java.version").split("\\.")[1], System.getProperty("java.version")), this.width / 2, offset, 0xFFFFFF);
offset += 10;
if (!java8VersionException.getMods().isEmpty())
{
this.drawCenteredString(this.fontRendererObj, I18n.format("fml.messages.upgradejavaorremove", TextFormatting.RED,TextFormatting.BOLD, TextFormatting.RESET), this.width / 2, offset, 0xFFFFFF);
offset += 15;
this.drawCenteredString(this.fontRendererObj, I18n.format("fml.messages.modslistedbelow", I18n.format("fml.messages.requirejava8")), this.width / 2, offset, 0xFFFFFF);
offset += 10;
this.drawCenteredString(this.fontRendererObj, I18n.format("fml.messages.countbadandgood", java8VersionException.getMods().size(), Loader.instance().getActiveModList().size()), this.width / 2, offset, 0xFFFFFF);
offset += 5;
for (ModContainer mc : java8VersionException.getMods())
{
offset += 10;
this.drawCenteredString(this.fontRendererObj, String.format("%s (%s)", mc.getName(), mc.getModId()), this.width / 2, offset, 0xEEEEEE);
}
}
else
{
String text = I18n.format("fml.messages.upgradejava", TextFormatting.RED,TextFormatting.BOLD, TextFormatting.RESET).replaceAll("\\\\n", "\n");
List<String> lines = Lists.newArrayList();
for (String line : text.split("\n"))
{
lines.addAll(this.fontRendererObj.listFormattedStringToWidth(line, this.width - this.fontRendererObj.FONT_HEIGHT * 4));
}
int maxWidth = 0;
for (String line : lines)
{
maxWidth = Math.max(maxWidth, this.fontRendererObj.getStringWidth(line));
}
for (String line : lines)
{
this.drawString(this.fontRendererObj, line, (this.width - maxWidth) / 2, offset, 0xFFFFFF);
offset += this.fontRendererObj.FONT_HEIGHT + 2;
}
offset += 15;
}
// super.super
for (int i = 0; i < this.buttonList.size(); ++i)
{
((GuiButton)this.buttonList.get(i)).drawButton(this.mc, mouseX, mouseY);
}
}
}

View file

@ -32,6 +32,7 @@ public class DummyModContainer implements ModContainer
private ModMetadata md;
private ArtifactVersion processedVersion;
private String label;
private int classVersion;
public DummyModContainer(ModMetadata md)
{
@ -213,4 +214,16 @@ public class DummyModContainer implements ModContainer
{
return null;
}
@Override
public void setClassVersion(int classVersion)
{
this.classVersion = classVersion;
}
@Override
public int getClassVersion()
{
return this.classVersion;
}
}

View file

@ -90,6 +90,7 @@ public class FMLModContainer implements ModContainer
private Map<String, String> customModProperties;
private ModCandidate candidate;
private URL updateJSONUrl;
private int classVersion;
public FMLModContainer(String className, ModCandidate container, Map<String, Object> modDescriptor)
{
@ -699,4 +700,16 @@ public class FMLModContainer implements ModContainer
{
return updateJSONUrl;
}
@Override
public void setClassVersion(int classVersion)
{
this.classVersion = classVersion;
}
@Override
public int getClassVersion()
{
return this.classVersion;
}
}

View file

@ -214,4 +214,16 @@ public class InjectedModContainer implements ModContainer
{
return wrappedContainer.getUpdateUrl();
}
@Override
public void setClassVersion(int classVersion)
{
wrappedContainer.setClassVersion(classVersion);
}
@Override
public int getClassVersion()
{
return wrappedContainer.getClassVersion();
}
}

View file

@ -0,0 +1,43 @@
/*
* Forge Mod Loader
* Copyright (c) 2012-2013 cpw.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* cpw - implementation
*/
package net.minecraftforge.fml.common;
import java.util.List;
public class Java8VersionException extends EnhancedRuntimeException
{
private static final long serialVersionUID = 1L;
private final List<ModContainer> mods;
public Java8VersionException(List<ModContainer> mods)
{
super("Mods require Java 8");
this.mods = mods;
}
@Override
protected void printStackTrace(WrappedPrintStream stream)
{
stream.println("Mods requiring Java 8:");
for (ModContainer mc : mods)
{
stream.println(String.format("\t%s : %s", mc.getName(), mc.getModId()));
}
stream.println("");
}
public List<ModContainer> getMods()
{
return mods;
}
}

View file

@ -161,6 +161,7 @@ public class Loader
private File forcedModFile;
private ModDiscoverer discoverer;
private ProgressBar progressBar;
public final boolean java8;
public static Loader instance()
{
@ -187,6 +188,14 @@ public class Loader
private Loader()
{
String[] ver = System.getProperty("java.version").split("\\.");
int major = Integer.parseInt(ver[1]);
java8 = major > 7;
if (!java8)
{
FMLLog.severe("The game is not running with Java 8. Forge recommends Java 8 for maximum compatibility with mods");
}
modClassLoader = new ModClassLoader(getClass().getClassLoader());
if (!mccversion.equals(MC_VERSION))
{
@ -489,6 +498,7 @@ public class Loader
ModAPIManager.INSTANCE.manageAPI(modClassLoader, discoverer);
disableRequestedMods();
modController.distributeStateMessage(FMLLoadEvent.class);
checkJavaCompatibility();
sortModList();
ModAPIManager.INSTANCE.cleanupAPIContainers(modController.getActiveModList());
ModAPIManager.INSTANCE.cleanupAPIContainers(mods);
@ -543,6 +553,24 @@ public class Loader
modController.transition(LoaderState.PREINITIALIZATION, false);
}
private void checkJavaCompatibility()
{
if (java8) return;
List<ModContainer> j8mods = Lists.newArrayList();
for (ModContainer mc : getActiveModList())
{
if (mc.getClassVersion() >= 52)
{
j8mods.add(mc);
}
}
if (!j8mods.isEmpty())
{
throw new Java8VersionException(j8mods);
}
}
public void preinitializeMods()
{
if (!modController.isInState(LoaderState.PREINITIALIZATION))

View file

@ -152,4 +152,8 @@ public interface ModContainer
boolean shouldLoadInEnvironment();
URL getUpdateUrl();
void setClassVersion(int classVersion);
int getClassVersion();
}

View file

@ -35,6 +35,7 @@ public class ASMDataTable
private String annotationName;
private String className;
private String objectName;
private int classVersion;
private Map<String,Object> annotationInfo;
public ASMData(ModCandidate candidate, String annotationName, String className, String objectName, Map<String,Object> info)
{

View file

@ -83,6 +83,7 @@ public class JarDiscoverer implements ITypeDiscoverer
table.addContainer(container);
foundMods.add(container);
container.bindMetadata(mc);
container.setClassVersion(modParser.getClassVersion());
}
}
}

View file

@ -1,5 +1,5 @@
commands.forge.usage=Use /forge <subcommand>. Subcommands are tps, track
commands.forge.usage.tracking=Use /forge track <type> <duration>. Valid types are te (Tile Entities). Duration is < 60.
commands.forge.usage.tracking=Use /forge track <type> <duration>. Valid types are te (Tile Entities). Duration is < 60.
commands.forge.tps.summary=%s : Mean tick time: %d ms. Mean TPS: %d
commands.forge.tracking.te.enabled=Tile Entity tracking enabled for %d seconds.
@ -153,4 +153,18 @@ fml.menu.mods.normal=Normal
fml.menu.mods.search=Search:
fml.menu.modoptions=Mod Options...
item.forge.bucketFilled.name=%s Bucket
item.forge.bucketFilled.name=%s Bucket
fml.messages.java8problem=%s%sJava Update Required%s
fml.messages.java8recommended=%s%sJava Update Recommended%s
fml.messages.modslistedbelow=The mods listed below %s
fml.messages.requirejava8=require Java 8
fml.messages.java8warning.1=%sJAVA VERSION WARNING%s UPDATE JAVA!
fml.messages.java8warning.2=You need to update Java
fml.messages.javaversion=Your Java version is Java %s (version string %s)
fml.messages.upgradejavaorremove=%s%sUpdate Java%s or remove these mods to play
fml.messages.upgradejava=\n\nPros of updating to Java 8\n- Better Performance\n- Better Security\n- Better Compatibility with newer mods
fml.messages.countbadandgood=%s of %s mods have this problem
fml.button.visitjavadownloads=Oracle Java SE Downloads
fml.button.continue=Continue