Add the server lookup command
This commit is contained in:
parent
1474598a1a
commit
6c8d486052
@ -2,6 +2,7 @@ package cc.restfulmc.bot.command;
|
||||
|
||||
import cc.restfulmc.bot.DiscordBot;
|
||||
import cc.restfulmc.bot.command.impl.PlayerCommand;
|
||||
import cc.restfulmc.bot.command.impl.ServerCommand;
|
||||
import cc.restfulmc.sdk.client.RESTfulMCClient;
|
||||
import lombok.NonNull;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
@ -20,7 +21,9 @@ public final class CommandManager extends ListenerAdapter {
|
||||
private final List<SlashCommand> commands = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
public CommandManager(@NonNull DiscordBot bot, @NonNull RESTfulMCClient apiClient) {
|
||||
// Register commands
|
||||
registerCommand(new PlayerCommand(apiClient));
|
||||
registerCommand(new ServerCommand(apiClient));
|
||||
|
||||
// Update the commands on Discord
|
||||
CommandListUpdateAction updateCommands = bot.getJda().updateCommands();
|
||||
|
@ -53,10 +53,21 @@ public abstract class SlashCommand {
|
||||
* @param apiError the api error to reply with
|
||||
*/
|
||||
protected final void replyWithApiError(@NonNull SlashCommandInteractionEvent event, @NonNull RESTfulMCAPIException apiError) {
|
||||
replyWithGenericError(event, apiError.getCode() + " | API Error", apiError.getLocalizedMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Reply to an interaction with a generic error.
|
||||
*
|
||||
* @param event the event to reply to
|
||||
* @param title the title of the error
|
||||
* @param description the description of the error
|
||||
*/
|
||||
protected final void replyWithGenericError(@NonNull SlashCommandInteractionEvent event, @NonNull String title, @NonNull String description) {
|
||||
event.getHook().sendMessageEmbeds(new EmbedBuilder()
|
||||
.setColor(0xAA0000)
|
||||
.setTitle(apiError.getCode() + " | API Error")
|
||||
.setDescription(apiError.getMessage())
|
||||
.setTitle(title)
|
||||
.setDescription(description)
|
||||
.build()).queue();
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import cc.restfulmc.sdk.client.RESTfulMCClient;
|
||||
import cc.restfulmc.sdk.exception.RESTfulMCAPIException;
|
||||
import cc.restfulmc.sdk.response.Player;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
@ -16,6 +17,7 @@ import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||
/**
|
||||
* @author Braydon
|
||||
*/
|
||||
@Slf4j(topic = "Server Lookup Command")
|
||||
public final class PlayerCommand extends SlashCommand {
|
||||
/**
|
||||
* The API client to use for lookups.
|
||||
@ -49,7 +51,7 @@ public final class PlayerCommand extends SlashCommand {
|
||||
if (ex.getCause() instanceof RESTfulMCAPIException apiError) {
|
||||
replyWithApiError(event, apiError);
|
||||
} else { // Only print real errors
|
||||
ex.printStackTrace();
|
||||
log.error("Failed fetching player:", ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -0,0 +1,160 @@
|
||||
package cc.restfulmc.bot.command.impl;
|
||||
|
||||
import cc.restfulmc.bot.command.SlashCommand;
|
||||
import cc.restfulmc.bot.common.StringUtils;
|
||||
import cc.restfulmc.sdk.client.RESTfulMCClient;
|
||||
import cc.restfulmc.sdk.exception.RESTfulMCAPIException;
|
||||
import cc.restfulmc.sdk.response.server.BedrockMinecraftServer;
|
||||
import cc.restfulmc.sdk.response.server.JavaMinecraftServer;
|
||||
import cc.restfulmc.sdk.response.server.MinecraftServer;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dv8tion.jda.api.EmbedBuilder;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
|
||||
import net.dv8tion.jda.api.interactions.commands.OptionType;
|
||||
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Braydon
|
||||
*/
|
||||
@Slf4j(topic = "Server Lookup Command")
|
||||
public final class ServerCommand extends SlashCommand {
|
||||
private static final Map<MinecraftServer.Platform, String> MAPPED_PLATFORM_EMOJIS = new HashMap<>() {{
|
||||
put(MinecraftServer.Platform.JAVA, "<:grass_block:1232798337300828181>");
|
||||
put(MinecraftServer.Platform.BEDROCK, "<:bedrock_block:1232798365427830928>");
|
||||
}};
|
||||
private static final DecimalFormat PLAYERS_FORMAT = new DecimalFormat("#,##0");
|
||||
|
||||
/**
|
||||
* The API client to use for lookups.
|
||||
*/
|
||||
@NonNull private final RESTfulMCClient apiClient;
|
||||
|
||||
public ServerCommand(@NonNull RESTfulMCClient apiClient) {
|
||||
super("server", "Lookup a server by its platform and hostname",
|
||||
new OptionData(OptionType.STRING, "platform", "The platform: JAVA | BEDROCK").setRequired(true),
|
||||
new OptionData(OptionType.STRING, "hostname", "The hostname of the server").setRequired(true)
|
||||
);
|
||||
this.apiClient = apiClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked when this command is executed.
|
||||
*
|
||||
* @param user the executing user
|
||||
* @param member the executing member, null if in dms
|
||||
* @param event the event that triggered this command
|
||||
*/
|
||||
@Override
|
||||
public void onExecute(@NonNull User user, Member member, @NonNull SlashCommandInteractionEvent event) {
|
||||
OptionMapping platformOption = event.getOption("platform"); // The platform to query
|
||||
assert platformOption != null;
|
||||
String platformValue = platformOption.getAsString();
|
||||
MinecraftServer.Platform platform; // The platform to lookup
|
||||
try {
|
||||
platform = MinecraftServer.Platform.valueOf(platformValue.toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
replyWithGenericError(event, "Invalid Platform", "You must specify either **Java** or **Bedrock** as the platform.");
|
||||
return;
|
||||
}
|
||||
|
||||
OptionMapping hostname = event.getOption("hostname"); // Get the hostname to query
|
||||
assert hostname != null;
|
||||
String hostnameValue = hostname.getAsString(); // Get the hostname value
|
||||
|
||||
// Lookup the requested server by the given platform and hostname
|
||||
apiClient.async().getMinecraftServer(platform, hostnameValue).whenComplete((server, ex) -> {
|
||||
// Failed to lookup the server, handle the error
|
||||
if (ex != null) {
|
||||
if (ex.getCause() instanceof RESTfulMCAPIException apiError) {
|
||||
replyWithApiError(event, apiError);
|
||||
} else { // Only print real errors
|
||||
log.error("Failed fetching Minecraft Server:", ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Respond with the server
|
||||
String ip = server.getIp(); // The resolved IP of the server
|
||||
MinecraftServer.GeoLocation geo = server.getGeo(); // The geo location of the server
|
||||
MinecraftServer.Players players = server.getPlayers(); // The players on the server
|
||||
long cached = server.getCached(); // The timestamp the server was cached
|
||||
|
||||
EmbedBuilder embed = new EmbedBuilder()
|
||||
.setColor(0x55FF55)
|
||||
.setTitle(
|
||||
MAPPED_PLATFORM_EMOJIS.get(platform) + " " + StringUtils.capitalize(platform.name()) + " Server Response: " + server.getHostname(),
|
||||
"https://api.restfulmc.cc/server/" + platformValue + "/" + hostnameValue
|
||||
).addField("IP", (ip == null ? server.getHostname() : ip) + ":" + server.getPort(), true);
|
||||
|
||||
// Show Geo location if resolved
|
||||
if (geo != null) {
|
||||
MinecraftServer.GeoLocation.LocationData country = geo.getCountry(); // The server's country
|
||||
embed.addField("Located", ":flag_" + country.getCode().toLowerCase() + ": " + country.getName(), true);
|
||||
}
|
||||
|
||||
// Append platform specific details to the embed
|
||||
if (server instanceof JavaMinecraftServer javaServer) {
|
||||
appendJavaEmbed(embed, javaServer);
|
||||
} else {
|
||||
appendBedrockEmbed(embed, (BedrockMinecraftServer) server);
|
||||
}
|
||||
|
||||
event.getHook().sendMessageEmbeds(embed
|
||||
.addField("Players", PLAYERS_FORMAT.format(players.getOnline()) + "/" + PLAYERS_FORMAT.format(players.getMax()), true)
|
||||
.addField("Cached", cached == -1L ? "No" : "Yes, <t:" + (cached / 1000L) + ":R>", true)
|
||||
.setThumbnail(server instanceof JavaMinecraftServer javaServer ? javaServer.getFavicon().getUrl() : "https://api.restfulmc.cc/server/icon/invalid")
|
||||
.setFooter("Requested by " + user.getName() + " | " + user.getId(), user.getEffectiveAvatarUrl())
|
||||
.build()).queue();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Append Java specific details to an embed.
|
||||
*
|
||||
* @param embed the embed to append to
|
||||
* @param javaServer the java server
|
||||
*/
|
||||
private void appendJavaEmbed(@NonNull EmbedBuilder embed, @NonNull JavaMinecraftServer javaServer) {
|
||||
JavaMinecraftServer.Version version = javaServer.getVersion(); // The version of the server
|
||||
String protocolName = version.getProtocolName(); // The name of the server's version protocol
|
||||
String platform = version.getPlatform(); // The server's platform
|
||||
String world = javaServer.getWorld(); // The server's main world
|
||||
JavaMinecraftServer.Plugin[] plugins = javaServer.getPlugins(); // The server's plugins
|
||||
|
||||
embed.addField("Version", version.getProtocol() + (protocolName == null ? "" : " (" + protocolName + ")"), true);
|
||||
if (platform != null) {
|
||||
embed.addField("Platform", platform, true);
|
||||
}
|
||||
if (world != null) {
|
||||
embed.addField("World", world, true);
|
||||
}
|
||||
if (plugins != null) {
|
||||
embed.addField("Plugins", String.valueOf(plugins.length), true);
|
||||
}
|
||||
|
||||
embed.addField("Query", javaServer.isQueryEnabled() ? "Enabled" : "Disabled", true);
|
||||
embed.addField("Mojang Banned", javaServer.isMojangBanned() ? "Yes" : "No", true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append Bedrock specific details to an embed.
|
||||
*
|
||||
* @param embed the embed to append to
|
||||
* @param bedrockServer the bedrock server
|
||||
*/
|
||||
private void appendBedrockEmbed(@NonNull EmbedBuilder embed, @NonNull BedrockMinecraftServer bedrockServer) {
|
||||
BedrockMinecraftServer.Version version = bedrockServer.getVersion(); // The version of the server
|
||||
BedrockMinecraftServer.GameMode gamemode = bedrockServer.getGamemode(); // The game mode of the server
|
||||
|
||||
embed.addField("Version", version.getProtocol() + " (" + version.getName() + ")", true);
|
||||
embed.addField("Edition", bedrockServer.getEdition().name(), true);
|
||||
embed.addField("GameMode", gamemode.getName() + " (" + gamemode.getNumericId() + ")", true);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cc.restfulmc.bot.common;
|
||||
|
||||
import lombok.NonNull;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
/**
|
||||
* @author Braydon
|
||||
*/
|
||||
@UtilityClass
|
||||
public final class StringUtils {
|
||||
/**
|
||||
* Capitalize the first character in the given string.
|
||||
*
|
||||
* @param input the input to capitalize
|
||||
* @return the capitalized string
|
||||
*/
|
||||
@NonNull
|
||||
public static String capitalize(@NonNull String input) {
|
||||
return Character.toUpperCase(input.charAt(0)) + input.substring(1).toLowerCase();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user