diff --git a/pom.xml b/pom.xml
index 96faaa218..76e3165d2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,7 +74,7 @@
1.7
1.7
2.10.5
- d5f5e0bbd8
+ e7597818f5
3.0-SNAPSHOT
7.0.0
diff --git a/src/main/java/world/bentobox/bentobox/Settings.java b/src/main/java/world/bentobox/bentobox/Settings.java
index 02d45db15..143116dc8 100644
--- a/src/main/java/world/bentobox/bentobox/Settings.java
+++ b/src/main/java/world/bentobox/bentobox/Settings.java
@@ -273,12 +273,17 @@ public class Settings implements ConfigObject {
@ConfigEntry(path = "web.github.connection-interval", since = "1.5.0")
private int githubConnectionInterval = 120;
- @ConfigEntry(path = "web.updater.check-updates.bentobox", since = "1.3.0", hidden = true)
+ @ConfigComment("Checks for BentoBox updates.")
+ @ConfigEntry(path = "web.updater.check-updates.bentobox", since = "1.14.0")
private boolean checkBentoBoxUpdates = true;
- @ConfigEntry(path = "web.updater.check-updates.addons", since = "1.3.0", hidden = true)
+ @ConfigComment("Checks for addons updates.")
+ @ConfigEntry(path = "web.updater.check-updates.addons", since = "1.14.0")
private boolean checkAddonsUpdates = true;
+ @ConfigEntry(path = "web.updater.check-updates.include-prereleases", since = "1.14.0")
+ private boolean checkPreReleasesUpdates = false;
+
// ---------------------------------------------
// Getters and setters
@@ -713,4 +718,12 @@ public class Settings implements ConfigObject {
public void setPanelFillerMaterial(Material panelFillerMaterial) {
this.panelFillerMaterial = panelFillerMaterial;
}
+
+ public boolean isCheckPreReleasesUpdates() {
+ return checkPreReleasesUpdates;
+ }
+
+ public void setCheckPreReleasesUpdates(boolean checkPreReleasesUpdates) {
+ this.checkPreReleasesUpdates = checkPreReleasesUpdates;
+ }
}
diff --git a/src/main/java/world/bentobox/bentobox/commands/BentoBoxVersionCommand.java b/src/main/java/world/bentobox/bentobox/commands/BentoBoxVersionCommand.java
index db9befa94..38a07bf0f 100644
--- a/src/main/java/world/bentobox/bentobox/commands/BentoBoxVersionCommand.java
+++ b/src/main/java/world/bentobox/bentobox/commands/BentoBoxVersionCommand.java
@@ -6,6 +6,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Optional;
+import javafx.scene.text.Text;
import org.bukkit.Bukkit;
import world.bentobox.bentobox.api.addons.GameModeAddon;
@@ -14,6 +15,7 @@ import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.versions.ServerCompatibility;
import world.bentobox.bentobox.versions.ServerCompatibility.ServerSoftware;
+import world.bentobox.bentobox.versions.UpdateChecker;
/**
* Displays information about Gamemodes, Addons and versioning.
@@ -85,6 +87,22 @@ public class BentoBoxVersionCommand extends CompositeCommand {
.forEach(a -> user.sendMessage("commands.bentobox.version.addon-syntax", TextVariables.NAME, a.getDescription().getName(),
TextVariables.VERSION, a.getDescription().getVersion(), "[state]", a.getState().toString()));
+ long availableUpdates = getPlugin().getWebManager().getUpdateCheckers().stream()
+ .filter(updateChecker -> updateChecker.getResult() != null)
+ .count();
+
+ if (availableUpdates > 0) {
+ user.sendMessage("commands.bentobox.version.available-updates", TextVariables.NUMBER, String.valueOf(availableUpdates));
+ for (UpdateChecker updateChecker : getPlugin().getWebManager().getUpdateCheckers()) {
+ UpdateChecker.Result result = updateChecker.getResult();
+ if (result != null) {
+ user.sendMessage("commands.bentobox.version.update", "[repo]", updateChecker.getRepository(),
+ TextVariables.VERSION, result.getVersion(),
+ "[link]", "https://github.com/" + updateChecker.getRepository() + "/releases/tag/" + result.getVersion());
+ }
+ }
+ }
+
return true;
}
}
diff --git a/src/main/java/world/bentobox/bentobox/listeners/JoinLeaveListener.java b/src/main/java/world/bentobox/bentobox/listeners/JoinLeaveListener.java
index 889fa7085..7e2112f81 100644
--- a/src/main/java/world/bentobox/bentobox/listeners/JoinLeaveListener.java
+++ b/src/main/java/world/bentobox/bentobox/listeners/JoinLeaveListener.java
@@ -89,8 +89,22 @@ public class JoinLeaveListener implements Listener {
// Clear inventory if required
clearPlayersInventory(Util.getWorld(event.getPlayer().getWorld()), user);
+
+ // Notify player about updates
+ notifyUpdates(user);
}
+ private void notifyUpdates(User user) {
+ if (user.hasPermission("bentobox.notify-updates")) {
+ long availableUpdates = plugin.getWebManager().getUpdateCheckers().stream()
+ .filter(updateChecker -> updateChecker.getResult() != null)
+ .count();
+
+ if (availableUpdates > 0) {
+ user.sendMessage("updates-available");
+ }
+ }
+ }
private void firstTime(User user) {
// Make sure the player is loaded into the cache or create the player if they don't exist
diff --git a/src/main/java/world/bentobox/bentobox/managers/WebManager.java b/src/main/java/world/bentobox/bentobox/managers/WebManager.java
index e8450c2d3..8b0fbf020 100644
--- a/src/main/java/world/bentobox/bentobox/managers/WebManager.java
+++ b/src/main/java/world/bentobox/bentobox/managers/WebManager.java
@@ -10,6 +10,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
+import io.github.TheBusyBiscuit.GitHubWebAPI4Java.objects.users.GitHubOrganization;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
@@ -23,6 +24,7 @@ import io.github.TheBusyBiscuit.GitHubWebAPI4Java.objects.repositories.GitHubCon
import io.github.TheBusyBiscuit.GitHubWebAPI4Java.objects.repositories.GitHubRepository;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.Settings;
+import world.bentobox.bentobox.versions.UpdateChecker;
import world.bentobox.bentobox.web.catalog.CatalogEntry;
import world.bentobox.bentobox.web.credits.Contributor;
@@ -34,17 +36,21 @@ import world.bentobox.bentobox.web.credits.Contributor;
*/
public class WebManager {
- private @NonNull BentoBox plugin;
+ private @NonNull final BentoBox plugin;
private @Nullable GitHubWebAPI gitHub;
- private @NonNull List addonsCatalog;
- private @NonNull List gamemodesCatalog;
- private @NonNull Map> contributors;
+ private @NonNull final List addonsCatalog;
+ private @NonNull final List gamemodesCatalog;
+ private @NonNull final Map> contributors;
+
+ @NonNull
+ private final List updateCheckers;
public WebManager(@NonNull BentoBox plugin) {
this.plugin = plugin;
this.addonsCatalog = new ArrayList<>();
this.gamemodesCatalog = new ArrayList<>();
this.contributors = new HashMap<>();
+ this.updateCheckers = new ArrayList<>();
// Setup the GitHub connection
if (plugin.getSettings().isGithubDownloadData()) {
@@ -100,12 +106,14 @@ public class WebManager {
.stream().map(addon -> addon.getDescription().getRepository())
.filter(repo -> !repo.isEmpty())
.collect(Collectors.toList()));
+ /*
repositories.addAll(addonsCatalog.stream().map(CatalogEntry::getRepository)
.filter(repo -> !repositories.contains(repo))
.collect(Collectors.toList()));
repositories.addAll(gamemodesCatalog.stream().map(CatalogEntry::getRepository)
.filter(repo -> !repositories.contains(repo))
.collect(Collectors.toList()));
+ */
/* Download the contributors */
if (plugin.getSettings().isLogGithubDownloadData()) {
@@ -128,6 +136,13 @@ public class WebManager {
}
}
+ /* Check for updates */
+ if (plugin.getSettings().isLogGithubDownloadData()) {
+ plugin.log("Checking for updates...");
+ }
+
+ checkUpdates(gh);
+
// People were concerned that the download took ages, so we need to tell them it's over now.
if (plugin.getSettings().isLogGithubDownloadData()) {
plugin.log("Successfully downloaded data from GitHub.");
@@ -223,6 +238,36 @@ public class WebManager {
}
}
+ private void checkUpdates(@NonNull GitHubWebAPI gh) {
+ if (updateCheckers.isEmpty()) {
+ // Grab the repositories we will have to go through
+ Map repositories = new HashMap<>();
+
+ if (plugin.getSettings().isCheckBentoBoxUpdates()) {
+ repositories.put("BentoBoxWorld/BentoBox", plugin.getDescription().getVersion());
+ }
+ if (plugin.getSettings().isCheckAddonsUpdates()) {
+ repositories.putAll(plugin.getAddonsManager().getEnabledAddons()
+ .stream()
+ .filter(addon -> !addon.getDescription().getRepository().isEmpty())
+ .collect(Collectors.toMap(addon -> addon.getDescription().getRepository(), addon -> addon.getDescription().getVersion())));
+ }
+
+ for (Map.Entry repo : repositories.entrySet()) {
+ UpdateChecker updateChecker = new UpdateChecker(gh, repo.getKey(), repo.getValue());
+ updateCheckers.add(updateChecker);
+ }
+ }
+
+ for (UpdateChecker updateChecker : updateCheckers) {
+ try {
+ updateChecker.checkUpdates();
+ } catch (IllegalAccessException e) {
+ // Fail silently
+ }
+ }
+ }
+
/**
* Returns the contents of the addons catalog (may be an empty list).
* @return the contents of the addons catalog.
@@ -263,4 +308,13 @@ public class WebManager {
public Optional getGitHub() {
return Optional.ofNullable(gitHub);
}
+
+ /**
+ * Returns the list of update checkers.
+ * @return the list of update checkers.
+ * @since 1.14.0
+ */
+ public List getUpdateCheckers() {
+ return updateCheckers;
+ }
}
diff --git a/src/main/java/world/bentobox/bentobox/versions/UpdateChecker.java b/src/main/java/world/bentobox/bentobox/versions/UpdateChecker.java
new file mode 100644
index 000000000..71265c5ea
--- /dev/null
+++ b/src/main/java/world/bentobox/bentobox/versions/UpdateChecker.java
@@ -0,0 +1,111 @@
+package world.bentobox.bentobox.versions;
+
+import io.github.TheBusyBiscuit.GitHubWebAPI4Java.GitHubWebAPI;
+import io.github.TheBusyBiscuit.GitHubWebAPI4Java.objects.repositories.GitHubRelease;
+import org.eclipse.jdt.annotation.Nullable;
+import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.util.Util;
+
+import java.util.List;
+
+/**
+ * Checks for updates through the GitHub API.
+ * @author Poslovitch
+ * @since 1.14.0
+ */
+public class UpdateChecker {
+
+ private final BentoBox plugin;
+ private final GitHubWebAPI gitHub;
+ private final String repository;
+ private final String currentVersion;
+
+ @Nullable
+ private Result result;
+
+ public UpdateChecker(GitHubWebAPI gitHub, String repository, String currentVersion) {
+ this.plugin = BentoBox.getInstance();
+ this.gitHub = gitHub;
+ this.repository = repository;
+ this.currentVersion = currentVersion;
+ }
+
+ public void checkUpdates() throws IllegalAccessException {
+ String[] repo = repository.split("/");
+
+ List releases = gitHub.getRepository(repo[0], repo[1]).getReleases();
+ if (!releases.isEmpty()) {
+ for (GitHubRelease release : releases) {
+ if (release.isDraft()) {
+ // Drafts should be ignored (they're not published yet)
+ continue;
+ }
+
+ if (release.isPreRelease() && !plugin.getSettings().isCheckPreReleasesUpdates()) {
+ // We don't care about pre-releases
+ continue;
+ }
+
+ String newVersion = release.getTagName();
+ if (isMoreRecent(newVersion)) {
+ // We found the new version, and it should be the latest.
+ this.result = new Result(newVersion, release.isPreRelease());
+ break;
+ }
+ }
+ } else {
+ this.result = null;
+ }
+ }
+
+ private boolean isMoreRecent(String newVersion) {
+ String[] currentVer = currentVersion.split("\\D");
+ String[] newVer = newVersion.split("\\D");
+
+ for (int i = 0; i < currentVer.length; i++) {
+ int newVersionNumber = 0;
+ if (i < newVer.length && Util.isInteger(newVer[i], false)) {
+ newVersionNumber = Integer.parseInt(newVer[i]);
+ }
+ int currentVersionNumber = Util.isInteger(currentVer[i], false) ? Integer.parseInt(currentVer[i]) : -1;
+
+ if (newVersionNumber > currentVersionNumber) {
+ return false; // The current version is greater than the "new" version -> up to date.
+ }
+ if (newVersionNumber < currentVersionNumber) {
+ return true; // The current version is outdated
+ }
+ // If it is equal, go to the next number
+ }
+
+ return false; // Everything is equal, so return true
+ }
+
+ @Nullable
+ public Result getResult() {
+ return result;
+ }
+
+ public String getRepository() {
+ return repository;
+ }
+
+ public static class Result {
+
+ private final String version;
+ private final boolean preRelease;
+
+ public Result(String version, boolean preRelease) {
+ this.version = version;
+ this.preRelease = preRelease;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public boolean isPreRelease() {
+ return preRelease;
+ }
+ }
+}
diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml
index 667ea2202..aa7b86ac0 100644
--- a/src/main/resources/locales/en-US.yml
+++ b/src/main/resources/locales/en-US.yml
@@ -413,6 +413,8 @@ commands:
game-world: "&2 [name] &7 (&3 [addon]&7 ): &3 [worlds]"
server: "&2 Running &3 [name] [version]&2 ."
database: "&2 Database: &3 [database]"
+ available-updates: "Available updates ([number]):"
+ update: "&2 [repo] &3 [version]&7 : &e [link]"
manage:
description: "displays the Management Panel"
catalog:
@@ -1405,6 +1407,10 @@ panel:
&a Allow BentoBox to connect to GitHub in
&a the configuration or try again later.
+updates-available: |
+ [prefix_bentobox]&6 &l Update Checker
+ [prefix_bentobox]&a Updates are available. Check &b /bentobox version &a for details.
+
successfully-loaded: |
&6 ____ _ ____
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 0526bc03e..1f6f5bed3 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -39,3 +39,6 @@ permissions:
bentobox.version:
description: Allows to use /bentobox version
default: op
+ bentobox.notify-updates:
+ description: Sends players a message about available updates when they join the server
+ default: op