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,8 +60,8 @@ archivesBaseName = "liteloader" | ||
| 60 | version = buildVersion + (project.isReleaseBuild ? '' : '-' + project.classifier) | 60 | version = buildVersion + (project.isReleaseBuild ? '' : '-' + project.classifier) |
| 61 | 61 | ||
| 62 | // Minimum version of Java required | 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 | repositories { | 66 | repositories { |
| 67 | mavenLocal() | 67 | mavenLocal() |
| @@ -72,7 +72,7 @@ repositories { | @@ -72,7 +72,7 @@ repositories { | ||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | dependencies { | 74 | dependencies { |
| 75 | - compile('org.spongepowered:mixin:0.6.8-SNAPSHOT') { | 75 | + compile('org.spongepowered:mixin:0.7.1-SNAPSHOT') { |
| 76 | exclude module: 'asm-commons' | 76 | exclude module: 'asm-commons' |
| 77 | exclude module: 'asm-tree' | 77 | exclude module: 'asm-tree' |
| 78 | exclude module: 'launchwrapper' | 78 | exclude module: 'launchwrapper' |
| @@ -89,11 +89,11 @@ minecraft { | @@ -89,11 +89,11 @@ minecraft { | ||
| 89 | 89 | ||
| 90 | sourceSets { | 90 | sourceSets { |
| 91 | main { | 91 | main { |
| 92 | - refMap = "mixins.liteloader.core.refmap.json" | 92 | + ext.refMap = "mixins.liteloader.core.refmap.json" |
| 93 | } | 93 | } |
| 94 | client { | 94 | client { |
| 95 | compileClasspath += main.compileClasspath + main.output | 95 | compileClasspath += main.compileClasspath + main.output |
| 96 | - refMap = "mixins.liteloader.client.refmap.json" | 96 | + ext.refMap = "mixins.liteloader.client.refmap.json" |
| 97 | } | 97 | } |
| 98 | debug { | 98 | debug { |
| 99 | compileClasspath += client.compileClasspath + client.output | 99 | compileClasspath += client.compileClasspath + client.output |
| @@ -123,7 +123,7 @@ javadoc { | @@ -123,7 +123,7 @@ javadoc { | ||
| 123 | afterEvaluate { | 123 | afterEvaluate { |
| 124 | logger.lifecycle '=================================================' | 124 | logger.lifecycle '=================================================' |
| 125 | logger.lifecycle ' LiteLoader' | 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 | logger.lifecycle ' Running in {} mode', (project.isReleaseBuild ? "RELEASE" : "SNAPSHOT") | 127 | logger.lifecycle ' Running in {} mode', (project.isReleaseBuild ? "RELEASE" : "SNAPSHOT") |
| 128 | logger.lifecycle '=================================================' | 128 | logger.lifecycle '=================================================' |
| 129 | 129 |
gradle.properties
| @@ -7,4 +7,4 @@ organization=LiteLoader | @@ -7,4 +7,4 @@ organization=LiteLoader | ||
| 7 | buildType=SNAPSHOT | 7 | buildType=SNAPSHOT |
| 8 | buildVersion=1.11.2 | 8 | buildVersion=1.11.2 |
| 9 | mcVersion=1.11.2 | 9 | mcVersion=1.11.2 |
| 10 | -mcMappings=snapshot_20161224 | ||
| 11 | \ No newline at end of file | 10 | \ No newline at end of file |
| 11 | +mcMappings=snapshot_20161224 |
src/client/java/com/mumfrey/liteloader/client/LiteLoaderEventBrokerClient.java
| @@ -9,24 +9,9 @@ import org.lwjgl.input.Mouse; | @@ -9,24 +9,9 @@ import org.lwjgl.input.Mouse; | ||
| 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |
| 10 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; | 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 | import com.mumfrey.liteloader.PlayerInteractionListener.MouseButton; | 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 | import com.mumfrey.liteloader.client.overlays.IEntityRenderer; | 14 | import com.mumfrey.liteloader.client.overlays.IEntityRenderer; |
| 29 | -import com.mumfrey.liteloader.client.overlays.IMinecraft; | ||
| 30 | import com.mumfrey.liteloader.common.LoadingProgress; | 15 | import com.mumfrey.liteloader.common.LoadingProgress; |
| 31 | import com.mumfrey.liteloader.core.InterfaceRegistrationDelegate; | 16 | import com.mumfrey.liteloader.core.InterfaceRegistrationDelegate; |
| 32 | import com.mumfrey.liteloader.core.LiteLoader; | 17 | import com.mumfrey.liteloader.core.LiteLoader; |
| @@ -51,7 +36,6 @@ import net.minecraft.client.shader.Framebuffer; | @@ -51,7 +36,6 @@ import net.minecraft.client.shader.Framebuffer; | ||
| 51 | import net.minecraft.entity.Entity; | 36 | import net.minecraft.entity.Entity; |
| 52 | import net.minecraft.network.play.client.CPacketChatMessage; | 37 | import net.minecraft.network.play.client.CPacketChatMessage; |
| 53 | import net.minecraft.server.integrated.IntegratedServer; | 38 | import net.minecraft.server.integrated.IntegratedServer; |
| 54 | -import net.minecraft.util.Timer; | ||
| 55 | import net.minecraft.util.text.ITextComponent; | 39 | import net.minecraft.util.text.ITextComponent; |
| 56 | 40 | ||
| 57 | public class LiteLoaderEventBrokerClient extends LiteLoaderEventBroker<Minecraft, IntegratedServer> implements IResourceManagerReloadListener | 41 | public class LiteLoaderEventBrokerClient extends LiteLoaderEventBroker<Minecraft, IntegratedServer> implements IResourceManagerReloadListener |
| @@ -427,14 +411,9 @@ public class LiteLoaderEventBrokerClient extends LiteLoaderEventBroker<Minecraft | @@ -427,14 +411,9 @@ public class LiteLoaderEventBrokerClient extends LiteLoaderEventBroker<Minecraft | ||
| 427 | /** | 411 | /** |
| 428 | * Callback from the tick hook, ticks all tickable mods | 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 | this.profiler.endStartSection("litemods"); | 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 | Minecraft minecraft = this.engine.getClient(); | 417 | Minecraft minecraft = this.engine.getClient(); |
| 439 | 418 | ||
| 440 | // Flag indicates whether we are in game at the moment | 419 | // Flag indicates whether we are in game at the moment |
| @@ -548,7 +527,7 @@ public class LiteLoaderEventBrokerClient extends LiteLoaderEventBroker<Minecraft | @@ -548,7 +527,7 @@ public class LiteLoaderEventBrokerClient extends LiteLoaderEventBroker<Minecraft | ||
| 548 | } | 527 | } |
| 549 | 528 | ||
| 550 | /** | 529 | /** |
| 551 | - * @param e | 530 | + * @param ci |
| 552 | * @param name | 531 | * @param name |
| 553 | * @param width | 532 | * @param width |
| 554 | * @param height | 533 | * @param height |
src/client/java/com/mumfrey/liteloader/client/LiteLoaderPanelManager.java
| @@ -9,6 +9,7 @@ import org.lwjgl.input.Keyboard; | @@ -9,6 +9,7 @@ import org.lwjgl.input.Keyboard; | ||
| 9 | 9 | ||
| 10 | import com.mumfrey.liteloader.client.gui.GuiLiteLoaderPanel; | 10 | import com.mumfrey.liteloader.client.gui.GuiLiteLoaderPanel; |
| 11 | import com.mumfrey.liteloader.common.GameEngine; | 11 | import com.mumfrey.liteloader.common.GameEngine; |
| 12 | +import com.mumfrey.liteloader.core.LiteLoader; | ||
| 12 | import com.mumfrey.liteloader.core.LiteLoaderMods; | 13 | import com.mumfrey.liteloader.core.LiteLoaderMods; |
| 13 | import com.mumfrey.liteloader.core.LiteLoaderUpdateSite; | 14 | import com.mumfrey.liteloader.core.LiteLoaderUpdateSite; |
| 14 | import com.mumfrey.liteloader.core.LiteLoaderVersion; | 15 | import com.mumfrey.liteloader.core.LiteLoaderVersion; |
| @@ -32,6 +33,13 @@ import net.minecraft.client.resources.I18n; | @@ -32,6 +33,13 @@ import net.minecraft.client.resources.I18n; | ||
| 32 | */ | 33 | */ |
| 33 | public class LiteLoaderPanelManager implements PanelManager<GuiScreen> | 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 | private final LoaderEnvironment environment; | 43 | private final LoaderEnvironment environment; |
| 36 | 44 | ||
| 37 | /** | 45 | /** |
| @@ -87,14 +95,14 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> | @@ -87,14 +95,14 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> | ||
| 87 | this.displayModInfoScreenTab = this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_MOD_INFO_SCREEN, true); | 95 | this.displayModInfoScreenTab = this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_MOD_INFO_SCREEN, true); |
| 88 | this.tabAlwaysExpanded = this.properties.getAndStoreBooleanProperty(LoaderProperties.OPTION_NO_HIDE_TAB, false); | 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 | int updateCheckInterval = this.properties.getIntegerProperty(LoaderProperties.OPTION_UPDATE_CHECK_INTR) + 1; | 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 | this.checkForUpdate = true; | 106 | this.checkForUpdate = true; |
| 99 | updateCheckInterval = 0; | 107 | updateCheckInterval = 0; |
| 100 | } | 108 | } |
| @@ -104,6 +112,16 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> | @@ -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 | @Override | 125 | @Override |
| 108 | public void init(LiteLoaderMods mods, ConfigManager configManager) | 126 | public void init(LiteLoaderMods mods, ConfigManager configManager) |
| 109 | { | 127 | { |
| @@ -141,7 +159,8 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> | @@ -141,7 +159,8 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> | ||
| 141 | this.checkForUpdate = false; | 159 | this.checkForUpdate = false; |
| 142 | if (updateSite.isCheckSucceess() && updateSite.isUpdateAvailable()) | 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,6 +270,19 @@ public class LiteLoaderPanelManager implements PanelManager<GuiScreen> | ||
| 251 | { | 270 | { |
| 252 | return this.properties.getBooleanProperty(LoaderProperties.OPTION_FORCE_UPDATE); | 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 | * Display the liteloader panel over the specified GUI | 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,7 +42,6 @@ public class LiteLoaderCoreAPIClient extends LiteLoaderCoreAPI | ||
| 42 | 42 | ||
| 43 | private static final String[] requiredDownstreamTransformers = { | 43 | private static final String[] requiredDownstreamTransformers = { |
| 44 | LiteLoaderCoreAPI.PKG_LITELOADER_COMMON + ".transformers.LiteLoaderPacketTransformer", | 44 | LiteLoaderCoreAPI.PKG_LITELOADER_COMMON + ".transformers.LiteLoaderPacketTransformer", |
| 45 | - LiteLoaderCoreAPIClient.PKG_LITELOADER_CLIENT + ".transformers.MinecraftTransformer", | ||
| 46 | LiteLoaderCoreAPI.PKG_LITELOADER + ".transformers.event.json.ModEventInjectionTransformer" | 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,11 +177,10 @@ public class GuiLiteLoaderPanel extends GuiScreen | ||
| 177 | this.startupErrorCount = mods.getStartupErrorCount(); | 177 | this.startupErrorCount = mods.getStartupErrorCount(); |
| 178 | this.criticalErrorCount = mods.getCriticalErrorCount(); | 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,6 +523,7 @@ public class GuiLiteLoaderPanel extends GuiScreen | ||
| 524 | 523 | ||
| 525 | if (annoyingTip) | 524 | if (annoyingTip) |
| 526 | { | 525 | { |
| 526 | + GuiLiteLoaderPanel.displayErrorToolTip = false; | ||
| 527 | this.drawNotificationTooltip(mouseX, mouseY - 13); | 527 | this.drawNotificationTooltip(mouseX, mouseY - 13); |
| 528 | } | 528 | } |
| 529 | } | 529 | } |
| @@ -542,8 +542,11 @@ public class GuiLiteLoaderPanel extends GuiScreen | @@ -542,8 +542,11 @@ public class GuiLiteLoaderPanel extends GuiScreen | ||
| 542 | } | 542 | } |
| 543 | else if (this.notification != null) | 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,21 +742,32 @@ public class GuiLiteLoaderPanel extends GuiScreen | ||
| 739 | * | 742 | * |
| 740 | * @param fontRenderer | 743 | * @param fontRenderer |
| 741 | * @param tooltipText | 744 | * @param tooltipText |
| 742 | - * @param mouseX | ||
| 743 | - * @param mouseY | 745 | + * @param left |
| 746 | + * @param top | ||
| 744 | * @param screenWidth | 747 | * @param screenWidth |
| 745 | * @param screenHeight | 748 | * @param screenHeight |
| 746 | * @param colour | 749 | * @param colour |
| 747 | * @param backgroundColour | 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 | int colour, int backgroundColour) | 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,10 +12,12 @@ import java.util.List; | ||
| 12 | 12 | ||
| 13 | import org.lwjgl.input.Keyboard; | 13 | import org.lwjgl.input.Keyboard; |
| 14 | 14 | ||
| 15 | +import com.google.common.base.Joiner; | ||
| 15 | import com.mumfrey.liteloader.core.ModInfo; | 16 | import com.mumfrey.liteloader.core.ModInfo; |
| 16 | 17 | ||
| 17 | import net.minecraft.client.Minecraft; | 18 | import net.minecraft.client.Minecraft; |
| 18 | import net.minecraft.client.gui.GuiButton; | 19 | import net.minecraft.client.gui.GuiButton; |
| 20 | +import net.minecraft.client.gui.GuiScreen; | ||
| 19 | import net.minecraft.client.resources.I18n; | 21 | import net.minecraft.client.resources.I18n; |
| 20 | 22 | ||
| 21 | public class GuiPanelError extends GuiPanel implements ScrollPanelContent | 23 | public class GuiPanelError extends GuiPanel implements ScrollPanelContent |
| @@ -98,6 +100,7 @@ public class GuiPanelError extends GuiPanel implements ScrollPanelContent | @@ -98,6 +100,7 @@ public class GuiPanelError extends GuiPanel implements ScrollPanelContent | ||
| 98 | 100 | ||
| 99 | this.scrollPane.setSizeAndPosition(MARGIN, TOP, this.width - (MARGIN * 2), this.height - TOP - BOTTOM); | 101 | this.scrollPane.setSizeAndPosition(MARGIN, TOP, this.width - (MARGIN * 2), this.height - TOP - BOTTOM); |
| 100 | this.controls.add(new GuiButton(0, this.width - 59 - MARGIN, this.height - BOTTOM + 9, 60, 20, I18n.format("gui.done"))); | 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 | @Override | 106 | @Override |
| @@ -131,7 +134,10 @@ public class GuiPanelError extends GuiPanel implements ScrollPanelContent | @@ -131,7 +134,10 @@ public class GuiPanelError extends GuiPanel implements ScrollPanelContent | ||
| 131 | @Override | 134 | @Override |
| 132 | void keyPressed(char keyChar, int keyCode) | 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 | @Override | 143 | @Override |
| @@ -161,6 +167,14 @@ public class GuiPanelError extends GuiPanel implements ScrollPanelContent | @@ -161,6 +167,14 @@ public class GuiPanelError extends GuiPanel implements ScrollPanelContent | ||
| 161 | @Override | 167 | @Override |
| 162 | void actionPerformed(GuiButton control) | 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,25 +17,29 @@ import net.minecraft.client.resources.I18n; | ||
| 17 | 17 | ||
| 18 | class GuiPanelSettings extends GuiPanel | 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 | private boolean hide; | 26 | private boolean hide; |
| 25 | 27 | ||
| 26 | private String[] helpText = new String[5]; | 28 | private String[] helpText = new String[5]; |
| 27 | - | 29 | + |
| 28 | GuiPanelSettings(GuiLiteLoaderPanel parentScreen, Minecraft minecraft) | 30 | GuiPanelSettings(GuiLiteLoaderPanel parentScreen, Minecraft minecraft) |
| 29 | { | 31 | { |
| 30 | super(minecraft); | 32 | super(minecraft); |
| 31 | 33 | ||
| 32 | this.parentScreen = parentScreen; | 34 | this.parentScreen = parentScreen; |
| 35 | + this.isSnapshot = LiteLoader.isSnapshot(); | ||
| 33 | 36 | ||
| 37 | + String helpKey = this.isSnapshot ? "checkforsnapshots" : "forceupdate"; | ||
| 34 | this.helpText[0] = I18n.format("gui.settings.showtab.help1"); | 38 | this.helpText[0] = I18n.format("gui.settings.showtab.help1"); |
| 35 | this.helpText[1] = I18n.format("gui.settings.showtab.help2"); | 39 | this.helpText[1] = I18n.format("gui.settings.showtab.help2"); |
| 36 | this.helpText[2] = I18n.format("gui.settings.notabhide.help1"); | 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 | @Override | 45 | @Override |
| @@ -61,6 +65,10 @@ class GuiPanelSettings extends GuiPanel | @@ -61,6 +65,10 @@ class GuiPanelSettings extends GuiPanel | ||
| 61 | this.controls.add(this.chkShowTab = new GuiCheckbox(0, 34, 90, I18n.format("gui.settings.showtab.label"))); | 65 | this.controls.add(this.chkShowTab = new GuiCheckbox(0, 34, 90, I18n.format("gui.settings.showtab.label"))); |
| 62 | this.controls.add(this.chkNoHide = new GuiCheckbox(1, 34, 128, I18n.format("gui.settings.notabhide.label"))); | 66 | this.controls.add(this.chkNoHide = new GuiCheckbox(1, 34, 128, I18n.format("gui.settings.notabhide.label"))); |
| 63 | this.controls.add(this.chkForceUpdate = new GuiCheckbox(2, 34, 158, I18n.format("gui.settings.forceupdate.label"))); | 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 | this.updateCheckBoxes(); | 73 | this.updateCheckBoxes(); |
| 66 | } | 74 | } |
| @@ -72,6 +80,7 @@ class GuiPanelSettings extends GuiPanel | @@ -72,6 +80,7 @@ class GuiPanelSettings extends GuiPanel | ||
| 72 | this.chkShowTab.checked = panelManager.isTabVisible(); | 80 | this.chkShowTab.checked = panelManager.isTabVisible(); |
| 73 | this.chkNoHide.checked = panelManager.isTabAlwaysExpanded(); | 81 | this.chkNoHide.checked = panelManager.isTabAlwaysExpanded(); |
| 74 | this.chkForceUpdate.checked = panelManager.isForceUpdateEnabled(); | 82 | this.chkForceUpdate.checked = panelManager.isForceUpdateEnabled(); |
| 83 | + this.chkCheckForSnapshots.checked = panelManager.isCheckForSnapshotsEnabled(); | ||
| 75 | } | 84 | } |
| 76 | 85 | ||
| 77 | private void updateSettings() | 86 | private void updateSettings() |
| @@ -81,6 +90,7 @@ class GuiPanelSettings extends GuiPanel | @@ -81,6 +90,7 @@ class GuiPanelSettings extends GuiPanel | ||
| 81 | panelManager.setTabVisible(this.chkShowTab.checked); | 90 | panelManager.setTabVisible(this.chkShowTab.checked); |
| 82 | panelManager.setTabAlwaysExpanded(this.chkNoHide.checked); | 91 | panelManager.setTabAlwaysExpanded(this.chkNoHide.checked); |
| 83 | panelManager.setForceUpdateEnabled(this.chkForceUpdate.checked); | 92 | panelManager.setForceUpdateEnabled(this.chkForceUpdate.checked); |
| 93 | + panelManager.setCheckForSnapshotsEnabled(this.chkCheckForSnapshots.checked); | ||
| 84 | } | 94 | } |
| 85 | 95 | ||
| 86 | @Override | 96 | @Override |
src/client/java/com/mumfrey/liteloader/client/gui/modlist/ModList.java
| @@ -15,6 +15,7 @@ import org.lwjgl.input.Keyboard; | @@ -15,6 +15,7 @@ import org.lwjgl.input.Keyboard; | ||
| 15 | import com.mumfrey.liteloader.LiteMod; | 15 | import com.mumfrey.liteloader.LiteMod; |
| 16 | import com.mumfrey.liteloader.api.ModInfoDecorator; | 16 | import com.mumfrey.liteloader.api.ModInfoDecorator; |
| 17 | import com.mumfrey.liteloader.client.gui.GuiLiteLoaderPanel; | 17 | import com.mumfrey.liteloader.client.gui.GuiLiteLoaderPanel; |
| 18 | +import com.mumfrey.liteloader.core.EnabledModsList.Enabled; | ||
| 18 | import com.mumfrey.liteloader.core.LiteLoaderMods; | 19 | import com.mumfrey.liteloader.core.LiteLoaderMods; |
| 19 | import com.mumfrey.liteloader.core.ModInfo; | 20 | import com.mumfrey.liteloader.core.ModInfo; |
| 20 | import com.mumfrey.liteloader.interfaces.Loadable; | 21 | import com.mumfrey.liteloader.interfaces.Loadable; |
| @@ -75,9 +76,12 @@ public class ModList | @@ -75,9 +76,12 @@ public class ModList | ||
| 75 | // Disabled mods | 76 | // Disabled mods |
| 76 | for (ModInfo<?> disabledMod : mods.getDisabledMods()) | 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 | sortedMods.put(modListEntry.getKey(), modListEntry); | 82 | sortedMods.put(modListEntry.getKey(), modListEntry); |
| 80 | } | 83 | } |
| 84 | + } | ||
| 81 | 85 | ||
| 82 | // Show bad containers if no other containers are found, should help users realise they have the wrong mod version! | 86 | // Show bad containers if no other containers are found, should help users realise they have the wrong mod version! |
| 83 | if (sortedMods.size() == 0) | 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,7 +19,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | ||
| 19 | import com.mumfrey.liteloader.PlayerInteractionListener.MouseButton; | 19 | import com.mumfrey.liteloader.PlayerInteractionListener.MouseButton; |
| 20 | import com.mumfrey.liteloader.client.LiteLoaderEventBrokerClient; | 20 | import com.mumfrey.liteloader.client.LiteLoaderEventBrokerClient; |
| 21 | import com.mumfrey.liteloader.client.ducks.IFramebuffer; | 21 | import com.mumfrey.liteloader.client.ducks.IFramebuffer; |
| 22 | +import com.mumfrey.liteloader.client.gui.startup.LoadingBar; | ||
| 22 | import com.mumfrey.liteloader.client.overlays.IMinecraft; | 23 | import com.mumfrey.liteloader.client.overlays.IMinecraft; |
| 24 | +import com.mumfrey.liteloader.launch.LiteLoaderTweaker; | ||
| 23 | 25 | ||
| 24 | import net.minecraft.client.Minecraft; | 26 | import net.minecraft.client.Minecraft; |
| 25 | import net.minecraft.client.renderer.OpenGlHelper; | 27 | import net.minecraft.client.renderer.OpenGlHelper; |
| @@ -35,6 +37,7 @@ public abstract class MixinMinecraft implements IMinecraft | @@ -35,6 +37,7 @@ public abstract class MixinMinecraft implements IMinecraft | ||
| 35 | @Shadow @Final private List<IResourcePack> defaultResourcePacks; | 37 | @Shadow @Final private List<IResourcePack> defaultResourcePacks; |
| 36 | @Shadow private String serverName; | 38 | @Shadow private String serverName; |
| 37 | @Shadow private int serverPort; | 39 | @Shadow private int serverPort; |
| 40 | + @Shadow private boolean isGamePaused; | ||
| 38 | 41 | ||
| 39 | @Shadow abstract void resize(int width, int height); | 42 | @Shadow abstract void resize(int width, int height); |
| 40 | @Shadow private void clickMouse() {} | 43 | @Shadow private void clickMouse() {} |
| @@ -43,6 +46,25 @@ public abstract class MixinMinecraft implements IMinecraft | @@ -43,6 +46,25 @@ public abstract class MixinMinecraft implements IMinecraft | ||
| 43 | 46 | ||
| 44 | private LiteLoaderEventBrokerClient broker; | 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 | @Inject(method = "init()V", at = @At("RETURN")) | 68 | @Inject(method = "init()V", at = @At("RETURN")) |
| 47 | private void onStartupComplete(CallbackInfo ci) | 69 | private void onStartupComplete(CallbackInfo ci) |
| 48 | { | 70 | { |
| @@ -79,7 +101,9 @@ public abstract class MixinMinecraft implements IMinecraft | @@ -79,7 +101,9 @@ public abstract class MixinMinecraft implements IMinecraft | ||
| 79 | )) | 101 | )) |
| 80 | private void onTick(CallbackInfo ci) | 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 | @Redirect(method = "runGameLoop()V", at = @At( | 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,15 +7,21 @@ package com.mumfrey.liteloader.modconfig; | ||
| 7 | 7 | ||
| 8 | import java.util.ArrayList; | 8 | import java.util.ArrayList; |
| 9 | import java.util.List; | 9 | import java.util.List; |
| 10 | +import java.util.regex.Pattern; | ||
| 10 | 11 | ||
| 11 | import org.lwjgl.input.Keyboard; | 12 | import org.lwjgl.input.Keyboard; |
| 12 | 13 | ||
| 14 | +import com.mumfrey.liteloader.client.gui.GuiLiteLoaderPanel; | ||
| 13 | import com.mumfrey.liteloader.client.mixin.IGuiButton; | 15 | import com.mumfrey.liteloader.client.mixin.IGuiButton; |
| 14 | 16 | ||
| 15 | import net.minecraft.client.Minecraft; | 17 | import net.minecraft.client.Minecraft; |
| 18 | +import net.minecraft.client.gui.FontRenderer; | ||
| 16 | import net.minecraft.client.gui.GuiButton; | 19 | import net.minecraft.client.gui.GuiButton; |
| 17 | import net.minecraft.client.gui.GuiLabel; | 20 | import net.minecraft.client.gui.GuiLabel; |
| 18 | import net.minecraft.client.gui.GuiScreen; | 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 | * A general-purpose base class for mod config panels which implements a lot of | 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,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 | this.label = label; | 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 | this.control = control; | 162 | this.control = control; |
| 66 | this.listener = listener; | 163 | this.listener = listener; |
| 67 | } | 164 | } |
| 68 | 165 | ||
| 166 | + @Override | ||
| 69 | void draw(Minecraft minecraft, int mouseX, int mouseY, float partialTicks) | 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 | boolean mousePressed(Minecraft minecraft, int mouseX, int mouseY) | 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 | return true; | 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 | return false; | 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 | protected final Minecraft mc; | 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 | private int contentHeight = 0; | 403 | private int contentHeight = 0; |
| 111 | 404 | ||
| 112 | - private ConfigOption<?> selected; | 405 | + private ConfigOption selected; |
| 113 | 406 | ||
| 114 | public AbstractConfigPanel() | 407 | public AbstractConfigPanel() |
| 115 | { | 408 | { |
| @@ -170,7 +463,7 @@ public abstract class AbstractConfigPanel implements ConfigPanel | @@ -170,7 +463,7 @@ public abstract class AbstractConfigPanel implements ConfigPanel | ||
| 170 | label.addLine(line); | 463 | label.addLine(line); |
| 171 | } | 464 | } |
| 172 | this.contentHeight = Math.max(y + height, this.contentHeight); | 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,12 +478,33 @@ public abstract class AbstractConfigPanel implements ConfigPanel | ||
| 185 | if (control != null) | 478 | if (control != null) |
| 186 | { | 479 | { |
| 187 | this.contentHeight = Math.max(control.yPosition + ((IGuiButton)control).getButtonHeight(), this.contentHeight); | 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 | return control; | 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 | @Override | 508 | @Override |
| 195 | public void onPanelResize(ConfigPanelHost host) | 509 | public void onPanelResize(ConfigPanelHost host) |
| 196 | { | 510 | { |
| @@ -199,12 +513,16 @@ public abstract class AbstractConfigPanel implements ConfigPanel | @@ -199,12 +513,16 @@ public abstract class AbstractConfigPanel implements ConfigPanel | ||
| 199 | @Override | 513 | @Override |
| 200 | public void onTick(ConfigPanelHost host) | 514 | public void onTick(ConfigPanelHost host) |
| 201 | { | 515 | { |
| 516 | + for (ConfigOption configOption : this.options) | ||
| 517 | + { | ||
| 518 | + configOption.onTick(); | ||
| 519 | + } | ||
| 202 | } | 520 | } |
| 203 | 521 | ||
| 204 | @Override | 522 | @Override |
| 205 | public void drawPanel(ConfigPanelHost host, int mouseX, int mouseY, float partialTicks) | 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 | configOption.draw(this.mc, mouseX, mouseY, partialTicks); | 527 | configOption.draw(this.mc, mouseX, mouseY, partialTicks); |
| 210 | } | 528 | } |
| @@ -219,7 +537,7 @@ public abstract class AbstractConfigPanel implements ConfigPanel | @@ -219,7 +537,7 @@ public abstract class AbstractConfigPanel implements ConfigPanel | ||
| 219 | return; | 537 | return; |
| 220 | } | 538 | } |
| 221 | 539 | ||
| 222 | - for (ConfigOption<?> configOption : this.options) | 540 | + for (ConfigOption configOption : this.options) |
| 223 | { | 541 | { |
| 224 | if (configOption.mousePressed(this.mc, mouseX, mouseY)) | 542 | if (configOption.mousePressed(this.mc, mouseX, mouseY)) |
| 225 | { | 543 | { |
| @@ -251,5 +569,22 @@ public abstract class AbstractConfigPanel implements ConfigPanel | @@ -251,5 +569,22 @@ public abstract class AbstractConfigPanel implements ConfigPanel | ||
| 251 | host.close(); | 569 | host.close(); |
| 252 | return; | 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
| 1 | { | 1 | { |
| 2 | "required": true, | 2 | "required": true, |
| 3 | - "minVersion": "0.6", | 3 | + "minVersion": "0.7", |
| 4 | + "compatibilityLevel": "JAVA_8", | ||
| 4 | "target": "@env(DEFAULT)", | 5 | "target": "@env(DEFAULT)", |
| 5 | "package": "com.mumfrey.liteloader.client.mixin", | 6 | "package": "com.mumfrey.liteloader.client.mixin", |
| 6 | "refmap": "mixins.liteloader.client.refmap.json", | 7 | "refmap": "mixins.liteloader.client.refmap.json", |
src/main/java/com/mumfrey/liteloader/core/EnabledModsList.java
| @@ -24,6 +24,34 @@ import com.google.gson.GsonBuilder; | @@ -24,6 +24,34 @@ import com.google.gson.GsonBuilder; | ||
| 24 | */ | 24 | */ |
| 25 | public final class EnabledModsList | 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 | @SuppressWarnings("unused") | 55 | @SuppressWarnings("unused") |
| 28 | private static final transient long serialVersionUID = -6449451105617763769L; | 56 | private static final transient long serialVersionUID = -6449451105617763769L; |
| 29 | 57 | ||
| @@ -45,7 +73,7 @@ public final class EnabledModsList | @@ -45,7 +73,7 @@ public final class EnabledModsList | ||
| 45 | * the mods list because the command line is supposed to be an override | 73 | * the mods list because the command line is supposed to be an override |
| 46 | * rather than a new mask. These two values provide this behaviour. | 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 | private transient boolean allowSave = true; | 77 | private transient boolean allowSave = true; |
| 50 | 78 | ||
| 51 | /** | 79 | /** |
| @@ -59,22 +87,27 @@ public final class EnabledModsList | @@ -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 | * @param profileName | 92 | * @param profileName |
| 65 | * @param identifier | 93 | * @param identifier |
| 66 | */ | 94 | */ |
| 67 | public boolean isEnabled(String profileName, String identifier) | 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 | Map<String, Boolean> profile = this.getProfile(profileName); | 102 | Map<String, Boolean> profile = this.getProfile(profileName); |
| 70 | identifier = identifier.toLowerCase().trim(); | 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,7 +120,7 @@ public final class EnabledModsList | ||
| 87 | public void setEnabled(String profileName, String identifier, boolean enabled) | 120 | public void setEnabled(String profileName, String identifier, boolean enabled) |
| 88 | { | 121 | { |
| 89 | Map<String, Boolean> profile = this.getProfile(profileName); | 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 | this.allowSave = true; | 125 | this.allowSave = true; |
| 93 | } | 126 | } |
| @@ -106,12 +139,9 @@ public final class EnabledModsList | @@ -106,12 +139,9 @@ public final class EnabledModsList | ||
| 106 | { | 139 | { |
| 107 | if (modNameFilter != null) | 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 | this.allowSave = false; | 145 | this.allowSave = false; |
| 116 | 146 | ||
| 117 | for (String filterEntry : modNameFilter) | 147 | for (String filterEntry : modNameFilter) |
| @@ -122,8 +152,8 @@ public final class EnabledModsList | @@ -122,8 +152,8 @@ public final class EnabledModsList | ||
| 122 | } | 152 | } |
| 123 | catch (Exception ex) | 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,7 +165,7 @@ public final class EnabledModsList | ||
| 135 | private Map<String, Boolean> getProfile(String profileName) | 165 | private Map<String, Boolean> getProfile(String profileName) |
| 136 | { | 166 | { |
| 137 | if (profileName == null) profileName = "default"; | 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 | if (!this.mods.containsKey(profileName)) | 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,6 +532,15 @@ public final class LiteLoader | ||
| 532 | { | 532 | { |
| 533 | return "true".equals(System.getProperty("mcpenv")); | 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 | * Dump debugging information to the console | 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,6 +8,10 @@ package com.mumfrey.liteloader.core; | ||
| 8 | import java.io.File; | 8 | import java.io.File; |
| 9 | import java.io.IOException; | 9 | import java.io.IOException; |
| 10 | import java.io.InputStream; | 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 | import com.google.common.io.ByteSink; | 16 | import com.google.common.io.ByteSink; |
| 13 | import com.google.common.io.Files; | 17 | import com.google.common.io.Files; |
| @@ -21,6 +25,8 @@ public class LiteLoaderUpdateSite extends UpdateSite | @@ -21,6 +25,8 @@ public class LiteLoaderUpdateSite extends UpdateSite | ||
| 21 | private static final String UPDATE_SITE_URL = "http://dl.liteloader.com/versions/"; | 25 | private static final String UPDATE_SITE_URL = "http://dl.liteloader.com/versions/"; |
| 22 | private static final String UPDATE_SITE_VERSIONS_JSON = "versions.json"; | 26 | private static final String UPDATE_SITE_VERSIONS_JSON = "versions.json"; |
| 23 | private static final String UPDATE_SITE_ARTEFACT_NAME = "com.mumfrey:liteloader"; | 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 | private String mcVersion; | 31 | private String mcVersion; |
| 26 | 32 | ||
| @@ -28,6 +34,10 @@ public class LiteLoaderUpdateSite extends UpdateSite | @@ -28,6 +34,10 @@ public class LiteLoaderUpdateSite extends UpdateSite | ||
| 28 | private File jarFile = null; | 34 | private File jarFile = null; |
| 29 | 35 | ||
| 30 | private boolean updateForced = false; | 36 | private boolean updateForced = false; |
| 37 | + private boolean isSnapshot = false; | ||
| 38 | + | ||
| 39 | + private int currentBuild, availableBuild; | ||
| 40 | + private String snapshotDate = null; | ||
| 31 | 41 | ||
| 32 | public LiteLoaderUpdateSite(String targetVersion, long currentTimeStamp) | 42 | public LiteLoaderUpdateSite(String targetVersion, long currentTimeStamp) |
| 33 | { | 43 | { |
| @@ -36,6 +46,64 @@ public class LiteLoaderUpdateSite extends UpdateSite | @@ -36,6 +46,64 @@ public class LiteLoaderUpdateSite extends UpdateSite | ||
| 36 | 46 | ||
| 37 | this.mcVersion = targetVersion; | 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 | public boolean canForceUpdate(LoaderProperties properties) | 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,14 +26,11 @@ public class Obf | ||
| 26 | public static final Obf BakedProfilingHandlerList = new Obf("com.mumfrey.liteloader.core.event.ProfilingHandlerList$BakedList" ); | 26 | public static final Obf BakedProfilingHandlerList = new Obf("com.mumfrey.liteloader.core.event.ProfilingHandlerList$BakedList" ); |
| 27 | public static final Obf PacketEvents = new Obf("com.mumfrey.liteloader.core.PacketEvents" ); | 27 | public static final Obf PacketEvents = new Obf("com.mumfrey.liteloader.core.PacketEvents" ); |
| 28 | public static final Obf PacketEventsClient = new Obf("com.mumfrey.liteloader.client.PacketEventsClient" ); | 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 | public static final Obf GameProfile = new Obf("com.mojang.authlib.GameProfile" ); | 29 | public static final Obf GameProfile = new Obf("com.mojang.authlib.GameProfile" ); |
| 31 | public static final Obf MinecraftMain = new Obf("net.minecraft.client.main.Main" ); | 30 | public static final Obf MinecraftMain = new Obf("net.minecraft.client.main.Main" ); |
| 32 | public static final Obf MinecraftServer = new Obf("net.minecraft.server.MinecraftServer" ); | 31 | public static final Obf MinecraftServer = new Obf("net.minecraft.server.MinecraftServer" ); |
| 33 | public static final Obf GL11 = new Obf("org.lwjgl.opengl.GL11" ); | 32 | public static final Obf GL11 = new Obf("org.lwjgl.opengl.GL11" ); |
| 34 | public static final Obf RealmsMainScreen = new Obf("com.mojang.realmsclient.RealmsMainScreen" ); | 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 | public static final Obf constructor = new Obf("<init>" ); | 34 | public static final Obf constructor = new Obf("<init>" ); |
| 38 | 35 | ||
| 39 | // CHECKSTYLE:OFF | 36 | // CHECKSTYLE:OFF |
src/main/java/com/mumfrey/liteloader/core/runtime/Packets.java
| @@ -5,6 +5,7 @@ | @@ -5,6 +5,7 @@ | ||
| 5 | */ | 5 | */ |
| 6 | package com.mumfrey.liteloader.core.runtime; | 6 | package com.mumfrey.liteloader.core.runtime; |
| 7 | 7 | ||
| 8 | +import java.lang.reflect.Field; | ||
| 8 | import java.util.HashMap; | 9 | import java.util.HashMap; |
| 9 | import java.util.Map; | 10 | import java.util.Map; |
| 10 | 11 | ||
| @@ -157,125 +158,7 @@ public final class Packets extends Obf | @@ -157,125 +158,7 @@ public final class Packets extends Obf | ||
| 157 | 158 | ||
| 158 | // CHECKSTYLE:ON | 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 | private static int nextPacketIndex; | 163 | private static int nextPacketIndex; |
| 281 | 164 | ||
| @@ -295,6 +178,24 @@ public final class Packets extends Obf | @@ -295,6 +178,24 @@ public final class Packets extends Obf | ||
| 295 | this.context = context; | 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 | public int getIndex() | 199 | public int getIndex() |
| 299 | { | 200 | { |
| 300 | return this.index; | 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,4 +88,14 @@ public interface PanelManager<TParentScreen> extends TickObserver, PostRenderObs | ||
| 88 | * Get whether "force update" is enabled | 88 | * Get whether "force update" is enabled |
| 89 | */ | 89 | */ |
| 90 | public abstract boolean isForceUpdateEnabled(); | 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,6 +99,7 @@ public interface LoaderProperties | ||
| 99 | public static final String OPTION_FORCE_UPDATE = "allowForceUpdate"; | 99 | public static final String OPTION_FORCE_UPDATE = "allowForceUpdate"; |
| 100 | public static final String OPTION_UPDATE_CHECK_INTR = "updateCheckInterval"; | 100 | public static final String OPTION_UPDATE_CHECK_INTR = "updateCheckInterval"; |
| 101 | public static final String OPTION_JINPUT_DISABLE = "disableJInput"; | 101 | public static final String OPTION_JINPUT_DISABLE = "disableJInput"; |
| 102 | + public static final String OPTION_CHECK_SNAPSHOTS = "checkForNewSnapshots"; | ||
| 102 | 103 | ||
| 103 | // Enumerator properties | 104 | // Enumerator properties |
| 104 | public static final String OPTION_SEARCH_MODS = "search.mods"; | 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,6 +17,7 @@ import com.google.common.collect.Maps; | ||
| 17 | import com.google.common.io.Files; | 17 | import com.google.common.io.Files; |
| 18 | import com.mumfrey.liteloader.Configurable; | 18 | import com.mumfrey.liteloader.Configurable; |
| 19 | import com.mumfrey.liteloader.LiteMod; | 19 | import com.mumfrey.liteloader.LiteMod; |
| 20 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogger; | ||
| 20 | 21 | ||
| 21 | /** | 22 | /** |
| 22 | * Registry where we keep the mod config panel classes and config file writers | 23 | * Registry where we keep the mod config panel classes and config file writers |
| @@ -165,6 +166,10 @@ public class ConfigManager | @@ -165,6 +166,10 @@ public class ConfigManager | ||
| 165 | } | 166 | } |
| 166 | catch (InstantiationException ex) {} | 167 | catch (InstantiationException ex) {} |
| 167 | catch (IllegalAccessException ex) {} | 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 | // If instantiation fails, remove the panel | 174 | // If instantiation fails, remove the panel |
| 170 | this.configPanels.remove(modClass); | 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,37 +47,37 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi | ||
| 47 | * Permissions permissible which is a proxy for permissions that are common | 47 | * Permissions permissible which is a proxy for permissions that are common |
| 48 | * to all mods. | 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 | * List of registered client mods supporting permissions | 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 | * List of registered client permissions, grouped by mod | 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 | * Objects which listen to events generated by this object | 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 | * Local permissions, used when server permissions are not available | 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 | * Server permissions, indexed by mod | 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 | * Last time onTick was called, used to detect tamper condition if no ticks | 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,8 +124,11 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi | ||
| 124 | if (mod == null) mod = allMods; | 124 | if (mod == null) mod = allMods; |
| 125 | String modName = mod.getPermissibleModName(); | 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 | /* (non-Javadoc) | 134 | /* (non-Javadoc) |
| @@ -138,8 +141,11 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi | @@ -138,8 +141,11 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi | ||
| 138 | if (mod == null) mod = allMods; | 141 | if (mod == null) mod = allMods; |
| 139 | String modName = mod.getPermissibleModName(); | 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,7 +214,10 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi | ||
| 208 | */ | 214 | */ |
| 209 | protected void clearServerPermissions() | 215 | protected void clearServerPermissions() |
| 210 | { | 216 | { |
| 211 | - this.serverPermissions.clear(); | 217 | + synchronized (this.serverPermissions) |
| 218 | + { | ||
| 219 | + this.serverPermissions.clear(); | ||
| 220 | + } | ||
| 212 | 221 | ||
| 213 | for (Permissible permissible : this.permissibles) | 222 | for (Permissible permissible : this.permissibles) |
| 214 | { | 223 | { |
| @@ -264,7 +273,10 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi | @@ -264,7 +273,10 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi | ||
| 264 | } | 273 | } |
| 265 | else | 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,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,7 +351,10 @@ public final class PermissionsManagerClient implements PermissionsManager, Plugi | ||
| 336 | 351 | ||
| 337 | if (modPermissions != null && modPermissions.getModName() != null) | 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 | Permissible permissible = this.registeredClientMods.get(modPermissions.getModName()); | 359 | Permissible permissible = this.registeredClientMods.get(modPermissions.getModName()); |
| 342 | if (permissible != null) permissible.onPermissionsChanged(this); | 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,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 | * Gets whether a check is in progress | 170 | * Gets whether a check is in progress |
| @@ -319,7 +324,7 @@ public class UpdateSite implements Comparator<Long> | @@ -319,7 +324,7 @@ public class UpdateSite implements Comparator<Long> | ||
| 319 | */ | 324 | */ |
| 320 | private void handleVersionData(Object key, Map<?, ?> value) | 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 | if (value.containsKey(this.artefact)) | 329 | if (value.containsKey(this.artefact)) |
| 325 | { | 330 | { |
| @@ -387,7 +392,7 @@ public class UpdateSite implements Comparator<Long> | @@ -387,7 +392,7 @@ public class UpdateSite implements Comparator<Long> | ||
| 387 | this.availableVersion = artefact.get("version").toString(); | 392 | this.availableVersion = artefact.get("version").toString(); |
| 388 | this.availableVersionDate = DateFormat.getDateTimeInstance().format(new Date(remoteTimeStamp * 1000L)); | 393 | this.availableVersionDate = DateFormat.getDateTimeInstance().format(new Date(remoteTimeStamp * 1000L)); |
| 389 | this.availableVersionURL = this.createArtefactURL(artefact.get("file").toString()); | 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 | return true; | 397 | return true; |
| 393 | } | 398 | } |
| @@ -395,6 +400,11 @@ public class UpdateSite implements Comparator<Long> | @@ -395,6 +400,11 @@ public class UpdateSite implements Comparator<Long> | ||
| 395 | return false; | 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 | * @param bestTimeStamp | 409 | * @param bestTimeStamp |
| 400 | * @param remoteTimeStamp | 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,6 +16,9 @@ gui.settings.notabhide.help1=Only applies if the above option is also checked | ||
| 16 | gui.settings.forceupdate.label=Periodically Check For Updates | 16 | gui.settings.forceupdate.label=Periodically Check For Updates |
| 17 | gui.settings.forceupdate.help1=This option is §cexperimental§r and may not work properly | 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. | 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 | gui.about.taboptions=§nLiteLoader Panel Options | 23 | gui.about.taboptions=§nLiteLoader Panel Options |
| 21 | 24 | ||
| @@ -83,7 +86,11 @@ gui.log.uploadsuccess=Upload succeeded, log available at | @@ -83,7 +86,11 @@ gui.log.uploadsuccess=Upload succeeded, log available at | ||
| 83 | gui.log.closedialog=Close | 86 | gui.log.closedialog=Close |
| 84 | 87 | ||
| 85 | gui.error.title=Startup errors for %s | 88 | gui.error.title=Startup errors for %s |
| 89 | +gui.error.copytoclipboard=Copy error to clipboard | ||
| 86 | 90 | ||
| 87 | gui.error.tooltip=%d mod startup error(s) detected (%d critical) | 91 | gui.error.tooltip=%d mod startup error(s) detected (%d critical) |
| 88 | 92 | ||
| 89 | -gui.notifications.updateavailable=LiteLoader Update Available! | ||
| 90 | \ No newline at end of file | 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 | \ No newline at end of file | 98 | \ No newline at end of file |
src/main/resources/mixins.liteloader.core.json
| 1 | { | 1 | { |
| 2 | "required": true, | 2 | "required": true, |
| 3 | - "minVersion": "0.5.3", | 3 | + "minVersion": "0.7", |
| 4 | + "compatibilityLevel": "JAVA_8", | ||
| 4 | "target": "@env(DEFAULT)", | 5 | "target": "@env(DEFAULT)", |
| 5 | "package": "com.mumfrey.liteloader.common.mixin", | 6 | "package": "com.mumfrey.liteloader.common.mixin", |
| 6 | "refmap": "mixins.liteloader.core.refmap.json", | 7 | "refmap": "mixins.liteloader.core.refmap.json", |