Commit faa26f42c4d95b314c6c9f24e70e6fb488b620f5

Authored by Mumfrey
1 parent 349f6093

updated ASM to 5.0.3, support automatic update check and forced update, minor fixes

Showing 26 changed files with 665 additions and 108 deletions
.classpath
... ... @@ -9,15 +9,15 @@
9 9 <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/com/google/code/gson/gson/2.2.4/gson-2.2.4.jar"/>
10 10 <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/com/google/guava/guava/15.0/guava-15.0.jar"/>
11 11 <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/commons-io/commons-io/2.4/commons-io-2.4.jar"/>
12   - <classpathentry exported="true" kind="lib" path="lib/launchwrapper-1.9.jar" sourcepath="externals/launchwrapper/src"/>
  12 + <classpathentry exported="true" kind="lib" path="lib/launchwrapper-1.11.jar" sourcepath="externals/launchwrapper/src"/>
13 13 <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/org/apache/commons/commons-lang3/3.1/commons-lang3-3.1.jar"/>
14 14 <classpathentry kind="lib" path="/Client/jars/libraries/net/sf/jopt-simple/jopt-simple/4.5/jopt-simple-4.5.jar"/>
15 15 <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/io/netty/netty-all/4.0.10.Final/netty-all-4.0.10.Final.jar"/>
16 16 <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/org/apache/logging/log4j/log4j-api/2.0-beta9/log4j-api-2.0-beta9.jar"/>
17 17 <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/org/apache/logging/log4j/log4j-core/2.0-beta9/log4j-core-2.0-beta9.jar"/>
18 18 <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar"/>
19   - <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/com/mojang/authlib/1.5.13/authlib-1.5.13.jar"/>
  19 + <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/com/mojang/authlib/1.5.16/authlib-1.5.16.jar"/>
20 20 <classpathentry exported="true" kind="lib" path="/Client/jars/libraries/org/lwjgl/lwjgl/lwjgl/2.9.1/lwjgl-2.9.1.jar"/>
21   - <classpathentry exported="true" kind="lib" path="lib/asm-debug-all-4.1.jar"/>
  21 + <classpathentry exported="true" kind="lib" path="lib/asm-debug-all-5.0.3.jar"/>
22 22 <classpathentry kind="output" path="bin"/>
23 23 </classpath>
... ...
LiteLoader.iml
... ... @@ -4,7 +4,7 @@
4 4 <libelement value="file:///Client/jars/libraries/com/google/code/gson/gson/2.2.4/gson-2.2.4.jar" />
5 5 <libelement value="file:///Client/jars/libraries/com/google/guava/guava/15.0/guava-15.0.jar" />
6 6 <libelement value="file:///Client/jars/libraries/commons-io/commons-io/2.4/commons-io-2.4.jar" />
7   - <libelement value="jar://$MODULE_DIR$/lib/launchwrapper-1.9.jar!/" />
  7 + <libelement value="jar://$MODULE_DIR$/lib/launchwrapper-1.11.jar!/" />
8 8 <libelement value="jar://$MODULE_DIR$/lib/asm-debug-all-4.1.jar!/" />
9 9 <libelement value="file:///Client/jars/libraries/org/apache/commons/commons-lang3/3.1/commons-lang3-3.1.jar" />
10 10 <libelement value="file:///Client/jars/libraries/net/sf/jopt-simple/jopt-simple/4.5/jopt-simple-4.5.jar" />
... ... @@ -12,7 +12,7 @@
12 12 <libelement value="file:///Client/jars/libraries/org/apache/logging/log4j/log4j-api/2.0-beta9/log4j-api-2.0-beta9.jar" />
13 13 <libelement value="file:///Client/jars/libraries/org/apache/logging/log4j/log4j-core/2.0-beta9/log4j-core-2.0-beta9.jar" />
14 14 <libelement value="file:///Client/jars/libraries/net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar" />
15   - <libelement value="file:///Client/jars/libraries/com/mojang/authlib/1.5.13/authlib-1.5.13.jar" />
  15 + <libelement value="file:///Client/jars/libraries/com/mojang/authlib/1.5.16/authlib-1.5.16.jar" />
16 16 <libelement value="file:///Client/jars/libraries/org/lwjgl/lwjgl/lwjgl/2.9.1/lwjgl-2.9.1.jar" />
17 17 <src_description expected_position="0">
18 18 <src_folder value="file://$MODULE_DIR$/debug" expected_position="0" />
... ... @@ -34,9 +34,9 @@
34 34 <orderEntry type="module" module-name="Client" exported="" />
35 35 <orderEntry type="jdk" jdkName="JavaSE-1.6" jdkType="JavaSDK" />
36 36 <orderEntry type="module-library" exported="">
37   - <library name="launchwrapper-1.9.jar">
  37 + <library name="launchwrapper-1.11.jar">
38 38 <CLASSES>
39   - <root url="jar://$MODULE_DIR$/lib/launchwrapper-1.9.jar!/" />
  39 + <root url="jar://$MODULE_DIR$/lib/launchwrapper-1.11.jar!/" />
40 40 </CLASSES>
41 41 <JAVADOC />
42 42 <SOURCES>
... ... @@ -47,7 +47,7 @@
47 47 <orderEntry type="module-library" exported="">
48 48 <library>
49 49 <CLASSES>
50   - <root url="jar://$MODULE_DIR$/lib/asm-debug-all-4.1.jar!/" />
  50 + <root url="jar://$MODULE_DIR$/lib/asm-debug-all-5.0.3.jar!/" />
51 51 </CLASSES>
52 52 <JAVADOC />
53 53 <SOURCES />
... ...
debug/com/mumfrey/liteloader/debug/LoginManager.java
... ... @@ -4,6 +4,7 @@ import java.io.File;
4 4 import java.io.FileReader;
5 5 import java.io.FileWriter;
6 6 import java.io.IOException;
  7 +import java.lang.reflect.Type;
7 8 import java.net.Proxy;
8 9 import java.util.HashMap;
9 10 import java.util.Map;
... ... @@ -14,12 +15,19 @@ import javax.swing.JOptionPane;
14 15 import com.google.common.base.Strings;
15 16 import com.google.gson.Gson;
16 17 import com.google.gson.GsonBuilder;
  18 +import com.google.gson.JsonArray;
  19 +import com.google.gson.JsonElement;
  20 +import com.google.gson.JsonObject;
  21 +import com.google.gson.JsonPrimitive;
  22 +import com.google.gson.JsonSerializationContext;
  23 +import com.google.gson.JsonSerializer;
17 24 import com.google.gson.annotations.SerializedName;
18 25 import com.mojang.authlib.Agent;
19 26 import com.mojang.authlib.GameProfile;
20 27 import com.mojang.authlib.UserType;
21 28 import com.mojang.authlib.exceptions.AuthenticationException;
22 29 import com.mojang.authlib.exceptions.InvalidCredentialsException;
  30 +import com.mojang.authlib.properties.Property;
23 31 import com.mojang.authlib.properties.PropertyMap;
24 32 import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
25 33 import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
... ... @@ -315,9 +323,32 @@ public class LoginManager
315 323 public String getUserProperties()
316 324 {
317 325 PropertyMap userProperties = this.authentication.getUserProperties();
318   - return userProperties != null ? userProperties.toString() : "{}";
  326 + return userProperties != null ? (new GsonBuilder()).registerTypeAdapter(PropertyMap.class, new UserPropertiesSerializer()).create().toJson(userProperties) : "{}";
319 327 }
320 328  
  329 + class UserPropertiesSerializer implements JsonSerializer<PropertyMap>
  330 + {
  331 + @Override
  332 + public JsonElement serialize(PropertyMap propertyMap, Type argType, JsonSerializationContext context)
  333 + {
  334 + JsonObject result = new JsonObject();
  335 +
  336 + for (String key : propertyMap.keySet())
  337 + {
  338 + JsonArray values = new JsonArray();
  339 + for (Property property : propertyMap.get(key))
  340 + {
  341 + values.add(new JsonPrimitive(property.getValue()));
  342 + }
  343 +
  344 + result.add(key, values);
  345 + }
  346 +
  347 + return result;
  348 + }
  349 + }
  350 +
  351 +
321 352 /**
322 353 * Struct for Gson serialisation of authenticaion settings
323 354 *
... ...
java/client/com/mumfrey/liteloader/client/LiteLoaderPanelManager.java
... ... @@ -5,16 +5,20 @@ import net.minecraft.client.gui.GuiIngameMenu;
5 5 import net.minecraft.client.gui.GuiMainMenu;
6 6 import net.minecraft.client.gui.GuiOptions;
7 7 import net.minecraft.client.gui.GuiScreen;
  8 +import net.minecraft.client.resources.I18n;
8 9  
9 10 import org.lwjgl.input.Keyboard;
10 11  
11 12 import com.mumfrey.liteloader.client.gui.GuiLiteLoaderPanel;
12 13 import com.mumfrey.liteloader.common.GameEngine;
13 14 import com.mumfrey.liteloader.core.LiteLoaderMods;
  15 +import com.mumfrey.liteloader.core.LiteLoaderUpdateSite;
  16 +import com.mumfrey.liteloader.core.LiteLoaderVersion;
14 17 import com.mumfrey.liteloader.interfaces.PanelManager;
15 18 import com.mumfrey.liteloader.launch.LoaderEnvironment;
16 19 import com.mumfrey.liteloader.launch.LoaderProperties;
17 20 import com.mumfrey.liteloader.modconfig.ConfigManager;
  21 +import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
18 22  
19 23 /**
20 24 * Observer which handles the display of the mod panel
... ... @@ -23,9 +27,6 @@ import com.mumfrey.liteloader.modconfig.ConfigManager;
23 27 */
24 28 public class LiteLoaderPanelManager implements PanelManager<GuiScreen>
25 29 {
26   - private static final String OPTION_MOD_INFO_SCREEN = "modInfoScreen";
27   - private static final String OPTION_NO_HIDE_TAB = "tabAlwaysExpanded";
28   -
29 30 private final LoaderEnvironment environment;
30 31  
31 32 /**
... ... @@ -54,6 +55,10 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
54 55 * can temporarily disable the function without having to change the underlying property
55 56 */
56 57 private boolean hideModInfoScreenTab = false;
  58 +
  59 + private boolean checkForUpdate = false;
  60 +
  61 + private String notification;
57 62  
58 63 /**
59 64 * Active "mod info" screen, drawn as an overlay when in the main menu and made the active screen if
... ... @@ -72,8 +77,24 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
72 77 this.properties = properties;
73 78 this.minecraft = ((GameEngine<Minecraft, ?>)engine).getClient();
74 79  
75   - this.displayModInfoScreenTab = this.properties.getAndStoreBooleanProperty(LiteLoaderPanelManager.OPTION_MOD_INFO_SCREEN, true);
76   - this.tabAlwaysExpanded = this.properties.getAndStoreBooleanProperty(LiteLoaderPanelManager.OPTION_NO_HIDE_TAB, false);
  80 + this.displayModInfoScreenTab = this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_MOD_INFO_SCREEN, true);
  81 + this.tabAlwaysExpanded = this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_NO_HIDE_TAB, false);
  82 +
  83 + if (this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_FORCE_UPDATE, false))
  84 + {
  85 + int updateCheckInterval = this.properties.getIntegerProperty(LoaderProperties.OPTION_UPDATE_CHECK_INTR) + 1;
  86 + LiteLoaderLogger.debug("Force update is TRUE, updateCheckInterval = %d", updateCheckInterval);
  87 +
  88 + if (updateCheckInterval > 10)
  89 + {
  90 + LiteLoaderLogger.debug("Forcing update check!");
  91 + this.checkForUpdate = true;
  92 + updateCheckInterval = 0;
  93 + }
  94 +
  95 + this.properties.setIntegerProperty(LoaderProperties.OPTION_UPDATE_CHECK_INTR, updateCheckInterval);
  96 + this.properties.writeProperties();
  97 + }
77 98 }
78 99  
79 100 @Override
... ... @@ -83,6 +104,15 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
83 104 this.configManager = configManager;
84 105 }
85 106  
  107 + @Override
  108 + public void onStartupComplete()
  109 + {
  110 + if (this.checkForUpdate)
  111 + {
  112 + LiteLoaderVersion.getUpdateSite().beginUpdateCheck();
  113 + }
  114 + }
  115 +
86 116 /* (non-Javadoc)
87 117 * @see com.mumfrey.liteloader.api.TickObserver#onTick(boolean, float, boolean)
88 118 */
... ... @@ -93,6 +123,20 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
93 123 {
94 124 this.panelHost.updateScreen();
95 125 }
  126 +
  127 + if (clock && this.checkForUpdate)
  128 + {
  129 + LiteLoaderUpdateSite updateSite = LiteLoaderVersion.getUpdateSite();
  130 + if (!updateSite.isCheckInProgress() && updateSite.isCheckComplete())
  131 + {
  132 + LiteLoaderLogger.debug("Scheduled update check completed, success=%s", updateSite.isCheckSucceess());
  133 + this.checkForUpdate = false;
  134 + if (updateSite.isCheckSucceess() && updateSite.isUpdateAvailable())
  135 + {
  136 + this.setNotification(I18n.format("gui.notifications.updateavailable"));
  137 + }
  138 + }
  139 + }
96 140 }
97 141  
98 142 /* (non-Javadoc)
... ... @@ -103,14 +147,18 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
103 147 {
104 148 if (this.mods == null) return;
105 149  
106   - boolean tabHidden = this.hideModInfoScreenTab && this.minecraft.currentScreen instanceof GuiMainMenu;
  150 + boolean tabHidden = this.isTabHidden() && this.minecraft.currentScreen instanceof GuiMainMenu;
107 151  
108 152 if (this.isPanelSupportedOnScreen(this.minecraft.currentScreen) && ((this.displayModInfoScreenTab && !tabHidden) || (this.panelHost != null && this.panelHost.isOpen())))
109 153 {
110 154 // If we're at the main menu, prepare the overlay
111 155 if (this.panelHost == null || this.panelHost.getScreen() != this.minecraft.currentScreen)
112 156 {
113   - this.panelHost = new GuiLiteLoaderPanel(this.minecraft, this.minecraft.currentScreen, this.mods, this.environment, this.configManager, !tabHidden);
  157 + this.panelHost = new GuiLiteLoaderPanel(this.minecraft, this.minecraft.currentScreen, this.mods, this.environment, this.properties, this.configManager, !tabHidden);
  158 + if (this.notification != null)
  159 + {
  160 + this.panelHost.setNotification(this.notification);
  161 + }
114 162 }
115 163  
116 164 this.minecraft.entityRenderer.setupOverlayRendering();
... ... @@ -127,7 +175,7 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
127 175 this.displayLiteLoaderPanel(this.minecraft.currentScreen);
128 176 }
129 177 }
130   -
  178 +
131 179 /**
132 180 * Set the "mod info" screen tab to hidden, regardless of the property setting
133 181 */
... ... @@ -137,6 +185,11 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
137 185 this.hideModInfoScreenTab = true;
138 186 }
139 187  
  188 + private boolean isTabHidden()
  189 + {
  190 + return this.hideModInfoScreenTab && this.getStartupErrorCount() == 0 && this.notification == null;
  191 + }
  192 +
140 193 /**
141 194 * Set whether the "mod info" screen tab should be shown in the main menu
142 195 */
... ... @@ -144,7 +197,7 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
144 197 public void setTabVisible(boolean show)
145 198 {
146 199 this.displayModInfoScreenTab = show;
147   - this.properties.setBooleanProperty(LiteLoaderPanelManager.OPTION_MOD_INFO_SCREEN, show);
  200 + this.properties.setBooleanProperty(LoaderProperties.OPTION_MOD_INFO_SCREEN, show);
148 201 this.properties.writeProperties();
149 202 }
150 203  
... ... @@ -161,7 +214,7 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
161 214 public void setTabAlwaysExpanded(boolean expand)
162 215 {
163 216 this.tabAlwaysExpanded = expand;
164   - this.properties.setBooleanProperty(LiteLoaderPanelManager.OPTION_NO_HIDE_TAB, expand);
  217 + this.properties.setBooleanProperty(LoaderProperties.OPTION_NO_HIDE_TAB, expand);
165 218 this.properties.writeProperties();
166 219 }
167 220  
... ... @@ -171,6 +224,19 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
171 224 return this.tabAlwaysExpanded;
172 225 }
173 226  
  227 + @Override
  228 + public void setForceUpdateEnabled(boolean forceUpdate)
  229 + {
  230 + this.properties.setBooleanProperty(LoaderProperties.OPTION_FORCE_UPDATE, forceUpdate);
  231 + this.properties.writeProperties();
  232 + }
  233 +
  234 + @Override
  235 + public boolean isForceUpdateEnabled()
  236 + {
  237 + return this.properties.getBooleanProperty(LoaderProperties.OPTION_FORCE_UPDATE);
  238 + }
  239 +
174 240 /**
175 241 * Display the liteloader panel over the specified GUI
176 242 *
... ... @@ -181,7 +247,7 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
181 247 {
182 248 if (this.isPanelSupportedOnScreen(parentScreen))
183 249 {
184   - this.panelHost = new GuiLiteLoaderPanel(this.minecraft, parentScreen, this.mods, this.environment, this.configManager, !this.hideModInfoScreenTab);
  250 + this.panelHost = new GuiLiteLoaderPanel(this.minecraft, parentScreen, this.mods, this.environment, this.properties, this.configManager, !this.isTabHidden());
185 251 this.minecraft.displayGuiScreen(this.panelHost);
186 252 }
187 253 }
... ... @@ -198,6 +264,18 @@ public class LiteLoaderPanelManager implements PanelManager&lt;GuiScreen&gt;
198 264 return this.mods.getCriticalErrorCount();
199 265 }
200 266  
  267 + @Override
  268 + public void setNotification(String notification)
  269 + {
  270 + LiteLoaderLogger.debug("Setting notification: " + notification);
  271 + this.notification = notification;
  272 +
  273 + if (this.panelHost != null)
  274 + {
  275 + this.panelHost.setNotification(notification);
  276 + }
  277 + }
  278 +
201 279 private boolean isPanelSupportedOnScreen(GuiScreen guiScreen)
202 280 {
203 281 return (
... ...
java/client/com/mumfrey/liteloader/client/gen/GenProfilerTransformer.java
... ... @@ -77,7 +77,7 @@ public class GenProfilerTransformer implements IClassTransformer
77 77  
78 78 for (Entry<MethodInsnNode, String> node : injectionNodes.entrySet())
79 79 {
80   - method.instructions.insert(node.getKey(), new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mumfrey/liteloader/core/gen/GenProfiler", "storeSignature", "(Ljava/lang/String;)V"));
  80 + method.instructions.insert(node.getKey(), new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mumfrey/liteloader/core/gen/GenProfiler", "storeSignature", "(Ljava/lang/String;)V", false));
81 81 method.instructions.insert(node.getKey(), new LdcInsnNode(node.getValue()));
82 82 }
83 83 }
... ...
java/client/com/mumfrey/liteloader/client/gui/GuiLiteLoaderPanel.java
... ... @@ -31,6 +31,7 @@ import com.mumfrey.liteloader.core.LiteLoaderMods;
31 31 import com.mumfrey.liteloader.core.ModInfo;
32 32 import com.mumfrey.liteloader.core.api.LiteLoaderCoreAPI;
33 33 import com.mumfrey.liteloader.launch.LoaderEnvironment;
  34 +import com.mumfrey.liteloader.launch.LoaderProperties;
34 35 import com.mumfrey.liteloader.modconfig.ConfigManager;
35 36 import com.mumfrey.liteloader.modconfig.ConfigPanel;
36 37  
... ... @@ -69,6 +70,11 @@ public class GuiLiteLoaderPanel extends GuiScreen
69 70 */
70 71 private GuiScreen parentScreen;
71 72  
  73 + @SuppressWarnings("unused")
  74 + private final LoaderEnvironment environment;
  75 +
  76 + private final LoaderProperties properties;
  77 +
72 78 /**
73 79 * Tick number (update counter) used for tweening
74 80 */
... ... @@ -87,7 +93,7 @@ public class GuiLiteLoaderPanel extends GuiScreen
87 93 /**
88 94 * Since we don't get real mouse events we have to simulate them by tracking the mouse state
89 95 */
90   - private boolean mouseDown, toggled;
  96 + private boolean mouseDown, toggled, toggleable;
91 97  
92 98 /**
93 99 * Hover opacity for the tab
... ... @@ -123,18 +129,25 @@ public class GuiLiteLoaderPanel extends GuiScreen
123 129  
124 130 private int startupErrorCount = 0, criticalErrorCount = 0;
125 131  
  132 + private String notification;
  133 +
126 134 /**
127 135 * @param minecraft
128 136 * @param parentScreen
129 137 * @param mods
130 138 */
131   - public GuiLiteLoaderPanel(Minecraft minecraft, GuiScreen parentScreen, LiteLoaderMods mods, LoaderEnvironment environment, ConfigManager configManager, boolean showTab)
  139 + public GuiLiteLoaderPanel(Minecraft minecraft, GuiScreen parentScreen, LiteLoaderMods mods, LoaderEnvironment environment, LoaderProperties properties, ConfigManager configManager, boolean showTab)
132 140 {
133 141 this.mc = minecraft;
134 142 this.fontRendererObj = minecraft.fontRendererObj;
135 143 this.parentScreen = parentScreen;
136 144 this.showTab = showTab;
137 145  
  146 + this.environment = environment;
  147 + this.properties = properties;
  148 +
  149 + this.toggleable = true;
  150 +
138 151 this.versionText = I18n.format("gui.about.versiontext", LiteLoader.getVersion());
139 152 this.activeModText = I18n.format("gui.about.modsloaded", mods.getLoadedMods().size());
140 153  
... ... @@ -233,6 +246,16 @@ public class GuiLiteLoaderPanel extends GuiScreen
233 246 {
234 247 return this.tweenAmount > 0.0;
235 248 }
  249 +
  250 + public void setToggleable(boolean toggleable)
  251 + {
  252 + this.toggleable = toggleable;
  253 + }
  254 +
  255 + public void setNotification(String notification)
  256 + {
  257 + this.notification = notification;
  258 + }
236 259  
237 260 /* (non-Javadoc)
238 261 * @see net.minecraft.client.gui.GuiScreen#initGui()
... ... @@ -247,7 +270,11 @@ public class GuiLiteLoaderPanel extends GuiScreen
247 270 this.currentPanel.setSize(this.width - LEFT_EDGE, this.height);
248 271  
249 272 this.buttonList.add(new GuiHoverLabel(2, LEFT_EDGE + MARGIN, this.height - PANEL_BOTTOM + 9, this.fontRendererObj, I18n.format("gui.about.taboptions"), this.brandColour));
250   - this.buttonList.add(new GuiHoverLabel(3, LEFT_EDGE + MARGIN + 38 + this.fontRendererObj.getStringWidth(this.versionText) + 6, 50, this.fontRendererObj, I18n.format("gui.about.checkupdates"), this.brandColour));
  273 +
  274 + if (LiteLoaderVersion.getUpdateSite().canCheckForUpdate() && this.mc.theWorld == null)
  275 + {
  276 + this.buttonList.add(new GuiHoverLabel(3, LEFT_EDGE + MARGIN + 38 + this.fontRendererObj.getStringWidth(this.versionText) + 6, 50, this.fontRendererObj, I18n.format("gui.about.checkupdates"), this.brandColour));
  277 + }
251 278  
252 279 Keyboard.enableRepeatEvents(true);
253 280 }
... ... @@ -290,7 +317,7 @@ public class GuiLiteLoaderPanel extends GuiScreen
290 317 this.mc.currentScreen = this;
291 318 }
292 319  
293   - if (this.toggled)
  320 + if (this.toggled && this.toggleable)
294 321 {
295 322 this.onToggled();
296 323 }
... ... @@ -338,7 +365,7 @@ public class GuiLiteLoaderPanel extends GuiScreen
338 365 this.handleMouseClick(offsetMouseX, mouseY, partialTicks, active, mouseOverTab);
339 366  
340 367 // Calculate the tab opacity, not framerate adjusted because we don't really care
341   - this.tabOpacity = mouseOverTab || alwaysExpandTab || this.startupErrorCount > 0 || this.isOpen() ? 0.5F : Math.max(0.0F, this.tabOpacity - partialTicks * 0.1F);
  368 + this.tabOpacity = mouseOverTab || alwaysExpandTab || this.startupErrorCount > 0 || this.notification != null || this.isOpen() ? 0.5F : Math.max(0.0F, this.tabOpacity - partialTicks * 0.1F);
342 369  
343 370 // Draw the panel contents
344 371 this.drawPanel(offsetMouseX, mouseY, partialTicks, active, xOffset);
... ... @@ -373,6 +400,10 @@ public class GuiLiteLoaderPanel extends GuiScreen
373 400 {
374 401 glDrawTexturedRect(LEFT_EDGE - TAB_WIDTH + 7, TAB_TOP + 2, 12, 12, 134, 92, 134 + 12, 92 + 12, 0.5F + this.tabOpacity);
375 402 }
  403 + else if (this.notification != null)
  404 + {
  405 + glDrawTexturedRect(LEFT_EDGE - TAB_WIDTH + 7, TAB_TOP + 2, 12, 12, 134 + 12, 92, 134 + 24, 92 + 12, 0.5F + this.tabOpacity);
  406 + }
376 407 }
377 408 else
378 409 {
... ... @@ -448,25 +479,34 @@ public class GuiLiteLoaderPanel extends GuiScreen
448 479  
449 480 private void drawTooltips(int mouseX, int mouseY, float partialTicks, boolean active, float xOffset, boolean mouseOverTab)
450 481 {
  482 + boolean annoyingTip = this.startupErrorCount > 0 || this.notification != null;
  483 +
451 484 if (mouseOverTab && this.tweenAmount < 0.01)
452 485 {
453 486 GuiLiteLoaderPanel.drawTooltip(this.fontRendererObj, LiteLoader.getVersionDisplayString(), mouseX, mouseY, this.width, this.height, 0xFFFFFF, 0xB0000000);
454 487 GuiLiteLoaderPanel.drawTooltip(this.fontRendererObj, this.activeModText, mouseX, mouseY + 13, this.width, this.height, 0xCCCCCC, 0xB0000000);
455 488  
456   - if (this.startupErrorCount > 0)
  489 + if (annoyingTip)
457 490 {
458   - this.drawErrorTooltip(mouseX, mouseY - 13);
  491 + this.drawNotificationTooltip(mouseX, mouseY - 13);
459 492 }
460 493 }
461   - else if (GuiLiteLoaderPanel.displayErrorToolTip && this.startupErrorCount > 0 && !active && this.parentScreen instanceof GuiMainMenu)
  494 + else if (GuiLiteLoaderPanel.displayErrorToolTip && annoyingTip && !active && this.parentScreen instanceof GuiMainMenu)
462 495 {
463   - this.drawErrorTooltip((int)xOffset + LEFT_EDGE - 12, TAB_TOP + 2);
  496 + this.drawNotificationTooltip((int)xOffset + LEFT_EDGE - 12, TAB_TOP + 2);
464 497 }
465 498 }
466 499  
467   - private void drawErrorTooltip(int left, int top)
  500 + private void drawNotificationTooltip(int left, int top)
468 501 {
469   - GuiLiteLoaderPanel.drawTooltip(this.fontRendererObj, I18n.format("gui.error.tooltip", this.startupErrorCount, this.criticalErrorCount), left, top, this.width, this.height, 0xFF5555, 0xB0330000);
  502 + if (this.startupErrorCount > 0)
  503 + {
  504 + GuiLiteLoaderPanel.drawTooltip(this.fontRendererObj, I18n.format("gui.error.tooltip", this.startupErrorCount, this.criticalErrorCount), left, top, this.width, this.height, 0xFF5555, 0xB0330000);
  505 + }
  506 + else if (this.notification != null)
  507 + {
  508 + GuiLiteLoaderPanel.drawTooltip(this.fontRendererObj, this.notification, left, top, this.width, this.height, 0xFFFFFF, 0xB0000099);
  509 + }
470 510 }
471 511  
472 512 /* (non-Javadoc)
... ... @@ -482,7 +522,7 @@ public class GuiLiteLoaderPanel extends GuiScreen
482 522  
483 523 if (button.id == 3)
484 524 {
485   - this.setCurrentPanel(new GuiPanelUpdateCheck(this.mc, LiteLoaderVersion.getUpdateSite(), "LiteLoader"));
  525 + this.setCurrentPanel(new GuiPanelUpdateCheck(this, this.mc, LiteLoaderVersion.getUpdateSite(), "LiteLoader", this.properties));
486 526 }
487 527 }
488 528  
... ...
java/client/com/mumfrey/liteloader/client/gui/GuiPanelSettings.java
... ... @@ -3,6 +3,7 @@ package com.mumfrey.liteloader.client.gui;
3 3 import org.lwjgl.input.Keyboard;
4 4  
5 5 import com.mumfrey.liteloader.core.LiteLoader;
  6 +import com.mumfrey.liteloader.interfaces.PanelManager;
6 7  
7 8 import net.minecraft.client.Minecraft;
8 9 import net.minecraft.client.gui.FontRenderer;
... ... @@ -13,12 +14,11 @@ class GuiPanelSettings extends GuiPanel
13 14 {
14 15 private GuiLiteLoaderPanel parentScreen;
15 16  
16   - private GuiCheckbox chkShowTab;
17   - private GuiCheckbox chkNoHide;
  17 + private GuiCheckbox chkShowTab, chkNoHide, chkForceUpdate;
18 18  
19 19 private boolean hide;
20 20  
21   - private String[] helpText = new String[3];
  21 + private String[] helpText = new String[5];
22 22  
23 23 GuiPanelSettings(GuiLiteLoaderPanel parentScreen, Minecraft minecraft)
24 24 {
... ... @@ -29,6 +29,8 @@ class GuiPanelSettings extends GuiPanel
29 29 this.helpText[0] = I18n.format("gui.settings.showtab.help1");
30 30 this.helpText[1] = I18n.format("gui.settings.showtab.help2");
31 31 this.helpText[2] = I18n.format("gui.settings.notabhide.help1");
  32 + this.helpText[3] = I18n.format("gui.settings.forceupdate.help1");
  33 + this.helpText[4] = I18n.format("gui.settings.forceupdate.help2");
32 34 }
33 35  
34 36 @Override
... ... @@ -53,26 +55,32 @@ class GuiPanelSettings extends GuiPanel
53 55 this.controls.add(new GuiButton(-1, this.width - 99 - MARGIN, this.height - BOTTOM + 9, 100, 20, I18n.format("gui.done")));
54 56 this.controls.add(this.chkShowTab = new GuiCheckbox(0, 34, 90, I18n.format("gui.settings.showtab.label")));
55 57 this.controls.add(this.chkNoHide = new GuiCheckbox(1, 34, 128, I18n.format("gui.settings.notabhide.label")));
  58 + this.controls.add(this.chkForceUpdate = new GuiCheckbox(2, 34, 158, I18n.format("gui.settings.forceupdate.label")));
56 59  
57 60 this.updateCheckBoxes();
58 61 }
59 62  
60 63 private void updateCheckBoxes()
61 64 {
62   - this.chkShowTab.checked = LiteLoader.getModPanelManager().isTabVisible();
63   - this.chkNoHide.checked = LiteLoader.getModPanelManager().isTabAlwaysExpanded();
  65 + PanelManager<?> panelManager = LiteLoader.getModPanelManager();
  66 +
  67 + this.chkShowTab.checked = panelManager.isTabVisible();
  68 + this.chkNoHide.checked = panelManager.isTabAlwaysExpanded();
  69 + this.chkForceUpdate.checked = panelManager.isForceUpdateEnabled();
64 70 }
65 71  
66 72 private void updateSettings()
67 73 {
68   - LiteLoader.getModPanelManager().setTabVisible(this.chkShowTab.checked);
69   - LiteLoader.getModPanelManager().setTabAlwaysExpanded(this.chkNoHide.checked);
  74 + PanelManager<?> panelManager = LiteLoader.getModPanelManager();
  75 +
  76 + panelManager.setTabVisible(this.chkShowTab.checked);
  77 + panelManager.setTabAlwaysExpanded(this.chkNoHide.checked);
  78 + panelManager.setForceUpdateEnabled(this.chkForceUpdate.checked);
70 79 }
71 80  
72 81 @Override
73 82 void draw(int mouseX, int mouseY, float partialTicks)
74 83 {
75   - this.setSize(this.width, this.height);
76 84 this.parentScreen.drawInfoPanel(mouseX, mouseY, partialTicks, 0, 38);
77 85  
78 86 FontRenderer fontRenderer = this.mc.fontRendererObj;
... ... @@ -81,6 +89,8 @@ class GuiPanelSettings extends GuiPanel
81 89 fontRenderer.drawString(this.helpText[0], 50, 104, brandColour);
82 90 fontRenderer.drawString(this.helpText[1], 50, 114, brandColour);
83 91 fontRenderer.drawString(this.helpText[2], 50, 142, brandColour);
  92 + fontRenderer.drawString(this.helpText[3], 50, 172, brandColour);
  93 + fontRenderer.drawString(this.helpText[4], 50, 182, brandColour);
84 94  
85 95 super.draw(mouseX, mouseY, partialTicks);
86 96 }
... ...
java/client/com/mumfrey/liteloader/client/gui/GuiPanelUpdateCheck.java
... ... @@ -2,15 +2,19 @@ package com.mumfrey.liteloader.client.gui;
2 2  
3 3 import java.net.URI;
4 4  
5   -import org.lwjgl.input.Keyboard;
6   -
7   -import com.mumfrey.liteloader.update.UpdateSite;
8   -
9 5 import net.minecraft.client.Minecraft;
10 6 import net.minecraft.client.gui.FontRenderer;
11 7 import net.minecraft.client.gui.GuiButton;
  8 +import net.minecraft.client.gui.ScaledResolution;
12 9 import net.minecraft.client.resources.I18n;
13 10  
  11 +import org.lwjgl.input.Keyboard;
  12 +
  13 +import com.mumfrey.liteloader.core.LiteLoaderUpdateSite;
  14 +import com.mumfrey.liteloader.launch.ClassPathUtilities;
  15 +import com.mumfrey.liteloader.launch.LoaderProperties;
  16 +import com.mumfrey.liteloader.update.UpdateSite;
  17 +
14 18 /**
15 19 * "Check for updates" panel which docks in the mod info screen
16 20 *
... ... @@ -23,15 +27,17 @@ class GuiPanelUpdateCheck extends GuiPanel
23 27 */
24 28 private static final URI DOWNLOAD_URI = URI.create("http://dl.liteloader.com");
25 29  
  30 + private final GuiLiteLoaderPanel parentScreen;
  31 +
26 32 /**
27 33 * Update site to contact
28 34 */
29   - private UpdateSite updateSite;
  35 + private final UpdateSite updateSite;
30 36  
31 37 /**
32 38 * Panel title
33 39 */
34   - private String panelTitle;
  40 + private final String panelTitle;
35 41  
36 42 /**
37 43 * Buttons
... ... @@ -43,12 +49,17 @@ class GuiPanelUpdateCheck extends GuiPanel
43 49 */
44 50 private int throb;
45 51  
46   - public GuiPanelUpdateCheck(Minecraft minecraft, UpdateSite updateSite, String updateName)
  52 + private boolean canForceUpdate, updateForced;
  53 +
  54 + public GuiPanelUpdateCheck(GuiLiteLoaderPanel parentScreen, Minecraft minecraft, UpdateSite updateSite, String updateName, LoaderProperties properties)
47 55 {
48 56 super(minecraft);
49 57  
  58 + this.parentScreen = parentScreen;
50 59 this.updateSite = updateSite;
51 60 this.panelTitle = I18n.format("gui.updates.title", updateName);
  61 +
  62 + this.canForceUpdate = (updateSite instanceof LiteLoaderUpdateSite && ((LiteLoaderUpdateSite)updateSite).canForceUpdate(properties));
52 63 }
53 64  
54 65 @Override
... ... @@ -56,9 +67,9 @@ class GuiPanelUpdateCheck extends GuiPanel
56 67 {
57 68 super.setSize(width, height);
58 69  
59   - this.controls.add(new GuiButton(0, this.width - 99 - MARGIN, this.height - BOTTOM + 9, 100, 20, I18n.format("gui.done")));
  70 + this.controls.add(new GuiButton(0, this.width - 99 - MARGIN, this.height - BOTTOM + 9, 100, 20, this.updateForced ? I18n.format("gui.exitgame") : I18n.format("gui.done")));
60 71 this.controls.add(this.btnCheck = new GuiButton(1, MARGIN + 16, TOP + 16, 100, 20, I18n.format("gui.checknow")));
61   - this.controls.add(this.btnDownload = new GuiButton(2, MARGIN + 16, TOP + 118, 100, 20, I18n.format("gui.downloadupdate")));
  72 + this.controls.add(this.btnDownload = new GuiButton(2, MARGIN + 16, TOP + 118, 100, 20, this.canForceUpdate ? I18n.format("gui.forceupdate") : I18n.format("gui.downloadupdate")));
62 73 }
63 74  
64 75 @Override
... ... @@ -73,7 +84,7 @@ class GuiPanelUpdateCheck extends GuiPanel
73 84 drawRect(MARGIN, TOP - 4, this.width - MARGIN, TOP - 3, 0xFF999999);
74 85 drawRect(MARGIN, this.height - BOTTOM + 2, this.width - MARGIN, this.height - BOTTOM + 3, 0xFF999999);
75 86  
76   - this.btnCheck.enabled = !this.updateSite.isCheckInProgress();
  87 + this.btnCheck.enabled = !this.updateForced && !this.updateSite.isCheckInProgress();
77 88 this.btnDownload.visible = false;
78 89  
79 90 if (this.updateSite.isCheckInProgress())
... ... @@ -92,10 +103,15 @@ class GuiPanelUpdateCheck extends GuiPanel
92 103 fontRenderer.drawString(I18n.format("gui.updates.available.title"), MARGIN + 18, TOP + 70, 0xFFFFFFFF);
93 104 if (this.updateSite.isUpdateAvailable())
94 105 {
95   - this.btnDownload.visible = true;
  106 + this.btnDownload.visible = !this.updateForced;
96 107 fontRenderer.drawString(I18n.format("gui.updates.available.newversion"), MARGIN + 18, TOP + 84, 0xFFFFFFFF);
97 108 fontRenderer.drawString(I18n.format("gui.updates.available.version", this.updateSite.getAvailableVersion()), MARGIN + 18, TOP + 94, 0xFFFFFFFF);
98 109 fontRenderer.drawString(I18n.format("gui.updates.available.date", this.updateSite.getAvailableVersionDate()), MARGIN + 18, TOP + 104, 0xFFFFFFFF);
  110 +
  111 + if (this.updateForced)
  112 + {
  113 + fontRenderer.drawString(I18n.format("gui.updates.forced"), MARGIN + 18, TOP + 144, 0xFFFFAA00);
  114 + }
99 115 }
100 116 else
101 117 {
... ... @@ -110,6 +126,17 @@ class GuiPanelUpdateCheck extends GuiPanel
110 126  
111 127 super.draw(mouseX, mouseY, partialTicks);
112 128 }
  129 +
  130 + @Override
  131 + public void close()
  132 + {
  133 + if (this.updateForced)
  134 + {
  135 + return;
  136 + }
  137 +
  138 + super.close();
  139 + }
113 140  
114 141 /**
115 142 * @param control
... ... @@ -117,11 +144,31 @@ class GuiPanelUpdateCheck extends GuiPanel
117 144 @Override
118 145 void actionPerformed(GuiButton control)
119 146 {
120   - if (control.id == 0) this.close();
  147 + if (control.id == 0)
  148 + {
  149 + if (this.updateForced)
  150 + {
  151 + ClassPathUtilities.terminateRuntime(0);
  152 + return;
  153 + }
  154 +
  155 + this.close();
  156 + }
121 157 if (control.id == 1) this.updateSite.beginUpdateCheck();
122 158 if (control.id == 2)
123 159 {
124   - this.openURI(GuiPanelUpdateCheck.DOWNLOAD_URI);
  160 + if (this.canForceUpdate && ((LiteLoaderUpdateSite)this.updateSite).forceUpdate())
  161 + {
  162 + this.updateForced = true;
  163 + this.parentScreen.setToggleable(false);
  164 + ScaledResolution sr = new ScaledResolution(this.mc, this.mc.displayWidth, this.mc.displayHeight);
  165 + this.parentScreen.setWorldAndResolution(this.mc, sr.getScaledWidth(), sr.getScaledHeight());
  166 + }
  167 + else
  168 + {
  169 + this.openURI(GuiPanelUpdateCheck.DOWNLOAD_URI);
  170 + }
  171 +
125 172 this.btnDownload.enabled = false;
126 173 }
127 174 }
... ...
java/client/com/mumfrey/liteloader/client/transformers/CrashReportTransformer.java
... ... @@ -58,7 +58,7 @@ public class CrashReportTransformer extends ClassTransformer
58 58 {
59 59 InsnList code = new InsnList();
60 60 code.add(new VarInsnNode(Opcodes.ALOAD, 1));
61   - code.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mumfrey/liteloader/core/LiteLoader", "populateCrashReport", "(Ljava/lang/Object;)V"));
  61 + code.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "com/mumfrey/liteloader/core/LiteLoader", "populateCrashReport", "(Ljava/lang/Object;)V", false));
62 62  
63 63 ListIterator<AbstractInsnNode> insns = ctor.instructions.iterator();
64 64 while (insns.hasNext())
... ...
java/client/com/mumfrey/liteloader/client/transformers/MinecraftOverlayTransformer.java
... ... @@ -66,8 +66,8 @@ public class MinecraftOverlayTransformer extends ClassOverlayTransformer
66 66 LiteLoaderLogger.info("MinecraftOverlayTransformer found INIT injection point, this is good.");
67 67 found = true;
68 68  
69   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftOverlayTransformer.LITELOADER_TWEAKER_CLASS, MinecraftOverlayTransformer.METHOD_INIT, "()V"));
70   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftOverlayTransformer.LITELOADER_TWEAKER_CLASS, MinecraftOverlayTransformer.METHOD_POSTINIT, "()V"));
  69 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftOverlayTransformer.LITELOADER_TWEAKER_CLASS, MinecraftOverlayTransformer.METHOD_INIT, "()V", false));
  70 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftOverlayTransformer.LITELOADER_TWEAKER_CLASS, MinecraftOverlayTransformer.METHOD_POSTINIT, "()V", false));
71 71 }
72 72 }
73 73  
... ... @@ -78,11 +78,11 @@ public class MinecraftOverlayTransformer extends ClassOverlayTransformer
78 78 LdcInsnNode ldcInsn = (LdcInsnNode)insn;
79 79 if ("textures/blocks".equals(ldcInsn.cst))
80 80 {
81   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.LoadingBar.ref, "initTextures", "()V"));
  81 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.LoadingBar.ref, "initTextures", "()V", false));
82 82 }
83 83 }
84 84  
85   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.LoadingBar.ref, "incrementProgress", "()V"));
  85 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.LoadingBar.ref, "incrementProgress", "()V", false));
86 86 }
87 87 }
88 88  
... ...
java/common/com/mumfrey/liteloader/core/LiteLoader.java
... ... @@ -154,7 +154,7 @@ public final class LiteLoader
154 154 * Mod panel manager, deliberately raw
155 155 */
156 156 @SuppressWarnings("rawtypes")
157   - private PanelManager modPanelManager;
  157 + private PanelManager panelManager;
158 158  
159 159 /**
160 160 * Interface Manager
... ... @@ -519,7 +519,7 @@ public final class LiteLoader
519 519 @SuppressWarnings({ "cast", "unchecked" })
520 520 public static <T> PanelManager<T> getModPanelManager()
521 521 {
522   - return (PanelManager<T>)LiteLoader.instance.modPanelManager;
  522 + return (PanelManager<T>)LiteLoader.instance.panelManager;
523 523 }
524 524  
525 525 /**
... ... @@ -869,10 +869,10 @@ public final class LiteLoader
869 869 }
870 870  
871 871 // Get the mod panel manager
872   - this.modPanelManager = this.objectFactory.getModPanelManager();
873   - if (this.modPanelManager != null)
  872 + this.panelManager = this.objectFactory.getModPanelManager();
  873 + if (this.panelManager != null)
874 874 {
875   - this.modPanelManager.init(this.mods, this.configManager);
  875 + this.panelManager.init(this.mods, this.configManager);
876 876 }
877 877  
878 878 // Create the interface manager
... ... @@ -933,6 +933,11 @@ public final class LiteLoader
933 933 {
934 934 coreProvider.onStartupComplete();
935 935 }
  936 +
  937 + if (this.panelManager != null)
  938 + {
  939 + this.panelManager.onStartupComplete();
  940 + }
936 941 }
937 942  
938 943 /**
... ... @@ -1043,7 +1048,7 @@ public final class LiteLoader
1043 1048 @Deprecated
1044 1049 public boolean getDisplayModInfoScreenTab()
1045 1050 {
1046   - return (this.modPanelManager != null) ? this.modPanelManager.isTabVisible() : false;
  1051 + return (this.panelManager != null) ? this.panelManager.isTabVisible() : false;
1047 1052 }
1048 1053  
1049 1054 /**
... ... @@ -1058,7 +1063,7 @@ public final class LiteLoader
1058 1063 public void displayModInfoScreen(Object parentScreen)
1059 1064 {
1060 1065 // Use implicit cast, because we want this to fail if the user tries to give us an invalid class
1061   - if (this.modPanelManager != null) this.modPanelManager.displayLiteLoaderPanel(parentScreen);
  1066 + if (this.panelManager != null) this.panelManager.displayLiteLoaderPanel(parentScreen);
1062 1067 }
1063 1068  
1064 1069 /**
... ...
java/common/com/mumfrey/liteloader/core/LiteLoaderBootstrap.java
... ... @@ -575,6 +575,26 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
575 575 {
576 576 this.localProperties.setProperty(propertyName, String.valueOf(value));
577 577 }
  578 +
  579 + @Override
  580 + public int getAndStoreIntegerProperty(String propertyName, int defaultValue)
  581 + {
  582 + int result = LiteLoaderBootstrap.tryParseInt(this.localProperties.getProperty(propertyName, String.valueOf(defaultValue)), defaultValue);
  583 + this.localProperties.setProperty(propertyName, String.valueOf(result));
  584 + return result;
  585 + }
  586 +
  587 + @Override
  588 + public int getIntegerProperty(String propertyName)
  589 + {
  590 + return LiteLoaderBootstrap.tryParseInt(this.localProperties.getProperty(propertyName, "0"), 0);
  591 + }
  592 +
  593 + @Override
  594 + public void setIntegerProperty(String propertyName, int value)
  595 + {
  596 + this.localProperties.setProperty(propertyName, String.valueOf(value));
  597 + }
578 598  
579 599 /**
580 600 * Store current revision for mod in the config file
... ... @@ -692,4 +712,16 @@ class LiteLoaderBootstrap implements LoaderBootstrap, LoaderEnvironment, LoaderP
692 712 {
693 713 return this.apiAdapter.getPacketTransformers();
694 714 }
  715 +
  716 + private static int tryParseInt(String string, int defaultValue)
  717 + {
  718 + try
  719 + {
  720 + return Integer.parseInt(string);
  721 + }
  722 + catch (NumberFormatException ex)
  723 + {
  724 + return defaultValue;
  725 + }
  726 + }
695 727 }
... ...
java/common/com/mumfrey/liteloader/core/LiteLoaderUpdateSite.java 0 → 100644
  1 +package com.mumfrey.liteloader.core;
  2 +
  3 +import java.io.File;
  4 +import java.io.FileOutputStream;
  5 +import java.io.IOException;
  6 +import java.io.InputStream;
  7 +
  8 +import net.minecraft.util.Util;
  9 +import net.minecraft.util.Util.EnumOS;
  10 +
  11 +import com.google.common.io.ByteStreams;
  12 +import com.google.common.io.Files;
  13 +import com.google.common.io.OutputSupplier;
  14 +import com.mumfrey.liteloader.launch.ClassPathUtilities;
  15 +import com.mumfrey.liteloader.launch.LoaderProperties;
  16 +import com.mumfrey.liteloader.update.UpdateSite;
  17 +import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
  18 +
  19 +public class LiteLoaderUpdateSite extends UpdateSite
  20 +{
  21 + private static final String UPDATE_SITE_URL = "http://dl.liteloader.com/versions/";
  22 + private static final String UPDATE_SITE_VERSIONS_JSON = "versions.json";
  23 + private static final String UPDATE_SITE_ARTEFACT_NAME = "com.mumfrey:liteloader";
  24 +
  25 + private String mcVersion;
  26 +
  27 + private File mcDir;
  28 + private File jarFile = null;
  29 +
  30 + private boolean updateForced = false;
  31 +
  32 + public LiteLoaderUpdateSite(String targetVersion, long currentTimeStamp)
  33 + {
  34 + super(LiteLoaderUpdateSite.UPDATE_SITE_URL, LiteLoaderUpdateSite.UPDATE_SITE_VERSIONS_JSON, targetVersion, LiteLoaderUpdateSite.UPDATE_SITE_ARTEFACT_NAME, currentTimeStamp);
  35 +
  36 + this.mcVersion = targetVersion;
  37 + }
  38 +
  39 + public boolean canForceUpdate(LoaderProperties properties)
  40 + {
  41 + if (!properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_FORCE_UPDATE, false))
  42 + {
  43 + return false;
  44 + }
  45 +
  46 + // TODO Enable force update
  47 + if (this.hasJarFile()) return true;
  48 + return this.findJarFile();
  49 + }
  50 +
  51 + /**
  52 + * @return
  53 + */
  54 + private boolean findJarFile()
  55 + {
  56 + // Find the jar containing liteloader
  57 + File jarFile = ClassPathUtilities.getPathToResource(LiteLoader.class, "/" + LiteLoader.class.getName().replace('.', '/') + ".class");
  58 + if (!jarFile.isFile()) return false;
  59 +
  60 + // Validate that the jar is in the expected name and location
  61 + this.mcDir = this.walkAndValidateParents(jarFile, "liteloader-" + this.mcVersion + ".jar", this.mcVersion, "liteloader", "mumfrey", "com", "libraries");
  62 + if (this.mcDir == null) return false;
  63 +
  64 + // Check that the jar we found is actually on the current classpath
  65 + if (!ClassPathUtilities.isJarOnClassPath(jarFile)) return false;
  66 + this.jarFile = jarFile;
  67 + return true;
  68 + }
  69 +
  70 + private File walkAndValidateParents(File file, String... breadcrumbs)
  71 + {
  72 + try
  73 + {
  74 + for (String breadcrumb : breadcrumbs)
  75 + {
  76 + if (file == null || !file.exists() || !file.getName().equals(breadcrumb)) return null;
  77 + file = file.getParentFile();
  78 + }
  79 +
  80 + return file;
  81 + }
  82 + catch (Exception ex)
  83 + {
  84 + ex.printStackTrace();
  85 + }
  86 +
  87 + return null;
  88 + }
  89 +
  90 +
  91 + public boolean canCheckForUpdate()
  92 + {
  93 + return !this.updateForced;
  94 + }
  95 +
  96 + public boolean hasJarFile()
  97 + {
  98 + return this.jarFile != null;
  99 + }
  100 +
  101 + public File getJarFile()
  102 + {
  103 + return this.jarFile;
  104 + }
  105 +
  106 + public boolean forceUpdate()
  107 + {
  108 + if (this.jarFile != null)
  109 + {
  110 + LiteLoaderLogger.info("Attempting to force update, extracting jar assassin...");
  111 +
  112 + // TODO Enable force update
  113 + File jarAssassinOutput = new File(this.jarFile.getParentFile(), "liteloader-update-agent.jar");
  114 +
  115 + if (!LiteLoaderUpdateSite.extractFile("/update/liteloader-update-agent.jar", jarAssassinOutput) || !jarAssassinOutput.isFile())
  116 + {
  117 + LiteLoaderLogger.info("Couldn't extract jarassassin jar, can't force update");
  118 + return false;
  119 + }
  120 +
  121 + File joptSimple = new File(this.mcDir, "libraries/net/sf/jopt-simple/jopt-simple/4.5/jopt-simple-4.5.jar");
  122 +
  123 + ProcessBuilder jarAssassinProcBuilder = new ProcessBuilder(
  124 + LiteLoaderUpdateSite.getJavaExecutable().getAbsolutePath(),
  125 + "-cp", joptSimple.getAbsolutePath(),
  126 + "-jar", jarAssassinOutput.getAbsolutePath(),
  127 + "--jarFile", this.jarFile.getAbsolutePath()).directory(this.jarFile.getParentFile());
  128 + try
  129 + {
  130 + System.err.println(jarAssassinProcBuilder.command());
  131 +
  132 + @SuppressWarnings("unused")
  133 + Process jarAssassin = jarAssassinProcBuilder.start();
  134 +
  135 + ClassPathUtilities.deleteClassPathJar(this.jarFile.getAbsolutePath());
  136 +
  137 + return true;
  138 + }
  139 + catch (Throwable th)
  140 + {
  141 + LiteLoaderLogger.info("Couldn't execute jarassassin jar, can't force update");
  142 + return false;
  143 + }
  144 + }
  145 +
  146 + return false;
  147 + }
  148 +
  149 + protected static boolean extractFile(String resourceName, File outputFile)
  150 + {
  151 + try
  152 + {
  153 + final InputStream inputStream = LiteLoaderUpdateSite.class.getResourceAsStream(resourceName);
  154 + final OutputSupplier<FileOutputStream> outputSupplier = Files.newOutputStreamSupplier(outputFile);
  155 + ByteStreams.copy(inputStream, outputSupplier);
  156 + }
  157 + catch (NullPointerException ex)
  158 + {
  159 + return false;
  160 + }
  161 + catch (IOException ex)
  162 + {
  163 + return false;
  164 + }
  165 +
  166 + return true;
  167 + }
  168 +
  169 + protected static File getJavaExecutable()
  170 + {
  171 + File javaBin = new File(new File(System.getProperty("java.home")), "bin");
  172 + File javaWin = new File(javaBin, "javaw.exe");
  173 +
  174 + return Util.getOSType() == EnumOS.WINDOWS && javaWin.isFile() ? javaWin : new File(javaBin, "java");
  175 + }
  176 +}
... ...
java/common/com/mumfrey/liteloader/core/LiteLoaderVersion.java
... ... @@ -3,8 +3,6 @@ package com.mumfrey.liteloader.core;
3 3 import java.util.HashSet;
4 4 import java.util.Set;
5 5  
6   -import com.mumfrey.liteloader.update.UpdateSite;
7   -
8 6 /**
9 7 * LiteLoader version table
10 8 *
... ... @@ -46,11 +44,7 @@ public enum LiteLoaderVersion
46 44 */
47 45 public static final LiteLoaderVersion CURRENT = LiteLoaderVersion.MC_1_7_10_R4;
48 46  
49   - private static final String UPDATE_SITE_URL = "http://dl.liteloader.com/versions/";
50   - private static final String UPDATE_SITE_VERSIONS_JSON = "versions.json";
51   - private static final String UPDATE_SITE_ARTEFACT_NAME = "com.mumfrey:liteloader";
52   -
53   - private static final UpdateSite updateSite = new UpdateSite(UPDATE_SITE_URL, UPDATE_SITE_VERSIONS_JSON, LiteLoaderVersion.CURRENT.getMinecraftVersion(), LiteLoaderVersion.UPDATE_SITE_ARTEFACT_NAME, LiteLoaderVersion.CURRENT.getReleaseTimestamp());
  47 + private static final LiteLoaderUpdateSite updateSite = new LiteLoaderUpdateSite(LiteLoaderVersion.CURRENT.getMinecraftVersion(), LiteLoaderVersion.CURRENT.getReleaseTimestamp());
54 48  
55 49 private final int revision;
56 50  
... ... @@ -131,7 +125,7 @@ public enum LiteLoaderVersion
131 125 return this.loaderVersion;
132 126 }
133 127  
134   - public static UpdateSite getUpdateSite()
  128 + public static LiteLoaderUpdateSite getUpdateSite()
135 129 {
136 130 return LiteLoaderVersion.updateSite;
137 131 }
... ...
java/common/com/mumfrey/liteloader/interfaces/PanelManager.java
... ... @@ -19,6 +19,11 @@ public interface PanelManager&lt;TParentScreen&gt; extends TickObserver, PostRenderObs
19 19 * @param configManager
20 20 */
21 21 public abstract void init(LiteLoaderMods mods, ConfigManager configManager);
  22 +
  23 + /**
  24 + *
  25 + */
  26 + public abstract void onStartupComplete();
22 27  
23 28 /**
24 29 *
... ... @@ -59,4 +64,19 @@ public interface PanelManager&lt;TParentScreen&gt; extends TickObserver, PostRenderObs
59 64 * @return
60 65 */
61 66 public abstract int getCriticalErrorCount();
  67 +
  68 + /**
  69 + * @param notification
  70 + */
  71 + public abstract void setNotification(String notification);
  72 +
  73 + /**
  74 + * @param forceUpdate
  75 + */
  76 + public abstract void setForceUpdateEnabled(boolean forceUpdate);
  77 +
  78 + /**
  79 + * @return
  80 + */
  81 + public abstract boolean isForceUpdateEnabled();
62 82 }
... ...
java/common/com/mumfrey/liteloader/launch/ClassPathUtilities.java
... ... @@ -12,6 +12,7 @@ import java.security.AccessController;
12 12 import java.security.PrivilegedActionException;
13 13 import java.security.PrivilegedExceptionAction;
14 14 import java.util.ArrayList;
  15 +import java.util.Iterator;
15 16 import java.util.Map;
16 17 import java.util.Map.Entry;
17 18 import java.util.Stack;
... ... @@ -58,6 +59,8 @@ public abstract class ClassPathUtilities
58 59  
59 60 private static boolean canInject;
60 61  
  62 + private static boolean canTerminate;
  63 +
61 64 static
62 65 {
63 66 try
... ... @@ -221,6 +224,33 @@ public abstract class ClassPathUtilities
221 224 catch (Exception ex) {}
222 225 }
223 226 }
  227 +
  228 + /**
  229 + * Is the specified jar on the game launch classpath
  230 + *
  231 + * @param jarFile
  232 + * @return
  233 + */
  234 + public static boolean isJarOnClassPath(File jarFile)
  235 + {
  236 + try
  237 + {
  238 + String jarURL = jarFile.toURI().toURL().toString();
  239 +
  240 + URL[] classPath = ((URLClassLoader)Launch.class.getClassLoader()).getURLs();
  241 + for (URL classPathEntry : classPath)
  242 + {
  243 + if (classPathEntry.toString().equals(jarURL))
  244 + return true;
  245 + }
  246 + }
  247 + catch (Exception ex)
  248 + {
  249 + ex.printStackTrace();
  250 + }
  251 +
  252 + return false;
  253 + }
224 254  
225 255 /**
226 256 * Gets the file containing the specified resource
... ... @@ -285,29 +315,20 @@ public abstract class ClassPathUtilities
285 315  
286 316 if (jar != null && parentJar != null && jar.getName().equals(parentJar.getName()))
287 317 {
288   - final JarFile jarInClassLoader = ClassPathUtilities.getJarFromClassLoader(Launch.classLoader, jarFileName, true);
289   - final JarFile jarInParentClassLoader = ClassPathUtilities.getJarFromClassLoader((URLClassLoader)Launch.class.getClassLoader(), jarFileName, true);
  318 + final JarDeletionHandler jarDeletionHandler = new JarDeletionHandler();
  319 +
  320 + JarFile jarInClassLoader = ClassPathUtilities.getJarFromClassLoader(Launch.classLoader, jarFileName, true);
  321 + JarFile jarInParentClassLoader = ClassPathUtilities.getJarFromClassLoader((URLClassLoader)Launch.class.getClassLoader(), jarFileName, true);
290 322  
291   - final File jarFileInClassLoader = new File(jarInClassLoader.getName());
292   - final File jarFileInParentClassLoader = new File(jarInParentClassLoader.getName());
  323 + File jarFileInClassLoader = new File(jarInClassLoader.getName());
  324 + File jarFileInParentClassLoader = new File(jarInParentClassLoader.getName());
  325 +
  326 + jarDeletionHandler.setPaths(jarInClassLoader, jarInParentClassLoader, jarFileInClassLoader, jarFileInParentClassLoader);
293 327  
294 328 try
295 329 {
296   - Boolean deleted = AccessController.doPrivileged(new PrivilegedExceptionAction<Boolean>()
297   - {
298   - @Override
299   - public Boolean run() throws Exception
300   - {
301   - jarInClassLoader.close();
302   - jarInParentClassLoader.close();
303   -
304   - boolean deletedJarFile = jarFileInClassLoader.delete();
305   - boolean deletedParentJarFile = jarFileInParentClassLoader.delete();
306   -
307   - return Boolean.valueOf(deletedJarFile || deletedParentJarFile);
308   - }
309   - });
310   -
  330 + Boolean deleted = AccessController.doPrivileged(jarDeletionHandler);
  331 + ClassPathUtilities.canTerminate |= deleted;
311 332 return deleted;
312 333 }
313 334 catch (PrivilegedActionException ex)
... ... @@ -323,6 +344,18 @@ public abstract class ClassPathUtilities
323 344  
324 345 return false;
325 346 }
  347 +
  348 + public static void terminateRuntime(int status)
  349 + {
  350 + if (ClassPathUtilities.canTerminate)
  351 + {
  352 + System.exit(status);
  353 + }
  354 + else
  355 + {
  356 + throw new IllegalStateException();
  357 + }
  358 + }
326 359  
327 360 /**
328 361 * @param classLoader
... ... @@ -341,8 +374,11 @@ public abstract class ClassPathUtilities
341 374 URLClassPath classPath = (URLClassPath)ClassPathUtilities.ucp.get(classLoader);
342 375 Map<String, ?> loaderMap = (Map<String, ?>)ClassPathUtilities.classPathLoaderMap.get(classPath);
343 376  
344   - for (Entry<String, ?> loaderEntry : loaderMap.entrySet())
  377 + Iterator<?> iter = loaderMap.entrySet().iterator();
  378 + while (iter.hasNext())
345 379 {
  380 + Entry<String, ?> loaderEntry = (Entry<String, ?>)iter.next();
  381 +
346 382 String url = loaderEntry.getKey();
347 383  
348 384 if (url.endsWith(fileName))
... ... @@ -362,7 +398,7 @@ public abstract class ClassPathUtilities
362 398 ArrayList<?> loaders = (ArrayList<?>)ClassPathUtilities.classPathLoaderList.get(classPath);
363 399  
364 400 loaders.remove(loader);
365   - loaderMap.remove(url);
  401 + iter.remove();
366 402  
367 403 URL jarURL = new URL(url);
368 404 urls.remove(jarURL);
... ... @@ -382,3 +418,40 @@ public abstract class ClassPathUtilities
382 418 return jar;
383 419 }
384 420 }
  421 +
  422 +class JarDeletionHandler implements PrivilegedExceptionAction<Boolean>
  423 +{
  424 + JarFile jarInClassLoader, jarInParentClassLoader;
  425 + File jarFileInClassLoader, jarFileInParentClassLoader;
  426 +
  427 + void setPaths(JarFile jarInClassLoader, JarFile jarInParentClassLoader, File jarFileInClassLoader, File jarFileInParentClassLoader)
  428 + {
  429 + this.jarInClassLoader = jarInClassLoader;
  430 + this.jarInParentClassLoader = jarInParentClassLoader;
  431 + this.jarFileInClassLoader = jarFileInClassLoader;
  432 + this.jarFileInParentClassLoader = jarFileInParentClassLoader;
  433 + }
  434 +
  435 + @Override
  436 + public Boolean run() throws Exception
  437 + {
  438 + this.jarInClassLoader.close();
  439 + this.jarInParentClassLoader.close();
  440 +
  441 + try
  442 + {
  443 + Thread.sleep(5000);
  444 + }
  445 + catch (Exception ex)
  446 + {
  447 + ex.printStackTrace();
  448 + }
  449 +
  450 + boolean deletedJarFile = this.jarFileInClassLoader.delete();
  451 + boolean deletedParentJarFile = this.jarFileInParentClassLoader.delete();
  452 +
  453 + System.err.println("deletedJarFile=" + deletedJarFile + " deletedParentJarFile=" + deletedParentJarFile);
  454 +
  455 + return Boolean.valueOf(deletedJarFile || deletedParentJarFile);
  456 + }
  457 +}
385 458 \ No newline at end of file
... ...
java/common/com/mumfrey/liteloader/launch/LiteLoaderTransformer.java
... ... @@ -40,7 +40,7 @@ public class LiteLoaderTransformer extends ClassTransformer
40 40 {
41 41 if ("main".equals(method.name))
42 42 {
43   - method.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, LiteLoaderTransformer.LITELOADER_TWEAKER_CLASS, LiteLoaderTransformer.METHOD_PRE_BEGIN_GAME, "()V"));
  43 + method.instructions.insert(new MethodInsnNode(Opcodes.INVOKESTATIC, LiteLoaderTransformer.LITELOADER_TWEAKER_CLASS, LiteLoaderTransformer.METHOD_PRE_BEGIN_GAME, "()V", false));
44 44 }
45 45 }
46 46  
... ...
java/common/com/mumfrey/liteloader/launch/LoaderProperties.java
... ... @@ -43,6 +43,31 @@ public interface LoaderProperties
43 43 public abstract boolean getAndStoreBooleanProperty(String propertyName, boolean defaultValue);
44 44  
45 45 /**
  46 + * Set an integer property in the properties file
  47 + *
  48 + * @param propertyName
  49 + * @param value
  50 + */
  51 + public abstract void setIntegerProperty(String propertyName, int value);
  52 +
  53 + /**
  54 + * Get an integer property from the properties file
  55 + *
  56 + * @param propertyName
  57 + * @return
  58 + */
  59 + public abstract int getIntegerProperty(String propertyName);
  60 +
  61 + /**
  62 + * Get an integer property but write and return the supplied default value if the property doesn't exist
  63 + *
  64 + * @param propertyName
  65 + * @param defaultValue
  66 + * @return
  67 + */
  68 + public abstract int getAndStoreIntegerProperty(String propertyName, int defaultValue);
  69 +
  70 + /**
46 71 * Get a stored mod revision number from the properties file
47 72 *
48 73 * @param modKey
... ... @@ -69,6 +94,8 @@ public interface LoaderProperties
69 94 public static final String OPTION_NO_HIDE_TAB = "tabAlwaysExpanded";
70 95 public static final String OPTION_BRAND = "brand";
71 96 public static final String OPTION_LOADING_BAR = "loadingbar";
  97 + public static final String OPTION_FORCE_UPDATE = "allowForceUpdate";
  98 + public static final String OPTION_UPDATE_CHECK_INTR = "updateCheckInterval";
72 99  
73 100 // Enumerator properties
74 101 public static final String OPTION_SEARCH_MODS = "search.mods";
... ...
java/common/com/mumfrey/liteloader/launch/OperatingSystem.java 0 → 100644
  1 +package com.mumfrey.liteloader.launch;
  2 +
  3 +public class OperatingSystem
  4 +{
  5 +
  6 + public OperatingSystem()
  7 + {
  8 + // TODO Auto-generated constructor stub
  9 + }
  10 +
  11 +}
... ...
java/common/com/mumfrey/liteloader/transformers/CallbackInjectionTransformer.java
... ... @@ -221,7 +221,7 @@ public abstract class CallbackInjectionTransformer extends ClassTransformer
221 221 private InsnList genProfilerCallbackInsns(InsnList injected, Callback callback, int refNumber)
222 222 {
223 223 injected.add(new LdcInsnNode(refNumber));
224   - injected.add(new MethodInsnNode(Opcodes.INVOKESTATIC, callback.getCallbackClass(), callback.getCallbackMethod(), "(I)V"));
  224 + injected.add(new MethodInsnNode(Opcodes.INVOKESTATIC, callback.getCallbackClass(), callback.getCallbackMethod(), "(I)V", false));
225 225  
226 226 if (callback.getChainedCallbacks().size() > 0)
227 227 {
... ... @@ -297,7 +297,7 @@ public abstract class CallbackInjectionTransformer extends ClassTransformer
297 297 String callbackMethodDesc = String.format("(%s%s%s%s)%s", hasReturnRef ? callbackReturnValueArg : "", hasReturnRef ? "I" : "", classInstanceArg, CallbackInjectionTransformer.getMethodArgs(methodNode), callbackReturnType);
298 298  
299 299 // Add the callback method insn to the injected instructions list
300   - injected.add(new MethodInsnNode(Opcodes.INVOKESTATIC, callback.getCallbackClass(), callback.getCallbackMethod(), callbackMethodDesc));
  300 + injected.add(new MethodInsnNode(Opcodes.INVOKESTATIC, callback.getCallbackClass(), callback.getCallbackMethod(), callbackMethodDesc, false));
301 301  
302 302 // If the callback RETURNs a value then push the appropriate RETURN opcode into the insns list
303 303 if (callback.injectReturn())
... ...
java/common/com/mumfrey/liteloader/transformers/PacketTransformer.java
... ... @@ -190,7 +190,7 @@ public abstract class PacketTransformer extends ClassTransformer
190 190 insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
191 191  
192 192 // Invoke the handler function with the args we just pushed onto the stack
193   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, this.handlerClassName, this.handlerMethodName, targetMethodSig));
  193 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, this.handlerClassName, this.handlerMethodName, targetMethodSig, false));
194 194  
195 195 method.instructions.insert(method.instructions.getFirst(), insns);
196 196 }
... ... @@ -217,7 +217,7 @@ public abstract class PacketTransformer extends ClassTransformer
217 217 method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
218 218  
219 219 // Invoke the handler function with the args we just pushed onto the stack
220   - method.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, this.handlerClassName, this.handlerMethodName, targetMethodSig));
  220 + method.instructions.add(new MethodInsnNode(Opcodes.INVOKESTATIC, this.handlerClassName, this.handlerMethodName, targetMethodSig, false));
221 221  
222 222 // Return if no exception
223 223 method.instructions.add(new InsnNode(Opcodes.RETURN));
... ...
java/common/com/mumfrey/liteloader/transformers/event/Event.java
... ... @@ -309,13 +309,13 @@ public class Event implements Comparable&lt;Event&gt;
309 309 insns.add(new LdcInsnNode(this.name)); ctorMAXS++;
310 310 insns.add(this.methodIsStatic ? new InsnNode(Opcodes.ACONST_NULL) : new VarInsnNode(Opcodes.ALOAD, 0)); ctorMAXS++;
311 311 insns.add(new InsnNode(cancellable ? Opcodes.ICONST_1 : Opcodes.ICONST_0)); ctorMAXS++;
312   - insns.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, this.eventInfoClass, Obf.constructor.name, EventInfo.getConstructorDescriptor()));
  312 + insns.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, this.eventInfoClass, Obf.constructor.name, EventInfo.getConstructorDescriptor(), false));
313 313 insns.add(new VarInsnNode(Opcodes.ASTORE, eventInfoVar));
314 314  
315 315 // Call the event handler method in the proxy
316 316 insns.add(new VarInsnNode(Opcodes.ALOAD, eventInfoVar));
317 317 Event.pushArgs(argumentTypes, insns, this.methodIsStatic);
318   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Event.getActiveProxyRef(), handler.name, handler.desc));
  318 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Event.getActiveProxyRef(), handler.name, handler.desc, false));
319 319  
320 320 if (cancellable)
321 321 {
... ... @@ -340,7 +340,7 @@ public class Event implements Comparable&lt;Event&gt;
340 340 protected void injectCancellationCode(final InsnList insns, final AbstractInsnNode injectionPoint, int eventInfoVar)
341 341 {
342 342 insns.add(new VarInsnNode(Opcodes.ALOAD, eventInfoVar));
343   - insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, this.eventInfoClass, EventInfo.getIsCancelledMethodName(), EventInfo.getIsCancelledMethodSig()));
  343 + insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, this.eventInfoClass, EventInfo.getIsCancelledMethodName(), EventInfo.getIsCancelledMethodSig(), false));
344 344  
345 345 LabelNode notCancelled = new LabelNode();
346 346 insns.add(new JumpInsnNode(Opcodes.IFEQ, notCancelled));
... ... @@ -371,7 +371,7 @@ public class Event implements Comparable&lt;Event&gt;
371 371 insns.add(new VarInsnNode(Opcodes.ALOAD, eventInfoVar));
372 372 String accessor = ReturnEventInfo.getReturnAccessor(this.methodReturnType);
373 373 String descriptor = ReturnEventInfo.getReturnDescriptor(this.methodReturnType);
374   - insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, this.eventInfoClass, accessor, descriptor));
  374 + insns.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, this.eventInfoClass, accessor, descriptor, false));
375 375 if (this.methodReturnType.getSort() == Type.OBJECT)
376 376 {
377 377 insns.add(new TypeInsnNode(Opcodes.CHECKCAST, this.methodReturnType.getInternalName()));
... ... @@ -509,7 +509,7 @@ public class Event implements Comparable&lt;Event&gt;
509 509 insns.add(new LineNumberNode(++lineNumber, lineNumberLabel));
510 510  
511 511 Event.pushArgs(args, insns, true);
512   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, listener.ownerRef, listener.getOrInflectName(event.name), handlerMethod.desc));
  512 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, listener.ownerRef, listener.getOrInflectName(event.name), handlerMethod.desc, false));
513 513 }
514 514  
515 515 insns.add(tryCatchEnd); // }
... ... @@ -517,12 +517,12 @@ public class Event implements Comparable&lt;Event&gt;
517 517  
518 518 insns.add(tryCatchHandler1); // catch (NoSuchMethodError err) {
519 519 insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
520   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.EventProxy.ref, "onMissingHandler", "(Ljava/lang/Error;Lcom/mumfrey/liteloader/transformers/event/EventInfo;)V"));
  520 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.EventProxy.ref, "onMissingHandler", "(Ljava/lang/Error;Lcom/mumfrey/liteloader/transformers/event/EventInfo;)V", false));
521 521 insns.add(new JumpInsnNode(Opcodes.GOTO, tryCatchExit));
522 522  
523 523 insns.add(tryCatchHandler2); // } catch (NoClassDefFoundError err) {
524 524 insns.add(new VarInsnNode(Opcodes.ALOAD, 0));
525   - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.EventProxy.ref, "onMissingClass", "(Ljava/lang/Error;Lcom/mumfrey/liteloader/transformers/event/EventInfo;)V"));
  525 + insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.EventProxy.ref, "onMissingClass", "(Ljava/lang/Error;Lcom/mumfrey/liteloader/transformers/event/EventInfo;)V", false));
526 526 insns.add(new JumpInsnNode(Opcodes.GOTO, tryCatchExit));
527 527  
528 528 insns.add(tryCatchExit); // }
... ...
java/common/com/mumfrey/liteloader/update/UpdateSite.java
... ... @@ -139,6 +139,7 @@ public class UpdateSite implements Comparator&lt;Long&gt;
139 139 {
140 140 if (this.stringRetriever == null)
141 141 {
  142 + LiteLoaderLogger.debug("Update site for %s is starting the update check", this.artefact);
142 143 this.stringRetriever = new HttpStringRetriever(String.format("%s%s", this.updateSiteUrl, this.updateSiteJsonFileName));
143 144 this.stringRetriever.start();
144 145 }
... ... @@ -231,10 +232,13 @@ public class UpdateSite implements Comparator&lt;Long&gt;
231 232 {
232 233 try
233 234 {
  235 + LiteLoaderLogger.debug("Update site for %s is parsing the update response", this.artefact);
234 236 this.parseData(this.stringRetriever.getString());
  237 + LiteLoaderLogger.debug("Update site for %s successfully parsed the update response", this.artefact);
235 238 }
236 239 catch (Exception ex)
237 240 {
  241 + LiteLoaderLogger.debug("Update site for %s failed parsing the update response: %s:%s", this.artefact, ex.getClass().getSimpleName(), ex.getMessage());
238 242 this.checkSuccess = false;
239 243 ex.printStackTrace();
240 244 }
... ...
lib/asm-debug-all-5.0.3.jar 0 → 100644
No preview for this file type
lib/launchwrapper-1.11.jar 0 → 100644
No preview for this file type
resources/assets/liteloader/lang/en_US.lang
... ... @@ -13,6 +13,9 @@ gui.settings.showtab.help1=If you disable this option, use CTRL+SHIFT+TAB
13 13 gui.settings.showtab.help2=to open the LiteLoader panel
14 14 gui.settings.notabhide.label=LiteLoader Tab Always Expanded
15 15 gui.settings.notabhide.help1=Only applies if the above option is also checked
  16 +gui.settings.forceupdate.label=Periodically Check For Updates
  17 +gui.settings.forceupdate.help1=This option is §cexperimental§r and may not work properly
  18 +gui.settings.forceupdate.help2=yet, it also enables the "force update" capability.
16 19  
17 20 gui.about.taboptions=§nLiteLoader Panel Options
18 21  
... ... @@ -55,9 +58,13 @@ gui.updates.available.newversion=§aNew version available
55 58 gui.updates.available.version=Version: §a%s
56 59 gui.updates.available.date=Release date: §a%s
57 60  
  61 +gui.updates.forced=Update forced, restart the game to apply update
  62 +
58 63 gui.checknow=Check now
59 64 gui.installupdate=Install now
60 65 gui.downloadupdate=Download now
  66 +gui.forceupdate=Force update
  67 +gui.exitgame=Exit Game
61 68  
62 69 gui.log.button=LiteLoader Log
63 70 gui.log.title=LiteLoader Log Viewer
... ... @@ -70,4 +77,6 @@ gui.log.closedialog=Close
70 77  
71 78 gui.error.title=Startup errors for %s
72 79  
73   -gui.error.tooltip=%d mod startup error(s) detected (%d critical)
74 80 \ No newline at end of file
  81 +gui.error.tooltip=%d mod startup error(s) detected (%d critical)
  82 +
  83 +gui.notifications.updateavailable=LiteLoader Update Available!
75 84 \ No newline at end of file
... ...