diff options
Diffstat (limited to 'src/main/java')
8 files changed, 321 insertions, 4 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java index 3392e83c7..48d49ec87 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.java @@ -34,6 +34,7 @@ import at.hannibal2.skyhanni.features.minion.MinionFeatures; import at.hannibal2.skyhanni.features.misc.*; import at.hannibal2.skyhanni.features.misc.tiarelay.TiaRelayHelper; import at.hannibal2.skyhanni.features.misc.tiarelay.TiaRelayWaypoints; +import at.hannibal2.skyhanni.features.misc.update.UpdateManager; import at.hannibal2.skyhanni.features.mobs.AreaMiniBossFeatures; import at.hannibal2.skyhanni.features.mobs.MobHighlight; import at.hannibal2.skyhanni.features.nether.ashfang.*; @@ -58,6 +59,7 @@ import kotlinx.coroutines.*; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; @@ -70,13 +72,17 @@ import org.apache.logging.log4j.Logger; import java.util.ArrayList; import java.util.List; -@Mod(modid = SkyHanniMod.MODID, version = SkyHanniMod.VERSION, clientSideOnly = true, useMetadata = true, +@Mod(modid = SkyHanniMod.MODID, clientSideOnly = true, useMetadata = true, guiFactory = "at.hannibal2.skyhanni.config.ConfigGuiForgeInterop", dependencies = SkyHanniMod.DEPENDENCIES) public class SkyHanniMod { public static final String MODID = "skyhanni"; - public static final String VERSION = "0.17.Beta.31"; + + public static String getVersion() { + return Loader.instance().getIndexedModList().get(MODID).getVersion(); + } + public static final String DEPENDENCIES = "after:notenoughupdates@[2.1.1,);"; @@ -126,6 +132,7 @@ public class SkyHanniMod { loadModule(new OwnInventoryData()); loadModule(new ToolTipData()); loadModule(new GuiEditManager()); + loadModule(UpdateManager.INSTANCE); // APIs loadModule(new BazaarApi()); diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt index dd10d8482..de41a1e4b 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.config import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.events.ConfigLoadEvent +import at.hannibal2.skyhanni.features.misc.update.UpdateManager import at.hannibal2.skyhanni.features.garden.CropType import com.google.gson.GsonBuilder import io.github.moulberry.moulconfig.observer.PropertyTypeAdapterFactory @@ -79,6 +80,7 @@ class ConfigManager { val features = SkyHanniMod.feature processor = MoulConfigProcessor(SkyHanniMod.feature) BuiltinMoulConfigGuis.addProcessors(processor) + UpdateManager.injectConfigProcessor(processor) ConfigProcessorDriver.processConfig( features.javaClass, features, diff --git a/src/main/java/at/hannibal2/skyhanni/config/Features.java b/src/main/java/at/hannibal2/skyhanni/config/Features.java index bc7913f37..064b5ce2a 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/Features.java +++ b/src/main/java/at/hannibal2/skyhanni/config/Features.java @@ -32,10 +32,14 @@ public class Features extends Config { @Override public String getTitle() { - return "SkyHanni " + SkyHanniMod.VERSION + " by §channibal2§r, config by §5Moulberry §rand §5nea89"; + return "SkyHanni " + SkyHanniMod.getVersion() + " by §channibal2§r, config by §5Moulberry §rand §5nea89"; } @Expose + @Category(name = "About", desc = "Information about SkyHanni and updates") + public About about = new About(); + + @Expose @Category(name = "GUI Locations", desc = "Change the locations of GUI elements. (§e/sh gui§7)") public GUI gui = new GUI(); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/About.java b/src/main/java/at/hannibal2/skyhanni/config/features/About.java new file mode 100644 index 000000000..0bb71a7e1 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/About.java @@ -0,0 +1,77 @@ +package at.hannibal2.skyhanni.config.features; + +import at.hannibal2.skyhanni.features.misc.update.ConfigVersionDisplay; +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.*; +import io.github.moulberry.moulconfig.observer.Property; +import io.github.moulberry.notenoughupdates.util.Utils; + +public class About { + + + @ConfigOption(name = "Current Version", desc = "This is the SkyHanni version you are running currently") + @ConfigVersionDisplay + public Void currentVersion = null; + + @ConfigOption(name = "Auto Updates", desc = "Automatically check for updates on each startup") + @Expose + @ConfigEditorBoolean + public boolean autoUpdates = true; + + @ConfigOption(name = "Update Stream", desc = "How frequently do you want updates for SkyHanni") + @Expose + @ConfigEditorDropdown + public Property<UpdateStream> updateStream = Property.of(UpdateStream.RELEASES); + + + @ConfigOption(name = "Used Software", desc = "Information about used software and licenses") + @Accordion + public Licenses licenses = new Licenses(); + + public enum UpdateStream { + NONE("None", "none"), + BETA("Beta", "pre"), + RELEASES("Full", "full"); + + private final String label; + private final String stream; + + UpdateStream(String label, String stream) { + this.label = label; + this.stream = stream; + } + + public String getStream() { + return stream; + } + + @Override + public String toString() { + return label; + } + } + + public static class Licenses { + + @ConfigOption(name = "MoulConfig", desc = "MoulConfig is available under the LGPL 3.0 License or later version") + @ConfigEditorButton(buttonText = "GitHub") + public Runnable moulConfig = () -> Utils.openUrl("https://github.com/NotEnoughUpdates/MoulConfig"); + + @ConfigOption(name = "NotEnoughUpdates", desc = "NotEnoughUpdates is available under the LGPL 3.0 License or later version") + @ConfigEditorButton(buttonText = "GitHub") + public Runnable notEnoughUpdates = () -> Utils.openUrl("https://github.com/NotEnoughUpdates/NotEnoughUpdates"); + + @ConfigOption(name = "Forge", desc = "Forge is available under the LGPL 3.0 license") + @ConfigEditorButton(buttonText = "GitHub") + public Runnable forge = () -> Utils.openUrl("https://github.com/MinecraftForge/MinecraftForge"); + + @ConfigOption(name = "LibAutoUpdate", desc = "LibAutoUpdate is available under the BSD 2 Clause License") + @ConfigEditorButton(buttonText = "Git") + public Runnable libAutoUpdate = () -> Utils.openUrl("https://git.nea.moe/nea/libautoupdate/"); + + @ConfigOption(name = "Mixin", desc = "LibAutoUpdate is available under the MIT License") + @ConfigEditorButton(buttonText = "GitHub") + public Runnable mixin = () -> Utils.openUrl("https://github.com/SpongePowered/Mixin/"); + + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/update/ConfigVersionDisplay.java b/src/main/java/at/hannibal2/skyhanni/features/misc/update/ConfigVersionDisplay.java new file mode 100644 index 000000000..ddb837efb --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/update/ConfigVersionDisplay.java @@ -0,0 +1,11 @@ +package at.hannibal2.skyhanni.features.misc.update; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigVersionDisplay { +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/update/GuiOptionEditorUpdateCheck.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/update/GuiOptionEditorUpdateCheck.kt new file mode 100644 index 000000000..395975aa6 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/update/GuiOptionEditorUpdateCheck.kt @@ -0,0 +1,88 @@ +package at.hannibal2.skyhanni.features.misc.update + +import io.github.moulberry.moulconfig.gui.GuiOptionEditor +import io.github.moulberry.moulconfig.internal.TextRenderUtils +import io.github.moulberry.moulconfig.processor.ProcessedOption +import io.github.moulberry.notenoughupdates.itemeditor.GuiElementButton +import net.minecraft.client.Minecraft +import net.minecraft.client.renderer.GlStateManager +import net.minecraft.util.EnumChatFormatting.GREEN +import net.minecraft.util.EnumChatFormatting.RED +import org.lwjgl.input.Mouse + +class GuiOptionEditorUpdateCheck(option: ProcessedOption) : GuiOptionEditor(option) { + val button = GuiElementButton("", -1) { } + + override fun render(x: Int, y: Int, width: Int) { + val fr = Minecraft.getMinecraft().fontRendererObj + + GlStateManager.pushMatrix() + GlStateManager.translate(x.toFloat() + 10, y.toFloat(), 1F) + val width = width - 20 + val nextVersion = UpdateManager.getNextVersion() + + button.text = when (UpdateManager.updateState) { + UpdateManager.UpdateState.AVAILABLE -> "Download update" + UpdateManager.UpdateState.QUEUED -> "Downloading..." + UpdateManager.UpdateState.DOWNLOADED -> "Downloaded" + UpdateManager.UpdateState.NONE -> if (nextVersion == null) "Check for Updates" else "Up to date" + } + button.render(getButtonPosition(width), 10) + + if (UpdateManager.updateState == UpdateManager.UpdateState.DOWNLOADED) { + TextRenderUtils.drawStringCentered( + "${GREEN}The update will be installed after your next restart.", + fr, + width / 2F, + 40F, + true, + -1 + ) + } + + val widthRemaining = width - button.width - 10 + + GlStateManager.scale(2F, 2F, 1F) + TextRenderUtils.drawStringCenteredScaledMaxWidth( + "${if (UpdateManager.updateState == UpdateManager.UpdateState.NONE) GREEN else RED}${UpdateManager.getCurrentVersion()}" + + if (nextVersion != null) "➜ ${GREEN}${nextVersion}" else "", + fr, + widthRemaining / 4F, + 10F, + true, + widthRemaining / 2, + -1 + ) + + GlStateManager.popMatrix() + } + + fun getButtonPosition(width: Int) = width - button.width + override fun getHeight(): Int { + return 55 + } + + override fun mouseInput(x: Int, y: Int, width: Int, mouseX: Int, mouseY: Int): Boolean { + val width = width - 20 + if (Mouse.getEventButtonState()) { + if ((mouseX - getButtonPosition(width) - x) in (0..button.width) && (mouseY - 10 - y) in (0..button.height)) { + when (UpdateManager.updateState) { + UpdateManager.UpdateState.AVAILABLE -> UpdateManager.queueUpdate() + UpdateManager.UpdateState.QUEUED -> {} + UpdateManager.UpdateState.DOWNLOADED -> {} + UpdateManager.UpdateState.NONE -> UpdateManager.checkUpdate() + } + return true + } + } + return false + } + + override fun keyboardInput(): Boolean { + return false + } + + override fun fulfillsSearch(word: String): Boolean { + return super.fulfillsSearch(word) || word in "download" || word in "update" + } +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/update/UpdateManager.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/update/UpdateManager.kt new file mode 100644 index 000000000..adb130a76 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/update/UpdateManager.kt @@ -0,0 +1,128 @@ +package at.hannibal2.skyhanni.features.misc.update + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.features.About +import at.hannibal2.skyhanni.events.ConfigLoadEvent +import at.hannibal2.skyhanni.utils.LorenzUtils +import io.github.moulberry.moulconfig.processor.MoulConfigProcessor +import io.github.moulberry.notenoughupdates.util.MinecraftExecutor +import moe.nea.libautoupdate.* +import net.minecraft.client.Minecraft +import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import net.minecraftforge.fml.common.gameevent.TickEvent +import java.util.concurrent.CompletableFuture + +object UpdateManager { + + private val logger = SkyHanniMod.getLogger("UpdateManager") + private var _activePromise: CompletableFuture<*>? = null + private var activePromise: CompletableFuture<*>? + get() = _activePromise + set(value) { + _activePromise?.cancel(true) + _activePromise = value + } + + var updateState: UpdateState = UpdateState.NONE + private set + + fun getNextVersion(): String? { + return potentialUpdate?.update?.versionNumber?.asString + } + + @SubscribeEvent + fun onConfigLoad(event: ConfigLoadEvent) { + SkyHanniMod.feature.about.updateStream.whenChanged { oldValue, newValue -> + if (oldValue != newValue) + reset() + } + } + + @SubscribeEvent + fun onPlayerAvailableOnce(event: TickEvent.ClientTickEvent) { + val p = Minecraft.getMinecraft().thePlayer ?: return + MinecraftForge.EVENT_BUS.unregister(this) + if (config.autoUpdates) + checkUpdate() + } + + fun getCurrentVersion(): String { + return SkyHanniMod.getVersion() + } + + fun injectConfigProcessor(processor: MoulConfigProcessor<*>) { + processor.registerConfigEditor(ConfigVersionDisplay::class.java) { option, _ -> + GuiOptionEditorUpdateCheck(option) + } + } + + fun isBetaRelease(): Boolean { + return getCurrentVersion().contains("beta", ignoreCase = true) + } + + val config get() = SkyHanniMod.feature.about + + fun reset() { + updateState = UpdateState.NONE + _activePromise = null + potentialUpdate = null + logger.info("Reset update state") + } + + fun checkUpdate() { + if (updateState != UpdateState.NONE) { + logger.error("Trying to perform update check while another update is already in progress") + return + } + logger.info("Starting update check") + var updateStream = config.updateStream.get() + if (updateStream == About.UpdateStream.RELEASES && isBetaRelease()) { + updateStream = About.UpdateStream.BETA + } + activePromise = context.checkUpdate(updateStream.stream) + .thenAcceptAsync({ + logger.info("Update check completed") + if (updateState != UpdateState.NONE) { + logger.warn("This appears to be the second update check. Ignoring this one") + return@thenAcceptAsync + } + potentialUpdate = it + if (it.isUpdateAvailable) { + updateState = UpdateState.AVAILABLE + LorenzUtils.chat("§e[SkyHanni] §aSkyhanni found a new update: ${it.update.versionName}. Go check §b/sh download update §afor more info.") + } + }, MinecraftExecutor.OnThread) + } + + fun queueUpdate() { + if (updateState != UpdateState.AVAILABLE) { + logger.error("Trying to enqueue an update while another one is already downloaded or none is present") + } + updateState = UpdateState.QUEUED + activePromise = CompletableFuture.supplyAsync { + logger.info("Update download started") + potentialUpdate!!.prepareUpdate() + }.thenAcceptAsync({ + logger.info("Update download completed, setting exit hook") + updateState = UpdateState.DOWNLOADED + potentialUpdate!!.executeUpdate() + }, MinecraftExecutor.OnThread) + } + + val context = UpdateContext( + UpdateSource.githubUpdateSource("hannibal002", "Skyhanni"), + UpdateTarget.deleteAndSaveInTheSameFolder(UpdateManager::class.java), + CurrentVersion.ofTag(SkyHanniMod.getVersion()), + SkyHanniMod.MODID, + ) + + enum class UpdateState { + AVAILABLE, + QUEUED, + DOWNLOADED, + NONE + } + + var potentialUpdate: PotentialUpdate? = null +}
\ No newline at end of file diff --git a/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt b/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt index 1f03ed837..ff0c7a1ea 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/APIUtil.kt @@ -22,7 +22,7 @@ object APIUtil { private var showApiErrors = false val builder: HttpClientBuilder = - HttpClients.custom().setUserAgent("SkyHanni/${SkyHanniMod.VERSION}") + HttpClients.custom().setUserAgent("SkyHanni/${SkyHanniMod.getVersion()}") .setDefaultHeaders( mutableListOf( BasicHeader("Pragma", "no-cache"), |