Skip to content

Commit

Permalink
feat: add support for Bedrock player avatars in embeds (closes #71) (#72
Browse files Browse the repository at this point in the history
)
  • Loading branch information
axieum authored Jun 5, 2023
1 parent a570d0a commit af69840
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ static Minecord getInstance()
/**
* Builds and returns a URL for retrieving a Minecraft player's avatar.
*
* @param username the Minecraft player username or UUID
* @param height the desired height of the avatar in pixels
* @param uuid the UUID of the Minecraft player
* @param height the desired height of the avatar in pixels
* @return the URL for the Minecraft player's avatar if enabled
* @see me.axieum.mcmod.minecord.impl.config.MiscConfig#enableAvatars
* @see me.axieum.mcmod.minecord.impl.config.MiscConfig#avatarUrl
*/
Optional<String> getAvatarUrl(@Nullable String username, int height);
Optional<String> getAvatarUrl(@Nullable String uuid, int height);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package me.axieum.mcmod.minecord.impl;

import java.util.Map;
import java.util.Optional;

import eu.pb4.placeholders.api.PlaceholderContext;
import me.shedaniel.autoconfig.ConfigHolder;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
Expand All @@ -24,11 +26,12 @@
import me.axieum.mcmod.minecord.api.addon.MinecordAddon;
import me.axieum.mcmod.minecord.api.event.JDAEvents;
import me.axieum.mcmod.minecord.api.event.ServerShutdownCallback;
import me.axieum.mcmod.minecord.api.util.StringTemplate;
import me.axieum.mcmod.minecord.api.util.PlaceholdersExt;
import me.axieum.mcmod.minecord.impl.callback.DiscordLifecycleListener;
import me.axieum.mcmod.minecord.impl.callback.ServerLifecycleCallback;
import me.axieum.mcmod.minecord.impl.config.MinecordConfig;
import me.axieum.mcmod.minecord.impl.placeholder.MinecordPlaceholders;
import static me.axieum.mcmod.minecord.api.util.PlaceholdersExt.string;

/**
* Minecord (API) implementation.
Expand Down Expand Up @@ -113,13 +116,15 @@ public Optional<JDA> getJDA()
}

@Override
public Optional<String> getAvatarUrl(@Nullable String username, int height)
public Optional<String> getAvatarUrl(@Nullable String uuid, int height)
{
// Only return an avatar URL if they are enabled and the provided username is valid
if (getConfig().misc.enableAvatars && username != null && !username.isBlank()) {
return Optional.ofNullable(
new StringTemplate().add("username", username).add("size", height).format(getConfig().misc.avatarUrl)
);
// Only return an avatar URL if they are enabled and the provided UUID is valid
if (getConfig().misc.enableAvatars && uuid != null && !uuid.isBlank()) {
return getMinecraft().map(server -> PlaceholdersExt.parseString(
getConfig().misc.avatarUrlNode,
PlaceholderContext.of(server),
Map.of("uuid", string(uuid), "size", string(String.valueOf(height)))
));
}
return Optional.empty();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package me.axieum.mcmod.minecord.impl.config;

import eu.pb4.placeholders.api.node.TextNode;
import me.shedaniel.autoconfig.ConfigData;
import me.shedaniel.autoconfig.annotation.Config;
import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment;
import static net.dv8tion.jda.api.EmbedBuilder.URL_PATTERN;

import static me.axieum.mcmod.minecord.api.util.PlaceholdersExt.parseNode;

/**
* Minecord miscellaneous configuration schema.
*/
Expand All @@ -18,12 +21,18 @@ public class MiscConfig implements ConfigData
/**
* The URL used for retrieving Minecraft player avatars.
*
* <p>Usages: {@code ${username}} and {@code ${size}} (height in pixels).
* <ul>
* <li>{@code ${uuid}} &mdash; the UUID of the Minecraft player</li>
* <li>{@code ${size}} &mdash; the desired avatar height in pixels</li>
* </ul>
*/
@Comment("""
The URL used for retrieving Minecraft player avatars
Usages: ${username} and ${size} (height in pixels)""")
public String avatarUrl = "https://minotar.net/helm/${username}/${size}";
Usages: ${uuid} and ${size} (height in pixels)""")
public String avatarUrl = "https://api.tydiumcraft.net/v1/players/skin?uuid=${uuid}&type=avatar&size=${size}";

/** Pre-parsed 'avatarUrl' text node. */
public transient TextNode avatarUrlNode;

@Override
public void validatePostLoad() throws ValidationException
Expand All @@ -36,5 +45,6 @@ public void validatePostLoad() throws ValidationException
} else if (!URL_PATTERN.matcher(avatarUrl).matches()) {
throw new ValidationException("The avatar URL must be a valid http(s) or attachment url!");
}
avatarUrlNode = parseNode(avatarUrl);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,19 @@ public static void embed(
* @param builder consumer to modify the Discord embed builder for a chat entry before queuing
* @param action consumer to act upon the resulting Discord message action
* @param predicate predicate that filters configured chat entries
* @param username Minecraft player username for the avatar embed thumbnail
* @param uuid the UUID of the Minecraft player in the avatar embed thumbnail
* @see #embed(BiConsumer, BiConsumer, Predicate)
*/
public static void embedWithAvatar(
BiConsumer<EmbedBuilder, ChatEntrySchema> builder,
BiConsumer<MessageCreateAction, ChatEntrySchema> action,
Predicate<ChatEntrySchema> predicate,
@Nullable String username
@Nullable String uuid
)
{
embed(
(message, entry) -> {
Minecord.getInstance().getAvatarUrl(username, 16).ifPresent(message::setThumbnail);
Minecord.getInstance().getAvatarUrl(uuid, 16).ifPresent(message::setThumbnail);
builder.accept(message, entry);
},
action,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ public void execute(@NotNull SlashCommandInteractionEvent event, @Nullable Minec
final CommandContext<ServerCommandSource> context = parseResults.getContext().build(mcCommand);

// Analyse the command context for a player's UUID to show their avatar on any command feedback
findPlayerUsernames(context.getLastChild()).findFirst()
.flatMap(name -> Minecord.getInstance().getAvatarUrl(name, 16))
findPlayerUuids(context.getLastChild()).findFirst()
.flatMap(uuid -> Minecord.getInstance().getAvatarUrl(uuid, 16))
.ifPresent(url -> output.thumbnailUrl = url);

// Execute the command
Expand Down Expand Up @@ -206,12 +206,12 @@ private static String prepareCommand(

/**
* Traverses the nodes of a Minecraft command context for a player-related
* argument and returns their UUID or username if present.
* argument and returns their UUID if present.
*
* @param context Minecraft command context
* @return a stream of Minecraft player usernames or UUIDs if present
* @return a stream of Minecraft player UUIDs if present
*/
private static Stream<String> findPlayerUsernames(CommandContext<ServerCommandSource> context)
private static Stream<String> findPlayerUuids(CommandContext<ServerCommandSource> context)
{
return context
.getNodes()
Expand Down

0 comments on commit af69840

Please sign in to comment.