diff --git a/api/src/main/java/net/momirealms/customfishing/api/manager/CompetitionManager.java b/api/src/main/java/net/momirealms/customfishing/api/manager/CompetitionManager.java index 51c282ff..d78ade4a 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/manager/CompetitionManager.java +++ b/api/src/main/java/net/momirealms/customfishing/api/manager/CompetitionManager.java @@ -47,10 +47,10 @@ public interface CompetitionManager { * * @param competition The name of the competition to start. * @param force Whether to force start the competition even if amount of the online players is lower than the requirement - * @param allServers Whether to apply the competition to the servers that connected to Redis. + * @param serverGroup Whether to apply the competition to the servers that connected to Redis. * @return {@code true} if the competition was started successfully, {@code false} otherwise. */ - boolean startCompetition(String competition, boolean force, boolean allServers); + boolean startCompetition(String competition, boolean force, @Nullable String serverGroup); /** * Gets the ongoing fishing competition, if one is currently in progress. @@ -64,10 +64,10 @@ public interface CompetitionManager { * * @param config The configuration of the competition to start. * @param force Whether to force start the competition even if amount of the online players is lower than the requirement - * @param allServers Whether the competition should start across all servers that connected to Redis + * @param serverGroup Whether the competition should start across all servers that connected to Redis * @return True if the competition was started successfully, false otherwise. */ - boolean startCompetition(CompetitionConfig config, boolean force, boolean allServers); + boolean startCompetition(CompetitionConfig config, boolean force, @Nullable String serverGroup); /** * Gets the number of seconds until the next competition. diff --git a/plugin/libs/notquests-5.17.1.jar b/plugin/libs/notquests-5.17.1.jar new file mode 100644 index 00000000..d308c7bf Binary files /dev/null and b/plugin/libs/notquests-5.17.1.jar differ diff --git a/plugin/src/main/java/net/momirealms/customfishing/CustomFishingPluginImpl.java b/plugin/src/main/java/net/momirealms/customfishing/CustomFishingPluginImpl.java index c95af8f2..d57263a2 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/CustomFishingPluginImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/CustomFishingPluginImpl.java @@ -131,8 +131,8 @@ public class CustomFishingPluginImpl extends CustomFishingPlugin { ((RequirementManagerImpl) this.requirementManager).disable(); ((SchedulerImpl) this.scheduler).shutdown(); ((IntegrationManagerImpl) this.integrationManager).disable(); - ((StorageManagerImpl) this.storageManager).disable(); ((CompetitionManagerImpl) this.competitionManager).disable(); + ((StorageManagerImpl) this.storageManager).disable(); ((PlaceholderManagerImpl) this.placeholderManager).disable(); ((StatisticsManagerImpl) this.statisticsManager).disable(); ((ActionManagerImpl) this.actionManager).disable(); diff --git a/plugin/src/main/java/net/momirealms/customfishing/command/sub/CompetitionCommand.java b/plugin/src/main/java/net/momirealms/customfishing/command/sub/CompetitionCommand.java index 9f8afc1a..9ef24ba6 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/command/sub/CompetitionCommand.java +++ b/plugin/src/main/java/net/momirealms/customfishing/command/sub/CompetitionCommand.java @@ -55,10 +55,7 @@ public class CompetitionCommand { ArgumentSuggestions.strings(allCompetitions) ) ); - if (CFConfig.redisRanking) command.withOptionalArguments(new BooleanArgument("servers").replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(new IStringTooltip[]{ - StringTooltip.ofString("true", "all the servers that connected to Redis"), - StringTooltip.ofString("false", "only this server") - }))); + if (CFConfig.redisRanking) command.withOptionalArguments(new StringArgument("server-group")); command.executes((sender, args) -> { String id = (String) args.get(0); assert id != null; @@ -66,22 +63,23 @@ public class CompetitionCommand { AdventureManagerImpl.getInstance().sendMessageWithPrefix(sender, CFLocale.MSG_Competition_Not_Exist.replace("{id}", id)); return; } - boolean allServer = (boolean) args.getOrDefault("servers", false); - CustomFishingPlugin.get().getCompetitionManager().startCompetition(id, true, allServer); + Object server = args.get("server-group"); + if (server != null) { + CustomFishingPlugin.get().getCompetitionManager().startCompetition(id, true, (String) server); + } else { + CustomFishingPlugin.get().getCompetitionManager().startCompetition(id, true, null); + } }); return command; } private CommandAPICommand getCompetitionEndCommand() { var command = new CommandAPICommand("end"); - if (CFConfig.redisRanking) command.withOptionalArguments(new BooleanArgument("servers").replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(new IStringTooltip[]{ - StringTooltip.ofString("true", "all the servers that connected to Redis"), - StringTooltip.ofString("false", "only this server") - }))); + if (CFConfig.redisRanking) command.withOptionalArguments(new StringArgument("server-group")); command.executes((sender, args) -> { - boolean allServer = (boolean) args.getOrDefault("servers", false); - if (allServer) { - RedisManager.getInstance().sendRedisMessage("cf_competition", "end"); + Object server = args.get("server-group"); + if (server != null) { + RedisManager.getInstance().publishRedisMessage((String) server, "end"); } else { FishingCompetition competition = CustomFishingPlugin.get().getCompetitionManager().getOnGoingCompetition(); if (competition != null) { @@ -97,14 +95,11 @@ public class CompetitionCommand { private CommandAPICommand getCompetitionStopCommand() { var command = new CommandAPICommand("stop"); - if (CFConfig.redisRanking) command.withOptionalArguments(new BooleanArgument("servers").replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(new IStringTooltip[]{ - StringTooltip.ofString("true", "all the servers that connected to Redis"), - StringTooltip.ofString("false", "only this server") - }))); + if (CFConfig.redisRanking) command.withOptionalArguments(new StringArgument("server-group")); command.executes((sender, args) -> { - boolean allServer = (boolean) args.getOrDefault("servers", false); - if (allServer) { - RedisManager.getInstance().sendRedisMessage("cf_competition", "stop"); + Object server = args.get("server-group"); + if (server != null) { + RedisManager.getInstance().publishRedisMessage((String) server, "stop"); } else { FishingCompetition competition = CustomFishingPlugin.get().getCompetitionManager().getOnGoingCompetition(); if (competition != null) { diff --git a/plugin/src/main/java/net/momirealms/customfishing/compatibility/IntegrationManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/compatibility/IntegrationManagerImpl.java index 220825c8..06576707 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/compatibility/IntegrationManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/compatibility/IntegrationManagerImpl.java @@ -146,6 +146,7 @@ public class IntegrationManagerImpl implements IntegrationManager { if (plugin.isHookedPluginEnabled("ClueScrolls")) { ClueScrollsHook clueScrollsHook = new ClueScrollsHook(); clueScrollsHook.register(); + Bukkit.getPluginManager().registerEvents(clueScrollsHook, plugin); hookMessage("ClueScrolls"); } if (plugin.isHookedPluginEnabled("BetonQuest")) { diff --git a/plugin/src/main/java/net/momirealms/customfishing/compatibility/quest/ClueScrollsHook.java b/plugin/src/main/java/net/momirealms/customfishing/compatibility/quest/ClueScrollsHook.java index 08878cc0..b4639a3b 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/compatibility/quest/ClueScrollsHook.java +++ b/plugin/src/main/java/net/momirealms/customfishing/compatibility/quest/ClueScrollsHook.java @@ -49,21 +49,21 @@ public class ClueScrollsHook implements Listener { idClue.handle( player, event.getAmount(), - new ClueDataPair("loot_id", "any") + new ClueDataPair("id", "any") ); Loot loot = event.getLoot(); if (loot != null) idClue.handle( player, event.getAmount(), - new ClueDataPair("loot_id", loot.getID()) + new ClueDataPair("id", loot.getID()) ); if (loot != null && loot.getLootGroup() != null) for (String group : event.getLoot().getLootGroup()) { groupClue.handle( player, event.getAmount(), - new ClueDataPair("loot_group", group) + new ClueDataPair("group", group) ); } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/gui/ItemPage.java b/plugin/src/main/java/net/momirealms/customfishing/gui/ItemPage.java deleted file mode 100644 index 7354e7a2..00000000 --- a/plugin/src/main/java/net/momirealms/customfishing/gui/ItemPage.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.momirealms.customfishing.gui; - -import org.bukkit.configuration.ConfigurationSection; - -public interface ItemPage extends YamlPage { - - ConfigurationSection getSection(); -} diff --git a/plugin/src/main/java/net/momirealms/customfishing/gui/page/item/ItemEditor.java b/plugin/src/main/java/net/momirealms/customfishing/gui/page/item/ItemEditor.java deleted file mode 100644 index 61f27d37..00000000 --- a/plugin/src/main/java/net/momirealms/customfishing/gui/page/item/ItemEditor.java +++ /dev/null @@ -1,136 +0,0 @@ -package net.momirealms.customfishing.gui.page.item; - -import net.momirealms.customfishing.adventure.AdventureManagerImpl; -import net.momirealms.customfishing.adventure.component.ShadedAdventureComponentWrapper; -import net.momirealms.customfishing.api.CustomFishingPlugin; -import net.momirealms.customfishing.gui.ItemPage; -import net.momirealms.customfishing.gui.icon.BackGroundItem; -import net.momirealms.customfishing.gui.icon.BackToPageItem; -import net.momirealms.customfishing.gui.icon.NextPageItem; -import net.momirealms.customfishing.gui.icon.PreviousPageItem; -import net.momirealms.customfishing.gui.icon.property.item.*; -import net.momirealms.customfishing.gui.icon.property.loot.*; -import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; -import xyz.xenondevs.invui.gui.Gui; -import xyz.xenondevs.invui.gui.PagedGui; -import xyz.xenondevs.invui.gui.structure.Markers; -import xyz.xenondevs.invui.item.Item; -import xyz.xenondevs.invui.item.ItemProvider; -import xyz.xenondevs.invui.item.builder.ItemBuilder; -import xyz.xenondevs.invui.item.impl.AbstractItem; -import xyz.xenondevs.invui.item.impl.SimpleItem; -import xyz.xenondevs.invui.window.AnvilWindow; - -import java.util.ArrayList; -import java.util.List; - -public class ItemEditor implements ItemPage { - - private final Player player; - private final ItemSelector itemSelector; - private final ConfigurationSection section; - private final String key; - - public ItemEditor(Player player, String key, ItemSelector itemSelector, ConfigurationSection section) { - this.player = player; - this.section = section; - this.itemSelector = itemSelector; - this.key = key; - this.reOpen(); - } - - @Override - public void reOpen() { - Gui upperGui = Gui.normal() - .setStructure( - "# a #" - ) - .addIngredient('a', new RefreshExample()) - .addIngredient('#', new ItemStack(Material.AIR)) - .build(); - - var gui = PagedGui.items() - .setStructure( - "x x x x x x x x x", - "x x x x x x x x x", - "x x x x x x x x x", - "# # a # c # b # #" - ) - .addIngredient('x', Markers.CONTENT_LIST_SLOT_HORIZONTAL) - .addIngredient('#', new BackGroundItem()) - .addIngredient('a', new PreviousPageItem()) - .addIngredient('b', new NextPageItem()) - .addIngredient('c', new BackToPageItem(itemSelector)) - .setContent(getItemList()) - .build(); - - var window = AnvilWindow.split() - .setViewer(player) - .setTitle(new ShadedAdventureComponentWrapper( - AdventureManagerImpl.getInstance().getComponentFromMiniMessage("Edit " + key) - )) - .setUpperGui(upperGui) - .setLowerGui(gui) - .build(); - - window.open(); - } - - @Override - public void save() { - itemSelector.save(); - } - - public class RefreshExample extends AbstractItem { - - @Override - public ItemProvider getItemProvider() { - return new ItemBuilder(CustomFishingPlugin.get().getItemManager().getItemBuilder(section, "item", key).build(player)); - } - - @Override - public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) { - notifyWindows(); - } - } - - public List getItemList() { - ArrayList items = new ArrayList<>(); - items.add(new MaterialItem(this)); - items.add(new NickItem(this)); - items.add(new DisplayNameItem(this)); - items.add(new LoreItem(this)); - items.add(new CMDItem(this)); - items.add(new AmountItem(this)); - items.add(new TagItem(this)); - items.add(new UnbreakableItem(this)); - items.add(new DurabilityItem(this)); - items.add(new RandomDurabilityItem(this)); - items.add(new StackableItem(this)); - items.add(new PreventGrabItem(this)); - items.add(new PriceItem(this)); - items.add(new ShowInFinderItem(this)); - items.add(new DisableStatsItem(this)); - items.add(new DisableGameItem(this)); - items.add(new InstantGameItem(this)); - items.add(new ScoreItem(this)); - items.add(new SizeItem(this)); - items.add(new ItemFlagItem(this)); - items.add(new Head64Item(this)); - items.add(new NBTItem(this)); - items.add(new EnchantmentItem(this)); - items.add(new StoredEnchantmentItem(this)); - return items; - } - - @Override - public ConfigurationSection getSection() { - return section; - } -} diff --git a/plugin/src/main/java/net/momirealms/customfishing/mechanic/competition/CompetitionManagerImpl.java b/plugin/src/main/java/net/momirealms/customfishing/mechanic/competition/CompetitionManagerImpl.java index 8d4a27d7..4473c0bc 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/mechanic/competition/CompetitionManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customfishing/mechanic/competition/CompetitionManagerImpl.java @@ -25,6 +25,7 @@ import net.momirealms.customfishing.api.mechanic.competition.*; import net.momirealms.customfishing.api.mechanic.condition.Condition; import net.momirealms.customfishing.api.scheduler.CancellableTask; import net.momirealms.customfishing.api.util.LogUtils; +import net.momirealms.customfishing.setting.CFConfig; import net.momirealms.customfishing.setting.CFLocale; import net.momirealms.customfishing.storage.method.database.nosql.RedisManager; import net.momirealms.customfishing.util.ConfigUtils; @@ -32,7 +33,6 @@ import org.bukkit.Bukkit; import org.bukkit.boss.BarColor; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -210,7 +210,7 @@ public class CompetitionManagerImpl implements CompetitionManager { this.nextCompetitionSeconds = nextCompetitionTime; CompetitionConfig config = timeConfigMap.get(competitionSchedule); if (config != null) { - startCompetition(config, false, false); + startCompetition(config, false, null); } } @@ -240,22 +240,14 @@ public class CompetitionManagerImpl implements CompetitionManager { return ""; } - /** - * Starts a competition with the specified name, allowing for the option to force start it or apply it to the entire server. - * - * @param competition The name of the competition to start. - * @param force Whether to force start the competition even if amount of the online players is lower than the requirement - * @param allServer Whether to apply the competition to the servers that connected to Redis. - * @return {@code true} if the competition was started successfully, {@code false} otherwise. - */ @Override - public boolean startCompetition(String competition, boolean force, boolean allServer) { + public boolean startCompetition(String competition, boolean force, String serverGroup) { CompetitionConfig config = commandConfigMap.get(competition); if (config == null) { LogUtils.warn("Competition " + competition + " doesn't exist."); return false; } - return startCompetition(config, force, allServer); + return startCompetition(config, force, serverGroup); } /** @@ -270,16 +262,8 @@ public class CompetitionManagerImpl implements CompetitionManager { return currentCompetition.isOnGoing() ? currentCompetition : null; } - /** - * Starts a competition using the specified configuration. - * - * @param config The configuration of the competition to start. - * @param force Whether to force the start of the competition. - * @param allServer Whether the competition should start across all servers in the network. - * @return True if the competition was started successfully, false otherwise. - */ @Override - public boolean startCompetition(CompetitionConfig config, boolean force, boolean allServer) { + public boolean startCompetition(CompetitionConfig config, boolean force, @Nullable String serverGroup) { if (!force) { int players = Bukkit.getOnlinePlayers().size(); if (players < config.getMinPlayersToStart()) { @@ -294,11 +278,11 @@ public class CompetitionManagerImpl implements CompetitionManager { } start(config); return true; - } else if (!allServer) { + } else if (serverGroup == null) { start(config); return true; } else { - RedisManager.getInstance().sendRedisMessage("cf_competition", "start;" + config.getKey()); + RedisManager.getInstance().publishRedisMessage(serverGroup, "start;" + config.getKey()); return true; } } diff --git a/plugin/src/main/java/net/momirealms/customfishing/setting/CFConfig.java b/plugin/src/main/java/net/momirealms/customfishing/setting/CFConfig.java index 48e30920..1b57cf0d 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/setting/CFConfig.java +++ b/plugin/src/main/java/net/momirealms/customfishing/setting/CFConfig.java @@ -26,6 +26,7 @@ import dev.dejvokep.boostedyaml.settings.updater.UpdaterSettings; import net.momirealms.customfishing.api.CustomFishingPlugin; import net.momirealms.customfishing.api.util.LogUtils; import net.momirealms.customfishing.api.util.OffsetUtils; +import net.momirealms.customfishing.util.ConfigUtils; import org.bukkit.Material; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.EventPriority; @@ -75,6 +76,7 @@ public class CFConfig { // Competition public static boolean redisRanking; + public static List serverGroup; public static int placeholderLimit; // Data save interval @@ -146,6 +148,7 @@ public class CFConfig { redisRanking = config.getBoolean("mechanics.competition.redis-ranking", false); placeholderLimit = config.getInt("mechanics.competition.placeholder-limit", 3); + serverGroup = ConfigUtils.stringListArgs(config.get("mechanics.competition.server-group","default")); dataSaveInterval = config.getInt("other-settings.data-saving-interval", 600); lockData = config.getBoolean("other-settings.lock-data", true); diff --git a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/RedisManager.java b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/RedisManager.java index f80b9adb..b1ba449a 100644 --- a/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/RedisManager.java +++ b/plugin/src/main/java/net/momirealms/customfishing/storage/method/database/nosql/RedisManager.java @@ -21,19 +21,21 @@ import net.momirealms.customfishing.api.CustomFishingPlugin; import net.momirealms.customfishing.api.data.PlayerData; import net.momirealms.customfishing.api.data.StorageType; import net.momirealms.customfishing.api.util.LogUtils; +import net.momirealms.customfishing.setting.CFConfig; import net.momirealms.customfishing.storage.method.AbstractStorage; +import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; import redis.clients.jedis.*; import redis.clients.jedis.exceptions.JedisException; +import redis.clients.jedis.params.XReadParams; +import redis.clients.jedis.resps.StreamEntry; import java.nio.charset.StandardCharsets; import java.time.Duration; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.CompletableFuture; /** @@ -42,11 +44,14 @@ import java.util.concurrent.CompletableFuture; public class RedisManager extends AbstractStorage { private static RedisManager instance; + private final static String STREAM = "customfishing"; private JedisPool jedisPool; private String password; private int port; private String host; private boolean useSSL; + private BlockingThreadTask threadTask; + private boolean isNewerThan5; public RedisManager(CustomFishingPlugin plugin) { super(plugin); @@ -103,14 +108,25 @@ public class RedisManager extends AbstractStorage { } else { jedisPool = new JedisPool(jedisPoolConfig, host, port, 0, password, useSSL); } + String info; try (Jedis jedis = jedisPool.getResource()) { - jedis.ping(); + info = jedis.info(); LogUtils.info("Redis server connected."); } catch (JedisException e) { LogUtils.warn("Failed to connect redis.", e); + return; } - subscribe(); + String version = parseRedisVersion(info); + if (isRedisNewerThan5(version)) { + // For Redis 5.0+ + this.threadTask = new BlockingThreadTask(); + this.isNewerThan5 = true; + } else { + // For Redis 2.0+ + this.subscribe(); + this.isNewerThan5 = false; + } } /** @@ -118,6 +134,8 @@ public class RedisManager extends AbstractStorage { */ @Override public void disable() { + if (threadTask != null) + threadTask.stop(); if (jedisPool != null && !jedisPool.isClosed()) jedisPool.close(); } @@ -125,13 +143,22 @@ public class RedisManager extends AbstractStorage { /** * Send a message to Redis on a specified channel. * - * @param channel The Redis channel to send the message to. + * @param server The Redis channel to send the message to. * @param message The message to send. */ - public void sendRedisMessage(@NotNull String channel, @NotNull String message) { - try (Jedis jedis = jedisPool.getResource()) { - jedis.publish(channel, message); - plugin.debug("Sent Redis message: " + message); + public void publishRedisMessage(@NotNull String server, @NotNull String message) { + message = server + ";" + message; + plugin.debug("Sent Redis message: " + message); + if (isNewerThan5) { + try (Jedis jedis = jedisPool.getResource()) { + HashMap messages = new HashMap<>(); + messages.put("value", message); + jedis.xadd(getStream(), StreamEntryID.NEW_ENTRY, messages); + } + } else { + try (Jedis jedis = jedisPool.getResource()) { + jedis.publish(getStream(), message); + } } } @@ -153,33 +180,43 @@ public class RedisManager extends AbstractStorage { jedis.subscribe(new JedisPubSub() { @Override public void onMessage(String channel, String message) { - if (!channel.equals("cf_competition")) { + if (!channel.equals(getStream())) { return; } - plugin.debug("Received Redis message: " + message); - String[] split = message.split(";"); - String action = split[0]; - switch (action) { - case "start" -> { - // start competition for all the servers that connected to redis - plugin.getCompetitionManager().startCompetition(split[1], true, false); - } - case "end" -> { - if (plugin.getCompetitionManager().getOnGoingCompetition() != null) - plugin.getCompetitionManager().getOnGoingCompetition().end(); - } - case "stop" -> { - if (plugin.getCompetitionManager().getOnGoingCompetition() != null) - plugin.getCompetitionManager().getOnGoingCompetition().stop(); - } - } + handleMessage(message); } - }, "cf_competition"); + }, getStream()); } }); thread.start(); } + private static void handleMessage(String message) { + CustomFishingPlugin.get().debug("Received Redis message: " + message); + String[] split = message.split(";"); + String server = split[0]; + if (!CFConfig.serverGroup.contains(server)) { + return; + } + String action = split[1]; + CustomFishingPlugin.get().getScheduler().runTaskSync(() -> { + switch (action) { + case "start" -> { + // start competition for all the servers that connected to redis + CustomFishingPlugin.get().getCompetitionManager().startCompetition(split[2], true, null); + } + case "end" -> { + if (CustomFishingPlugin.get().getCompetitionManager().getOnGoingCompetition() != null) + CustomFishingPlugin.get().getCompetitionManager().getOnGoingCompetition().end(); + } + case "stop" -> { + if (CustomFishingPlugin.get().getCompetitionManager().getOnGoingCompetition() != null) + CustomFishingPlugin.get().getCompetitionManager().getOnGoingCompetition().stop(); + } + } + }, new Location(Bukkit.getWorlds().get(0),0,0,0)); + } + @Override public StorageType getStorageType() { return StorageType.Redis; @@ -226,7 +263,6 @@ public class RedisManager extends AbstractStorage { future.complete(false); plugin.debug("Server data retrieved for " + uuid + "; value: false"); } - } }); return future; @@ -312,4 +348,70 @@ public class RedisManager extends AbstractStorage { private byte[] getRedisKey(String key, @NotNull UUID uuid) { return (key + ":" + uuid).getBytes(StandardCharsets.UTF_8); } + + public static String getStream() { + return STREAM; + } + + private static boolean isRedisNewerThan5(String version) { + String[] split = version.split("\\."); + int major = Integer.parseInt(split[0]); + if (major < 7) { + LogUtils.warn(String.format("Detected that you are running an outdated Redis server. v%s. ", version)); + LogUtils.warn("It's recommended to update to avoid security vulnerabilities!"); + } + return major >= 5; + } + + private static String parseRedisVersion(String info) { + for (String line : info.split("\n")) { + if (line.startsWith("redis_version:")) { + return line.split(":")[1]; + } + } + return "Unknown"; + } + + public class BlockingThreadTask { + + private boolean stopped; + + public void stop() { + stopped = true; + } + + public BlockingThreadTask() { + Thread thread = new Thread(() -> { + var map = new HashMap(); + map.put(getStream(), StreamEntryID.LAST_ENTRY); + while (!this.stopped) { + try { + var connection = getJedis(); + if (connection != null) { + var messages = connection.xread(XReadParams.xReadParams().count(1).block(2000), map); + connection.close(); + if (messages != null && messages.size() != 0) { + for (Map.Entry> message : messages) { + if (message.getKey().equals(getStream())) { + var value = message.getValue().get(0).getFields().get("value"); + handleMessage(value); + } + } + } + } else { + Thread.sleep(2000); + } + } catch (Exception e) { + LogUtils.warn("Failed to connect redis. Try reconnecting 10s later",e); + try { + Thread.sleep(10000); + } catch (InterruptedException ex) { + this.stopped = true; + } + } + } + }); + thread.start(); + } + } } diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index 4f5927ab..960dbc80 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -125,6 +125,8 @@ mechanics: competition: # Use redis for cross server data synchronization redis-ranking: false + # Server group + server-group: default # Increase this value would allow you to use more placeholders like {4_player} {5_score} in sacrifice of some performance placeholder-limit: 3 diff --git a/plugin/src/main/resources/database.yml b/plugin/src/main/resources/database.yml index 7bc7a071..d5a94fb7 100644 --- a/plugin/src/main/resources/database.yml +++ b/plugin/src/main/resources/database.yml @@ -13,9 +13,6 @@ # data-storage-method: H2 -# Server unique id, make sure that all the servers are using different ids -server-unique-id: "plz_edit_this" - SQLite: file: 'sqlite' table-prefix: customfishing