From f38d92497a511bde33db3a6ad729a85a2662254b Mon Sep 17 00:00:00 2001 From: nossr50 Date: Thu, 7 Jan 2021 13:33:12 -0800 Subject: [PATCH] Add broadcasting when players reach certain level milestones (defaults to every 100 levels) --- Changelog.txt | 4 + .../commands/experience/AddlevelsCommand.java | 11 +- .../commands/experience/MmoeditCommand.java | 11 +- .../java/com/gmail/nossr50/config/Config.java | 8 ++ .../datatypes/LevelUpBroadcastPredicate.java | 100 ++++++++++++++++++ .../nossr50/datatypes/player/McMMOPlayer.java | 2 +- .../com/gmail/nossr50/util/EventUtils.java | 37 +++++++ .../util/player/NotificationManager.java | 43 ++++++++ src/main/resources/config.yml | 18 ++++ .../resources/locale/locale_en_US.properties | 3 +- 10 files changed, 233 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java diff --git a/Changelog.txt b/Changelog.txt index 520a72476..d3ce333d8 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,5 +1,9 @@ Version 2.1.171 Axes can now replant cocoa plants (thanks Lyther) + Players who level up at certain milestones have their level ups broadcast to the server (very configurable and optional, see notes) + Added Level_Up_Chat_Broadcasts settings to config.yml under General + New locale string 'Broadcasts.LevelUpMilestone' + Version 2.1.170 Reverted a change that broke compatibility with the mcMMO papi ecloud thingy diff --git a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java index 6c736fd2c..af3b3366c 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/AddlevelsCommand.java @@ -1,11 +1,13 @@ package com.gmail.nossr50.commands.experience; import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -30,7 +32,14 @@ public class AddlevelsCommand extends ExperienceCommand { return; } - EventUtils.tryLevelChangeEvent(player, skill, value, xpRemoved, true, XPGainReason.COMMAND); + McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + + if(mmoPlayer == null) { + EventUtils.tryLevelChangeEvent(player, skill, value, xpRemoved, true, XPGainReason.COMMAND); + } else { + EventUtils.tryLevelChangeEvent(mmoPlayer, skill, value, xpRemoved, true, XPGainReason.COMMAND); + } + } @Override diff --git a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java b/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java index 9aa02b164..ac8405525 100644 --- a/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java +++ b/src/main/java/com/gmail/nossr50/commands/experience/MmoeditCommand.java @@ -1,11 +1,13 @@ package com.gmail.nossr50.commands.experience; import com.gmail.nossr50.datatypes.experience.XPGainReason; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.util.EventUtils; import com.gmail.nossr50.util.Permissions; +import com.gmail.nossr50.util.player.UserManager; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -36,7 +38,14 @@ public class MmoeditCommand extends ExperienceCommand { return; } - EventUtils.tryLevelEditEvent(player, skill, value, xpRemoved, value > skillLevel, XPGainReason.COMMAND, skillLevel); + McMMOPlayer mmoPlayer = UserManager.getPlayer(player); + + if(mmoPlayer != null) { + EventUtils.tryLevelEditEvent(mmoPlayer, skill, value, xpRemoved, value > skillLevel, XPGainReason.COMMAND, skillLevel); + } else { + EventUtils.tryLevelEditEvent(player, skill, value, xpRemoved, value > skillLevel, XPGainReason.COMMAND, skillLevel); + } + } @Override diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java index 9747d3acb..297ab3088 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -581,4 +581,12 @@ public class Config extends AutoUpdateConfigLoader { public boolean playerJoinEventInfo() { return config.getBoolean("General.EventInfoOnPlayerJoin", true);} public boolean adminNotifications() { return config.getBoolean("General.AdminNotifications", true);} + public boolean shouldLevelUpBroadcasts() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Enabled", true); } + public boolean shouldLevelUpBroadcastToConsole() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Send_To_Console", true); } + public boolean isLevelUpBroadcastsPartyMembersOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Only_Party_Members", false); } + public boolean isLevelUpBroadcastsSameWorldOnly() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Only_Same_World", false); } + public boolean shouldLevelUpBroadcastsRestrictDistance() { return config.getBoolean("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Distance_Restrictions.Restrict_Distance", false); } + public int getLevelUpBroadcastRadius() { return config.getInt("General.Level_Up_Chat_Broadcasts.Broadcast_Targets.Distance_Restrictions.Restricted_Radius", 100); } + public int getLevelUpBroadcastInterval() { return config.getInt("General.Level_Up_Chat_Broadcasts.Milestone_Interval", 100); } + } diff --git a/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java b/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java new file mode 100644 index 000000000..8820f7742 --- /dev/null +++ b/src/main/java/com/gmail/nossr50/datatypes/LevelUpBroadcastPredicate.java @@ -0,0 +1,100 @@ +package com.gmail.nossr50.datatypes; + +import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.datatypes.party.Party; +import com.gmail.nossr50.datatypes.player.McMMOPlayer; +import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.Misc; +import com.gmail.nossr50.util.player.UserManager; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Predicate; + +//TODO: Allow for offline players to broadcast +public class LevelUpBroadcastPredicate implements Predicate { + + private final @NotNull T broadcaster; + + public LevelUpBroadcastPredicate(@NotNull T broadcaster) { + this.broadcaster = broadcaster; + } + + @Override + public boolean test(@NotNull T t) { + Player broadcastingPlayer = (Player) broadcaster; //Always a player no need to check cast + + //Broadcaster should be online + if(!broadcastingPlayer.isOnline()) { + return false; + } + + McMMOPlayer mmoBroadcastingPlayer = UserManager.getPlayer(broadcastingPlayer); + + if(mmoBroadcastingPlayer == null) { + //This should never be null, but just in case... + mcMMO.p.getLogger().severe("McMMOPlayer was null for broadcaster in LevelUpBroadcastPredicate when it should never be null!"); + return false; + } + + if(t instanceof Player) { + Player listeningPlayer = (Player) t; + + //Party Member Check + if(Config.getInstance().isLevelUpBroadcastsPartyMembersOnly()) { + McMMOPlayer mmoListeningPlayer = UserManager.getPlayer(listeningPlayer); + + if(mmoListeningPlayer == null) { + return false; //No profile so therefor no party + } + + Party playerWhoLeveledParty = mmoBroadcastingPlayer.getParty(); + Party broadcastRecipientParty = mmoListeningPlayer.getParty(); + + if(playerWhoLeveledParty == null || broadcastRecipientParty == null) { + return false; //No party on either player when being in the same party is required + } + + if(!playerWhoLeveledParty.equals(broadcastRecipientParty)) { + return false; //Not in the same party when it is required + } + } + + //Same world check + if(isLevelUpBroadcastsSameWorldOnly()) { + if(!mmoBroadcastingPlayer.getPlayer().getWorld().equals(listeningPlayer.getWorld())) { + return false; //Not in the same world when its required + } + + //Distance checks + if(Config.getInstance().shouldLevelUpBroadcastsRestrictDistance()) { + if(!Misc.isNear(mmoBroadcastingPlayer.getPlayer().getLocation(), listeningPlayer.getLocation(), Config.getInstance().getLevelUpBroadcastRadius())) { + return false; + } + } + } + + //Visibility checks + if(!listeningPlayer.canSee(mmoBroadcastingPlayer.getPlayer())) { + return false; //Player who leveled should be invisible to this player so don't send the message + } + + return true; + } else { + //Send out to console + return Config.getInstance().shouldLevelUpBroadcastToConsole(); + } + } + + private static boolean isLevelUpBroadcastsSameWorldOnly() { + return Config.getInstance().isLevelUpBroadcastsSameWorldOnly(); + } + + @Override + public String toString() { + return "LevelUpBroadcastPredicate{" + + "broadcaster=" + broadcaster + + '}'; + } +} diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index db72ffeec..fb68f24ea 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -652,7 +652,7 @@ public class McMMOPlayer implements Identified { levelsGained++; } - if (EventUtils.tryLevelChangeEvent(player, primarySkillType, levelsGained, xpRemoved, true, xpGainReason)) { + if (EventUtils.tryLevelChangeEvent(this, primarySkillType, levelsGained, xpRemoved, true, xpGainReason)) { return; } diff --git a/src/main/java/com/gmail/nossr50/util/EventUtils.java b/src/main/java/com/gmail/nossr50/util/EventUtils.java index 52a2f989e..a928c7c82 100644 --- a/src/main/java/com/gmail/nossr50/util/EventUtils.java +++ b/src/main/java/com/gmail/nossr50/util/EventUtils.java @@ -32,6 +32,7 @@ import com.gmail.nossr50.events.skills.secondaryabilities.SubSkillEvent; import com.gmail.nossr50.events.skills.unarmed.McMMOPlayerDisarmEvent; import com.gmail.nossr50.locale.LocaleLoader; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.player.NotificationManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.CombatUtils; import org.bukkit.block.Block; @@ -232,6 +233,24 @@ public final class EventUtils { return isCancelled; } + public static boolean tryLevelChangeEvent(@NotNull McMMOPlayer mmoPlayer, PrimarySkillType skill, int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason) { + McMMOPlayerLevelChangeEvent event = isLevelUp ? new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), skill, levelsChanged, xpGainReason) : new McMMOPlayerLevelDownEvent(mmoPlayer.getPlayer(), skill, levelsChanged, xpGainReason); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + boolean isCancelled = event.isCancelled(); + + if (isCancelled) { + mmoPlayer.modifySkill(skill, mmoPlayer.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); + mmoPlayer.addXp(skill, xpRemoved); + } else { + if (isLevelUp) { + NotificationManager.processLevelUpBroadcasting(mmoPlayer, skill, mmoPlayer.getSkillLevel(skill)); + } + } + + return isCancelled; + } + public static boolean tryLevelEditEvent(Player player, PrimarySkillType skill, int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason, int oldLevel) { McMMOPlayerLevelChangeEvent event = isLevelUp ? new McMMOPlayerLevelUpEvent(player, skill, levelsChanged - oldLevel, xpGainReason) : new McMMOPlayerLevelDownEvent(player, skill, levelsChanged, xpGainReason); mcMMO.p.getServer().getPluginManager().callEvent(event); @@ -248,6 +267,24 @@ public final class EventUtils { return isCancelled; } + public static boolean tryLevelEditEvent(@NotNull McMMOPlayer mmoPlayer, PrimarySkillType skill, int levelsChanged, float xpRemoved, boolean isLevelUp, XPGainReason xpGainReason, int oldLevel) { + McMMOPlayerLevelChangeEvent event = isLevelUp ? new McMMOPlayerLevelUpEvent(mmoPlayer.getPlayer(), skill, levelsChanged - oldLevel, xpGainReason) : new McMMOPlayerLevelDownEvent(mmoPlayer.getPlayer(), skill, levelsChanged, xpGainReason); + mcMMO.p.getServer().getPluginManager().callEvent(event); + + boolean isCancelled = event.isCancelled(); + + if (isCancelled) { + mmoPlayer.modifySkill(skill, mmoPlayer.getSkillLevel(skill) - (isLevelUp ? levelsChanged : -levelsChanged)); + mmoPlayer.addXp(skill, xpRemoved); + } else { + if (isLevelUp) { + NotificationManager.processLevelUpBroadcasting(mmoPlayer, skill, mmoPlayer.getSkillLevel(skill)); + } + } + + return isCancelled; + } + /** * Simulate a block break event. * diff --git a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java index b334566f2..5e20de087 100644 --- a/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java +++ b/src/main/java/com/gmail/nossr50/util/player/NotificationManager.java @@ -2,6 +2,7 @@ package com.gmail.nossr50.util.player; import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.Config; +import com.gmail.nossr50.datatypes.LevelUpBroadcastPredicate; import com.gmail.nossr50.datatypes.interactions.NotificationType; import com.gmail.nossr50.datatypes.notifications.SensitiveCommandType; import com.gmail.nossr50.datatypes.player.McMMOPlayer; @@ -19,14 +20,23 @@ import net.kyori.adventure.audience.Audience; import net.kyori.adventure.audience.MessageType; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.TextColor; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Server; import org.bukkit.SoundCategory; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.time.LocalDate; public class NotificationManager { + + public static final String HEX_BEIGE_COLOR = "#c2a66e"; + public static final String HEX_LIME_GREEN_COLOR = "#8ec26e"; + /** * Sends players notifications from mcMMO * Does so by sending out an event so other plugins can cancel it @@ -256,4 +266,37 @@ public class NotificationManager { return newArray; } + public static void processLevelUpBroadcasting(@NotNull McMMOPlayer mmoPlayer, @NotNull PrimarySkillType primarySkillType, int level) { + if(level <= 0) + return; + + //Check if broadcasting is enabled + if(Config.getInstance().shouldLevelUpBroadcasts()) { + int levelInterval = Config.getInstance().getLevelUpBroadcastInterval(); + int remainder = level % levelInterval; + + if(remainder == 0) { + //Grab appropriate audience + Audience audience = mcMMO.getAudiences().filter(getLevelUpBroadcastPredicate(mmoPlayer.getPlayer())); + //TODO: Make prettier+ + HoverEvent levelMilestoneHover = Component.text(mmoPlayer.getPlayer().getName()) + .append(Component.newline()) + .append(Component.text(LocalDate.now().toString())) + .append(Component.newline()) + .append(Component.text(primarySkillType.getName()+" reached level "+level)).color(TextColor.fromHexString(HEX_BEIGE_COLOR)) + .asHoverEvent(); + + String localeMessage = LocaleLoader.getString("Broadcasts.LevelUpMilestone", mmoPlayer.getPlayer().getDisplayName(), level, primarySkillType.toString()); + Component message = Component.text(localeMessage).hoverEvent(levelMilestoneHover); + + audience.sendMessage(Identity.nil(), message); + } + } + } + + //TODO: Could cache + public static @NotNull LevelUpBroadcastPredicate getLevelUpBroadcastPredicate(@NotNull CommandSender levelUpPlayer) { + return new LevelUpBroadcastPredicate<>(levelUpPlayer); + } + } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 748d8a6ba..7e2d6b787 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -8,6 +8,24 @@ # Settings for mcMMO in general ### General: + # When players reach certain level milestones messages will be broadcast + Level_Up_Chat_Broadcasts: + # Whether or not level up broadcasts are enabled + Enabled: true + # How often to broadcast, you can change this to 1 to always broadcast a level up event, a setting of 100 will limit it to every 100 levels (for example level 100, level 200, etc) + Milestone_Interval: 100 + Broadcast_Targets: + # Send the message to the console as well + Send_To_Console: true + # Whether or not to only send chat messages to party members + Only_Party_Members: false + # Whether or not players who recieve a level up broadcast have to be on the same world as the one who leveled up + Only_Same_World: false + # Distance restrictions + Distance_Restrictions: + Restrict_Distance: false + # When using Restrict_Distance the blow setting configures the range of the broadcast + Restricted_Radius: 100 # Turning this on will scale mcMMO around 1-1000 with default scaling factor # Everything in your config related to skill level requirements, skill level bonuses, etc will be multiplied by 10 when this mode is on # This change is purely cosmetic, it retains the old feel of mcMMO where you could level up thousands of times diff --git a/src/main/resources/locale/locale_en_US.properties b/src/main/resources/locale/locale_en_US.properties index 9e98a9420..ae6616f7e 100644 --- a/src/main/resources/locale/locale_en_US.properties +++ b/src/main/resources/locale/locale_en_US.properties @@ -1135,4 +1135,5 @@ Chat.Style.Party.Leader=&a(P) &r{0} &6\u2192 &r{1} Chat.Identity.Console=&6* Console * Chat.Channel.On=&6(&amcMMO-Chat&6) &eYour chat messages will now be automatically delivered to the &a{0}&e chat channel. Chat.Channel.Off=&6(&amcMMO-Chat&6) &7Your chat messages will no longer be automatically delivered to specific chat channels. -Chat.Spy.Party=&6[&eSPY&6-&a{2}&6] &r{0} &b\u2192 &r{1} \ No newline at end of file +Chat.Spy.Party=&6[&eSPY&6-&a{2}&6] &r{0} &b\u2192 &r{1} +Broadcasts.LevelUpMilestone=&6(&amcMMO&6) {0}&7 has reached level &a{1}&7 in [[DARK_AQUA]]{2}&7! \ No newline at end of file