From 86c42f4dd2216504351b89e4e9cb99991e9c9dcd Mon Sep 17 00:00:00 2001 From: Daniel She Date: Sat, 2 Feb 2019 01:16:40 +0800 Subject: Update Checker (#25) * WIP Update Checker (Not working) * Pushed this for testing * Working as intended --- .../me/shedaniel/rei/RoughlyEnoughItemsCore.java | 5 + .../java/me/shedaniel/rei/client/ConfigHelper.java | 4 + .../java/me/shedaniel/rei/client/REIConfig.java | 1 + .../me/shedaniel/rei/update/UpdateChecker.java | 202 +++++++++++++++++++++ .../me/shedaniel/rei/update/UpdatePriority.java | 13 ++ src/main/java/me/shedaniel/rei/update/Version.java | 49 +++++ 6 files changed, 274 insertions(+) create mode 100644 src/main/java/me/shedaniel/rei/update/UpdateChecker.java create mode 100644 src/main/java/me/shedaniel/rei/update/UpdatePriority.java create mode 100644 src/main/java/me/shedaniel/rei/update/Version.java (limited to 'src/main/java/me/shedaniel') diff --git a/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java b/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java index 308f3d571..fcfaa961e 100644 --- a/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java +++ b/src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java @@ -7,6 +7,7 @@ import me.shedaniel.rei.client.ConfigHelper; import me.shedaniel.rei.client.GuiHelper; import me.shedaniel.rei.client.RecipeHelper; import me.shedaniel.rei.plugin.DefaultPlugin; +import me.shedaniel.rei.update.UpdateChecker; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ModInitializer; import net.fabricmc.api.loader.Loader; @@ -75,6 +76,10 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer, ModInitiali configHelper = new ConfigHelper(); ClientTickEvent.CLIENT.register(GuiHelper::onTick); + if (getConfigHelper().checkUpdates()) + ClientTickEvent.CLIENT.register(UpdateChecker::onTick); + + new UpdateChecker().onInitializeClient(); } @Override diff --git a/src/main/java/me/shedaniel/rei/client/ConfigHelper.java b/src/main/java/me/shedaniel/rei/client/ConfigHelper.java index 68af75008..41996052e 100644 --- a/src/main/java/me/shedaniel/rei/client/ConfigHelper.java +++ b/src/main/java/me/shedaniel/rei/client/ConfigHelper.java @@ -103,4 +103,8 @@ public class ConfigHelper { config.sideSearchField = sideSearchField; } + public boolean checkUpdates() { + return config.checkUpdates; + } + } diff --git a/src/main/java/me/shedaniel/rei/client/REIConfig.java b/src/main/java/me/shedaniel/rei/client/REIConfig.java index 49ccb1dec..cdb5df330 100644 --- a/src/main/java/me/shedaniel/rei/client/REIConfig.java +++ b/src/main/java/me/shedaniel/rei/client/REIConfig.java @@ -12,5 +12,6 @@ public class REIConfig { public boolean enableCraftableOnlyButton = true; public boolean sideSearchField = false; public String giveCommandPrefix = "/give"; + public boolean checkUpdates = true; } diff --git a/src/main/java/me/shedaniel/rei/update/UpdateChecker.java b/src/main/java/me/shedaniel/rei/update/UpdateChecker.java new file mode 100644 index 000000000..9c60d9e6b --- /dev/null +++ b/src/main/java/me/shedaniel/rei/update/UpdateChecker.java @@ -0,0 +1,202 @@ +package me.shedaniel.rei.update; + +import com.google.common.collect.Lists; +import com.google.gson.*; +import com.google.gson.annotations.SerializedName; +import me.shedaniel.rei.RoughlyEnoughItemsCore; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.loader.FabricLoader; +import net.fabricmc.loader.ModContainer; +import net.minecraft.SharedConstants; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.text.StringTextComponent; +import net.minecraft.world.World; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringBufferInputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.stream.Collectors; + +public class UpdateChecker implements ClientModInitializer { + + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + private static Version currentVersion = null, latestForGame = null; + private static JsonVersionElement element; + private static World lastWorld = null; + private static String VERSION_STRING = "https://raw.githubusercontent.com/shedaniel/RoughlyEnoughItems/1.14/version.json"; + + public static boolean isOutdated() { + return latestForGame.compareTo(currentVersion) == 1 && currentVersion != null; + } + + public static UpdatePriority getUpdatePriority(List versions) { + UpdatePriority p = UpdatePriority.NONE; + List priorities = Arrays.asList(UpdatePriority.values()); + for(UpdatePriority priority : versions.stream().map(UpdateChecker::getUpdatePriority).collect(Collectors.toList())) + if (priority.compareTo(p) > 0) + p = priority; + return p; + } + + public static UpdatePriority getUpdatePriority(Version version) { + JsonArray array = element.getChangelogs().getFabric(); + for(JsonElement element : array) { + JsonObject jsonObject = element.getAsJsonObject(); + if (jsonObject.has("version") && jsonObject.get("version").getAsString().equals(version.toString())) + return UpdatePriority.fromString(jsonObject.get("level").getAsString()); + } + return UpdatePriority.NONE; + } + + public static boolean checkUpdates() { + return RoughlyEnoughItemsCore.getConfigHelper().checkUpdates(); + } + + public static List getChangelog(Version currentVersion) { + List changelogs = Lists.newLinkedList(); + JsonArray array = element.getChangelogs().getFabric(); + array.forEach(jsonElement -> { + JsonObject jsonObject = jsonElement.getAsJsonObject(); + Version jsonVersion = new Version(jsonObject.get("version").getAsString()); + if (jsonVersion.compareTo(currentVersion) > 0 && jsonVersion.compareTo(latestForGame) <= 0) + changelogs.add(I18n.translate("text.rei.update_changelog_line", jsonObject.get("text").getAsString())); + }); + return changelogs; + } + + public static Version getCurrentVersion() { + return currentVersion; + } + + public static Version getLatestForGame() { + return latestForGame; + } + + public static void onTick(MinecraftClient client) { + if (client.world != lastWorld) { + lastWorld = client.world; + if (lastWorld != null) { + if (checkUpdates() && isOutdated()) { + String currentVersionString = getCurrentVersion() == null ? "null" : getCurrentVersion().toString(); + List versions = getVersionsHigherThan(currentVersion); + String t[] = I18n.translate("text.rei.update_outdated", currentVersionString, getLatestForGame(), getUpdatePriority(versions).name().toUpperCase()).split("\n"); + for(String s : t) + client.player.addChatMessage(new StringTextComponent(s), false); + getChangelog(currentVersion).forEach(s -> client.player.addChatMessage(new StringTextComponent(s), false)); + } + } + } + } + + private static List getVersionsHigherThan(Version currentVersion) { + List versions = Lists.newLinkedList(); + JsonArray array = element.getChangelogs().getFabric(); + array.forEach(jsonElement -> { + Version jsonVersion = new Version(jsonElement.getAsJsonObject().get("version").getAsString()); + if (jsonVersion.compareTo(currentVersion) > 0) + versions.add(jsonVersion); + }); + return versions; + } + + @Override + public void onInitializeClient() { + if (!checkUpdates()) + return; + FabricLoader.INSTANCE.getMods().stream().map(ModContainer::getInfo).forEach(modInfo -> { + if (modInfo.getId().equals("roughlyenoughitems")) + try { + currentVersion = new Version(modInfo.getVersionString()); + } catch (Exception e) { + } + }); + InputStream downloadedStream = downloadVersionString(); + String downloadedString = null; + try { + downloadedString = IOUtils.toString(downloadedStream, StandardCharsets.UTF_8); + element = GSON.fromJson(downloadedString, JsonVersionElement.class); + } catch (IOException e) { + e.printStackTrace(); + } + if (downloadedString != null && !downloadedString.equalsIgnoreCase("{}")) + latestForGame = new Version(parseLatest(element, SharedConstants.getGameVersion().getName())); + else latestForGame = new Version("0.0.0"); + } + + private InputStream downloadVersionString() { + try { + URL versionUrl = new URL(VERSION_STRING); + return versionUrl.openStream(); + } catch (IOException e) { + return new StringBufferInputStream("{}"); + } + } + + private String parseLatest(JsonVersionElement element, String gameVersion) { + List objects = new LinkedList<>(element.getLatestVersions()); + for(int i = objects.size() - 1; i >= 0; i--) + if (objects.get(i).getGameVersion().equals(gameVersion)) + return objects.get(i).getModVersion(); + return objects.get(objects.size() - 1).getModVersion(); + } + + private class JsonVersionElement { + @SerializedName("latest") + private List latestVersions; + private ChangelogObject changelogs; + + public JsonVersionElement() { + this.latestVersions = Lists.newArrayList(); + changelogs = new ChangelogObject(); + } + + public List getLatestVersions() { + return latestVersions; + } + + public ChangelogObject getChangelogs() { + return changelogs; + } + } + + private class LatestVersionObject { + @SerializedName("game") + private String gameVersion = ""; + @SerializedName("mod") + private String modVersion = ""; + + public String getGameVersion() { + return gameVersion; + } + + public String getModVersion() { + return modVersion; + } + + @Override + public String toString() { + return String.format("LatestVersion[%s] = %s", getGameVersion(), getModVersion()); + } + } + + private class ChangelogObject { + private JsonArray fabric = new JsonArray(); + private JsonArray rift = new JsonArray(); + + public JsonArray getFabric() { + return fabric; + } + + public JsonArray getRift() { + return rift; + } + } + +} diff --git a/src/main/java/me/shedaniel/rei/update/UpdatePriority.java b/src/main/java/me/shedaniel/rei/update/UpdatePriority.java new file mode 100644 index 000000000..433cf2fca --- /dev/null +++ b/src/main/java/me/shedaniel/rei/update/UpdatePriority.java @@ -0,0 +1,13 @@ +package me.shedaniel.rei.update; + +import java.util.Arrays; + +public enum UpdatePriority { + + NONE, LIGHT, NORMAL, USEFUL, IMPORTANT; + + public static UpdatePriority fromString(String string) { + return Arrays.stream(values()).filter(updatePriority -> updatePriority.name().toLowerCase().equals(string)).findFirst().orElse(NONE); + } + +} diff --git a/src/main/java/me/shedaniel/rei/update/Version.java b/src/main/java/me/shedaniel/rei/update/Version.java new file mode 100644 index 000000000..a60086fac --- /dev/null +++ b/src/main/java/me/shedaniel/rei/update/Version.java @@ -0,0 +1,49 @@ +package me.shedaniel.rei.update; + +public class Version implements Comparable { + + private String version; + + public Version(String version) { + if (version == null) + throw new IllegalArgumentException("Version can not be null"); + if (!version.matches("[0-9]+(\\.[0-9]+)*")) + throw new IllegalArgumentException("Invalid version format"); + this.version = version; + } + + @Override + public final String toString() { + return this.version; + } + + @Override + public int compareTo(Version other) { + if (other == null) + return 1; + String[] thisParts = this.toString().split("\\."); + String[] thatParts = other.toString().split("\\."); + int length = Math.max(thisParts.length, thatParts.length); + for(int i = 0; i < length; i++) { + int thisPart = i < thisParts.length ? Integer.parseInt(thisParts[i]) : 0; + int thatPart = i < thatParts.length ? Integer.parseInt(thatParts[i]) : 0; + if (thisPart < thatPart) + return -1; + if (thisPart > thatPart) + return 1; + } + return 0; + } + + @Override + public boolean equals(Object that) { + if (this == that) + return true; + if (that == null) + return false; + if (this.getClass() != that.getClass()) + return false; + return this.compareTo((Version) that) == 0; + } + +} -- cgit