diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/CompetitionConfig.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/CompetitionConfig.java index 8b3d8407..08dd19b6 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/CompetitionConfig.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/CompetitionConfig.java @@ -20,6 +20,7 @@ package net.momirealms.customfishing.api.mechanic.competition; import net.momirealms.customfishing.api.mechanic.action.Action; import net.momirealms.customfishing.api.mechanic.competition.info.ActionBarConfig; import net.momirealms.customfishing.api.mechanic.competition.info.BossBarConfig; +import net.momirealms.customfishing.api.mechanic.competition.info.BroadcastConfig; import net.momirealms.customfishing.api.mechanic.requirement.Requirement; import org.bukkit.entity.Player; @@ -125,6 +126,13 @@ public interface CompetitionConfig { */ ActionBarConfig actionBarConfig(); + /** + * Gets the configuration for the broadcast during the competition. + * + * @return the broadcast configuration + */ + BroadcastConfig broadcastConfig(); + /** * Get the time to start competition * @@ -242,6 +250,14 @@ public interface CompetitionConfig { */ Builder actionBarConfig(ActionBarConfig actionBarConfig); + /** + * Sets the configuration for the broadcast during the competition. + * + * @param broadcastConfig the broadcast configuration. + * @return the builder instance. + */ + Builder broadcastConfig(BroadcastConfig broadcastConfig); + /** * Sets the configuration for schedules of the competition. * diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/CompetitionConfigImpl.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/CompetitionConfigImpl.java index e055e8f2..e800f981 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/CompetitionConfigImpl.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/CompetitionConfigImpl.java @@ -20,6 +20,8 @@ package net.momirealms.customfishing.api.mechanic.competition; import net.momirealms.customfishing.api.mechanic.action.Action; import net.momirealms.customfishing.api.mechanic.competition.info.ActionBarConfig; import net.momirealms.customfishing.api.mechanic.competition.info.BossBarConfig; +import net.momirealms.customfishing.api.mechanic.competition.info.BroadcastConfig; +import net.momirealms.customfishing.api.mechanic.competition.info.BroadcastConfigImpl; import net.momirealms.customfishing.api.mechanic.requirement.Requirement; import org.bukkit.entity.Player; @@ -41,9 +43,13 @@ public class CompetitionConfigImpl implements CompetitionConfig { private final HashMap[]> rewards; private final BossBarConfig bossBarConfig; private final ActionBarConfig actionBarConfig; + private final BroadcastConfig broadcastConfig; private final List schedules; - public CompetitionConfigImpl(String key, CompetitionGoal goal, int duration, int minPlayers, Requirement[] joinRequirements, Action[] skipActions, Action[] startActions, Action[] endActions, Action[] joinActions, HashMap[]> rewards, BossBarConfig bossBarConfig, ActionBarConfig actionBarConfig, List schedules) { + public CompetitionConfigImpl(String key, CompetitionGoal goal, int duration, int minPlayers, Requirement[] joinRequirements, + Action[] skipActions, Action[] startActions, Action[] endActions, Action[] joinActions, HashMap[]> rewards, + BossBarConfig bossBarConfig, ActionBarConfig actionBarConfig, BroadcastConfig broadcastConfig, + List schedules) { this.key = key; this.goal = goal; this.duration = duration; @@ -56,6 +62,7 @@ public class CompetitionConfigImpl implements CompetitionConfig { this.rewards = rewards; this.bossBarConfig = bossBarConfig; this.actionBarConfig = actionBarConfig; + this.broadcastConfig = broadcastConfig; this.schedules = schedules; } @@ -119,6 +126,11 @@ public class CompetitionConfigImpl implements CompetitionConfig { return actionBarConfig; } + @Override + public BroadcastConfig broadcastConfig() { + return broadcastConfig; + } + @Override public List schedules() { return schedules; @@ -137,6 +149,7 @@ public class CompetitionConfigImpl implements CompetitionConfig { private HashMap[]> rewards = DEFAULT_REWARDS; private BossBarConfig bossBarConfig; private ActionBarConfig actionBarConfig; + private BroadcastConfig broadcastConfig; private final List schedules = new ArrayList<>(); @Override public Builder id(String key) { @@ -199,13 +212,18 @@ public class CompetitionConfigImpl implements CompetitionConfig { return this; } @Override + public Builder broadcastConfig(BroadcastConfig broadcastConfig) { + this.broadcastConfig = broadcastConfig; + return this; + } + @Override public Builder schedules(List schedules) { this.schedules.addAll(schedules); return this; } @Override public CompetitionConfig build() { - return new CompetitionConfigImpl(key, goal, duration, minPlayers, joinRequirements, skipActions, startActions, endActions, joinActions, rewards, bossBarConfig, actionBarConfig, schedules); + return new CompetitionConfigImpl(key, goal, duration, minPlayers, joinRequirements, skipActions, startActions, endActions, joinActions, rewards, bossBarConfig, actionBarConfig, broadcastConfig, schedules); } } } diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/info/BroadcastConfig.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/info/BroadcastConfig.java new file mode 100644 index 00000000..e4174659 --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/info/BroadcastConfig.java @@ -0,0 +1,90 @@ +package net.momirealms.customfishing.api.mechanic.competition.info; + +public interface BroadcastConfig { + int DEFAULT_INTERVAL = 200; + boolean DEFAULT_SHOW_TO_ALL = true; + String[] DEFAULT_TEXTS = new String[]{""}; + boolean DEFAULT_ENABLED = true; + + /** + * Get the interval for broadcasting competition information. + * + * @return The interval in ticks. + */ + int interval(); + + /** + * Check if competition information should be shown to all players. + * + * @return True if information is shown to all players, otherwise only to participants. + */ + boolean showToAll(); + + /** + * Get an array of competition information texts to be broadcasted. + * + * @return An array of broadcast texts. + */ + String[] texts(); + + /** + * Check if the broadcast is enabled. + * + * @return True if the broadcast is enabled, false otherwise. + */ + boolean enabled(); + + /** + * Creates a new builder instance for constructing {@link BroadcastConfig} objects. + * + * @return A new {@link Builder} instance. + */ + static Builder builder() { + return new BroadcastConfigImpl.BuilderImpl(); + } + + /** + * Builder interface for constructing {@link BroadcastConfig} objects. + */ + interface Builder { + + /** + * Sets the interval between broadcasting messages. + * + * @param interval The interval in ticks. + * @return The current {@link Builder} instance. + */ + Builder interval(int interval); + + /** + * Sets whether the broadcast should be visible to all players. + * + * @param showToAll True to show to all players, false for participants only. + * @return The current {@link Builder} instance. + */ + Builder showToAll(boolean showToAll); + + /** + * Sets the texts to be broadcasted during the competition. + * + * @param texts An array of broadcast texts. + * @return The current {@link Builder} instance. + */ + Builder texts(String[] texts); + + /** + * Enables or disables the broadcast. + * + * @param enable True to enable the broadcast, false to disable. + * @return The current {@link Builder} instance. + */ + Builder enable(boolean enable); + + /** + * Builds the {@link BroadcastConfig} object with the configured settings. + * + * @return The constructed {@link BroadcastConfig} object. + */ + BroadcastConfig build(); + } +} \ No newline at end of file diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/info/BroadcastConfigImpl.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/info/BroadcastConfigImpl.java new file mode 100644 index 00000000..3e46d36a --- /dev/null +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/competition/info/BroadcastConfigImpl.java @@ -0,0 +1,71 @@ +package net.momirealms.customfishing.api.mechanic.competition.info; + +public class BroadcastConfigImpl implements BroadcastConfig { + private final String[] texts; + private final boolean showToAll; + private final boolean enabled; + private final int interval; + + public BroadcastConfigImpl(boolean enable, int interval, String[] texts, boolean showToAll) { + this.texts = texts; + this.showToAll = showToAll; + this.enabled = enable; + this.interval = interval; + } + + @Override + public int interval() { + return this.interval; + } + + @Override + public boolean showToAll() { + return this.showToAll; + } + + @Override + public String[] texts() { + return this.texts; + } + + @Override + public boolean enabled() { + return this.enabled; + } + + public static class BuilderImpl implements BroadcastConfig.Builder { + private int interval = DEFAULT_INTERVAL; + private boolean showToAll = DEFAULT_SHOW_TO_ALL; + private String[] texts = DEFAULT_TEXTS; + private boolean enabled = DEFAULT_ENABLED; + + @Override + public Builder interval(int interval) { + this.interval = interval; + return this; + } + + @Override + public Builder showToAll(boolean showToAll) { + this.showToAll = showToAll; + return this; + } + + @Override + public Builder texts(String[] texts) { + this.texts = texts; + return this; + } + + @Override + public Builder enable(boolean enable) { + this.enabled = enable; + return this; + } + + @Override + public BroadcastConfig build() { + return new BroadcastConfigImpl(enabled, interval, texts, showToAll); + } + } +} diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/CompetitionConfigParser.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/CompetitionConfigParser.java index 8ec4288b..b31dc54e 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/CompetitionConfigParser.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/config/CompetitionConfigParser.java @@ -26,6 +26,7 @@ import net.momirealms.customfishing.api.mechanic.competition.CompetitionGoal; import net.momirealms.customfishing.api.mechanic.competition.CompetitionSchedule; import net.momirealms.customfishing.api.mechanic.competition.info.ActionBarConfig; import net.momirealms.customfishing.api.mechanic.competition.info.BossBarConfig; +import net.momirealms.customfishing.api.mechanic.competition.info.BroadcastConfig; import net.momirealms.customfishing.common.util.Pair; import org.bukkit.entity.Player; @@ -77,6 +78,16 @@ public class CompetitionConfigParser { .build() ); } + if (section.getBoolean("broadcast.enable", false)) { + builder.broadcastConfig( + BroadcastConfig.builder() + .enable(true) + .interval(section.getInt("broadcast.interval", 1200)) + .showToAll(!section.getBoolean("broadcast.only-show-to-participants", true)) + .texts(section.getStringList("broadcast.text").toArray(new String[0])) + .build() + ); + } List> timePairs = section.getStringList("start-time") .stream().map(it -> { String[] split = it.split(":"); diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/ContextKeys.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/ContextKeys.java index 2c0bdbfb..c6b72847 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/ContextKeys.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/context/ContextKeys.java @@ -44,6 +44,7 @@ public class ContextKeys { public static final ContextKeys LOOT = of("loot", LootType.class); public static final ContextKeys NICK = of("nick", String.class); public static final ContextKeys OPEN_WATER = of("open_water", Boolean.class); + public static final ContextKeys IS_NEW_SIZE_RECORD = of("is_new_size_record", Boolean.class); public static final ContextKeys SIZE = of("size", Float.class); public static final ContextKeys SIZE_MULTIPLIER = of("size_multiplier", Double.class); public static final ContextKeys SIZE_ADDER = of("size_adder", Double.class); diff --git a/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/CustomFishingHook.java b/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/CustomFishingHook.java index 18699065..40d73f88 100644 --- a/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/CustomFishingHook.java +++ b/api/src/main/java/net/momirealms/customfishing/api/mechanic/fishing/CustomFishingHook.java @@ -619,7 +619,7 @@ public class CustomFishingHook { userData -> { Pair result = userData.statistics().addAmount(nextLoot.statisticKey().amountKey(), 1); context.arg(ContextKeys.TOTAL_AMOUNT, userData.statistics().getAmount(nextLoot.statisticKey().amountKey())); - Optional.ofNullable(context.arg(ContextKeys.SIZE)).ifPresent(size -> { + Optional.ofNullable(context.arg(ContextKeys.SIZE)).ifPresentOrElse(size -> { float currentRecord = userData.statistics().getMaxSize(nextLoot.statisticKey().sizeKey()); float max = Math.max(size, currentRecord); context.arg(ContextKeys.RECORD, max); @@ -627,10 +627,11 @@ public class CustomFishingHook { context.arg(ContextKeys.RECORD_FORMATTED, String.format("%.2f", max)); context.arg(ContextKeys.PREVIOUS_RECORD_FORMATTED, String.format("%.2f", currentRecord)); if (userData.statistics().updateSize(nextLoot.statisticKey().sizeKey(), size)) { + context.arg(ContextKeys.IS_NEW_SIZE_RECORD, true); + plugin.getEventManager().trigger(context, id, MechanicType.LOOT, ActionTrigger.SUCCESS, result.left(), result.right()); plugin.getEventManager().trigger(context, id, MechanicType.LOOT, ActionTrigger.NEW_SIZE_RECORD); } - }); - plugin.getEventManager().trigger(context, id, MechanicType.LOOT, ActionTrigger.SUCCESS, result.left(), result.right()); + }, () -> plugin.getEventManager().trigger(context, id, MechanicType.LOOT, ActionTrigger.SUCCESS, result.left(), result.right())); } ); } diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/competition/BukkitCompetitionManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/competition/BukkitCompetitionManager.java index e4502995..6bc7e46b 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/competition/BukkitCompetitionManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/competition/BukkitCompetitionManager.java @@ -40,7 +40,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; public class BukkitCompetitionManager implements CompetitionManager { - private final BukkitCustomFishingPlugin plugin; private final NavigableMap timeConfigMap; private final HashMap commandConfigMap; diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/competition/Competition.java b/core/src/main/java/net/momirealms/customfishing/bukkit/competition/Competition.java index b265ca84..d268303a 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/competition/Competition.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/competition/Competition.java @@ -17,6 +17,7 @@ package net.momirealms.customfishing.bukkit.competition; +import net.kyori.adventure.audience.Audience; import net.momirealms.customfishing.api.BukkitCustomFishingPlugin; import net.momirealms.customfishing.api.event.CompetitionEvent; import net.momirealms.customfishing.api.mechanic.action.Action; @@ -25,13 +26,16 @@ import net.momirealms.customfishing.api.mechanic.competition.CompetitionConfig; import net.momirealms.customfishing.api.mechanic.competition.CompetitionGoal; import net.momirealms.customfishing.api.mechanic.competition.FishingCompetition; import net.momirealms.customfishing.api.mechanic.competition.RankingProvider; +import net.momirealms.customfishing.api.mechanic.competition.info.BroadcastConfig; import net.momirealms.customfishing.api.mechanic.config.ConfigManager; import net.momirealms.customfishing.api.mechanic.context.Context; import net.momirealms.customfishing.api.mechanic.context.ContextKeys; +import net.momirealms.customfishing.api.mechanic.misc.value.DynamicText; import net.momirealms.customfishing.bukkit.competition.actionbar.ActionBarManager; import net.momirealms.customfishing.bukkit.competition.bossbar.BossBarManager; import net.momirealms.customfishing.bukkit.competition.ranking.LocalRankingProvider; import net.momirealms.customfishing.bukkit.competition.ranking.RedisRankingProvider; +import net.momirealms.customfishing.common.helper.AdventureHelper; import net.momirealms.customfishing.common.locale.MessageConstants; import net.momirealms.customfishing.common.locale.TranslationManager; import net.momirealms.customfishing.common.plugin.scheduler.SchedulerTask; @@ -49,7 +53,6 @@ import java.util.Optional; import java.util.concurrent.TimeUnit; public class Competition implements FishingCompetition { - private final BukkitCustomFishingPlugin plugin; private final CompetitionConfig config; private SchedulerTask competitionTimerTask; @@ -180,9 +183,28 @@ public class Competition implements FishingCompetition { return; } updatePublicPlaceholders(); + BroadcastConfig broadcastConfig = config.broadcastConfig(); + if (broadcastConfig != null && broadcastConfig.enabled()) { + int intervalInSeconds = broadcastConfig.interval() / 20; + if ((this.config.durationInSeconds() - this.remainingTime) % intervalInSeconds == 0) { + this.broadcast(broadcastConfig); + } + } }, 1, 1, TimeUnit.SECONDS); } + private void broadcast(BroadcastConfig config) { + String[] texts = config.texts(); + for (Player player : Bukkit.getOnlinePlayers()) { + Audience audience = plugin.getSenderFactory().getAudience(player); + for (String s : texts) { + DynamicText text = new DynamicText(player, s); + text.update(this.publicContext.placeholderMap()); + AdventureHelper.sendMessage(audience, AdventureHelper.miniMessage(text.getLatestValue())); + } + } + } + private void updatePublicPlaceholders() { for (int i = 1; i < ConfigManager.placeholderLimit() + 1; i++) { Optional player = Optional.ofNullable(this.rankingProvider.getPlayerAt(i)); diff --git a/core/src/main/java/net/momirealms/customfishing/bukkit/requirement/BukkitRequirementManager.java b/core/src/main/java/net/momirealms/customfishing/bukkit/requirement/BukkitRequirementManager.java index 940c0609..96707747 100644 --- a/core/src/main/java/net/momirealms/customfishing/bukkit/requirement/BukkitRequirementManager.java +++ b/core/src/main/java/net/momirealms/customfishing/bukkit/requirement/BukkitRequirementManager.java @@ -212,6 +212,7 @@ public class BukkitRequirementManager implements RequirementManager { this.registerHasPlayerLootRequirement(); this.registerLootOrderRequirement(); this.registerIsBedrockPlayerRequirement(); + this.registerIsNewSizeRecordRequirement(); } private void registerIsBedrockPlayerRequirement() { @@ -659,6 +660,19 @@ public class BukkitRequirementManager implements RequirementManager { }, "open-water"); } + private void registerIsNewSizeRecordRequirement() { + registerRequirement((args, actions, runActions) -> { + boolean is = (boolean) args; + return context -> { + boolean current = Optional.ofNullable(context.arg(ContextKeys.IS_NEW_SIZE_RECORD)).orElse(false); + if (is == current) + return true; + if (runActions) ActionManager.trigger(context, actions); + return false; + }; + }, "new-size-record"); + } + private void registerHasStatsRequirement() { registerRequirement((args, actions, runActions) -> { boolean has = (boolean) args; diff --git a/core/src/main/resources/contents/competition/default.yml b/core/src/main/resources/contents/competition/default.yml index d892199c..76fb1300 100644 --- a/core/src/main/resources/contents/competition/default.yml +++ b/core/src/main/resources/contents/competition/default.yml @@ -44,8 +44,8 @@ weekend_competition: - '[<#87CEFA>🎣] Time Left: <#E6E6FA>{seconds}s | Your Rank: <#E6E6FA>{rank} | No.1 Player: <#E6E6FA>{1_player}' - '[<#87CEFA>🎣] Time Left: <#E6E6FA>{minute}{second} | Your Score: <#E6E6FA>{score_formatted} | No.1 Score: <#E6E6FA>{1_score}' - '[<#87CEFA>🎣] Time Left: <#E6E6FA>{minute}{second} | Winning condition: <#E6E6FA>{goal}' - refresh-rate: 20 - switch-interval: 200 + refresh-rate: 20 # in ticks + switch-interval: 200 # in ticks only-show-to-participants: true actionbar: @@ -54,10 +54,26 @@ weekend_competition: - 'Time Left: <#E6E6FA>{seconds}s | Your Rank: <#E6E6FA>{rank} | No.1 Player: <#E6E6FA>{1_player}' - 'Time Left: <#E6E6FA>{minute}{second} | Your Score: <#E6E6FA>{score_formatted} | No.1 Score: <#E6E6FA>{1_score}' - 'Time Left: <#E6E6FA>{minute}{second} | Winning condition: <#E6E6FA>{goal}' - refresh-rate: 5 - switch-interval: 200 + refresh-rate: 5 # in ticks + switch-interval: 200 # in ticks only-show-to-participants: true + # timely broadcast competition + broadcast: + enable: false + text: + - '<#D4F2E7>◤─────────────────────────◥' + - '' + - ' [<#87CEFA>🎣] Fishing Competition' + - '' + - ' <#E1FFFF>Current Ranking:' + - ' <#E1FFFF>No.①: {1_player} - {1_score}' + - ' <#E1FFFF>No.②: {2_player} - {2_score}' + - ' <#E1FFFF>No.③: {3_player} - {3_score}' + - '' + - '<#D4F2E7>◣─────────────────────────◢' + interval: 1200 # in ticks + start-actions: broadcast: type: broadcast @@ -67,7 +83,7 @@ weekend_competition: - ' [<#87CEFA>🎣] Fishing Competition' - '' - ' <#E1FFFF>Objectives:' - - ' <#B0C4DE>Catch as many fish as possible' + - ' <#B0C4DE>{goal}' - ' <#B0C4DE>Start fishing to participate!' - '' - '<#D4F2E7>◣─────────────────────────◢' diff --git a/gradle.properties b/gradle.properties index 781a772c..b529a14c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=2.3.7 +project_version=2.3.8 config_version=38 project_group=net.momirealms