mirror of
https://github.com/WiIIiam278/HuskSync.git
synced 2025-12-31 04:36:45 +00:00
Migrate to DesertWell for about menu, version checking
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package net.william278.husksync;
|
||||
|
||||
import net.william278.desertwell.UpdateChecker;
|
||||
import net.william278.husksync.config.Locales;
|
||||
import net.william278.husksync.config.Settings;
|
||||
import net.william278.husksync.data.DataAdapter;
|
||||
@@ -11,7 +12,7 @@ import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.redis.RedisManager;
|
||||
import net.william278.husksync.util.Logger;
|
||||
import net.william278.husksync.util.ResourceReader;
|
||||
import net.william278.husksync.util.Version;
|
||||
import net.william278.desertwell.Version;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
@@ -25,6 +26,8 @@ import java.util.concurrent.CompletableFuture;
|
||||
*/
|
||||
public interface HuskSync {
|
||||
|
||||
int SPIGOT_RESOURCE_ID = 97144;
|
||||
|
||||
/**
|
||||
* Returns a set of online players.
|
||||
*
|
||||
@@ -131,6 +134,22 @@ public interface HuskSync {
|
||||
@NotNull
|
||||
Version getPluginVersion();
|
||||
|
||||
/**
|
||||
* Returns a future returning the latest plugin {@link Version} if the plugin is out-of-date
|
||||
*
|
||||
* @return a {@link CompletableFuture} returning the latest {@link Version} if the current one is out-of-date
|
||||
*/
|
||||
default CompletableFuture<Optional<Version>> getLatestVersionIfOutdated() {
|
||||
final UpdateChecker updateChecker = UpdateChecker.create(getPluginVersion(), SPIGOT_RESOURCE_ID);
|
||||
return updateChecker.isUpToDate().thenApply(upToDate -> {
|
||||
if (upToDate) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return Optional.of(updateChecker.getLatestVersion().join());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Minecraft version implementation
|
||||
*
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package net.william278.husksync.command;
|
||||
|
||||
import de.themoep.minedown.MineDown;
|
||||
import net.william278.desertwell.AboutMenu;
|
||||
import net.william278.husksync.HuskSync;
|
||||
import net.william278.husksync.config.Locales;
|
||||
import net.william278.husksync.migrator.Migrator;
|
||||
import net.william278.husksync.player.OnlineUser;
|
||||
import net.william278.husksync.util.UpdateChecker;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -17,16 +16,41 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class HuskSyncCommand extends CommandBase implements TabCompletable, ConsoleExecutable {
|
||||
|
||||
private final String[] COMMAND_ARGUMENTS = {"update", "about", "reload", "migrate"};
|
||||
private final String[] SUB_COMMANDS = {"update", "about", "reload", "migrate"};
|
||||
private final AboutMenu aboutMenu;
|
||||
|
||||
public HuskSyncCommand(@NotNull HuskSync implementor) {
|
||||
super("husksync", Permission.COMMAND_HUSKSYNC, implementor);
|
||||
this.aboutMenu = AboutMenu.create("HuskSync")
|
||||
.withDescription("A modern, cross-server player data synchronization system")
|
||||
.withVersion(implementor.getPluginVersion())
|
||||
.addAttribution("Author",
|
||||
AboutMenu.Credit.of("William278").withDescription("Click to visit website").withUrl("https://william278.net"))
|
||||
.addAttribution("Contributors",
|
||||
AboutMenu.Credit.of("HarvelsX").withDescription("Code"),
|
||||
AboutMenu.Credit.of("HookWoods").withDescription("Code"))
|
||||
.addAttribution("Translators",
|
||||
AboutMenu.Credit.of("Namiu").withDescription("Japanese (ja-jp)"),
|
||||
AboutMenu.Credit.of("anchelthe").withDescription("Spanish (es-es)"),
|
||||
AboutMenu.Credit.of("Melonzio").withDescription("Spanish (es-es)"),
|
||||
AboutMenu.Credit.of("Ceddix").withDescription("German (de-de)"),
|
||||
AboutMenu.Credit.of("Pukejoy_1").withDescription("Bulgarian (bg-bg)"),
|
||||
AboutMenu.Credit.of("mateusneresrb").withDescription("Brazilian Portuguese (pt-br)"),
|
||||
AboutMenu.Credit.of("小蔡").withDescription("Traditional Chinese (zh-tw)"),
|
||||
AboutMenu.Credit.of("Ghost-chu").withDescription("Simplified Chinese (zh-cn)"),
|
||||
AboutMenu.Credit.of("DJelly4K").withDescription("Simplified Chinese (zh-cn)"),
|
||||
AboutMenu.Credit.of("Thourgard").withDescription("Ukrainian (uk-ua)"),
|
||||
AboutMenu.Credit.of("xF3d3").withDescription("Italian (it-it)"))
|
||||
.addButtons(
|
||||
AboutMenu.Link.of("https://william278.net/docs/husksync").withText("Documentation").withIcon("⛏"),
|
||||
AboutMenu.Link.of("https://github.com/WiIIiam278/HuskSync/issues").withText("Issues").withIcon("❌").withColor("#ff9f0f"),
|
||||
AboutMenu.Link.of("https://discord.gg/tVYhJfyDWG").withText("Discord").withIcon("⭐").withColor("#6773f5"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExecute(@NotNull OnlineUser player, @NotNull String[] args) {
|
||||
if (args.length < 1) {
|
||||
displayPluginInformation(player);
|
||||
sendAboutMenu(player);
|
||||
return;
|
||||
}
|
||||
switch (args[0].toLowerCase()) {
|
||||
@@ -35,18 +59,16 @@ public class HuskSyncCommand extends CommandBase implements TabCompletable, Cons
|
||||
plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
final UpdateChecker updateChecker = new UpdateChecker(plugin.getPluginVersion(), plugin.getLoggingAdapter());
|
||||
updateChecker.fetchLatestVersion().thenAccept(latestVersion -> {
|
||||
if (updateChecker.isUpdateAvailable(latestVersion)) {
|
||||
player.sendMessage(new MineDown("[HuskSync](#00fb9a bold) [| A new update is available:](#00fb9a) [HuskSync " + latestVersion + "](#00fb9a bold)" +
|
||||
"[•](white) [Currently running:](#00fb9a) [Version " + updateChecker.getCurrentVersion() + "](gray)" +
|
||||
"[•](white) [Download links:](#00fb9a) [[⏩ Spigot]](gray open_url=https://www.spigotmc.org/resources/husksync.97144/updates) [•](#262626) [[⏩ Polymart]](gray open_url=https://polymart.org/resource/husksync.1634/updates) [•](#262626) [[⏩ Songoda]](gray open_url=https://songoda.com/marketplace/product/husksync-a-modern-cross-server-player-data-synchronization-system.758)"));
|
||||
} else {
|
||||
player.sendMessage(new MineDown("[HuskSync](#00fb9a bold) [| HuskSync is up-to-date, running version " + updateChecker.getCurrentVersion() + "](#00fb9a)"));
|
||||
}
|
||||
});
|
||||
plugin.getLatestVersionIfOutdated().thenAccept(newestVersion ->
|
||||
newestVersion.ifPresentOrElse(
|
||||
newVersion -> player.sendMessage(
|
||||
new MineDown("[HuskSync](#00fb9a bold) [| A new version of HuskSync is available!"
|
||||
+ " (v" + newVersion + " (Running: v" + plugin.getPluginVersion() + ")](#00fb9a)")),
|
||||
() -> player.sendMessage(
|
||||
new MineDown("[HuskSync](#00fb9a bold) [| HuskSync is up-to-date."
|
||||
+ " (Running: v" + plugin.getPluginVersion() + ")](#00fb9a)"))));
|
||||
}
|
||||
case "info", "about" -> displayPluginInformation(player);
|
||||
case "about", "info" -> sendAboutMenu(player);
|
||||
case "reload" -> {
|
||||
if (!player.hasPermission(Permission.COMMAND_HUSKSYNC_RELOAD.node)) {
|
||||
plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage);
|
||||
@@ -70,11 +92,14 @@ public class HuskSyncCommand extends CommandBase implements TabCompletable, Cons
|
||||
return;
|
||||
}
|
||||
switch (args[0].toLowerCase()) {
|
||||
case "update", "version" ->
|
||||
new UpdateChecker(plugin.getPluginVersion(), plugin.getLoggingAdapter()).logToConsole();
|
||||
case "info", "about" ->
|
||||
plugin.getLoggingAdapter().log(Level.INFO, new MineDown(plugin.getLocales().stripMineDown(
|
||||
Locales.PLUGIN_INFORMATION.replace("%version%", plugin.getPluginVersion().toString()))));
|
||||
case "update", "version" -> plugin.getLatestVersionIfOutdated().thenAccept(newestVersion ->
|
||||
newestVersion.ifPresentOrElse(newVersion -> plugin.getLoggingAdapter().log(Level.WARNING,
|
||||
"An update is available for HuskSync, v" + newVersion
|
||||
+ " (Running v" + plugin.getPluginVersion() + ")"),
|
||||
() -> plugin.getLoggingAdapter().log(Level.INFO,
|
||||
"HuskSync is up to date" +
|
||||
" (Running v" + plugin.getPluginVersion() + ")")));
|
||||
case "about", "info" -> aboutMenu.toString().lines().forEach(plugin.getLoggingAdapter()::info);
|
||||
case "reload" -> {
|
||||
plugin.reload();
|
||||
plugin.getLoggingAdapter().log(Level.INFO, "Reloaded config & message files.");
|
||||
@@ -108,7 +133,7 @@ public class HuskSyncCommand extends CommandBase implements TabCompletable, Cons
|
||||
}, () -> {
|
||||
plugin.getLoggingAdapter().log(Level.INFO,
|
||||
"Please specify a valid migrator.\n" +
|
||||
"If a migrator is not available, please verify that you meet the prerequisites to use it.");
|
||||
"If a migrator is not available, please verify that you meet the prerequisites to use it.");
|
||||
logMigratorsList();
|
||||
});
|
||||
}
|
||||
@@ -120,26 +145,26 @@ public class HuskSyncCommand extends CommandBase implements TabCompletable, Cons
|
||||
private void logMigratorsList() {
|
||||
plugin.getLoggingAdapter().log(Level.INFO,
|
||||
"List of available migrators:\nMigrator ID / Migrator Name:\n" +
|
||||
plugin.getAvailableMigrators().stream()
|
||||
.map(migrator -> migrator.getIdentifier() + " - " + migrator.getName())
|
||||
.collect(Collectors.joining("\n")));
|
||||
plugin.getAvailableMigrators().stream()
|
||||
.map(migrator -> migrator.getIdentifier() + " - " + migrator.getName())
|
||||
.collect(Collectors.joining("\n")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull String[] args) {
|
||||
if (args.length <= 1) {
|
||||
return Arrays.stream(COMMAND_ARGUMENTS)
|
||||
return Arrays.stream(SUB_COMMANDS)
|
||||
.filter(argument -> argument.startsWith(args.length >= 1 ? args[0] : ""))
|
||||
.sorted().collect(Collectors.toList());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private void displayPluginInformation(@NotNull OnlineUser player) {
|
||||
if (!player.hasPermission(Permission.COMMAND_HUSKSYNC_INFO.node)) {
|
||||
private void sendAboutMenu(@NotNull OnlineUser player) {
|
||||
if (!player.hasPermission(Permission.COMMAND_HUSKSYNC_ABOUT.node)) {
|
||||
plugin.getLocales().getLocale("error_no_permission").ifPresent(player::sendMessage);
|
||||
return;
|
||||
}
|
||||
player.sendMessage(new MineDown(Locales.PLUGIN_INFORMATION.replace("%version%", plugin.getPluginVersion().toString())));
|
||||
player.sendMessage(aboutMenu.toMineDown());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public enum Permission {
|
||||
/**
|
||||
* Lets the user view plugin info {@code /husksync info}
|
||||
*/
|
||||
COMMAND_HUSKSYNC_INFO("husksync.command.husksync.info", DefaultAccess.EVERYONE),
|
||||
COMMAND_HUSKSYNC_ABOUT("husksync.command.husksync.info", DefaultAccess.EVERYONE),
|
||||
/**
|
||||
* Lets the user reload the plugin {@code /husksync reload}
|
||||
*/
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -14,16 +13,6 @@ import java.util.regex.Pattern;
|
||||
*/
|
||||
public class Locales {
|
||||
|
||||
public static final String PLUGIN_INFORMATION = """
|
||||
[HuskSync](#00fb9a bold) [| Version %version%](#00fb9a)
|
||||
[A modern, cross-server player data synchronization system](gray)
|
||||
[• Author:](white) [William278](gray show_text=&7Click to visit website open_url=https://william278.net)
|
||||
[• Contributors:](white) [HarvelsX](gray show_text=&7Code), [HookWoods](gray show_text=&7Code)
|
||||
[• Translators:](white) [Namiu](gray show_text=&7\\(うにたろう\\) - Japanese, ja-jp), [anchelthe](gray show_text=&7Spanish, es-es), [Melonzio](gray show_text=&7Spanish, es-es), [Ceddix](gray show_text=&7German, de-de), [Pukejoy_1](gray show_text=&7Bulgarian, bg-bg), [mateusneresrb](gray show_text=&7Brazilian Portuguese, pt-br], [小蔡](gray show_text=&7Traditional Chinese, zh-tw), [Ghost-chu](gray show_text=&7Simplified Chinese, zh-cn), [DJelly4K](gray show_text=&7Simplified Chinese, zh-cn), [Thourgard](gray show_text=&7Ukrainian, uk-ua), [xF3d3](gray show_text=&7Italian, it-it)
|
||||
[• Documentation:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://william278.net/docs/husksync/Home/)
|
||||
[• Bug reporting:](white) [[Link]](#00fb9a show_text=&7Click to open link open_url=https://github.com/WiIIiam278/HuskSync/issues)
|
||||
[• Discord support:](white) [[Link]](#00fb9a show_text=&7Click to join open_url=https://discord.gg/tVYhJfyDWG)""";
|
||||
|
||||
@NotNull
|
||||
private final HashMap<String, String> rawLocales;
|
||||
|
||||
@@ -106,34 +95,4 @@ public class Locales {
|
||||
return new Locales(localesConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips a string of basic MineDown formatting, used for displaying plugin info to console
|
||||
*
|
||||
* @param string The string to strip
|
||||
* @return The MineDown-stripped string
|
||||
*/
|
||||
public String stripMineDown(@NotNull String string) {
|
||||
final String[] in = string.split("\n");
|
||||
final StringBuilder out = new StringBuilder();
|
||||
String regex = "[^\\[\\]() ]*\\[([^()]+)]\\([^()]+open_url=(\\S+).*\\)";
|
||||
|
||||
for (int i = 0; i < in.length; i++) {
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher m = pattern.matcher(in[i]);
|
||||
|
||||
if (m.find()) {
|
||||
out.append(in[i].replace(m.group(0), ""));
|
||||
out.append(m.group(2));
|
||||
} else {
|
||||
out.append(in[i]);
|
||||
}
|
||||
|
||||
if (i + 1 != in.length) {
|
||||
out.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import net.william278.husksync.editor.ItemEditorMenu;
|
||||
import net.william278.husksync.event.EventCannon;
|
||||
import net.william278.husksync.event.PreSyncEvent;
|
||||
import net.william278.husksync.util.Logger;
|
||||
import net.william278.husksync.util.Version;
|
||||
import net.william278.desertwell.Version;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -176,7 +176,7 @@ public abstract class OnlineUser extends User {
|
||||
@NotNull Version serverMinecraftVersion) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
// Prevent synchronising user data from newer versions of Minecraft
|
||||
if (Version.minecraftVersion(data.getMinecraftVersion()).compareTo(serverMinecraftVersion) > 0) {
|
||||
if (Version.fromMinecraftVersionString(data.getMinecraftVersion()).compareTo(serverMinecraftVersion) > 0) {
|
||||
logger.log(Level.SEVERE, "Cannot set data for " + username +
|
||||
" because the Minecraft version of their user data (" + data.getMinecraftVersion() +
|
||||
") is newer than the server's Minecraft version (" + serverMinecraftVersion + ").");
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package net.william278.husksync.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class UpdateChecker {
|
||||
|
||||
private final static int SPIGOT_PROJECT_ID = 97144;
|
||||
private final Logger logger;
|
||||
private final Version currentVersion;
|
||||
|
||||
public UpdateChecker(@NotNull Version currentVersion, @NotNull Logger logger) {
|
||||
this.currentVersion = currentVersion;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public CompletableFuture<Version> fetchLatestVersion() {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
final URL url = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + SPIGOT_PROJECT_ID);
|
||||
URLConnection urlConnection = url.openConnection();
|
||||
return Version.pluginVersion(new BufferedReader(new InputStreamReader(urlConnection.getInputStream())).readLine());
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "Failed to fetch the latest plugin version", e);
|
||||
}
|
||||
return new Version();
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isUpdateAvailable(@NotNull Version latestVersion) {
|
||||
return latestVersion.compareTo(currentVersion) > 0;
|
||||
}
|
||||
|
||||
public Version getCurrentVersion() {
|
||||
return currentVersion;
|
||||
}
|
||||
|
||||
public CompletableFuture<Boolean> isUpToDate() {
|
||||
return fetchLatestVersion().thenApply(this::isUpdateAvailable);
|
||||
}
|
||||
|
||||
public void logToConsole() {
|
||||
fetchLatestVersion().thenAccept(latestVersion -> {
|
||||
if (isUpdateAvailable(latestVersion)) {
|
||||
logger.log(Level.WARNING, "A new version of HuskSync is available: v" + latestVersion);
|
||||
} else {
|
||||
logger.log(Level.INFO, "HuskSync is up-to-date! (Running: v" + getCurrentVersion().toString() + ")");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package net.william278.husksync.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Version implements Comparable<Version> {
|
||||
private final static String VERSION_SEPARATOR = ".";
|
||||
private final static String MINECRAFT_META_SEPARATOR = "-";
|
||||
private final static String PLUGIN_META_SEPARATOR = "-";
|
||||
|
||||
private int[] versions = new int[]{};
|
||||
@NotNull
|
||||
private String metadata = "";
|
||||
@NotNull
|
||||
private String metaSeparator = "";
|
||||
|
||||
protected Version() {
|
||||
}
|
||||
|
||||
private Version(@NotNull String version, @NotNull String metaSeparator) {
|
||||
this.parse(version, metaSeparator);
|
||||
this.metaSeparator = metaSeparator;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Version pluginVersion(@NotNull String versionString) {
|
||||
return new Version(versionString, PLUGIN_META_SEPARATOR);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Version minecraftVersion(@NotNull String versionString) {
|
||||
return new Version(versionString, MINECRAFT_META_SEPARATOR);
|
||||
}
|
||||
|
||||
private void parse(@NotNull String version, @NotNull String metaSeparator) {
|
||||
int metaIndex = version.indexOf(metaSeparator);
|
||||
if (metaIndex > 0) {
|
||||
this.metadata = version.substring(metaIndex + 1);
|
||||
version = version.substring(0, metaIndex);
|
||||
}
|
||||
String[] versions = version.split(Pattern.quote(VERSION_SEPARATOR));
|
||||
this.versions = Arrays.stream(versions).mapToInt(Integer::parseInt).toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull Version other) {
|
||||
int length = Math.max(this.versions.length, other.versions.length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
int a = i < this.versions.length ? this.versions[i] : 0;
|
||||
int b = i < other.versions.length ? other.versions[i] : 0;
|
||||
|
||||
if (a < b) return -1;
|
||||
if (a > b) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringJoiner joiner = new StringJoiner(VERSION_SEPARATOR);
|
||||
for (int version : this.versions) {
|
||||
joiner.add(String.valueOf(version));
|
||||
}
|
||||
return joiner + ((!this.metadata.isEmpty()) ? (this.metaSeparator + this.metadata) : "");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package net.william278.husksync.player;
|
||||
import de.themoep.minedown.MineDown;
|
||||
import net.william278.husksync.data.*;
|
||||
import net.william278.husksync.editor.ItemEditorMenu;
|
||||
import net.william278.husksync.util.Version;
|
||||
import net.william278.desertwell.Version;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -132,7 +132,7 @@ public class DummyPlayer extends OnlineUser {
|
||||
@NotNull
|
||||
@Override
|
||||
public Version getMinecraftVersion() {
|
||||
return Version.minecraftVersion("1.19-beta123456");
|
||||
return Version.fromMinecraftVersionString("1.19-beta123456");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user