forked from Fascinated/Bat
add a basic event system to clean up scoresaber score receiving
This commit is contained in:
parent
c0ae0fc596
commit
aa6ab7d3d8
@ -1,6 +1,5 @@
|
|||||||
package cc.fascinated.bat.common;
|
package cc.fascinated.bat.common;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
20
src/main/java/cc/fascinated/bat/event/EventListener.java
Normal file
20
src/main/java/cc/fascinated/bat/event/EventListener.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package cc.fascinated.bat.event;
|
||||||
|
|
||||||
|
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberLeaderboardToken;
|
||||||
|
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberPlayerScoreToken;
|
||||||
|
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberScoreToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fascinated (fascinated7)
|
||||||
|
*/
|
||||||
|
public interface EventListener {
|
||||||
|
/**
|
||||||
|
* Called when a ScoreSaber score is received
|
||||||
|
*
|
||||||
|
* @param score the score that was set
|
||||||
|
* @param leaderboard the leaderboard that the score was set on
|
||||||
|
* @param player the player that set the score
|
||||||
|
*/
|
||||||
|
default void onScoresaberScoreReceived(ScoreSaberPlayerScoreToken score, ScoreSaberLeaderboardToken leaderboard,
|
||||||
|
ScoreSaberScoreToken.LeaderboardPlayerInfo player) {}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package cc.fascinated.bat.features.scoresaber;
|
||||||
|
|
||||||
|
import cc.fascinated.bat.common.Colors;
|
||||||
|
import cc.fascinated.bat.common.DateUtils;
|
||||||
|
import cc.fascinated.bat.common.NumberUtils;
|
||||||
|
import cc.fascinated.bat.common.ScoreSaberUtils;
|
||||||
|
import cc.fascinated.bat.event.EventListener;
|
||||||
|
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberLeaderboardToken;
|
||||||
|
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberPlayerScoreToken;
|
||||||
|
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberScoreToken;
|
||||||
|
import cc.fascinated.bat.model.guild.BatGuild;
|
||||||
|
import cc.fascinated.bat.model.guild.profiles.ScoreSaberUserScoreFeedProfile;
|
||||||
|
import cc.fascinated.bat.service.DiscordService;
|
||||||
|
import cc.fascinated.bat.service.GuildService;
|
||||||
|
import net.dv8tion.jda.api.EmbedBuilder;
|
||||||
|
import net.dv8tion.jda.api.entities.Guild;
|
||||||
|
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fascinated (fascinated7)
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ScoreSaberScoreFeedListener implements EventListener {
|
||||||
|
private final GuildService guildService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ScoreSaberScoreFeedListener(GuildService guildService) {
|
||||||
|
this.guildService = guildService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onScoresaberScoreReceived(ScoreSaberPlayerScoreToken score, ScoreSaberLeaderboardToken leaderboard,
|
||||||
|
ScoreSaberScoreToken.LeaderboardPlayerInfo player) {
|
||||||
|
for (Guild guild : DiscordService.JDA.getGuilds()) {
|
||||||
|
BatGuild batGuild = guildService.getGuild(guild.getId());
|
||||||
|
if (batGuild == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScoreSaberUserScoreFeedProfile profile = batGuild.getProfile(ScoreSaberUserScoreFeedProfile.class);
|
||||||
|
if (profile == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (profile.getChannelId() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!profile.getTrackedUsers().contains(player.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.getAsTextChannel().sendMessageEmbeds(this.buildScoreEmbed(score)).queue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an embed for a score.
|
||||||
|
*
|
||||||
|
* @param score The score.
|
||||||
|
* @return The embed.
|
||||||
|
*/
|
||||||
|
public MessageEmbed buildScoreEmbed(ScoreSaberPlayerScoreToken score) {
|
||||||
|
ScoreSaberScoreToken scoreToken = score.getScore();
|
||||||
|
ScoreSaberLeaderboardToken leaderboardToken = score.getLeaderboard();
|
||||||
|
ScoreSaberScoreToken.LeaderboardPlayerInfo playerInfo = scoreToken.getLeaderboardPlayerInfo();
|
||||||
|
return new EmbedBuilder()
|
||||||
|
.setAuthor(playerInfo.getName() + " just set a new score!", "https://scoresaber.com/u/%s".formatted(playerInfo.getId()),
|
||||||
|
"https://cdn.scoresaber.com/avatars/%s.jpg".formatted(playerInfo.getId()))
|
||||||
|
.setDescription("**%s** (%s%s)\n[[Map Link]](%s) [[SS Profile]](%s)".formatted(
|
||||||
|
leaderboardToken.getSongName(),
|
||||||
|
ScoreSaberUtils.getFormattedDifficulty(leaderboardToken.getDifficulty().getDifficulty()),
|
||||||
|
leaderboardToken.isRanked() ? " " + leaderboardToken.getStars() + "⭐" : "",
|
||||||
|
"https://scoresaber.com/leaderboard/%s".formatted(leaderboardToken.getId()),
|
||||||
|
"https://scoresaber.com/u/%s".formatted(playerInfo.getId())
|
||||||
|
))
|
||||||
|
.addField("Accuracy", "%s%%".formatted(
|
||||||
|
leaderboardToken.getMaxScore() == 0 ? "N/A" : NumberUtils.formatNumberCommas(((double) scoreToken.getBaseScore() / leaderboardToken.getMaxScore()) * 100)
|
||||||
|
), true)
|
||||||
|
.addField("Raw PP", scoreToken.getPp() == 0 ? "Unranked" : NumberUtils.formatNumberCommas(scoreToken.getPp()), true)
|
||||||
|
.addField("Global Rank", "#%s".formatted(NumberUtils.formatNumberCommas(scoreToken.getRank())), true)
|
||||||
|
.addField("Misses", "%s".formatted(scoreToken.getMissedNotes()), true)
|
||||||
|
.addField("Bad Cuts", "%s".formatted(scoreToken.getBadCuts()), true)
|
||||||
|
.addField("Max Combo", "%s %s".formatted(
|
||||||
|
scoreToken.getMaxCombo(),
|
||||||
|
scoreToken.getMaxCombo() == leaderboardToken.getMaxScore() ? "(FC)" : ""
|
||||||
|
), true)
|
||||||
|
.setColor(Colors.DEFAULT)
|
||||||
|
.setTimestamp(DateUtils.getDateFromString(scoreToken.getTimeSet()).toInstant())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
package cc.fascinated.bat.command.impl.global.beatsaber.scoresaber;
|
package cc.fascinated.bat.features.scoresaber.command.scoresaber;
|
||||||
|
|
||||||
import cc.fascinated.bat.command.BatSubCommand;
|
import cc.fascinated.bat.command.BatSubCommand;
|
||||||
import cc.fascinated.bat.common.EmbedUtils;
|
import cc.fascinated.bat.common.EmbedUtils;
|
||||||
import cc.fascinated.bat.model.guild.BatGuild;
|
|
||||||
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberAccountToken;
|
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberAccountToken;
|
||||||
|
import cc.fascinated.bat.model.guild.BatGuild;
|
||||||
import cc.fascinated.bat.model.user.BatUser;
|
import cc.fascinated.bat.model.user.BatUser;
|
||||||
import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile;
|
import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile;
|
||||||
import cc.fascinated.bat.service.ScoreSaberService;
|
import cc.fascinated.bat.service.ScoreSaberService;
|
@ -1,21 +1,19 @@
|
|||||||
package cc.fascinated.bat.command.impl.global.beatsaber.scoresaber;
|
package cc.fascinated.bat.features.scoresaber.command.scoresaber;
|
||||||
|
|
||||||
import cc.fascinated.bat.command.BatCommand;
|
import cc.fascinated.bat.command.BatCommand;
|
||||||
import cc.fascinated.bat.common.Colors;
|
import cc.fascinated.bat.common.Colors;
|
||||||
import cc.fascinated.bat.common.DateUtils;
|
import cc.fascinated.bat.common.DateUtils;
|
||||||
import cc.fascinated.bat.common.EmbedUtils;
|
import cc.fascinated.bat.common.EmbedUtils;
|
||||||
import cc.fascinated.bat.common.NumberUtils;
|
import cc.fascinated.bat.common.NumberUtils;
|
||||||
import cc.fascinated.bat.model.guild.BatGuild;
|
|
||||||
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberAccountToken;
|
import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberAccountToken;
|
||||||
|
import cc.fascinated.bat.model.guild.BatGuild;
|
||||||
import cc.fascinated.bat.model.user.BatUser;
|
import cc.fascinated.bat.model.user.BatUser;
|
||||||
import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile;
|
import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile;
|
||||||
import cc.fascinated.bat.service.ScoreSaberService;
|
import cc.fascinated.bat.service.ScoreSaberService;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
import net.dv8tion.jda.api.EmbedBuilder;
|
||||||
import net.dv8tion.jda.api.Permission;
|
|
||||||
import net.dv8tion.jda.api.entities.Member;
|
import net.dv8tion.jda.api.entities.Member;
|
||||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||||
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||||
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||||
@ -44,21 +42,9 @@ public class ScoreSaberCommand extends BatCommand {
|
|||||||
.addSubcommands(new SubcommandData("link", "Link your ScoreSaber profile")
|
.addSubcommands(new SubcommandData("link", "Link your ScoreSaber profile")
|
||||||
.addOptions(new OptionData(OptionType.STRING, "link", "Link your ScoreSaber profile", true))
|
.addOptions(new OptionData(OptionType.STRING, "link", "Link your ScoreSaber profile", true))
|
||||||
)
|
)
|
||||||
|
|
||||||
.addSubcommands(new SubcommandData("user", "View a user's ScoreSaber profile")
|
.addSubcommands(new SubcommandData("user", "View a user's ScoreSaber profile")
|
||||||
.addOptions(new OptionData(OptionType.USER, "user", "The user to view the ScoreSaber profile of", true))
|
.addOptions(new OptionData(OptionType.USER, "user", "The user to view the ScoreSaber profile of", true))
|
||||||
)
|
)
|
||||||
|
|
||||||
.addSubcommands(new SubcommandData("score-feed-user", "Edit your ScoreSaber score feed settings")
|
|
||||||
.addOptions(new OptionData(OptionType.USER, "user", "Add or remove a user from the score feed", false))
|
|
||||||
).setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER))
|
|
||||||
|
|
||||||
.addSubcommands(new SubcommandData("score-feed-clear-users", "Remove all users from the score feed"))
|
|
||||||
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER))
|
|
||||||
|
|
||||||
.addSubcommands(new SubcommandData("score-feed-channel", "Edit your ScoreSaber score feed settings")
|
|
||||||
.addOptions(new OptionData(OptionType.CHANNEL, "channel", "Set the channel to send the score feed in", false))
|
|
||||||
).setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package cc.fascinated.bat.command.impl.global.beatsaber.scoresaber;
|
package cc.fascinated.bat.features.scoresaber.command.scoresaber;
|
||||||
|
|
||||||
import cc.fascinated.bat.command.BatSubCommand;
|
import cc.fascinated.bat.command.BatSubCommand;
|
||||||
import cc.fascinated.bat.common.EmbedUtils;
|
import cc.fascinated.bat.common.EmbedUtils;
|
@ -1,10 +1,10 @@
|
|||||||
package cc.fascinated.bat.command.impl.guild.beatsaber.scoresaber;
|
package cc.fascinated.bat.features.scoresaber.command.userfeed;
|
||||||
|
|
||||||
import cc.fascinated.bat.command.BatSubCommand;
|
import cc.fascinated.bat.command.BatSubCommand;
|
||||||
import cc.fascinated.bat.common.EmbedUtils;
|
import cc.fascinated.bat.common.EmbedUtils;
|
||||||
import cc.fascinated.bat.common.TextChannelUtils;
|
import cc.fascinated.bat.common.TextChannelUtils;
|
||||||
import cc.fascinated.bat.model.guild.BatGuild;
|
import cc.fascinated.bat.model.guild.BatGuild;
|
||||||
import cc.fascinated.bat.model.guild.profiles.ScoreSaberScoreFeedProfile;
|
import cc.fascinated.bat.model.guild.profiles.ScoreSaberUserScoreFeedProfile;
|
||||||
import cc.fascinated.bat.model.user.BatUser;
|
import cc.fascinated.bat.model.user.BatUser;
|
||||||
import cc.fascinated.bat.service.GuildService;
|
import cc.fascinated.bat.service.GuildService;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -31,7 +31,7 @@ public class ScoreFeedChannelCommand extends BatSubCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) {
|
public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) {
|
||||||
ScoreSaberScoreFeedProfile profile = guild.getProfile(ScoreSaberScoreFeedProfile.class);
|
ScoreSaberUserScoreFeedProfile profile = guild.getProfile(ScoreSaberUserScoreFeedProfile.class);
|
||||||
OptionMapping option = interaction.getOption("channel");
|
OptionMapping option = interaction.getOption("channel");
|
||||||
if (option == null) {
|
if (option == null) {
|
||||||
if (!TextChannelUtils.isValidChannel(profile.getChannelId())) {
|
if (!TextChannelUtils.isValidChannel(profile.getChannelId())) {
|
@ -1,18 +1,15 @@
|
|||||||
package cc.fascinated.bat.command.impl.guild.beatsaber.scoresaber;
|
package cc.fascinated.bat.features.scoresaber.command.userfeed;
|
||||||
|
|
||||||
import cc.fascinated.bat.command.BatSubCommand;
|
import cc.fascinated.bat.command.BatSubCommand;
|
||||||
import cc.fascinated.bat.common.EmbedUtils;
|
import cc.fascinated.bat.common.EmbedUtils;
|
||||||
import cc.fascinated.bat.model.guild.BatGuild;
|
import cc.fascinated.bat.model.guild.BatGuild;
|
||||||
import cc.fascinated.bat.model.guild.profiles.ScoreSaberScoreFeedProfile;
|
import cc.fascinated.bat.model.guild.profiles.ScoreSaberUserScoreFeedProfile;
|
||||||
import cc.fascinated.bat.model.user.BatUser;
|
import cc.fascinated.bat.model.user.BatUser;
|
||||||
import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile;
|
|
||||||
import cc.fascinated.bat.service.GuildService;
|
import cc.fascinated.bat.service.GuildService;
|
||||||
import cc.fascinated.bat.service.UserService;
|
import cc.fascinated.bat.service.UserService;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import net.dv8tion.jda.api.entities.Member;
|
import net.dv8tion.jda.api.entities.Member;
|
||||||
import net.dv8tion.jda.api.entities.User;
|
|
||||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
|
||||||
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -31,7 +28,7 @@ public class ScoreFeedClearUsersCommand extends BatSubCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) {
|
public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) {
|
||||||
ScoreSaberScoreFeedProfile profile = guild.getProfile(ScoreSaberScoreFeedProfile.class);
|
ScoreSaberUserScoreFeedProfile profile = guild.getProfile(ScoreSaberUserScoreFeedProfile.class);
|
||||||
profile.getTrackedUsers().clear();
|
profile.getTrackedUsers().clear();
|
||||||
guildService.saveGuild(guild);
|
guildService.saveGuild(guild);
|
||||||
|
|
@ -1,10 +1,9 @@
|
|||||||
package cc.fascinated.bat.command.impl.guild.beatsaber.scoresaber;
|
package cc.fascinated.bat.features.scoresaber.command.userfeed;
|
||||||
|
|
||||||
import cc.fascinated.bat.command.BatSubCommand;
|
import cc.fascinated.bat.command.BatSubCommand;
|
||||||
import cc.fascinated.bat.common.EmbedUtils;
|
import cc.fascinated.bat.common.EmbedUtils;
|
||||||
import cc.fascinated.bat.common.Profile;
|
|
||||||
import cc.fascinated.bat.model.guild.BatGuild;
|
import cc.fascinated.bat.model.guild.BatGuild;
|
||||||
import cc.fascinated.bat.model.guild.profiles.ScoreSaberScoreFeedProfile;
|
import cc.fascinated.bat.model.guild.profiles.ScoreSaberUserScoreFeedProfile;
|
||||||
import cc.fascinated.bat.model.user.BatUser;
|
import cc.fascinated.bat.model.user.BatUser;
|
||||||
import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile;
|
import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile;
|
||||||
import cc.fascinated.bat.service.GuildService;
|
import cc.fascinated.bat.service.GuildService;
|
||||||
@ -34,7 +33,7 @@ public class ScoreFeedUserCommand extends BatSubCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) {
|
public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) {
|
||||||
ScoreSaberScoreFeedProfile profile = guild.getProfile(ScoreSaberScoreFeedProfile.class);
|
ScoreSaberUserScoreFeedProfile profile = guild.getProfile(ScoreSaberUserScoreFeedProfile.class);
|
||||||
OptionMapping option = interaction.getOption("user");
|
OptionMapping option = interaction.getOption("user");
|
||||||
if (option == null){
|
if (option == null){
|
||||||
if (profile.getTrackedUsers().isEmpty()) {
|
if (profile.getTrackedUsers().isEmpty()) {
|
35
src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ScoreSaberUserFeedCommand.java
Normal file
35
src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ScoreSaberUserFeedCommand.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package cc.fascinated.bat.features.scoresaber.command.userfeed;
|
||||||
|
|
||||||
|
import cc.fascinated.bat.command.BatCommand;
|
||||||
|
import net.dv8tion.jda.api.Permission;
|
||||||
|
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
|
||||||
|
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||||
|
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||||
|
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
|
||||||
|
import net.dv8tion.jda.internal.interactions.CommandDataImpl;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fascinated (fascinated7)
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ScoreSaberUserFeedCommand extends BatCommand {
|
||||||
|
public ScoreSaberUserFeedCommand() {
|
||||||
|
super("scoresaber-userfeed");
|
||||||
|
super.setCategory(Category.BEAT_SABER);
|
||||||
|
|
||||||
|
super.setDescription("ScoreSaber user score feed commands");
|
||||||
|
super.setCommandData(new CommandDataImpl(this.getName(), this.getDescription())
|
||||||
|
.addSubcommands(new SubcommandData("user", "Edit your ScoreSaber score feed settings")
|
||||||
|
.addOptions(new OptionData(OptionType.USER, "user", "Add or remove a user from the score feed", false))
|
||||||
|
).setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER))
|
||||||
|
|
||||||
|
.addSubcommands(new SubcommandData("clear-users", "Remove all users from the score feed"))
|
||||||
|
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER))
|
||||||
|
|
||||||
|
.addSubcommands(new SubcommandData("channel", "Edit your ScoreSaber score feed settings")
|
||||||
|
.addOptions(new OptionData(OptionType.CHANNEL, "channel", "Set the channel to send the score feed in", false))
|
||||||
|
).setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -13,9 +13,9 @@ import java.util.List;
|
|||||||
* @author Fascinated (fascinated7)
|
* @author Fascinated (fascinated7)
|
||||||
*/
|
*/
|
||||||
@Getter @Setter
|
@Getter @Setter
|
||||||
public class ScoreSaberScoreFeedProfile extends Profile {
|
public class ScoreSaberUserScoreFeedProfile extends Profile {
|
||||||
public ScoreSaberScoreFeedProfile() {
|
public ScoreSaberUserScoreFeedProfile() {
|
||||||
super("scoresaber-score-feed");
|
super("scoresaber-user-score-feed");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
@ -2,13 +2,14 @@ package cc.fascinated.bat.service;
|
|||||||
|
|
||||||
import cc.fascinated.bat.command.BatCommand;
|
import cc.fascinated.bat.command.BatCommand;
|
||||||
import cc.fascinated.bat.command.BatSubCommand;
|
import cc.fascinated.bat.command.BatSubCommand;
|
||||||
import cc.fascinated.bat.command.impl.global.beatsaber.scoresaber.LinkSubCommand;
|
|
||||||
import cc.fascinated.bat.command.impl.global.beatsaber.scoresaber.ScoreSaberCommand;
|
|
||||||
import cc.fascinated.bat.command.impl.global.beatsaber.scoresaber.UserSubCommand;
|
|
||||||
import cc.fascinated.bat.command.impl.guild.beatsaber.scoresaber.ScoreFeedChannelCommand;
|
|
||||||
import cc.fascinated.bat.command.impl.guild.beatsaber.scoresaber.ScoreFeedClearUsersCommand;
|
|
||||||
import cc.fascinated.bat.command.impl.guild.beatsaber.scoresaber.ScoreFeedUserCommand;
|
|
||||||
import cc.fascinated.bat.common.EmbedUtils;
|
import cc.fascinated.bat.common.EmbedUtils;
|
||||||
|
import cc.fascinated.bat.features.scoresaber.command.scoresaber.LinkSubCommand;
|
||||||
|
import cc.fascinated.bat.features.scoresaber.command.scoresaber.ScoreSaberCommand;
|
||||||
|
import cc.fascinated.bat.features.scoresaber.command.scoresaber.UserSubCommand;
|
||||||
|
import cc.fascinated.bat.features.scoresaber.command.userfeed.ScoreFeedChannelCommand;
|
||||||
|
import cc.fascinated.bat.features.scoresaber.command.userfeed.ScoreFeedClearUsersCommand;
|
||||||
|
import cc.fascinated.bat.features.scoresaber.command.userfeed.ScoreFeedUserCommand;
|
||||||
|
import cc.fascinated.bat.features.scoresaber.command.userfeed.ScoreSaberUserFeedCommand;
|
||||||
import cc.fascinated.bat.model.guild.BatGuild;
|
import cc.fascinated.bat.model.guild.BatGuild;
|
||||||
import cc.fascinated.bat.model.user.BatUser;
|
import cc.fascinated.bat.model.user.BatUser;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -47,16 +48,10 @@ public class CommandService extends ListenerAdapter {
|
|||||||
*/
|
*/
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
|
|
||||||
/**
|
|
||||||
* The application context to use
|
|
||||||
*/
|
|
||||||
private final ApplicationContext context;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public CommandService(@NonNull GuildService guildService, @NonNull UserService userService, @NonNull ApplicationContext context) {
|
public CommandService(@NonNull GuildService guildService, @NonNull UserService userService, @NonNull ApplicationContext context) {
|
||||||
this.guildService = guildService;
|
this.guildService = guildService;
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.context = context;
|
|
||||||
DiscordService.JDA.addEventListener(this);
|
DiscordService.JDA.addEventListener(this);
|
||||||
|
|
||||||
// Guild commands
|
// Guild commands
|
||||||
@ -66,9 +61,11 @@ public class CommandService extends ListenerAdapter {
|
|||||||
registerCommand(context.getBean(ScoreSaberCommand.class)
|
registerCommand(context.getBean(ScoreSaberCommand.class)
|
||||||
.addSubCommand("link", context.getBean(LinkSubCommand.class))
|
.addSubCommand("link", context.getBean(LinkSubCommand.class))
|
||||||
.addSubCommand("user", context.getBean(UserSubCommand.class))
|
.addSubCommand("user", context.getBean(UserSubCommand.class))
|
||||||
.addSubCommand("score-feed-user", context.getBean(ScoreFeedUserCommand.class))
|
);
|
||||||
.addSubCommand("score-feed-channel", context.getBean(ScoreFeedChannelCommand.class))
|
registerCommand(context.getBean(ScoreSaberUserFeedCommand.class)
|
||||||
.addSubCommand("score-feed-clear-users", context.getBean(ScoreFeedClearUsersCommand.class))
|
.addSubCommand("user", context.getBean(ScoreFeedUserCommand.class))
|
||||||
|
.addSubCommand("channel", context.getBean(ScoreFeedChannelCommand.class))
|
||||||
|
.addSubCommand("clear-users", context.getBean(ScoreFeedClearUsersCommand.class))
|
||||||
);
|
);
|
||||||
|
|
||||||
registerSlashCommands(); // Register all slash commands
|
registerSlashCommands(); // Register all slash commands
|
||||||
|
40
src/main/java/cc/fascinated/bat/service/EventService.java
Normal file
40
src/main/java/cc/fascinated/bat/service/EventService.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package cc.fascinated.bat.service;
|
||||||
|
|
||||||
|
import cc.fascinated.bat.event.EventListener;
|
||||||
|
import cc.fascinated.bat.features.scoresaber.ScoreSaberScoreFeedListener;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Fascinated (fascinated7)
|
||||||
|
*/
|
||||||
|
@Service @Log4j2
|
||||||
|
public class EventService {
|
||||||
|
/**
|
||||||
|
* The list of listeners registered
|
||||||
|
*/
|
||||||
|
public static final Set<EventListener> LISTENERS = new HashSet<>();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public EventService(@NonNull ApplicationContext context) {
|
||||||
|
registerListeners(
|
||||||
|
context.getBean(ScoreSaberScoreFeedListener.class)
|
||||||
|
);
|
||||||
|
log.info("Registered {} listeners.", LISTENERS.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers an event listener
|
||||||
|
*
|
||||||
|
* @param listener the listener to register
|
||||||
|
*/
|
||||||
|
public void registerListeners(EventListener... listener) {
|
||||||
|
LISTENERS.addAll(Set.of(listener));
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,17 @@
|
|||||||
package cc.fascinated.bat.service;
|
package cc.fascinated.bat.service;
|
||||||
|
|
||||||
import cc.fascinated.bat.BatApplication;
|
import cc.fascinated.bat.BatApplication;
|
||||||
import cc.fascinated.bat.common.*;
|
import cc.fascinated.bat.common.DateUtils;
|
||||||
|
import cc.fascinated.bat.common.WebRequest;
|
||||||
|
import cc.fascinated.bat.event.EventListener;
|
||||||
import cc.fascinated.bat.exception.BadRequestException;
|
import cc.fascinated.bat.exception.BadRequestException;
|
||||||
import cc.fascinated.bat.exception.ResourceNotFoundException;
|
import cc.fascinated.bat.exception.ResourceNotFoundException;
|
||||||
import cc.fascinated.bat.model.beatsaber.scoresaber.*;
|
import cc.fascinated.bat.model.beatsaber.scoresaber.*;
|
||||||
import cc.fascinated.bat.model.guild.BatGuild;
|
|
||||||
import cc.fascinated.bat.model.guild.profiles.ScoreSaberScoreFeedProfile;
|
|
||||||
import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile;
|
import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import net.dv8tion.jda.api.EmbedBuilder;
|
|
||||||
import net.dv8tion.jda.api.entities.Guild;
|
|
||||||
import net.dv8tion.jda.api.entities.MessageEmbed;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.socket.CloseStatus;
|
import org.springframework.web.socket.CloseStatus;
|
||||||
@ -26,19 +23,15 @@ import org.springframework.web.socket.handler.TextWebSocketHandler;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Service @Log4j2(topic = "ScoreSaber Service")
|
@Service @Log4j2(topic = "ScoreSaber Service")
|
||||||
public class ScoreSaberService extends TextWebSocketHandler {
|
public class ScoreSaberService extends TextWebSocketHandler {
|
||||||
private final GuildService guildService;
|
|
||||||
|
|
||||||
private static final String SCORESABER_API = "https://scoresaber.com/api/";
|
private static final String SCORESABER_API = "https://scoresaber.com/api/";
|
||||||
private static final String GET_PLAYER_ENDPOINT = SCORESABER_API + "player/%s/full";
|
private static final String GET_PLAYER_ENDPOINT = SCORESABER_API + "player/%s/full";
|
||||||
private static final String GET_PLAYER_SCORES_ENDPOINT = SCORESABER_API + "player/%s/scores?limit=100&sort=%s&page=%s&withMetadata=true";
|
private static final String GET_PLAYER_SCORES_ENDPOINT = SCORESABER_API + "player/%s/scores?limit=100&sort=%s&page=%s&withMetadata=true";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ScoreSaberService(@NonNull GuildService guildService) {
|
public ScoreSaberService() {
|
||||||
this.guildService = guildService;
|
|
||||||
connectWebSocket();
|
connectWebSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,42 +96,6 @@ public class ScoreSaberService extends TextWebSocketHandler {
|
|||||||
return scores;
|
return scores;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds an embed for a score.
|
|
||||||
*
|
|
||||||
* @param score The score.
|
|
||||||
* @return The embed.
|
|
||||||
*/
|
|
||||||
public MessageEmbed buildScoreEmbed(ScoreSaberPlayerScoreToken score) {
|
|
||||||
ScoreSaberScoreToken scoreToken = score.getScore();
|
|
||||||
ScoreSaberLeaderboardToken leaderboardToken = score.getLeaderboard();
|
|
||||||
ScoreSaberScoreToken.LeaderboardPlayerInfo playerInfo = scoreToken.getLeaderboardPlayerInfo();
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setAuthor(playerInfo.getName() + " just set a new score!", "https://scoresaber.com/u/%s".formatted(playerInfo.getId()),
|
|
||||||
"https://cdn.scoresaber.com/avatars/%s.jpg".formatted(playerInfo.getId()))
|
|
||||||
.setDescription("**%s** (%s%s)\n[[Map Link]](%s) [[SS Profile]](%s)".formatted(
|
|
||||||
leaderboardToken.getSongName(),
|
|
||||||
ScoreSaberUtils.getFormattedDifficulty(leaderboardToken.getDifficulty().getDifficulty()),
|
|
||||||
leaderboardToken.isRanked() ? " " + leaderboardToken.getStars() + "⭐" : "",
|
|
||||||
"https://scoresaber.com/leaderboard/%s".formatted(leaderboardToken.getId()),
|
|
||||||
"https://scoresaber.com/u/%s".formatted(playerInfo.getId())
|
|
||||||
))
|
|
||||||
.addField("Accuracy", "%s%%".formatted(
|
|
||||||
leaderboardToken.getMaxScore() == 0 ? "N/A" : NumberUtils.formatNumberCommas(((double) scoreToken.getBaseScore() / leaderboardToken.getMaxScore()) * 100)
|
|
||||||
), true)
|
|
||||||
.addField("Raw PP", scoreToken.getPp() == 0 ? "Unranked" : NumberUtils.formatNumberCommas(scoreToken.getPp()), true)
|
|
||||||
.addField("Global Rank", "#%s".formatted(NumberUtils.formatNumberCommas(scoreToken.getRank())), true)
|
|
||||||
.addField("Misses", "%s".formatted(scoreToken.getMissedNotes()), true)
|
|
||||||
.addField("Bad Cuts", "%s".formatted(scoreToken.getBadCuts()), true)
|
|
||||||
.addField("Max Combo", "%s %s".formatted(
|
|
||||||
scoreToken.getMaxCombo(),
|
|
||||||
scoreToken.getMaxCombo() == leaderboardToken.getMaxScore() ? "(FC)" : ""
|
|
||||||
), true)
|
|
||||||
.setColor(Colors.DEFAULT)
|
|
||||||
.setTimestamp(DateUtils.getDateFromString(scoreToken.getTimeSet()).toInstant())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects to the ScoreSaber WebSocket.
|
* Connects to the ScoreSaber WebSocket.
|
||||||
*/
|
*/
|
||||||
@ -175,24 +132,8 @@ public class ScoreSaberService extends TextWebSocketHandler {
|
|||||||
ScoreSaberPlayerScoreToken score = BatApplication.GSON.fromJson(data, ScoreSaberPlayerScoreToken.class);
|
ScoreSaberPlayerScoreToken score = BatApplication.GSON.fromJson(data, ScoreSaberPlayerScoreToken.class);
|
||||||
ScoreSaberScoreToken.LeaderboardPlayerInfo playerInfo = score.getScore().getLeaderboardPlayerInfo();
|
ScoreSaberScoreToken.LeaderboardPlayerInfo playerInfo = score.getScore().getLeaderboardPlayerInfo();
|
||||||
|
|
||||||
for (Guild guild : DiscordService.JDA.getGuilds()) {
|
for (EventListener listener : EventService.LISTENERS) {
|
||||||
BatGuild batGuild = guildService.getGuild(guild.getId());
|
listener.onScoresaberScoreReceived(score, score.getLeaderboard(), playerInfo);
|
||||||
if (batGuild == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScoreSaberScoreFeedProfile profile = batGuild.getProfile(ScoreSaberScoreFeedProfile.class);
|
|
||||||
if (profile == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (profile.getChannelId() == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!profile.getTrackedUsers().contains(playerInfo.getId())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.getAsTextChannel().sendMessageEmbeds(this.buildScoreEmbed(score)).queue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
Loading…
Reference in New Issue
Block a user