Commit e13e19ac4972f7bae1a25a94e104efa7b027527f
Backport all 1.12+ changes to 1.11.2
Showing
25 changed files
with
720 additions
and
343 deletions
build.gradle
| ... | ... | @@ -60,8 +60,8 @@ archivesBaseName = "liteloader" |
| 60 | 60 | version = buildVersion + (project.isReleaseBuild ? '' : '-' + project.classifier) |
| 61 | 61 | |
| 62 | 62 | // Minimum version of Java required |
| 63 | -sourceCompatibility = '1.6' | |
| 64 | -targetCompatibility = '1.6' | |
| 63 | +sourceCompatibility = '1.8' | |
| 64 | +targetCompatibility = '1.8' | |
| 65 | 65 | |
| 66 | 66 | repositories { |
| 67 | 67 | mavenLocal() |
| ... | ... | @@ -72,7 +72,7 @@ repositories { |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | dependencies { |
| 75 | - compile('org.spongepowered:mixin:0.6.8-SNAPSHOT') { | |
| 75 | + compile('org.spongepowered:mixin:0.7.1-SNAPSHOT') { | |
| 76 | 76 | exclude module: 'asm-commons' |
| 77 | 77 | exclude module: 'asm-tree' |
| 78 | 78 | exclude module: 'launchwrapper' |
| ... | ... | @@ -89,11 +89,11 @@ minecraft { |
| 89 | 89 | |
| 90 | 90 | sourceSets { |
| 91 | 91 | main { |
| 92 | - refMap = "mixins.liteloader.core.refmap.json" | |
| 92 | + ext.refMap = "mixins.liteloader.core.refmap.json" | |
| 93 | 93 | } |
| 94 | 94 | client { |
| 95 | 95 | compileClasspath += main.compileClasspath + main.output |
| 96 | - refMap = "mixins.liteloader.client.refmap.json" | |
| 96 | + ext.refMap = "mixins.liteloader.client.refmap.json" | |
| 97 | 97 | } |
| 98 | 98 | debug { |
| 99 | 99 | compileClasspath += client.compileClasspath + client.output |
| ... | ... | @@ -123,7 +123,7 @@ javadoc { |
| 123 | 123 | afterEvaluate { |
| 124 | 124 | logger.lifecycle '=================================================' |
| 125 | 125 | logger.lifecycle ' LiteLoader' |
| 126 | - logger.lifecycle ' Copyright (C) 2011-2016 Adam Mummery-Smith' | |
| 126 | + logger.lifecycle ' Copyright (C) 2011-2017 Adam Mummery-Smith' | |
| 127 | 127 | logger.lifecycle ' Running in {} mode', (project.isReleaseBuild ? "RELEASE" : "SNAPSHOT") |
| 128 | 128 | logger.lifecycle '=================================================' |
| 129 | 129 | ... | ... |
gradle.properties
src/client/java/com/mumfrey/liteloader/client/LiteLoaderEventBrokerClient.java
| ... | ... | @@ -9,24 +9,9 @@ import org.lwjgl.input.Mouse; |
| 9 | 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |
| 10 | 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; |
| 11 | 11 | |
| 12 | -import com.mumfrey.liteloader.ChatRenderListener; | |
| 13 | -import com.mumfrey.liteloader.EntityRenderListener; | |
| 14 | -import com.mumfrey.liteloader.FrameBufferListener; | |
| 15 | -import com.mumfrey.liteloader.GameLoopListener; | |
| 16 | -import com.mumfrey.liteloader.HUDRenderListener; | |
| 17 | -import com.mumfrey.liteloader.InitCompleteListener; | |
| 18 | -import com.mumfrey.liteloader.OutboundChatFilter; | |
| 19 | -import com.mumfrey.liteloader.OutboundChatListener; | |
| 20 | -import com.mumfrey.liteloader.PlayerClickListener; | |
| 12 | +import com.mumfrey.liteloader.*; | |
| 21 | 13 | import com.mumfrey.liteloader.PlayerInteractionListener.MouseButton; |
| 22 | -import com.mumfrey.liteloader.PostRenderListener; | |
| 23 | -import com.mumfrey.liteloader.PreRenderListener; | |
| 24 | -import com.mumfrey.liteloader.RenderListener; | |
| 25 | -import com.mumfrey.liteloader.ScreenshotListener; | |
| 26 | -import com.mumfrey.liteloader.Tickable; | |
| 27 | -import com.mumfrey.liteloader.ViewportListener; | |
| 28 | 14 | import com.mumfrey.liteloader.client.overlays.IEntityRenderer; |
| 29 | -import com.mumfrey.liteloader.client.overlays.IMinecraft; | |
| 30 | 15 | import com.mumfrey.liteloader.common.LoadingProgress; |
| 31 | 16 | import com.mumfrey.liteloader.core.InterfaceRegistrationDelegate; |
| 32 | 17 | import com.mumfrey.liteloader.core.LiteLoader; |
| ... | ... | @@ -51,7 +36,6 @@ import net.minecraft.client.shader.Framebuffer; |
| 51 | 36 | import net.minecraft.entity.Entity; |
| 52 | 37 | import net.minecraft.network.play.client.CPacketChatMessage; |
| 53 | 38 | import net.minecraft.server.integrated.IntegratedServer; |
| 54 | -import net.minecraft.util.Timer; | |
| 55 | 39 | import net.minecraft.util.text.ITextComponent; |
| 56 | 40 | |
| 57 | 41 | public class LiteLoaderEventBrokerClient extends LiteLoaderEventBroker<Minecraft, IntegratedServer> implements IResourceManagerReloadListener |
| ... | ... | @@ -427,14 +411,9 @@ public class LiteLoaderEventBrokerClient extends LiteLoaderEventBroker<Minecraft |
| 427 | 411 | /** |
| 428 | 412 | * Callback from the tick hook, ticks all tickable mods |
| 429 | 413 | */ |
| 430 | - public void onTick() | |
| 414 | + public void onTick(boolean clock, float partialTicks) | |
| 431 | 415 | { |
| 432 | 416 | this.profiler.endStartSection("litemods"); |
| 433 | - | |
| 434 | - Timer minecraftTimer = ((IMinecraft)this.engine.getClient()).getTimer(); | |
| 435 | - float partialTicks = minecraftTimer.renderPartialTicks; | |
| 436 | - boolean clock = minecraftTimer.elapsedTicks > 0; | |
| 437 | - | |
| 438 | 417 | Minecraft minecraft = this.engine.getClient(); |
| 439 | 418 | |
| 440 | 419 | // Flag indicates whether we are in game at the moment |
| ... | ... | @@ -548,7 +527,7 @@ public class LiteLoaderEventBrokerClient extends LiteLoaderEventBroker<Minecraft |
| 548 | 527 | } |
| 549 | 528 | |
| 550 | 529 | /** |
| 551 | - * @param e | |
| 530 | + * @param ci | |
| 552 | 531 | * @param name |
| 553 | 532 | * @param width |
| 554 | 533 | * @param height | ... | ... |
src/client/java/com/mumfrey/liteloader/client/LiteLoaderPanelManager.java
| ... | ... | @@ -9,6 +9,7 @@ import org.lwjgl.input.Keyboard; |
| 9 | 9 | |
| 10 | 10 | import com.mumfrey.liteloader.client.gui.GuiLiteLoaderPanel; |
| 11 | 11 | import com.mumfrey.liteloader.common.GameEngine; |
| 12 | +import com.mumfrey.liteloader.core.LiteLoader; | |
| 12 | 13 | import com.mumfrey.liteloader.core.LiteLoaderMods; |
| 13 | 14 | import com.mumfrey.liteloader.core.LiteLoaderUpdateSite; |
| 14 | 15 | import com.mumfrey.liteloader.core.LiteLoaderVersion; |
| ... | ... | @@ -32,6 +33,13 @@ import net.minecraft.client.resources.I18n; |
| 32 | 33 | */ |
| 33 | 34 | public class LiteLoaderPanelManager implements PanelManager<GuiScreen> |
| 34 | 35 | { |
| 36 | + /** | |
| 37 | + * Number of launches required before an update check is forced when the | |
| 38 | + * "force update check" option is enabled. For snapshot versions this is | |
| 39 | + * ignored and an update check is always performed. | |
| 40 | + */ | |
| 41 | + private static final int UPDATE_CHECK_INTERVAL = 10; | |
| 42 | + | |
| 35 | 43 | private final LoaderEnvironment environment; |
| 36 | 44 | |
| 37 | 45 | /** |
| ... | ... | @@ -87,14 +95,14 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> |
| 87 | 95 | this.displayModInfoScreenTab = this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_MOD_INFO_SCREEN, true); |
| 88 | 96 | this.tabAlwaysExpanded = this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_NO_HIDE_TAB, false); |
| 89 | 97 | |
| 90 | - if (this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_FORCE_UPDATE, false)) | |
| 98 | + if (this.shouldCheckForUpdates()) | |
| 91 | 99 | { |
| 92 | 100 | int updateCheckInterval = this.properties.getIntegerProperty(LoaderProperties.OPTION_UPDATE_CHECK_INTR) + 1; |
| 93 | - LiteLoaderLogger.debug("Force update is TRUE, updateCheckInterval = %d", updateCheckInterval); | |
| 101 | + LiteLoaderLogger.debug("Regular update check enabled, updateCheckInterval = %d", updateCheckInterval); | |
| 94 | 102 | |
| 95 | - if (updateCheckInterval > 10) | |
| 103 | + if (LiteLoader.isSnapshot() || updateCheckInterval > LiteLoaderPanelManager.UPDATE_CHECK_INTERVAL) | |
| 96 | 104 | { |
| 97 | - LiteLoaderLogger.debug("Forcing update check!"); | |
| 105 | + LiteLoaderLogger.debug("Checking for updates..."); | |
| 98 | 106 | this.checkForUpdate = true; |
| 99 | 107 | updateCheckInterval = 0; |
| 100 | 108 | } |
| ... | ... | @@ -104,6 +112,16 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> |
| 104 | 112 | } |
| 105 | 113 | } |
| 106 | 114 | |
| 115 | + private boolean shouldCheckForUpdates() | |
| 116 | + { | |
| 117 | + if (LiteLoader.isSnapshot() && this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_CHECK_SNAPSHOTS, true)) | |
| 118 | + { | |
| 119 | + return true; | |
| 120 | + } | |
| 121 | + | |
| 122 | + return this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_FORCE_UPDATE, false); | |
| 123 | + } | |
| 124 | + | |
| 107 | 125 | @Override |
| 108 | 126 | public void init(LiteLoaderMods mods, ConfigManager configManager) |
| 109 | 127 | { |
| ... | ... | @@ -141,7 +159,8 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> |
| 141 | 159 | this.checkForUpdate = false; |
| 142 | 160 | if (updateSite.isCheckSucceess() && updateSite.isUpdateAvailable()) |
| 143 | 161 | { |
| 144 | - this.setNotification(I18n.format("gui.notifications.updateavailable")); | |
| 162 | + this.setNotification(I18n.format("gui.notifications." + (LiteLoader.isSnapshot() ? "newsnapshotavailable" : "updateavailable"), | |
| 163 | + updateSite.getAvailableVersion(), updateSite.getAvailableVersionDate())); | |
| 145 | 164 | } |
| 146 | 165 | } |
| 147 | 166 | } |
| ... | ... | @@ -251,6 +270,19 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> |
| 251 | 270 | { |
| 252 | 271 | return this.properties.getBooleanProperty(LoaderProperties.OPTION_FORCE_UPDATE); |
| 253 | 272 | } |
| 273 | + | |
| 274 | + @Override | |
| 275 | + public void setCheckForSnapshotsEnabled(boolean checkForSnapshots) | |
| 276 | + { | |
| 277 | + this.properties.setBooleanProperty(LoaderProperties.OPTION_CHECK_SNAPSHOTS, checkForSnapshots); | |
| 278 | + this.properties.writeProperties(); | |
| 279 | + } | |
| 280 | + | |
| 281 | + @Override | |
| 282 | + public boolean isCheckForSnapshotsEnabled() | |
| 283 | + { | |
| 284 | + return this.properties.getBooleanProperty(LoaderProperties.OPTION_CHECK_SNAPSHOTS); | |
| 285 | + } | |
| 254 | 286 | |
| 255 | 287 | /** |
| 256 | 288 | * Display the liteloader panel over the specified GUI | ... | ... |
src/client/java/com/mumfrey/liteloader/client/api/LiteLoaderCoreAPIClient.java
| ... | ... | @@ -42,7 +42,6 @@ public class LiteLoaderCoreAPIClient extends LiteLoaderCoreAPI |
| 42 | 42 | |
| 43 | 43 | private static final String[] requiredDownstreamTransformers = { |
| 44 | 44 | LiteLoaderCoreAPI.PKG_LITELOADER_COMMON + ".transformers.LiteLoaderPacketTransformer", |
| 45 | - LiteLoaderCoreAPIClient.PKG_LITELOADER_CLIENT + ".transformers.MinecraftTransformer", | |
| 46 | 45 | LiteLoaderCoreAPI.PKG_LITELOADER + ".transformers.event.json.ModEventInjectionTransformer" |
| 47 | 46 | }; |
| 48 | 47 | ... | ... |
src/client/java/com/mumfrey/liteloader/client/gui/GuiLiteLoaderPanel.java
| ... | ... | @@ -177,11 +177,10 @@ public class GuiLiteLoaderPanel extends GuiScreen |
| 177 | 177 | this.startupErrorCount = mods.getStartupErrorCount(); |
| 178 | 178 | this.criticalErrorCount = mods.getCriticalErrorCount(); |
| 179 | 179 | |
| 180 | - String branding = LiteLoader.getBranding(); | |
| 181 | - if (branding != null && branding.contains("SNAPSHOT")) | |
| 180 | + this.isSnapshot = LiteLoader.isSnapshot(); | |
| 181 | + if (this.isSnapshot) | |
| 182 | 182 | { |
| 183 | - this.isSnapshot = true; | |
| 184 | - this.versionText = "\247c" + branding; | |
| 183 | + this.versionText = "\247c" + LiteLoader.getBranding(); | |
| 185 | 184 | } |
| 186 | 185 | } |
| 187 | 186 | |
| ... | ... | @@ -524,6 +523,7 @@ public class GuiLiteLoaderPanel extends GuiScreen |
| 524 | 523 | |
| 525 | 524 | if (annoyingTip) |
| 526 | 525 | { |
| 526 | + GuiLiteLoaderPanel.displayErrorToolTip = false; | |
| 527 | 527 | this.drawNotificationTooltip(mouseX, mouseY - 13); |
| 528 | 528 | } |
| 529 | 529 | } |
| ... | ... | @@ -542,8 +542,11 @@ public class GuiLiteLoaderPanel extends GuiScreen |
| 542 | 542 | } |
| 543 | 543 | else if (this.notification != null) |
| 544 | 544 | { |
| 545 | - GuiLiteLoaderPanel.drawTooltip(this.fontRendererObj, this.notification, left, top, this.width, this.height, | |
| 546 | - GuiLiteLoaderPanel.NOTIFICATION_TOOLTIP_FOREGROUND, GuiLiteLoaderPanel.NOTIFICATION_TOOLTIP_BACKGROUND); | |
| 545 | + boolean isCritical = this.notification.startsWith("!!"); | |
| 546 | + String text = isCritical ? this.notification.substring(2) : this.notification; | |
| 547 | + int bgColour = isCritical ? GuiLiteLoaderPanel.ERROR_TOOLTIP_BACKGROUND : GuiLiteLoaderPanel.NOTIFICATION_TOOLTIP_BACKGROUND; | |
| 548 | + GuiLiteLoaderPanel.drawTooltip(this.fontRendererObj, text, left, top, this.width, this.height, | |
| 549 | + GuiLiteLoaderPanel.NOTIFICATION_TOOLTIP_FOREGROUND, bgColour); | |
| 547 | 550 | } |
| 548 | 551 | } |
| 549 | 552 | |
| ... | ... | @@ -739,21 +742,32 @@ public class GuiLiteLoaderPanel extends GuiScreen |
| 739 | 742 | * |
| 740 | 743 | * @param fontRenderer |
| 741 | 744 | * @param tooltipText |
| 742 | - * @param mouseX | |
| 743 | - * @param mouseY | |
| 745 | + * @param left | |
| 746 | + * @param top | |
| 744 | 747 | * @param screenWidth |
| 745 | 748 | * @param screenHeight |
| 746 | 749 | * @param colour |
| 747 | 750 | * @param backgroundColour |
| 748 | 751 | */ |
| 749 | - public static void drawTooltip(FontRenderer fontRenderer, String tooltipText, int mouseX, int mouseY, int screenWidth, int screenHeight, | |
| 752 | + public static void drawTooltip(FontRenderer fontRenderer, String text, int left, int top, int screenWidth, int screenHeight, | |
| 750 | 753 | int colour, int backgroundColour) |
| 751 | 754 | { |
| 752 | - int textSize = fontRenderer.getStringWidth(tooltipText); | |
| 753 | - mouseX = Math.max(0, Math.min(screenWidth - 4, mouseX - 4)); | |
| 754 | - mouseY = Math.max(0, Math.min(screenHeight - 16, mouseY)); | |
| 755 | - drawRect(mouseX - textSize - 2, mouseY, mouseX + 2, mouseY + 12, backgroundColour); | |
| 756 | - fontRenderer.drawStringWithShadow(tooltipText, mouseX - textSize, mouseY + 2, colour); | |
| 755 | + String[] lines = text.trim().split("\\r?\\n"); | |
| 756 | + int textWidth = 0; | |
| 757 | + int textHeight = 9 * lines.length; | |
| 758 | + for (String line : lines) | |
| 759 | + { | |
| 760 | + textWidth = Math.max(textWidth, fontRenderer.getStringWidth(line)); | |
| 761 | + top -= 9; | |
| 762 | + } | |
| 763 | + | |
| 764 | + left = Math.max(0, Math.min(screenWidth - 4, left - 4)); | |
| 765 | + top = Math.max(0, Math.min(screenHeight - 16, top + 9)); | |
| 766 | + drawRect(left - textWidth - 2, top, left + 2, top + textHeight + 2, backgroundColour); | |
| 767 | + for (String line : lines) | |
| 768 | + { | |
| 769 | + fontRenderer.drawStringWithShadow(line, left - textWidth, (top += 9) - 7, colour); | |
| 770 | + } | |
| 757 | 771 | } |
| 758 | 772 | |
| 759 | 773 | ... | ... |
src/client/java/com/mumfrey/liteloader/client/gui/GuiPanelError.java
| ... | ... | @@ -12,10 +12,12 @@ import java.util.List; |
| 12 | 12 | |
| 13 | 13 | import org.lwjgl.input.Keyboard; |
| 14 | 14 | |
| 15 | +import com.google.common.base.Joiner; | |
| 15 | 16 | import com.mumfrey.liteloader.core.ModInfo; |
| 16 | 17 | |
| 17 | 18 | import net.minecraft.client.Minecraft; |
| 18 | 19 | import net.minecraft.client.gui.GuiButton; |
| 20 | +import net.minecraft.client.gui.GuiScreen; | |
| 19 | 21 | import net.minecraft.client.resources.I18n; |
| 20 | 22 | |
| 21 | 23 | public class GuiPanelError extends GuiPanel implements ScrollPanelContent |
| ... | ... | @@ -98,6 +100,7 @@ public class GuiPanelError extends GuiPanel implements ScrollPanelContent |
| 98 | 100 | |
| 99 | 101 | this.scrollPane.setSizeAndPosition(MARGIN, TOP, this.width - (MARGIN * 2), this.height - TOP - BOTTOM); |
| 100 | 102 | this.controls.add(new GuiButton(0, this.width - 59 - MARGIN, this.height - BOTTOM + 9, 60, 20, I18n.format("gui.done"))); |
| 103 | + this.controls.add(new GuiButton(1, this.width - 204 - MARGIN, this.height - BOTTOM + 9, 140, 20, I18n.format("gui.error.copytoclipboard"))); | |
| 101 | 104 | } |
| 102 | 105 | |
| 103 | 106 | @Override |
| ... | ... | @@ -131,7 +134,10 @@ public class GuiPanelError extends GuiPanel implements ScrollPanelContent |
| 131 | 134 | @Override |
| 132 | 135 | void keyPressed(char keyChar, int keyCode) |
| 133 | 136 | { |
| 134 | - if (keyCode == Keyboard.KEY_ESCAPE) this.close(); | |
| 137 | + if (keyCode == Keyboard.KEY_ESCAPE) | |
| 138 | + { | |
| 139 | + this.close(); | |
| 140 | + } | |
| 135 | 141 | } |
| 136 | 142 | |
| 137 | 143 | @Override |
| ... | ... | @@ -161,6 +167,14 @@ public class GuiPanelError extends GuiPanel implements ScrollPanelContent |
| 161 | 167 | @Override |
| 162 | 168 | void actionPerformed(GuiButton control) |
| 163 | 169 | { |
| 164 | - if (control.id == 0) this.close(); | |
| 170 | + if (control.id == 0) | |
| 171 | + { | |
| 172 | + this.close(); | |
| 173 | + } | |
| 174 | + | |
| 175 | + if (control.id == 1) | |
| 176 | + { | |
| 177 | + GuiScreen.setClipboardString(Joiner.on('\n').join(this.scrollPaneContent)); | |
| 178 | + } | |
| 165 | 179 | } |
| 166 | 180 | } | ... | ... |
src/client/java/com/mumfrey/liteloader/client/gui/GuiPanelSettings.java
| ... | ... | @@ -17,25 +17,29 @@ import net.minecraft.client.resources.I18n; |
| 17 | 17 | |
| 18 | 18 | class GuiPanelSettings extends GuiPanel |
| 19 | 19 | { |
| 20 | - private GuiLiteLoaderPanel parentScreen; | |
| 20 | + private final GuiLiteLoaderPanel parentScreen; | |
| 21 | + | |
| 22 | + private final boolean isSnapshot; | |
| 21 | 23 | |
| 22 | - private GuiCheckbox chkShowTab, chkNoHide, chkForceUpdate; | |
| 24 | + private GuiCheckbox chkShowTab, chkNoHide, chkForceUpdate, chkCheckForSnapshots; | |
| 23 | 25 | |
| 24 | 26 | private boolean hide; |
| 25 | 27 | |
| 26 | 28 | private String[] helpText = new String[5]; |
| 27 | - | |
| 29 | + | |
| 28 | 30 | GuiPanelSettings(GuiLiteLoaderPanel parentScreen, Minecraft minecraft) |
| 29 | 31 | { |
| 30 | 32 | super(minecraft); |
| 31 | 33 | |
| 32 | 34 | this.parentScreen = parentScreen; |
| 35 | + this.isSnapshot = LiteLoader.isSnapshot(); | |
| 33 | 36 | |
| 37 | + String helpKey = this.isSnapshot ? "checkforsnapshots" : "forceupdate"; | |
| 34 | 38 | this.helpText[0] = I18n.format("gui.settings.showtab.help1"); |
| 35 | 39 | this.helpText[1] = I18n.format("gui.settings.showtab.help2"); |
| 36 | 40 | this.helpText[2] = I18n.format("gui.settings.notabhide.help1"); |
| 37 | - this.helpText[3] = I18n.format("gui.settings.forceupdate.help1"); | |
| 38 | - this.helpText[4] = I18n.format("gui.settings.forceupdate.help2"); | |
| 41 | + this.helpText[3] = I18n.format("gui.settings." + helpKey + ".help1"); | |
| 42 | + this.helpText[4] = I18n.format("gui.settings." + helpKey + ".help2"); | |
| 39 | 43 | } |
| 40 | 44 | |
| 41 | 45 | @Override |
| ... | ... | @@ -61,6 +65,10 @@ class GuiPanelSettings extends GuiPanel |
| 61 | 65 | this.controls.add(this.chkShowTab = new GuiCheckbox(0, 34, 90, I18n.format("gui.settings.showtab.label"))); |
| 62 | 66 | this.controls.add(this.chkNoHide = new GuiCheckbox(1, 34, 128, I18n.format("gui.settings.notabhide.label"))); |
| 63 | 67 | this.controls.add(this.chkForceUpdate = new GuiCheckbox(2, 34, 158, I18n.format("gui.settings.forceupdate.label"))); |
| 68 | + this.controls.add(this.chkCheckForSnapshots = new GuiCheckbox(2, 34, 158, I18n.format("gui.settings.checkforsnapshots.label"))); | |
| 69 | + | |
| 70 | + this.chkForceUpdate.visible = !this.isSnapshot; | |
| 71 | + this.chkCheckForSnapshots.visible = this.isSnapshot; | |
| 64 | 72 | |
| 65 | 73 | this.updateCheckBoxes(); |
| 66 | 74 | } |
| ... | ... | @@ -72,6 +80,7 @@ class GuiPanelSettings extends GuiPanel |
| 72 | 80 | this.chkShowTab.checked = panelManager.isTabVisible(); |
| 73 | 81 | this.chkNoHide.checked = panelManager.isTabAlwaysExpanded(); |
| 74 | 82 | this.chkForceUpdate.checked = panelManager.isForceUpdateEnabled(); |
| 83 | + this.chkCheckForSnapshots.checked = panelManager.isCheckForSnapshotsEnabled(); | |
| 75 | 84 | } |
| 76 | 85 | |
| 77 | 86 | private void updateSettings() |
| ... | ... | @@ -81,6 +90,7 @@ class GuiPanelSettings extends GuiPanel |
| 81 | 90 | panelManager.setTabVisible(this.chkShowTab.checked); |
| 82 | 91 | panelManager.setTabAlwaysExpanded(this.chkNoHide.checked); |
| 83 | 92 | panelManager.setForceUpdateEnabled(this.chkForceUpdate.checked); |
| 93 | + panelManager.setCheckForSnapshotsEnabled(this.chkCheckForSnapshots.checked); | |
| 84 | 94 | } |
| 85 | 95 | |
| 86 | 96 | @Override | ... | ... |
src/client/java/com/mumfrey/liteloader/client/gui/modlist/ModList.java
| ... | ... | @@ -15,6 +15,7 @@ import org.lwjgl.input.Keyboard; |
| 15 | 15 | import com.mumfrey.liteloader.LiteMod; |
| 16 | 16 | import com.mumfrey.liteloader.api.ModInfoDecorator; |
| 17 | 17 | import com.mumfrey.liteloader.client.gui.GuiLiteLoaderPanel; |
| 18 | +import com.mumfrey.liteloader.core.EnabledModsList.Enabled; | |
| 18 | 19 | import com.mumfrey.liteloader.core.LiteLoaderMods; |
| 19 | 20 | import com.mumfrey.liteloader.core.ModInfo; |
| 20 | 21 | import com.mumfrey.liteloader.interfaces.Loadable; |
| ... | ... | @@ -75,9 +76,12 @@ public class ModList |
| 75 | 76 | // Disabled mods |
| 76 | 77 | for (ModInfo<?> disabledMod : mods.getDisabledMods()) |
| 77 | 78 | { |
| 78 | - ModListEntry modListEntry = new ModListEntry(this, mods, environment, minecraft.fontRendererObj, brandColour, decorators, disabledMod); | |
| 79 | + if (environment.getEnabledModsList().getEnabled(environment.getProfile(), disabledMod.getIdentifier()) != Enabled.FILTERED) | |
| 80 | + { | |
| 81 | + ModListEntry modListEntry = new ModListEntry(this, mods, environment, minecraft.fontRendererObj, brandColour, decorators, disabledMod); | |
| 79 | 82 | sortedMods.put(modListEntry.getKey(), modListEntry); |
| 80 | 83 | } |
| 84 | + } | |
| 81 | 85 | |
| 82 | 86 | // Show bad containers if no other containers are found, should help users realise they have the wrong mod version! |
| 83 | 87 | if (sortedMods.size() == 0) | ... | ... |
src/client/java/com/mumfrey/liteloader/client/mixin/MixinMinecraft.java
| ... | ... | @@ -19,7 +19,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |
| 19 | 19 | import com.mumfrey.liteloader.PlayerInteractionListener.MouseButton; |
| 20 | 20 | import com.mumfrey.liteloader.client.LiteLoaderEventBrokerClient; |
| 21 | 21 | import com.mumfrey.liteloader.client.ducks.IFramebuffer; |
| 22 | +import com.mumfrey.liteloader.client.gui.startup.LoadingBar; | |
| 22 | 23 | import com.mumfrey.liteloader.client.overlays.IMinecraft; |
| 24 | +import com.mumfrey.liteloader.launch.LiteLoaderTweaker; | |
| 23 | 25 | |
| 24 | 26 | import net.minecraft.client.Minecraft; |
| 25 | 27 | import net.minecraft.client.renderer.OpenGlHelper; |
| ... | ... | @@ -35,6 +37,7 @@ public abstract class MixinMinecraft implements IMinecraft |
| 35 | 37 | @Shadow @Final private List<IResourcePack> defaultResourcePacks; |
| 36 | 38 | @Shadow private String serverName; |
| 37 | 39 | @Shadow private int serverPort; |
| 40 | + @Shadow private boolean isGamePaused; | |
| 38 | 41 | |
| 39 | 42 | @Shadow abstract void resize(int width, int height); |
| 40 | 43 | @Shadow private void clickMouse() {} |
| ... | ... | @@ -43,6 +46,25 @@ public abstract class MixinMinecraft implements IMinecraft |
| 43 | 46 | |
| 44 | 47 | private LiteLoaderEventBrokerClient broker; |
| 45 | 48 | |
| 49 | + @Inject(method = "init()V", at = @At(value = "NEW", target = "net/minecraft/client/renderer/EntityRenderer")) | |
| 50 | + private void init(CallbackInfo ci) | |
| 51 | + { | |
| 52 | + LiteLoaderTweaker.init(); | |
| 53 | + LiteLoaderTweaker.postInit(); | |
| 54 | + } | |
| 55 | + | |
| 56 | + @Inject(method = "init()V", at = @At(value = "NEW", target = "net/minecraft/client/renderer/texture/TextureMap")) | |
| 57 | + private void initTextures(CallbackInfo ci) | |
| 58 | + { | |
| 59 | + LoadingBar.initTextures(); | |
| 60 | + } | |
| 61 | + | |
| 62 | + @Inject(method = "init()V", at = @At("INVOKE")) | |
| 63 | + private void progress(CallbackInfo ci) | |
| 64 | + { | |
| 65 | + LoadingBar.incrementProgress(); | |
| 66 | + } | |
| 67 | + | |
| 46 | 68 | @Inject(method = "init()V", at = @At("RETURN")) |
| 47 | 69 | private void onStartupComplete(CallbackInfo ci) |
| 48 | 70 | { |
| ... | ... | @@ -79,7 +101,9 @@ public abstract class MixinMinecraft implements IMinecraft |
| 79 | 101 | )) |
| 80 | 102 | private void onTick(CallbackInfo ci) |
| 81 | 103 | { |
| 82 | - this.broker.onTick(); | |
| 104 | + boolean clock = this.timer.elapsedTicks > 0; | |
| 105 | + float partialTicks = this.timer.renderPartialTicks; | |
| 106 | + this.broker.onTick(clock, partialTicks); | |
| 83 | 107 | } |
| 84 | 108 | |
| 85 | 109 | @Redirect(method = "runGameLoop()V", at = @At( | ... | ... |
src/client/java/com/mumfrey/liteloader/client/transformers/MinecraftTransformer.java deleted
100644 → 0
| 1 | -/* | |
| 2 | - * This file is part of LiteLoader. | |
| 3 | - * Copyright (C) 2012-16 Adam Mummery-Smith | |
| 4 | - * All Rights Reserved. | |
| 5 | - */ | |
| 6 | -package com.mumfrey.liteloader.client.transformers; | |
| 7 | - | |
| 8 | -import java.util.Iterator; | |
| 9 | - | |
| 10 | -import org.objectweb.asm.Opcodes; | |
| 11 | -import org.objectweb.asm.tree.AbstractInsnNode; | |
| 12 | -import org.objectweb.asm.tree.ClassNode; | |
| 13 | -import org.objectweb.asm.tree.InsnList; | |
| 14 | -import org.objectweb.asm.tree.LdcInsnNode; | |
| 15 | -import org.objectweb.asm.tree.MethodInsnNode; | |
| 16 | -import org.objectweb.asm.tree.MethodNode; | |
| 17 | -import org.objectweb.asm.tree.TypeInsnNode; | |
| 18 | - | |
| 19 | -import com.mumfrey.liteloader.core.runtime.Obf; | |
| 20 | -import com.mumfrey.liteloader.launch.LiteLoaderTweaker; | |
| 21 | -import com.mumfrey.liteloader.transformers.ClassTransformer; | |
| 22 | -import com.mumfrey.liteloader.util.log.LiteLoaderLogger; | |
| 23 | - | |
| 24 | -public class MinecraftTransformer extends ClassTransformer | |
| 25 | -{ | |
| 26 | - private static final String TWEAKCLASS = LiteLoaderTweaker.class.getName().replace('.', '/'); | |
| 27 | - | |
| 28 | - @Override | |
| 29 | - public byte[] transform(String name, String transformedName, byte[] basicClass) | |
| 30 | - { | |
| 31 | - if ((Obf.Minecraft.name.equals(transformedName) || Obf.Minecraft.obf.equals(transformedName))) | |
| 32 | - { | |
| 33 | - ClassNode classNode = this.readClass(basicClass, true); | |
| 34 | - for (MethodNode method : classNode.methods) | |
| 35 | - { | |
| 36 | - if (Obf.startGame.obf.equals(method.name) || Obf.startGame.srg.equals(method.name) || Obf.startGame.name.equals(method.name)) | |
| 37 | - { | |
| 38 | - this.transformStartGame(method); | |
| 39 | - } | |
| 40 | - } | |
| 41 | - return this.writeClass(classNode); | |
| 42 | - } | |
| 43 | - return basicClass; | |
| 44 | - } | |
| 45 | - | |
| 46 | - | |
| 47 | - private void transformStartGame(MethodNode method) | |
| 48 | - { | |
| 49 | - InsnList insns = new InsnList(); | |
| 50 | - | |
| 51 | - boolean loadingBarEnabled = LiteLoaderTweaker.loadingBarEnabled(); | |
| 52 | - boolean found = false; | |
| 53 | - | |
| 54 | - Iterator<AbstractInsnNode> iter = method.instructions.iterator(); | |
| 55 | - while (iter.hasNext()) | |
| 56 | - { | |
| 57 | - AbstractInsnNode insn = iter.next(); | |
| 58 | - if (loadingBarEnabled && insn instanceof MethodInsnNode) | |
| 59 | - { | |
| 60 | - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.LoadingBar.ref, "incrementProgress", "()V", false)); | |
| 61 | - } | |
| 62 | - | |
| 63 | - insns.add(insn); | |
| 64 | - | |
| 65 | - if (insn instanceof TypeInsnNode && insn.getOpcode() == Opcodes.NEW && insns.getLast() != null) | |
| 66 | - { | |
| 67 | - TypeInsnNode typeNode = (TypeInsnNode)insn; | |
| 68 | - if (!found && (Obf.EntityRenderer.obf.equals(typeNode.desc) || Obf.EntityRenderer.ref.equals(typeNode.desc))) | |
| 69 | - { | |
| 70 | - LiteLoaderLogger.info("MinecraftTransformer found INIT injection point, this is good."); | |
| 71 | - found = true; | |
| 72 | - | |
| 73 | - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftTransformer.TWEAKCLASS, Obf.init.name, "()V", false)); | |
| 74 | - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, MinecraftTransformer.TWEAKCLASS, Obf.postInit.name, "()V", false)); | |
| 75 | - } | |
| 76 | - } | |
| 77 | - | |
| 78 | - if (loadingBarEnabled && insn instanceof LdcInsnNode) | |
| 79 | - { | |
| 80 | - LdcInsnNode ldcInsn = (LdcInsnNode)insn; | |
| 81 | - if ("textures/blocks".equals(ldcInsn.cst)) | |
| 82 | - { | |
| 83 | - insns.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Obf.LoadingBar.ref, "initTextures", "()V", false)); | |
| 84 | - } | |
| 85 | - } | |
| 86 | - } | |
| 87 | - | |
| 88 | - method.instructions = insns; | |
| 89 | - | |
| 90 | - if (!found) LiteLoaderLogger.severe("MinecraftTransformer failed to find INIT injection point, the game will probably crash pretty soon."); | |
| 91 | - } | |
| 92 | -} |
src/client/java/com/mumfrey/liteloader/modconfig/AbstractConfigPanel.java
| ... | ... | @@ -7,15 +7,21 @@ package com.mumfrey.liteloader.modconfig; |
| 7 | 7 | |
| 8 | 8 | import java.util.ArrayList; |
| 9 | 9 | import java.util.List; |
| 10 | +import java.util.regex.Pattern; | |
| 10 | 11 | |
| 11 | 12 | import org.lwjgl.input.Keyboard; |
| 12 | 13 | |
| 14 | +import com.mumfrey.liteloader.client.gui.GuiLiteLoaderPanel; | |
| 13 | 15 | import com.mumfrey.liteloader.client.mixin.IGuiButton; |
| 14 | 16 | |
| 15 | 17 | import net.minecraft.client.Minecraft; |
| 18 | +import net.minecraft.client.gui.FontRenderer; | |
| 16 | 19 | import net.minecraft.client.gui.GuiButton; |
| 17 | 20 | import net.minecraft.client.gui.GuiLabel; |
| 18 | 21 | import net.minecraft.client.gui.GuiScreen; |
| 22 | +import net.minecraft.client.gui.GuiTextField; | |
| 23 | +import net.minecraft.client.renderer.RenderHelper; | |
| 24 | +import net.minecraft.client.resources.I18n; | |
| 19 | 25 | |
| 20 | 26 | /** |
| 21 | 27 | * A general-purpose base class for mod config panels which implements a lot of |
| ... | ... | @@ -42,74 +48,361 @@ public abstract class AbstractConfigPanel implements ConfigPanel |
| 42 | 48 | } |
| 43 | 49 | |
| 44 | 50 | /** |
| 45 | - * Struct which keeps a control together with its callback object | |
| 51 | + * A handle to an option text field, used to get and retrieve text and set | |
| 52 | + * the max length. It is possible to obtain the native text field as well, | |
| 53 | + * however caution should be used when doing so to avoid breaking the | |
| 54 | + * contract of the text field wrapper used in the config panel itself. | |
| 55 | + */ | |
| 56 | + public interface ConfigTextField | |
| 57 | + { | |
| 58 | + /** | |
| 59 | + * Get the inner text field | |
| 60 | + */ | |
| 61 | + public abstract GuiTextField getNativeTextField(); | |
| 62 | + | |
| 63 | + /** | |
| 64 | + * Get the text field's text | |
| 65 | + */ | |
| 66 | + public abstract String getText(); | |
| 67 | + | |
| 68 | + /** | |
| 69 | + * Set the text field's text | |
| 70 | + * | |
| 71 | + * @param text text to set | |
| 72 | + * @return fluent interface | |
| 73 | + */ | |
| 74 | + public abstract ConfigTextField setText(String text); | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * Set a validation regex for this text box. | |
| 78 | + * | |
| 79 | + * @param regex Validation regex to use for this text field | |
| 80 | + * @param force If set to <tt>false</tt>, invalid values will only cause | |
| 81 | + * the text field to display an error when invalid text is present. | |
| 82 | + * If set to <tt>true</tt>, invalid values will be forcibly | |
| 83 | + * prohibited from being entered. | |
| 84 | + * @return fluent interfaces | |
| 85 | + */ | |
| 86 | + public abstract ConfigTextField setRegex(String regex, boolean force); | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * If the validation regex is not set, always returns true. Otherwise | |
| 90 | + * returns true if the current text value matches the validation regex. | |
| 91 | + * | |
| 92 | + * @return validation state of the current text value | |
| 93 | + */ | |
| 94 | + public abstract boolean isValid(); | |
| 95 | + | |
| 96 | + /** | |
| 97 | + * Set the max allowed string length, defaults to 32 | |
| 46 | 98 | * |
| 47 | - * @param <T> control type | |
| 99 | + * @param maxLength max string length to use | |
| 100 | + * @return fluent interface | |
| 101 | + */ | |
| 102 | + public abstract ConfigTextField setMaxLength(int maxLength); | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * Base for config option handle structs | |
| 48 | 107 | */ |
| 49 | - class ConfigOption<T extends GuiButton> | |
| 108 | + static abstract class ConfigOption | |
| 50 | 109 | { |
| 51 | - final GuiLabel label; | |
| 52 | - final T control; | |
| 53 | - final ConfigOptionListener<T> listener; | |
| 110 | + void onTick() | |
| 111 | + { | |
| 112 | + } | |
| 113 | + | |
| 114 | + abstract void draw(Minecraft minecraft, int mouseX, int mouseY, float partialTicks); | |
| 115 | + | |
| 116 | + void mouseReleased(Minecraft minecraft, int mouseX, int mouseY) | |
| 117 | + { | |
| 118 | + } | |
| 119 | + | |
| 120 | + boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY) | |
| 121 | + { | |
| 122 | + return false; | |
| 123 | + } | |
| 54 | 124 | |
| 55 | - ConfigOption(GuiLabel label) | |
| 125 | + boolean keyPressed(Minecraft minecraft, char keyChar, int keyCode) | |
| 126 | + { | |
| 127 | + return false; | |
| 128 | + } | |
| 129 | + } | |
| 130 | + | |
| 131 | + /** | |
| 132 | + * Struct for labels | |
| 133 | + */ | |
| 134 | + static class ConfigOptionLabel extends ConfigOption | |
| 135 | + { | |
| 136 | + private final GuiLabel label; | |
| 137 | + | |
| 138 | + ConfigOptionLabel(GuiLabel label) | |
| 56 | 139 | { |
| 57 | 140 | this.label = label; |
| 58 | - this.control = null; | |
| 59 | - this.listener = null; | |
| 60 | 141 | } |
| 61 | 142 | |
| 62 | - ConfigOption(T control, ConfigOptionListener<T> listener) | |
| 143 | + @Override | |
| 144 | + void draw(Minecraft minecraft, int mouseX, int mouseY, float partialTicks) | |
| 145 | + { | |
| 146 | + this.label.drawLabel(minecraft, mouseX, mouseY); | |
| 147 | + } | |
| 148 | + } | |
| 149 | + | |
| 150 | + /** | |
| 151 | + * Struct which keeps a control together with its callback object | |
| 152 | + * | |
| 153 | + * @param <T> control type | |
| 154 | + */ | |
| 155 | + static class ConfigOptionButton<T extends GuiButton> extends ConfigOption | |
| 156 | + { | |
| 157 | + private final T control; | |
| 158 | + private final ConfigOptionListener<T> listener; | |
| 159 | + | |
| 160 | + ConfigOptionButton(T control, ConfigOptionListener<T> listener) | |
| 63 | 161 | { |
| 64 | - this.label = null; | |
| 65 | 162 | this.control = control; |
| 66 | 163 | this.listener = listener; |
| 67 | 164 | } |
| 68 | 165 | |
| 166 | + @Override | |
| 69 | 167 | void draw(Minecraft minecraft, int mouseX, int mouseY, float partialTicks) |
| 70 | 168 | { |
| 71 | - if (this.label != null) | |
| 169 | + this.control.drawButton(minecraft, mouseX, mouseY); | |
| 170 | + } | |
| 171 | + | |
| 172 | + @Override | |
| 173 | + boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY) | |
| 174 | + { | |
| 175 | + if (this.control.mousePressed(minecraft, mouseX, mouseY)) | |
| 176 | + { | |
| 177 | + this.control.playPressSound(minecraft.getSoundHandler()); | |
| 178 | + if (this.listener != null) | |
| 179 | + { | |
| 180 | + this.listener.actionPerformed(this.control); | |
| 181 | + } | |
| 182 | + return true; | |
| 183 | + } | |
| 184 | + | |
| 185 | + return false; | |
| 186 | + } | |
| 187 | + | |
| 188 | + @Override | |
| 189 | + void mouseReleased(Minecraft minecraft, int mouseX, int mouseY) | |
| 190 | + { | |
| 191 | + this.control.mouseReleased(mouseX, mouseY); | |
| 192 | + } | |
| 193 | + } | |
| 194 | + | |
| 195 | + /** | |
| 196 | + * Struct for text fields | |
| 197 | + */ | |
| 198 | + class ConfigOptionTextField extends ConfigOption implements ConfigTextField | |
| 199 | + { | |
| 200 | + /** | |
| 201 | + * List for accessing via tab order | |
| 202 | + */ | |
| 203 | + private final List<GuiConfigTextField> tabOrder; | |
| 204 | + | |
| 205 | + /** | |
| 206 | + * Tab index | |
| 207 | + */ | |
| 208 | + private final int tabIndex; | |
| 209 | + | |
| 210 | + /** | |
| 211 | + * Inner text field | |
| 212 | + */ | |
| 213 | + private final GuiConfigTextField textField; | |
| 214 | + | |
| 215 | + ConfigOptionTextField(List<GuiConfigTextField> tabOrder, GuiConfigTextField textField) | |
| 216 | + { | |
| 217 | + this.tabOrder = tabOrder; | |
| 218 | + this.tabIndex = tabOrder.indexOf(textField); | |
| 219 | + this.textField = textField; | |
| 220 | + | |
| 221 | + if (this.tabIndex == 0) | |
| 72 | 222 | { |
| 73 | - this.label.drawLabel(minecraft, mouseX, mouseY); | |
| 223 | + textField.setFocused(true); | |
| 224 | + } | |
| 74 | 225 | } |
| 75 | 226 | |
| 76 | - if (this.control != null) | |
| 227 | + @Override | |
| 228 | + void onTick() | |
| 77 | 229 | { |
| 78 | - this.control.drawButton(minecraft, mouseX, mouseY); | |
| 230 | + this.textField.updateCursorCounter(); | |
| 79 | 231 | } |
| 232 | + | |
| 233 | + @Override | |
| 234 | + void draw(Minecraft minecraft, int mouseX, int mouseY, float partialTicks) | |
| 235 | + { | |
| 236 | + this.textField.drawTextBox(mouseX, mouseY); | |
| 80 | 237 | } |
| 81 | 238 | |
| 239 | + @Override | |
| 82 | 240 | boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY) |
| 83 | 241 | { |
| 84 | - if (this.control != null && this.control.mousePressed(minecraft, mouseX, mouseY)) | |
| 242 | + this.textField.mouseClicked(mouseX, mouseY, 0); | |
| 243 | + if (this.textField.isFocused()) | |
| 85 | 244 | { |
| 86 | - this.control.playPressSound(minecraft.getSoundHandler()); | |
| 87 | - if (this.listener != null) | |
| 245 | + // Unfocus all other text fields | |
| 246 | + for (GuiTextField textField : this.tabOrder) | |
| 88 | 247 | { |
| 89 | - this.listener.actionPerformed(this.control); | |
| 248 | + if (textField != this.textField) | |
| 249 | + { | |
| 250 | + textField.setFocused(false); | |
| 251 | + } | |
| 90 | 252 | } |
| 253 | + } | |
| 254 | + | |
| 255 | + return false; | |
| 256 | + } | |
| 257 | + | |
| 258 | + @Override | |
| 259 | + boolean keyPressed(Minecraft minecraft, char keyChar, int keyCode) | |
| 260 | + { | |
| 261 | + if (!this.textField.isFocused()) | |
| 262 | + { | |
| 263 | + return false; | |
| 264 | + } | |
| 265 | + | |
| 266 | + if (keyCode == Keyboard.KEY_TAB) | |
| 267 | + { | |
| 268 | + this.textField.setFocused(false); | |
| 269 | + int tabOrderSize = this.tabOrder.size(); | |
| 270 | + this.tabOrder.get((this.tabIndex + (GuiScreen.isShiftKeyDown() ? -1 : 1) + tabOrderSize) % tabOrderSize).setFocused(true); | |
| 91 | 271 | return true; |
| 92 | 272 | } |
| 93 | 273 | |
| 274 | + return this.textField.textboxKeyTyped(keyChar, keyCode); | |
| 275 | + } | |
| 276 | + | |
| 277 | + @Override | |
| 278 | + public GuiTextField getNativeTextField() | |
| 279 | + { | |
| 280 | + return this.textField; | |
| 281 | + } | |
| 282 | + | |
| 283 | + @Override | |
| 284 | + public String getText() | |
| 285 | + { | |
| 286 | + return this.textField.getText(); | |
| 287 | + } | |
| 288 | + | |
| 289 | + @Override | |
| 290 | + public ConfigTextField setText(String text) | |
| 291 | + { | |
| 292 | + this.textField.setText(text); | |
| 293 | + return this; | |
| 294 | + } | |
| 295 | + | |
| 296 | + @Override | |
| 297 | + public ConfigTextField setMaxLength(int maxLength) | |
| 298 | + { | |
| 299 | + this.textField.setMaxStringLength(maxLength); | |
| 300 | + return this; | |
| 301 | + } | |
| 302 | + | |
| 303 | + @Override | |
| 304 | + public ConfigTextField setRegex(String regex, boolean force) | |
| 305 | + { | |
| 306 | + this.textField.setRegex(Pattern.compile(regex), force);; | |
| 307 | + return this; | |
| 308 | + } | |
| 309 | + | |
| 310 | + @Override | |
| 311 | + public boolean isValid() | |
| 312 | + { | |
| 313 | + return this.textField.isValid(); | |
| 314 | + } | |
| 315 | + } | |
| 316 | + | |
| 317 | + /** | |
| 318 | + * Custom text field which supports "soft" validation by regex (draws red | |
| 319 | + * border and error message when invalid) | |
| 320 | + */ | |
| 321 | + class GuiConfigTextField extends GuiTextField | |
| 322 | + { | |
| 323 | + private final FontRenderer fontRenderer; | |
| 324 | + private final int width, height; | |
| 325 | + private Pattern regex; | |
| 326 | + private boolean valid, drawing; | |
| 327 | + | |
| 328 | + GuiConfigTextField(int id, FontRenderer fontRenderer, int x, int y, int width, int height) | |
| 329 | + { | |
| 330 | + super(id, fontRenderer, x, y, width, height); | |
| 331 | + this.fontRenderer = fontRenderer; | |
| 332 | + this.width = width; | |
| 333 | + this.height = height; | |
| 334 | + this.setRegex(null, false); | |
| 335 | + } | |
| 336 | + | |
| 337 | + void setRegex(Pattern regex, boolean restrict) | |
| 338 | + { | |
| 339 | + if (restrict && regex != null) | |
| 340 | + { | |
| 341 | + this.setValidator((text) -> regex.matcher(text).matches()); | |
| 342 | + this.regex = null; | |
| 343 | + } | |
| 344 | + else | |
| 345 | + { | |
| 346 | + this.setValidator((text) -> { | |
| 347 | + this.validate(text); | |
| 348 | + return true; | |
| 349 | + }); | |
| 350 | + this.regex = regex; | |
| 351 | + this.validate(this.getText()); | |
| 352 | + } | |
| 353 | + } | |
| 354 | + | |
| 355 | + private boolean validate(String text) | |
| 356 | + { | |
| 357 | + this.valid = (this.regex == null || this.regex.matcher(text).matches()); | |
| 358 | + return true; | |
| 359 | + } | |
| 360 | + | |
| 361 | + boolean isValid() | |
| 362 | + { | |
| 363 | + return this.valid; | |
| 364 | + } | |
| 365 | + | |
| 366 | + @Override | |
| 367 | + public boolean getEnableBackgroundDrawing() | |
| 368 | + { | |
| 369 | + boolean bg = super.getEnableBackgroundDrawing(); | |
| 370 | + if (bg && this.drawing && !this.isValid()) | |
| 371 | + { | |
| 372 | + drawRect(this.xPosition - 1, this.yPosition - 1, this.xPosition + this.width + 1, this.yPosition + this.height + 1, 0xFFFF5555); | |
| 373 | + drawRect(this.xPosition, this.yPosition, this.xPosition + this.width, this.yPosition + this.height, 0xFF000000); | |
| 94 | 374 | return false; |
| 95 | 375 | } |
| 96 | 376 | |
| 97 | - void mouseReleased(Minecraft mc, int mouseX, int mouseY) | |
| 377 | + return bg; | |
| 378 | + } | |
| 379 | + | |
| 380 | + public void drawTextBox(int mouseX, int mouseY) | |
| 98 | 381 | { |
| 99 | - if (this.control != null) | |
| 382 | + this.drawing = true; | |
| 383 | + super.drawTextBox(); | |
| 384 | + if (!this.isValid()) | |
| 385 | + { | |
| 386 | + drawRect(this.xPosition + this.width - 10, this.yPosition, this.xPosition + this.width, this.yPosition + this.height, 0x66000000); | |
| 387 | + this.fontRenderer.drawString("\247l!", this.xPosition + this.width - 6, this.yPosition + (this.height / 2) - 4, 0xFFFF5555); | |
| 388 | + if (mouseX >= this.xPosition && mouseX < this.xPosition + this.width && mouseY >= this.yPosition && mouseY < this.yPosition + this.height) | |
| 100 | 389 | { |
| 101 | - this.control.mouseReleased(mouseX, mouseY); | |
| 390 | + AbstractConfigPanel.this.drawHoveringText(I18n.format("gui.invalidvalue"), mouseX, mouseY); | |
| 391 | + } | |
| 102 | 392 | } |
| 393 | + this.drawing = false; | |
| 103 | 394 | } |
| 104 | 395 | } |
| 105 | 396 | |
| 106 | 397 | protected final Minecraft mc; |
| 107 | 398 | |
| 108 | - private final List<ConfigOption<?>> options = new ArrayList<ConfigOption<?>>(); | |
| 399 | + private final List<ConfigOption> options = new ArrayList<ConfigOption>(); | |
| 400 | + | |
| 401 | + private final List<GuiConfigTextField> textFields = new ArrayList<GuiConfigTextField>(); | |
| 109 | 402 | |
| 110 | 403 | private int contentHeight = 0; |
| 111 | 404 | |
| 112 | - private ConfigOption<?> selected; | |
| 405 | + private ConfigOption selected; | |
| 113 | 406 | |
| 114 | 407 | public AbstractConfigPanel() |
| 115 | 408 | { |
| ... | ... | @@ -170,7 +463,7 @@ public abstract class AbstractConfigPanel implements ConfigPanel |
| 170 | 463 | label.addLine(line); |
| 171 | 464 | } |
| 172 | 465 | this.contentHeight = Math.max(y + height, this.contentHeight); |
| 173 | - this.options.add(new ConfigOption<GuiButton>(label)); | |
| 466 | + this.options.add(new ConfigOptionLabel(label)); | |
| 174 | 467 | } |
| 175 | 468 | |
| 176 | 469 | /** |
| ... | ... | @@ -185,12 +478,33 @@ public abstract class AbstractConfigPanel implements ConfigPanel |
| 185 | 478 | if (control != null) |
| 186 | 479 | { |
| 187 | 480 | this.contentHeight = Math.max(control.yPosition + ((IGuiButton)control).getButtonHeight(), this.contentHeight); |
| 188 | - this.options.add(new ConfigOption<T>(control, listener)); | |
| 481 | + this.options.add(new ConfigOptionButton<T>(control, listener)); | |
| 189 | 482 | } |
| 190 | 483 | |
| 191 | 484 | return control; |
| 192 | 485 | } |
| 193 | 486 | |
| 487 | + /** | |
| 488 | + * Add a text field to the panel, returns a handle through which the created | |
| 489 | + * text field can be accessed | |
| 490 | + * | |
| 491 | + * @param id control id | |
| 492 | + * @param x text field x position | |
| 493 | + * @param y text field y position | |
| 494 | + * @param width text field width | |
| 495 | + * @param height text field height | |
| 496 | + * @return text field handle | |
| 497 | + */ | |
| 498 | + protected ConfigTextField addTextField(int id, int x, int y, int width, int height) | |
| 499 | + { | |
| 500 | + GuiConfigTextField textField = new GuiConfigTextField(id, this.mc.fontRendererObj, x + 2, y, width, height); | |
| 501 | + this.textFields.add(textField); | |
| 502 | + | |
| 503 | + ConfigOptionTextField configOption = new ConfigOptionTextField(this.textFields, textField); | |
| 504 | + this.options.add(configOption); | |
| 505 | + return configOption; | |
| 506 | + } | |
| 507 | + | |
| 194 | 508 | @Override |
| 195 | 509 | public void onPanelResize(ConfigPanelHost host) |
| 196 | 510 | { |
| ... | ... | @@ -199,12 +513,16 @@ public abstract class AbstractConfigPanel implements ConfigPanel |
| 199 | 513 | @Override |
| 200 | 514 | public void onTick(ConfigPanelHost host) |
| 201 | 515 | { |
| 516 | + for (ConfigOption configOption : this.options) | |
| 517 | + { | |
| 518 | + configOption.onTick(); | |
| 519 | + } | |
| 202 | 520 | } |
| 203 | 521 | |
| 204 | 522 | @Override |
| 205 | 523 | public void drawPanel(ConfigPanelHost host, int mouseX, int mouseY, float partialTicks) |
| 206 | 524 | { |
| 207 | - for (ConfigOption<?> configOption : this.options) | |
| 525 | + for (ConfigOption configOption : this.options) | |
| 208 | 526 | { |
| 209 | 527 | configOption.draw(this.mc, mouseX, mouseY, partialTicks); |
| 210 | 528 | } |
| ... | ... | @@ -219,7 +537,7 @@ public abstract class AbstractConfigPanel implements ConfigPanel |
| 219 | 537 | return; |
| 220 | 538 | } |
| 221 | 539 | |
| 222 | - for (ConfigOption<?> configOption : this.options) | |
| 540 | + for (ConfigOption configOption : this.options) | |
| 223 | 541 | { |
| 224 | 542 | if (configOption.mousePressed(this.mc, mouseX, mouseY)) |
| 225 | 543 | { |
| ... | ... | @@ -251,5 +569,22 @@ public abstract class AbstractConfigPanel implements ConfigPanel |
| 251 | 569 | host.close(); |
| 252 | 570 | return; |
| 253 | 571 | } |
| 572 | + | |
| 573 | + for (ConfigOption configOption : this.options) | |
| 574 | + { | |
| 575 | + if (configOption.keyPressed(this.mc, keyChar, keyCode)) | |
| 576 | + { | |
| 577 | + break; | |
| 578 | + } | |
| 579 | + } | |
| 580 | + } | |
| 581 | + | |
| 582 | + protected final void drawHoveringText(String text, int x, int y) | |
| 583 | + { | |
| 584 | + if (this.mc.currentScreen != null) | |
| 585 | + { | |
| 586 | + GuiLiteLoaderPanel.drawTooltip(this.mc.fontRendererObj, text, x, y, Integer.MAX_VALUE, Integer.MAX_VALUE, 0xFFFF5555, 0xB0000000); | |
| 587 | + RenderHelper.disableStandardItemLighting(); | |
| 588 | + } | |
| 254 | 589 | } |
| 255 | 590 | } | ... | ... |
src/client/resources/mixins.liteloader.client.json
src/main/java/com/mumfrey/liteloader/core/EnabledModsList.java
| ... | ... | @@ -24,6 +24,34 @@ import com.google.gson.GsonBuilder; |
| 24 | 24 | */ |
| 25 | 25 | public final class EnabledModsList |
| 26 | 26 | { |
| 27 | + /** | |
| 28 | + * Tristate for enablement which allows us to determine whether mod is | |
| 29 | + * forcibly disabled by user or passively disabled by mod name filter | |
| 30 | + */ | |
| 31 | + public enum Enabled | |
| 32 | + { | |
| 33 | + ENABLED(true), | |
| 34 | + DISABLED(false), | |
| 35 | + FILTERED(false); | |
| 36 | + | |
| 37 | + private final boolean value; | |
| 38 | + | |
| 39 | + private Enabled(boolean value) | |
| 40 | + { | |
| 41 | + this.value = value; | |
| 42 | + } | |
| 43 | + | |
| 44 | + public boolean booleanValue() | |
| 45 | + { | |
| 46 | + return this.value; | |
| 47 | + } | |
| 48 | + | |
| 49 | + public static Enabled of(Boolean value) | |
| 50 | + { | |
| 51 | + return value == null ? Enabled.FILTERED : (value ? Enabled.ENABLED : Enabled.DISABLED); | |
| 52 | + } | |
| 53 | + } | |
| 54 | + | |
| 27 | 55 | @SuppressWarnings("unused") |
| 28 | 56 | private static final transient long serialVersionUID = -6449451105617763769L; |
| 29 | 57 | |
| ... | ... | @@ -45,7 +73,7 @@ public final class EnabledModsList |
| 45 | 73 | * the mods list because the command line is supposed to be an override |
| 46 | 74 | * rather than a new mask. These two values provide this behaviour. |
| 47 | 75 | */ |
| 48 | - private transient Boolean defaultEnabledValue = Boolean.TRUE; | |
| 76 | + private transient Enabled defaultEnabledValue = Enabled.ENABLED; | |
| 49 | 77 | private transient boolean allowSave = true; |
| 50 | 78 | |
| 51 | 79 | /** |
| ... | ... | @@ -59,22 +87,27 @@ public final class EnabledModsList |
| 59 | 87 | } |
| 60 | 88 | |
| 61 | 89 | /** |
| 62 | - * Check whether a particular mod is enabled | |
| 90 | + * Check whether a particular container is enabled | |
| 63 | 91 | * |
| 64 | 92 | * @param profileName |
| 65 | 93 | * @param identifier |
| 66 | 94 | */ |
| 67 | 95 | public boolean isEnabled(String profileName, String identifier) |
| 68 | 96 | { |
| 97 | + return this.getEnabled(profileName, identifier).booleanValue(); | |
| 98 | + } | |
| 99 | + | |
| 100 | + public Enabled getEnabled(String profileName, String identifier) | |
| 101 | + { | |
| 69 | 102 | Map<String, Boolean> profile = this.getProfile(profileName); |
| 70 | 103 | identifier = identifier.toLowerCase().trim(); |
| 71 | 104 | |
| 72 | - if (!profile.containsKey(identifier)) | |
| 105 | + if (!profile.containsKey(identifier) && this.defaultEnabledValue != Enabled.FILTERED) | |
| 73 | 106 | { |
| 74 | - profile.put(identifier, this.defaultEnabledValue); | |
| 107 | + profile.put(identifier, this.defaultEnabledValue.booleanValue()); | |
| 75 | 108 | } |
| 76 | 109 | |
| 77 | - return profile.get(identifier); | |
| 110 | + return Enabled.of(profile.get(identifier)); | |
| 78 | 111 | } |
| 79 | 112 | |
| 80 | 113 | /** |
| ... | ... | @@ -87,7 +120,7 @@ public final class EnabledModsList |
| 87 | 120 | public void setEnabled(String profileName, String identifier, boolean enabled) |
| 88 | 121 | { |
| 89 | 122 | Map<String, Boolean> profile = this.getProfile(profileName); |
| 90 | - profile.put(identifier.toLowerCase().trim(), Boolean.valueOf(enabled)); | |
| 123 | + profile.put(identifier.toLowerCase().trim(), enabled ? Boolean.TRUE : Boolean.FALSE); | |
| 91 | 124 | |
| 92 | 125 | this.allowSave = true; |
| 93 | 126 | } |
| ... | ... | @@ -106,12 +139,9 @@ public final class EnabledModsList |
| 106 | 139 | { |
| 107 | 140 | if (modNameFilter != null) |
| 108 | 141 | { |
| 109 | - for (String modName : profile.keySet()) | |
| 110 | - { | |
| 111 | - profile.put(modName, Boolean.FALSE); | |
| 112 | - } | |
| 142 | + profile.clear(); | |
| 113 | 143 | |
| 114 | - this.defaultEnabledValue = Boolean.FALSE; | |
| 144 | + this.defaultEnabledValue = Enabled.FILTERED; | |
| 115 | 145 | this.allowSave = false; |
| 116 | 146 | |
| 117 | 147 | for (String filterEntry : modNameFilter) |
| ... | ... | @@ -122,8 +152,8 @@ public final class EnabledModsList |
| 122 | 152 | } |
| 123 | 153 | catch (Exception ex) |
| 124 | 154 | { |
| 125 | - this.defaultEnabledValue = Boolean.TRUE; | |
| 126 | - this.allowSave = true; | |
| 155 | + this.defaultEnabledValue = Enabled.ENABLED; | |
| 156 | +// this.allowSave = true; | |
| 127 | 157 | } |
| 128 | 158 | } |
| 129 | 159 | |
| ... | ... | @@ -135,7 +165,7 @@ public final class EnabledModsList |
| 135 | 165 | private Map<String, Boolean> getProfile(String profileName) |
| 136 | 166 | { |
| 137 | 167 | if (profileName == null) profileName = "default"; |
| 138 | - if (this.mods == null) this.mods = new TreeMap<String, TreeMap<String,Boolean>>(); | |
| 168 | + if (this.mods == null) this.mods = new TreeMap<String, TreeMap<String, Boolean>>(); | |
| 139 | 169 | |
| 140 | 170 | if (!this.mods.containsKey(profileName)) |
| 141 | 171 | { | ... | ... |
src/main/java/com/mumfrey/liteloader/core/LiteLoader.java
| ... | ... | @@ -532,6 +532,15 @@ public final class LiteLoader |
| 532 | 532 | { |
| 533 | 533 | return "true".equals(System.getProperty("mcpenv")); |
| 534 | 534 | } |
| 535 | + | |
| 536 | + /** | |
| 537 | + * Get whether the current running version is a snapshot build | |
| 538 | + */ | |
| 539 | + public static boolean isSnapshot() | |
| 540 | + { | |
| 541 | + String branding = LiteLoader.getBranding(); | |
| 542 | + return branding != null && branding.contains("SNAPSHOT"); | |
| 543 | + } | |
| 535 | 544 | |
| 536 | 545 | /** |
| 537 | 546 | * Dump debugging information to the console | ... | ... |
src/main/java/com/mumfrey/liteloader/core/LiteLoaderUpdateSite.java
| ... | ... | @@ -8,6 +8,10 @@ package com.mumfrey.liteloader.core; |
| 8 | 8 | import java.io.File; |
| 9 | 9 | import java.io.IOException; |
| 10 | 10 | import java.io.InputStream; |
| 11 | +import java.util.Date; | |
| 12 | +import java.util.Map; | |
| 13 | +import java.util.regex.Matcher; | |
| 14 | +import java.util.regex.Pattern; | |
| 11 | 15 | |
| 12 | 16 | import com.google.common.io.ByteSink; |
| 13 | 17 | import com.google.common.io.Files; |
| ... | ... | @@ -21,6 +25,8 @@ public class LiteLoaderUpdateSite extends UpdateSite |
| 21 | 25 | private static final String UPDATE_SITE_URL = "http://dl.liteloader.com/versions/"; |
| 22 | 26 | private static final String UPDATE_SITE_VERSIONS_JSON = "versions.json"; |
| 23 | 27 | private static final String UPDATE_SITE_ARTEFACT_NAME = "com.mumfrey:liteloader"; |
| 28 | + | |
| 29 | + private static final Pattern SNAPSHOT_REGEX = Pattern.compile("^([0-9\\._]+)-SNAPSHOT-(r[0-9a-z]+)-(b([0-9]+))-(.*)$", Pattern.CASE_INSENSITIVE); | |
| 24 | 30 | |
| 25 | 31 | private String mcVersion; |
| 26 | 32 | |
| ... | ... | @@ -28,6 +34,10 @@ public class LiteLoaderUpdateSite extends UpdateSite |
| 28 | 34 | private File jarFile = null; |
| 29 | 35 | |
| 30 | 36 | private boolean updateForced = false; |
| 37 | + private boolean isSnapshot = false; | |
| 38 | + | |
| 39 | + private int currentBuild, availableBuild; | |
| 40 | + private String snapshotDate = null; | |
| 31 | 41 | |
| 32 | 42 | public LiteLoaderUpdateSite(String targetVersion, long currentTimeStamp) |
| 33 | 43 | { |
| ... | ... | @@ -36,6 +46,64 @@ public class LiteLoaderUpdateSite extends UpdateSite |
| 36 | 46 | |
| 37 | 47 | this.mcVersion = targetVersion; |
| 38 | 48 | } |
| 49 | + | |
| 50 | + @Override | |
| 51 | + public void beginUpdateCheck() | |
| 52 | + { | |
| 53 | + this.isSnapshot = LiteLoader.isSnapshot(); | |
| 54 | + super.beginUpdateCheck(); | |
| 55 | + } | |
| 56 | + | |
| 57 | + @Override | |
| 58 | + public boolean isSnapshot() | |
| 59 | + { | |
| 60 | + return this.isSnapshot; | |
| 61 | + } | |
| 62 | + | |
| 63 | + @Override | |
| 64 | + public String getAvailableVersion() | |
| 65 | + { | |
| 66 | + if (this.isSnapshot() && this.availableBuild > 0) | |
| 67 | + { | |
| 68 | + return String.valueOf(this.availableBuild); | |
| 69 | + } | |
| 70 | + | |
| 71 | + return super.getAvailableVersion(); | |
| 72 | + } | |
| 73 | + | |
| 74 | + @Override | |
| 75 | + public String getAvailableVersionDate() | |
| 76 | + { | |
| 77 | + if (this.snapshotDate != null) | |
| 78 | + { | |
| 79 | + return this.snapshotDate; | |
| 80 | + } | |
| 81 | + | |
| 82 | + return super.getAvailableVersionDate(); | |
| 83 | + } | |
| 84 | + | |
| 85 | + @Override | |
| 86 | + protected boolean compareArtefact(Map<?, ?> artefact, long bestTimeStamp, Long remoteTimeStamp) | |
| 87 | + { | |
| 88 | + if (this.isSnapshot()) | |
| 89 | + { | |
| 90 | + String remoteBuild = artefact.get("build").toString(); | |
| 91 | + String myBuild = LiteLoader.getBranding(); | |
| 92 | + | |
| 93 | + Matcher remoteMatcher = LiteLoaderUpdateSite.SNAPSHOT_REGEX.matcher(remoteBuild); | |
| 94 | + Matcher myMatcher = LiteLoaderUpdateSite.SNAPSHOT_REGEX.matcher(myBuild); | |
| 95 | + | |
| 96 | + if (remoteMatcher.matches() && myMatcher.matches()) | |
| 97 | + { | |
| 98 | + this.currentBuild = Integer.parseInt(myMatcher.group(4)); | |
| 99 | + this.availableBuild = Integer.parseInt(remoteMatcher.group(4)); | |
| 100 | + this.snapshotDate = String.format("%1$tY-%1$tm-%1$td %1$tH:%1$tM", new Date(remoteTimeStamp * 1000L)); | |
| 101 | + return this.availableBuild > this.currentBuild; | |
| 102 | + } | |
| 103 | + } | |
| 104 | + | |
| 105 | + return super.compareArtefact(artefact, bestTimeStamp, remoteTimeStamp); | |
| 106 | + } | |
| 39 | 107 | |
| 40 | 108 | public boolean canForceUpdate(LoaderProperties properties) |
| 41 | 109 | { | ... | ... |
src/main/java/com/mumfrey/liteloader/core/runtime/Obf.java
| ... | ... | @@ -26,14 +26,11 @@ public class Obf |
| 26 | 26 | public static final Obf BakedProfilingHandlerList = new Obf("com.mumfrey.liteloader.core.event.ProfilingHandlerList$BakedList" ); |
| 27 | 27 | public static final Obf PacketEvents = new Obf("com.mumfrey.liteloader.core.PacketEvents" ); |
| 28 | 28 | public static final Obf PacketEventsClient = new Obf("com.mumfrey.liteloader.client.PacketEventsClient" ); |
| 29 | - public static final Obf LoadingBar = new Obf("com.mumfrey.liteloader.client.gui.startup.LoadingBar" ); | |
| 30 | 29 | public static final Obf GameProfile = new Obf("com.mojang.authlib.GameProfile" ); |
| 31 | 30 | public static final Obf MinecraftMain = new Obf("net.minecraft.client.main.Main" ); |
| 32 | 31 | public static final Obf MinecraftServer = new Obf("net.minecraft.server.MinecraftServer" ); |
| 33 | 32 | public static final Obf GL11 = new Obf("org.lwjgl.opengl.GL11" ); |
| 34 | 33 | public static final Obf RealmsMainScreen = new Obf("com.mojang.realmsclient.RealmsMainScreen" ); |
| 35 | - public static final Obf init = new Obf("init" ); | |
| 36 | - public static final Obf postInit = new Obf("postInit" ); | |
| 37 | 34 | public static final Obf constructor = new Obf("<init>" ); |
| 38 | 35 | |
| 39 | 36 | // CHECKSTYLE:OFF | ... | ... |
src/main/java/com/mumfrey/liteloader/core/runtime/Packets.java
| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | */ |
| 6 | 6 | package com.mumfrey.liteloader.core.runtime; |
| 7 | 7 | |
| 8 | +import java.lang.reflect.Field; | |
| 8 | 9 | import java.util.HashMap; |
| 9 | 10 | import java.util.Map; |
| 10 | 11 | |
| ... | ... | @@ -157,125 +158,7 @@ public final class Packets extends Obf |
| 157 | 158 | |
| 158 | 159 | // CHECKSTYLE:ON |
| 159 | 160 | |
| 160 | - public static final Packets[] packets = new Packets[] { | |
| 161 | - CPacketEncryptionResponse, | |
| 162 | - CPacketLoginStart, | |
| 163 | - SPacketDisconnectLogin, | |
| 164 | - SPacketEnableCompression, | |
| 165 | - SPacketEncryptionRequest, | |
| 166 | - SPacketLoginSuccess, | |
| 167 | - CPacketAnimation, | |
| 168 | - CPacketChatMessage, | |
| 169 | - CPacketClickWindow, | |
| 170 | - CPacketClientSettings, | |
| 171 | - CPacketClientStatus, | |
| 172 | - CPacketCloseWindow, | |
| 173 | - CPacketConfirmTeleport, | |
| 174 | - CPacketConfirmTransaction, | |
| 175 | - CPacketCreativeInventoryAction, | |
| 176 | - CPacketCustomPayload, | |
| 177 | - CPacketEnchantItem, | |
| 178 | - CPacketEntityAction, | |
| 179 | - CPacketHeldItemChange, | |
| 180 | - CPacketInput, | |
| 181 | - C00Handshake, | |
| 182 | - CPacketKeepAlive, | |
| 183 | - CPacketPlayer, | |
| 184 | - CPacketPlayerPosition, | |
| 185 | - CPacketPlayerPositionRotation, | |
| 186 | - CPacketPlayerRotation, | |
| 187 | - CPacketPlayerAbilities, | |
| 188 | - CPacketPlayerDigging, | |
| 189 | - CPacketPlayerTryUseItem, | |
| 190 | - CPacketPlayerTryUseItemOnBlock, | |
| 191 | - CPacketResourcePackStatus, | |
| 192 | - CPacketSpectate, | |
| 193 | - CPacketSteerBoat, | |
| 194 | - CPacketTabComplete, | |
| 195 | - CPacketUpdateSign, | |
| 196 | - CPacketUseEntity, | |
| 197 | - CPacketVehicleMove, | |
| 198 | - SPacketAnimation, | |
| 199 | - SPacketBlockAction, | |
| 200 | - SPacketBlockBreakAnim, | |
| 201 | - SPacketBlockChange, | |
| 202 | - SPacketCamera, | |
| 203 | - SPacketChangeGameState, | |
| 204 | - SPacketChat, | |
| 205 | - SPacketChunkData, | |
| 206 | - SPacketCloseWindow, | |
| 207 | - SPacketCollectItem, | |
| 208 | - SPacketCombatEvent, | |
| 209 | - SPacketConfirmTransaction, | |
| 210 | - SPacketCooldown, | |
| 211 | - SPacketCustomPayload, | |
| 212 | - SPacketCustomSound, | |
| 213 | - SPacketDestroyEntities, | |
| 214 | - SPacketDisconnect, | |
| 215 | - SPacketDisplayObjective, | |
| 216 | - SPacketEffect, | |
| 217 | - SPacketEntity, | |
| 218 | - S15PacketEntityRelMove, | |
| 219 | - S16PacketEntityLook, | |
| 220 | - S17PacketEntityLookMove, | |
| 221 | - SPacketEntityAttach, | |
| 222 | - SPacketEntityEffect, | |
| 223 | - SPacketEntityEquipment, | |
| 224 | - SPacketEntityHeadLook, | |
| 225 | - SPacketEntityMetadata, | |
| 226 | - SPacketEntityProperties, | |
| 227 | - SPacketEntityStatus, | |
| 228 | - SPacketEntityTeleport, | |
| 229 | - SPacketEntityVelocity, | |
| 230 | - SPacketExplosion, | |
| 231 | - SPacketHeldItemChange, | |
| 232 | - SPacketJoinGame, | |
| 233 | - SPacketKeepAlive, | |
| 234 | - SPacketMaps, | |
| 235 | - SPacketMoveVehicle, | |
| 236 | - SPacketMultiBlockChange, | |
| 237 | - SPacketOpenWindow, | |
| 238 | - SPacketParticles, | |
| 239 | - SPacketPlayerAbilities, | |
| 240 | - SPacketPlayerListHeaderFooter, | |
| 241 | - SPacketPlayerListItem, | |
| 242 | - SPacketPlayerPosLook, | |
| 243 | - SPacketRemoveEntityEffect, | |
| 244 | - SPacketResourcePackSend, | |
| 245 | - SPacketRespawn, | |
| 246 | - SPacketScoreboardObjective, | |
| 247 | - SPacketServerDifficulty, | |
| 248 | - SPacketSetExperience, | |
| 249 | - SPacketSetPassengers, | |
| 250 | - SPacketSetSlot, | |
| 251 | - SPacketSignEditorOpen, | |
| 252 | - SPacketSoundEffect, | |
| 253 | - SPacketSpawnExperienceOrb, | |
| 254 | - SPacketSpawnGlobalEntity, | |
| 255 | - SPacketSpawnMob, | |
| 256 | - SPacketSpawnObject, | |
| 257 | - SPacketSpawnPainting, | |
| 258 | - SPacketSpawnPlayer, | |
| 259 | - SPacketSpawnPosition, | |
| 260 | - SPacketStatistics, | |
| 261 | - SPacketTabComplete, | |
| 262 | - SPacketTeams, | |
| 263 | - SPacketTimeUpdate, | |
| 264 | - SPacketTitle, | |
| 265 | - SPacketUnloadChunk, | |
| 266 | - SPacketUpdateBossInfo, | |
| 267 | - SPacketUpdateHealth, | |
| 268 | - SPacketUpdateScore, | |
| 269 | - SPacketUpdateTileEntity, | |
| 270 | - SPacketUseBed, | |
| 271 | - SPacketWindowItems, | |
| 272 | - SPacketWindowProperty, | |
| 273 | - SPacketWorldBorder, | |
| 274 | - CPacketPing, | |
| 275 | - CPacketServerQuery, | |
| 276 | - SPacketPong, | |
| 277 | - SPacketServerInfo | |
| 278 | - }; | |
| 161 | + public static final Packets[] packets = Packets.toArray(); | |
| 279 | 162 | |
| 280 | 163 | private static int nextPacketIndex; |
| 281 | 164 | |
| ... | ... | @@ -295,6 +178,24 @@ public final class Packets extends Obf |
| 295 | 178 | this.context = context; |
| 296 | 179 | } |
| 297 | 180 | |
| 181 | + private static Packets[] toArray() | |
| 182 | + { | |
| 183 | + Field[] fields = Packets.class.getFields(); | |
| 184 | + Packets[] packets = new Packets[Packets.nextPacketIndex]; | |
| 185 | + for (int index = 0; index < Packets.nextPacketIndex; index++) | |
| 186 | + { | |
| 187 | + try | |
| 188 | + { | |
| 189 | + packets[index] = (Packets)fields[index].get(null); | |
| 190 | + } | |
| 191 | + catch (Exception ex) | |
| 192 | + { | |
| 193 | + throw new RuntimeException(ex); | |
| 194 | + } | |
| 195 | + } | |
| 196 | + return packets; | |
| 197 | + } | |
| 198 | + | |
| 298 | 199 | public int getIndex() |
| 299 | 200 | { |
| 300 | 201 | return this.index; | ... | ... |
src/main/java/com/mumfrey/liteloader/interfaces/PanelManager.java
| ... | ... | @@ -88,4 +88,14 @@ public interface PanelManager<TParentScreen> extends TickObserver, PostRenderObs |
| 88 | 88 | * Get whether "force update" is enabled |
| 89 | 89 | */ |
| 90 | 90 | public abstract boolean isForceUpdateEnabled(); |
| 91 | + | |
| 92 | + /** | |
| 93 | + * Set whether "check for new snapshots" is enabled | |
| 94 | + */ | |
| 95 | + public abstract void setCheckForSnapshotsEnabled(boolean checkForSnapshots); | |
| 96 | + | |
| 97 | + /** | |
| 98 | + * Get whether "check for new snapshots" is enabled | |
| 99 | + */ | |
| 100 | + public abstract boolean isCheckForSnapshotsEnabled(); | |
| 91 | 101 | } | ... | ... |
src/main/java/com/mumfrey/liteloader/launch/LoaderProperties.java
| ... | ... | @@ -99,6 +99,7 @@ public interface LoaderProperties |
| 99 | 99 | public static final String OPTION_FORCE_UPDATE = "allowForceUpdate"; |
| 100 | 100 | public static final String OPTION_UPDATE_CHECK_INTR = "updateCheckInterval"; |
| 101 | 101 | public static final String OPTION_JINPUT_DISABLE = "disableJInput"; |
| 102 | + public static final String OPTION_CHECK_SNAPSHOTS = "checkForNewSnapshots"; | |
| 102 | 103 | |
| 103 | 104 | // Enumerator properties |
| 104 | 105 | public static final String OPTION_SEARCH_MODS = "search.mods"; | ... | ... |
src/main/java/com/mumfrey/liteloader/modconfig/ConfigManager.java
| ... | ... | @@ -17,6 +17,7 @@ import com.google.common.collect.Maps; |
| 17 | 17 | import com.google.common.io.Files; |
| 18 | 18 | import com.mumfrey.liteloader.Configurable; |
| 19 | 19 | import com.mumfrey.liteloader.LiteMod; |
| 20 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogger; | |
| 20 | 21 | |
| 21 | 22 | /** |
| 22 | 23 | * Registry where we keep the mod config panel classes and config file writers |
| ... | ... | @@ -165,6 +166,10 @@ public class ConfigManager |
| 165 | 166 | } |
| 166 | 167 | catch (InstantiationException ex) {} |
| 167 | 168 | catch (IllegalAccessException ex) {} |
| 169 | + catch (Exception ex) | |
| 170 | + { | |
| 171 | + LiteLoaderLogger.severe("Error creating mod configuration panel <%s> for mod %s", this.configPanels.get(modClass), modClass); | |
| 172 | + } | |
| 168 | 173 | |
| 169 | 174 | // If instantiation fails, remove the panel |
| 170 | 175 | this.configPanels.remove(modClass); | ... | ... |
src/main/java/com/mumfrey/liteloader/permissions/PermissionsManagerClient.java
| ... | ... | @@ -47,37 +47,37 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi |
| 47 | 47 | * Permissions permissible which is a proxy for permissions that are common |
| 48 | 48 | * to all mods. |
| 49 | 49 | */ |
| 50 | - private static Permissible allMods = new PermissibleAllMods(); | |
| 51 | - | |
| 52 | - /** | |
| 53 | - * Minecraft instance | |
| 54 | - */ | |
| 55 | - private GameEngine<?, ?> engine; | |
| 50 | + private final static Permissible allMods = new PermissibleAllMods(); | |
| 56 | 51 | |
| 57 | 52 | /** |
| 58 | 53 | * List of registered client mods supporting permissions |
| 59 | 54 | */ |
| 60 | - private Map<String, Permissible> registeredClientMods = new HashMap<String, Permissible>(); | |
| 55 | + private final Map<String, Permissible> registeredClientMods = new HashMap<String, Permissible>(); | |
| 61 | 56 | |
| 62 | 57 | /** |
| 63 | 58 | * List of registered client permissions, grouped by mod |
| 64 | 59 | */ |
| 65 | - private Map<Permissible, TreeSet<String>> registeredClientPermissions = new HashMap<Permissible, TreeSet<String>>(); | |
| 60 | + private final Map<Permissible, TreeSet<String>> registeredClientPermissions = new HashMap<Permissible, TreeSet<String>>(); | |
| 66 | 61 | |
| 67 | 62 | /** |
| 68 | 63 | * Objects which listen to events generated by this object |
| 69 | 64 | */ |
| 70 | - private Set<Permissible> permissibles = new HashSet<Permissible>(); | |
| 65 | + private final Set<Permissible> permissibles = new HashSet<Permissible>(); | |
| 71 | 66 | |
| 72 | 67 | /** |
| 73 | 68 | * Local permissions, used when server permissions are not available |
| 74 | 69 | */ |
| 75 | - private LocalPermissions localPermissions = new LocalPermissions(); | |
| 70 | + private final LocalPermissions localPermissions = new LocalPermissions(); | |
| 76 | 71 | |
| 77 | 72 | /** |
| 78 | 73 | * Server permissions, indexed by mod |
| 79 | 74 | */ |
| 80 | - private Map<String, ServerPermissions> serverPermissions = new HashMap<String, ServerPermissions>(); | |
| 75 | + private final Map<String, ServerPermissions> serverPermissions = new HashMap<String, ServerPermissions>(); | |
| 76 | + | |
| 77 | + /** | |
| 78 | + * Minecraft instance | |
| 79 | + */ | |
| 80 | + private GameEngine<?, ?> engine; | |
| 81 | 81 | |
| 82 | 82 | /** |
| 83 | 83 | * Last time onTick was called, used to detect tamper condition if no ticks |
| ... | ... | @@ -124,8 +124,11 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi |
| 124 | 124 | if (mod == null) mod = allMods; |
| 125 | 125 | String modName = mod.getPermissibleModName(); |
| 126 | 126 | |
| 127 | - ServerPermissions modPermissions = this.serverPermissions.get(modName); | |
| 128 | - return modPermissions != null ? modPermissions : this.localPermissions; | |
| 127 | + synchronized (this.serverPermissions) | |
| 128 | + { | |
| 129 | + ServerPermissions modPermissions = this.serverPermissions.get(modName); | |
| 130 | + return modPermissions != null ? modPermissions : this.localPermissions; | |
| 131 | + } | |
| 129 | 132 | } |
| 130 | 133 | |
| 131 | 134 | /* (non-Javadoc) |
| ... | ... | @@ -138,8 +141,11 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi |
| 138 | 141 | if (mod == null) mod = allMods; |
| 139 | 142 | String modName = mod.getPermissibleModName(); |
| 140 | 143 | |
| 141 | - ServerPermissions modPermissions = this.serverPermissions.get(modName); | |
| 142 | - return modPermissions != null ? modPermissions.getReplicationTime() : 0; | |
| 144 | + synchronized (this.serverPermissions) | |
| 145 | + { | |
| 146 | + ServerPermissions modPermissions = this.serverPermissions.get(modName); | |
| 147 | + return modPermissions != null ? modPermissions.getReplicationTime() : 0; | |
| 148 | + } | |
| 143 | 149 | } |
| 144 | 150 | |
| 145 | 151 | /** |
| ... | ... | @@ -208,7 +214,10 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi |
| 208 | 214 | */ |
| 209 | 215 | protected void clearServerPermissions() |
| 210 | 216 | { |
| 211 | - this.serverPermissions.clear(); | |
| 217 | + synchronized (this.serverPermissions) | |
| 218 | + { | |
| 219 | + this.serverPermissions.clear(); | |
| 220 | + } | |
| 212 | 221 | |
| 213 | 222 | for (Permissible permissible : this.permissibles) |
| 214 | 223 | { |
| ... | ... | @@ -264,7 +273,10 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi |
| 264 | 273 | } |
| 265 | 274 | else |
| 266 | 275 | { |
| 267 | - this.serverPermissions.remove(modName); | |
| 276 | + synchronized (this.serverPermissions) | |
| 277 | + { | |
| 278 | + this.serverPermissions.remove(modName); | |
| 279 | + } | |
| 268 | 280 | } |
| 269 | 281 | } |
| 270 | 282 | |
| ... | ... | @@ -289,12 +301,15 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi |
| 289 | 301 | } |
| 290 | 302 | } |
| 291 | 303 | |
| 292 | - for (Map.Entry<String, ServerPermissions> modPermissions : this.serverPermissions.entrySet()) | |
| 304 | + synchronized (this.serverPermissions) | |
| 293 | 305 | { |
| 294 | - if (!modPermissions.getValue().isValid()) | |
| 306 | + for (Map.Entry<String, ServerPermissions> modPermissions : this.serverPermissions.entrySet()) | |
| 295 | 307 | { |
| 296 | - modPermissions.getValue().notifyRefreshPending(); | |
| 297 | - this.sendPermissionQuery(this.registeredClientMods.get(modPermissions.getKey())); | |
| 308 | + if (!modPermissions.getValue().isValid()) | |
| 309 | + { | |
| 310 | + modPermissions.getValue().notifyRefreshPending(); | |
| 311 | + this.sendPermissionQuery(this.registeredClientMods.get(modPermissions.getKey())); | |
| 312 | + } | |
| 298 | 313 | } |
| 299 | 314 | } |
| 300 | 315 | |
| ... | ... | @@ -336,7 +351,10 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi |
| 336 | 351 | |
| 337 | 352 | if (modPermissions != null && modPermissions.getModName() != null) |
| 338 | 353 | { |
| 339 | - this.serverPermissions.put(modPermissions.getModName(), modPermissions); | |
| 354 | + synchronized (this.serverPermissions) | |
| 355 | + { | |
| 356 | + this.serverPermissions.put(modPermissions.getModName(), modPermissions); | |
| 357 | + } | |
| 340 | 358 | |
| 341 | 359 | Permissible permissible = this.registeredClientMods.get(modPermissions.getModName()); |
| 342 | 360 | if (permissible != null) permissible.onPermissionsChanged(this); | ... | ... |
src/main/java/com/mumfrey/liteloader/update/UpdateSite.java
| ... | ... | @@ -160,6 +160,11 @@ public class UpdateSite implements Comparator<Long> |
| 160 | 160 | } |
| 161 | 161 | } |
| 162 | 162 | } |
| 163 | + | |
| 164 | + public boolean isSnapshot() | |
| 165 | + { | |
| 166 | + return false; | |
| 167 | + } | |
| 163 | 168 | |
| 164 | 169 | /** |
| 165 | 170 | * Gets whether a check is in progress |
| ... | ... | @@ -319,7 +324,7 @@ public class UpdateSite implements Comparator<Long> |
| 319 | 324 | */ |
| 320 | 325 | private void handleVersionData(Object key, Map<?, ?> value) |
| 321 | 326 | { |
| 322 | - if ("artefacts".equals(key)) | |
| 327 | + if ((this.isSnapshot() && "snapshots".equals(key)) || (!this.isSnapshot() && "artefacts".equals(key))) | |
| 323 | 328 | { |
| 324 | 329 | if (value.containsKey(this.artefact)) |
| 325 | 330 | { |
| ... | ... | @@ -387,7 +392,7 @@ public class UpdateSite implements Comparator<Long> |
| 387 | 392 | this.availableVersion = artefact.get("version").toString(); |
| 388 | 393 | this.availableVersionDate = DateFormat.getDateTimeInstance().format(new Date(remoteTimeStamp * 1000L)); |
| 389 | 394 | this.availableVersionURL = this.createArtefactURL(artefact.get("file").toString()); |
| 390 | - this.updateAvailable = this.compareTimeStamps(bestTimeStamp, remoteTimeStamp); | |
| 395 | + this.updateAvailable = this.compareArtefact(artefact, bestTimeStamp, remoteTimeStamp); | |
| 391 | 396 | |
| 392 | 397 | return true; |
| 393 | 398 | } |
| ... | ... | @@ -395,6 +400,11 @@ public class UpdateSite implements Comparator<Long> |
| 395 | 400 | return false; |
| 396 | 401 | } |
| 397 | 402 | |
| 403 | + protected boolean compareArtefact(Map<?, ?> artefact, long bestTimeStamp, Long remoteTimeStamp) | |
| 404 | + { | |
| 405 | + return this.compareTimeStamps(bestTimeStamp, remoteTimeStamp); | |
| 406 | + } | |
| 407 | + | |
| 398 | 408 | /** |
| 399 | 409 | * @param bestTimeStamp |
| 400 | 410 | * @param remoteTimeStamp | ... | ... |
src/main/resources/assets/liteloader/lang/en_us.lang
| ... | ... | @@ -16,6 +16,9 @@ gui.settings.notabhide.help1=Only applies if the above option is also checked |
| 16 | 16 | gui.settings.forceupdate.label=Periodically Check For Updates |
| 17 | 17 | gui.settings.forceupdate.help1=This option is §cexperimental§r and may not work properly |
| 18 | 18 | gui.settings.forceupdate.help2=yet, it also enables the "force update" capability. |
| 19 | +gui.settings.checkforsnapshots.label=Check For New Snapshots | |
| 20 | +gui.settings.checkforsnapshots.help1=If this option is enabled, LiteLoader will check | |
| 21 | +gui.settings.checkforsnapshots.help2=for new SNAPSHOT releases each time it it launched | |
| 19 | 22 | |
| 20 | 23 | gui.about.taboptions=§nLiteLoader Panel Options |
| 21 | 24 | |
| ... | ... | @@ -83,7 +86,11 @@ gui.log.uploadsuccess=Upload succeeded, log available at |
| 83 | 86 | gui.log.closedialog=Close |
| 84 | 87 | |
| 85 | 88 | gui.error.title=Startup errors for %s |
| 89 | +gui.error.copytoclipboard=Copy error to clipboard | |
| 86 | 90 | |
| 87 | 91 | gui.error.tooltip=%d mod startup error(s) detected (%d critical) |
| 88 | 92 | |
| 89 | -gui.notifications.updateavailable=LiteLoader Update Available! | |
| 90 | 93 | \ No newline at end of file |
| 94 | +gui.notifications.updateavailable=LiteLoader Update Available! | |
| 95 | +gui.notifications.newsnapshotavailable=!!New Snapshot Available:%nBuild #%s (%s) | |
| 96 | + | |
| 97 | +gui.invalidvalue=§cInvalid value! | |
| 91 | 98 | \ No newline at end of file | ... | ... |
src/main/resources/mixins.liteloader.core.json