Avatar urls, ignoring users/roles/bots/webhooks, changed config option naming scheme

This commit is contained in:
Vankka 2021-10-19 01:33:20 +03:00
parent 8accdbbdcd
commit a1b11c973c
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
23 changed files with 239 additions and 82 deletions

View File

@ -33,10 +33,16 @@ public interface DiscordUser extends Snowflake {
/**
* Gets if this user is the bot this DiscordSRV instance is connected.
* @return true if the bot is the bot connected to this DiscordSRV instance
* @return true if this user is the bot connected to this DiscordSRV instance
*/
boolean isSelf();
/**
* Gets if this user is a bot (or webhook).
* @return true if this user is a bot or webhook
*/
boolean isBot();
/**
* Gets the username of the Discord user.
* @return the user's username

View File

@ -82,7 +82,7 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
@Override
public @NotNull Optional<String> getWebhookAvatarUrl() {
return Optional.of(webhookAvatarUrl);
return Optional.ofNullable(webhookAvatarUrl);
}
public static class BuilderImpl implements SendableDiscordMessage.Builder {

View File

@ -40,7 +40,7 @@ public class Placeholders {
}
public Placeholders addAll(Map<Pattern, Function<Matcher, Object>> replacements) {
replacements.forEach(this.replacements::put);
this.replacements.putAll(replacements);
return this;
}

View File

@ -47,6 +47,6 @@ public interface DiscordSRVPlayer {
*/
@Placeholder("player_uuid")
@NotNull
UUID uuid();
UUID getUniqueId();
}

View File

@ -16,9 +16,9 @@ ext {
// MinecraftDependencyDownload
mddVersion = '1.0.0-SNAPSHOT'
// JDA
jdaVersion = '4.3.0_278'
jdaVersion = '4.3.0_334'
// Configurate
configurateVersion = '4.1.1'
configurateVersion = '4.1.2'
// Adventure & Adventure Platform
adventureVersion = '4.9.1'
adventurePlatformVersion = '4.0.0'

View File

@ -19,6 +19,7 @@
package com.discordsrv.bukkit.player;
import com.discordsrv.bukkit.BukkitDiscordSRV;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.component.util.ComponentUtil;
import com.discordsrv.common.player.IPlayer;
import net.kyori.adventure.audience.Audience;
@ -74,9 +75,14 @@ public class BukkitPlayer extends BukkitOfflinePlayer implements IPlayer {
discordSRV.server().dispatchCommand(player, command));
}
@Override
public DiscordSRV discordSRV() {
return discordSRV;
}
@SuppressWarnings("deprecation") // Paper
@Override
public @NotNull Component displayName() {
public @NotNull Component getDisplayName() {
if (DISPLAY_NAME_METHOD != null) {
try {
return ComponentUtil.fromUnrelocated(DISPLAY_NAME_METHOD.invoke(player));

View File

@ -20,6 +20,7 @@ package com.discordsrv.bungee.player;
import com.discordsrv.bungee.BungeeDiscordSRV;
import com.discordsrv.bungee.component.util.BungeeComponentUtil;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.player.IPlayer;
import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.identity.Identity;
@ -58,6 +59,11 @@ public class BungeePlayer implements IPlayer {
discordSRV.proxy().getPluginManager().dispatchCommand(player, command);
}
@Override
public DiscordSRV discordSRV() {
return discordSRV;
}
@Override
public @NotNull String getUsername() {
return player.getName();
@ -69,7 +75,7 @@ public class BungeePlayer implements IPlayer {
}
@Override
public @NotNull Component displayName() {
public @NotNull Component getDisplayName() {
return BungeeComponentUtil.fromLegacy(player.getDisplayName());
}
}

View File

@ -24,7 +24,7 @@ import com.discordsrv.common.config.main.channels.BaseChannelConfig;
import com.discordsrv.common.config.main.channels.ChannelConfig;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
@ConfigSerializable
@ -38,8 +38,8 @@ public class MainConfig implements Config {
}
@DefaultOnly("default")
public Map<String, BaseChannelConfig> channels = new HashMap<String, BaseChannelConfig>() {{
put("default", new BaseChannelConfig());
public Map<String, BaseChannelConfig> channels = new LinkedHashMap<String, BaseChannelConfig>() {{
put("global", new ChannelConfig());
put("default", new BaseChannelConfig());
}};
}

View File

@ -35,6 +35,8 @@ public class BaseChannelConfig {
public MinecraftToDiscordChatConfig minecraftToDiscord = new MinecraftToDiscordChatConfig();
public DiscordToMinecraftChatConfig discordToMinecraft = new DiscordToMinecraftChatConfig();
public String avatarUrlProvider = "https://heads.discordsrv.com/head.png?texture=%texture%&uuid=%uuid%&name=%username%&overlay";
public static class Serializer implements TypeSerializer<BaseChannelConfig> {
private final ObjectMapper.Factory mapperFactory;

View File

@ -24,7 +24,6 @@ import org.spongepowered.configurate.objectmapping.meta.Comment;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ConfigSerializable
@ -50,6 +49,6 @@ public class ChannelConfig extends BaseChannelConfig {
}
@Comment("The channels this in-game channel will forward to in Discord")
public List<Long> channelIds = new ArrayList<>(Collections.singletonList(0L));
public List<Long> channelIds = new ArrayList<>();
}

View File

@ -19,9 +19,36 @@
package com.discordsrv.common.config.main.channels.discordtominecraft;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
import org.spongepowered.configurate.objectmapping.meta.Comment;
import java.util.ArrayList;
import java.util.List;
@ConfigSerializable
public class DiscordToMinecraftChatConfig {
public String format = "[&#5865F2Discord&r] [hover:show_text:Tag: %user_tag%&r\nRoles: %user_roles_, %]%user_color%%user_effective_name%&r » %message%";
@Comment("The Discord to Minecraft message format for regular users")
public String format = "[&#5865F2Discord&r] [hover:show_text:Tag: %user_tag%&r\\nRoles: %user_roles_, %]%user_color%%user_effective_name%&r » %message%";
@Comment("The Discord to Minecraft message format for webhook messages (if enabled)")
public String webhookFormat = "[&#5865F2Discord&r] [hover:show_text:Webhook message]%user_name% » %message%";
@Comment("Users, bots and webhooks to ignore")
public Ignores ignores = new Ignores();
@ConfigSerializable
public static class Ignores {
@Comment("User and Webhook ids to ignore")
public List<Long> usersAndWebhookIds = new ArrayList<>();
@Comment("Role IDs for users/bots to ignore")
public List<Long> roleIds = new ArrayList<>();
@Comment("If bots (webhooks not included) should be ignored")
public boolean bots = false;
@Comment("If webhooks should be ignored")
public boolean webhooks = false;
}
}

View File

@ -20,14 +20,13 @@ package com.discordsrv.common.config.main.channels.minecraftodiscord;
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
import org.spongepowered.configurate.objectmapping.meta.Setting;
@ConfigSerializable
public class MinecraftToDiscordChatConfig {
@Setting("Format")
public SendableDiscordMessage.Builder messageFormat = SendableDiscordMessage.builder()
public SendableDiscordMessage.Builder format = SendableDiscordMessage.builder()
.setWebhookUsername("%player_display_name%")
.setWebhookAvatarUrl("%player_avatar_url%")
.setContent("%message%");// TODO
}

View File

@ -38,6 +38,7 @@ import org.spongepowered.configurate.loader.AbstractConfigurationLoader;
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
import org.spongepowered.configurate.objectmapping.ObjectMapper;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.util.NamingScheme;
import org.spongepowered.configurate.util.NamingSchemes;
import java.nio.file.Path;
@ -48,6 +49,12 @@ import java.util.Map;
public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurationLoader<CommentedConfigurationNode>>
implements ConfigManager<T>, ConfigLoaderProvider<LT> {
public static NamingScheme NAMING_SCHEME = in -> {
in = Character.toLowerCase(in.charAt(0)) + in.substring(1);
in = NamingSchemes.LOWER_CASE_DASHED.coerce(in);
return in;
};
protected final DiscordSRV discordSRV;
private final Path filePath;
private final ObjectMapper.Factory configObjectMapper;
@ -87,9 +94,9 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
ObjectMapper.Factory objectMapper = configObjectMapper();
builder.register(Color.class, new ColorSerializer());
builder.register(BaseChannelConfig.class, new BaseChannelConfig.Serializer(objectMapper));
builder.register(DiscordMessageEmbed.Builder.class, new DiscordMessageEmbedSerializer());
builder.register(DiscordMessageEmbed.Field.class, new DiscordMessageEmbedSerializer.FieldSerializer());
builder.register(SendableDiscordMessage.Builder.class, new SendableDiscordMessageSerializer());
builder.register(DiscordMessageEmbed.Builder.class, new DiscordMessageEmbedSerializer(NAMING_SCHEME));
builder.register(DiscordMessageEmbed.Field.class, new DiscordMessageEmbedSerializer.FieldSerializer(NAMING_SCHEME));
builder.register(SendableDiscordMessage.Builder.class, new SendableDiscordMessageSerializer(NAMING_SCHEME));
});
}
@ -103,10 +110,7 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
protected ObjectMapper.Factory.Builder objectMapperBuilder() {
return ObjectMapper.factoryBuilder()
.defaultNamingScheme(input -> {
String camelCase = NamingSchemes.CAMEL_CASE.coerce(input); // Gets rid of underscores and dashes
return Character.toUpperCase(camelCase.charAt(0)) + camelCase.substring(1);
});
.defaultNamingScheme(NAMING_SCHEME);
}
protected ObjectMapper.Factory.Builder configObjectMapperBuilder() {

View File

@ -25,48 +25,59 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import org.spongepowered.configurate.util.NamingScheme;
import java.lang.reflect.Type;
import java.util.Collections;
public class DiscordMessageEmbedSerializer implements TypeSerializer<DiscordMessageEmbed.Builder> {
private final NamingScheme namingScheme;
public DiscordMessageEmbedSerializer(NamingScheme namingScheme) {
this.namingScheme = namingScheme;
}
private String map(String option) {
return namingScheme.coerce(option);
}
@Override
public DiscordMessageEmbed.Builder deserialize(Type type, ConfigurationNode node) throws SerializationException {
if (!node.node("Enabled").getBoolean(node.node("Enable").getBoolean(true))) {
if (!node.node(map("Enabled")).getBoolean(node.node(map("Enable")).getBoolean(true))) {
return null;
}
DiscordMessageEmbed.Builder builder = DiscordMessageEmbed.builder();
Color color = node.node("Color").get(Color.class);
Color color = node.node(map("Color")).get(Color.class);
builder.setColor(color != null ? color.rgb() : Role.DEFAULT_COLOR_RAW);
ConfigurationNode author = node.node("Author");
builder.setAuthor(
author.node("Name").getString(),
author.node("Url").getString(),
author.node("ImageUrl").getString());
author.node(map("Name")).getString(),
author.node(map("Url")).getString(),
author.node(map("ImageUrl")).getString());
ConfigurationNode title = node.node("Title");
ConfigurationNode title = node.node(map("Title"));
builder.setTitle(
title.node("Text").getString(),
title.node("Url").getString());
title.node(map("Text")).getString(),
title.node(map("Url")).getString());
builder.setDescription(node.node("Description").getString());
builder.setDescription(node.node(map("Description")).getString());
for (DiscordMessageEmbed.Field field : node.getList(DiscordMessageEmbed.Field.class, Collections.emptyList())) {
builder.addField(field);
}
builder.setThumbnailUrl(node.node("ThumbnailUrl").getString());
builder.setImageUrl(node.node("ImageUrl").getString());
builder.setThumbnailUrl(node.node(map("ThumbnailUrl")).getString());
builder.setImageUrl(node.node(map("ImageUrl")).getString());
// TODO: timestamp
ConfigurationNode footer = node.node("Footer");
ConfigurationNode footer = node.node(map("Footer"));
builder.setFooter(
footer.node("Text").getString(),
footer.node("ImageUrl").getString(footer.node("IconUrl").getString()));
footer.node(map("Text")).getString(),
footer.node(map("ImageUrl")).getString(footer.node(map("IconUrl")).getString()));
return builder;
}
@ -79,30 +90,40 @@ public class DiscordMessageEmbedSerializer implements TypeSerializer<DiscordMess
return;
}
node.node("Color").set(obj.getColor());
node.node(map("Color")).set(obj.getColor());
ConfigurationNode author = node.node("Author");
author.node("Name").set(obj.getAuthorName());
author.node("Url").set(obj.getAuthorUrl());
author.node("ImageUrl").set(obj.getAuthorImageUrl());
ConfigurationNode author = node.node(map("Author"));
author.node(map("Name")).set(obj.getAuthorName());
author.node(map("Url")).set(obj.getAuthorUrl());
author.node(map("ImageUrl")).set(obj.getAuthorImageUrl());
ConfigurationNode title = node.node("Title");
title.node("Text").set(obj.getTitle());
title.node("Url").set(obj.getTitleUrl());
ConfigurationNode title = node.node(map("Title"));
title.node(map("Text")).set(obj.getTitle());
title.node(map("Url")).set(obj.getTitleUrl());
node.node("Description").set(obj.getDescription());
node.node("Fields").setList(DiscordMessageEmbed.Field.class, obj.getFields());
node.node(map("Description")).set(obj.getDescription());
node.node(map("Fields")).setList(DiscordMessageEmbed.Field.class, obj.getFields());
node.node("ThumbnailUrl").set(obj.getThumbnailUrl());
node.node("ImageUrl").set(obj.getImageUrl());
node.node(map("ThumbnailUrl")).set(obj.getThumbnailUrl());
node.node(map("ImageUrl")).set(obj.getImageUrl());
ConfigurationNode footer = node.node("Footer");
footer.node("Text").set(obj.getFooter());
footer.node("ImageUrl").set(obj.getFooterImageUrl());
ConfigurationNode footer = node.node(map("Footer"));
footer.node(map("Text")).set(obj.getFooter());
footer.node(map("ImageUrl")).set(obj.getFooterImageUrl());
}
public static class FieldSerializer implements TypeSerializer<DiscordMessageEmbed.Field> {
private final NamingScheme namingScheme;
public FieldSerializer(NamingScheme namingScheme) {
this.namingScheme = namingScheme;
}
private String map(String option) {
return namingScheme.coerce(option);
}
@Override
public DiscordMessageEmbed.Field deserialize(Type type, ConfigurationNode node) {
// v1 compat
@ -123,9 +144,9 @@ public class DiscordMessageEmbedSerializer implements TypeSerializer<DiscordMess
}
return new DiscordMessageEmbed.Field(
node.node("Title").getString(),
node.node("Value").getString(),
node.node("Inline").getBoolean()
node.node(map("Title")).getString(),
node.node(map("Value")).getString(),
node.node(map("Inline")).getBoolean()
);
}
@ -137,9 +158,9 @@ public class DiscordMessageEmbedSerializer implements TypeSerializer<DiscordMess
return;
}
node.node("Title").set(obj.getTitle());
node.node("Value").set(obj.getValue());
node.node("Inline").set(obj.isInline());
node.node(map("Title")).set(obj.getTitle());
node.node(map("Value")).set(obj.getValue());
node.node(map("Inline")).set(obj.isInline());
}
}

View File

@ -24,6 +24,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import org.spongepowered.configurate.util.NamingScheme;
import java.lang.reflect.Type;
import java.util.ArrayList;
@ -32,6 +33,16 @@ import java.util.List;
public class SendableDiscordMessageSerializer implements TypeSerializer<SendableDiscordMessage.Builder> {
private final NamingScheme namingScheme;
public SendableDiscordMessageSerializer(NamingScheme namingScheme) {
this.namingScheme = namingScheme;
}
private String map(String option) {
return namingScheme.coerce(option);
}
@Override
public SendableDiscordMessage.Builder deserialize(Type type, ConfigurationNode node)
throws SerializationException {
@ -43,27 +54,27 @@ public class SendableDiscordMessageSerializer implements TypeSerializer<Sendable
SendableDiscordMessage.Builder builder = SendableDiscordMessage.builder();
ConfigurationNode webhook = node.node("Webhook");
String webhookUsername = webhook.node("Username").getString();
if (webhook.node("Enabled").getBoolean(
webhook.node("Enable").getBoolean(
ConfigurationNode webhook = node.node(map("Webhook"));
String webhookUsername = webhook.node(map("Username")).getString();
if (webhook.node(map("Enabled")).getBoolean(
webhook.node(map("Enable")).getBoolean(
webhookUsername != null))) {
builder.setWebhookUsername(webhookUsername);
builder.setWebhookAvatarUrl(webhook.node("AvatarUrl").getString());
builder.setWebhookAvatarUrl(webhook.node(map("AvatarUrl")).getString());
}
// v1 compat
DiscordMessageEmbed.Builder singleEmbed = node.node("Embed").get(
DiscordMessageEmbed.Builder singleEmbed = node.node(map("Embed")).get(
DiscordMessageEmbed.Builder.class);
List<DiscordMessageEmbed.Builder> embedList = singleEmbed != null
? Collections.singletonList(singleEmbed) : Collections.emptyList();
for (DiscordMessageEmbed.Builder embed : node.node("Embeds")
for (DiscordMessageEmbed.Builder embed : node.node(map("Embeds"))
.getList(DiscordMessageEmbed.Builder.class, embedList)) {
builder.addEmbed(embed.build());
}
builder.setContent(node.node("Content").getString());
builder.setContent(node.node(map("Content")).getString());
return builder;
}
@ -77,17 +88,17 @@ public class SendableDiscordMessageSerializer implements TypeSerializer<Sendable
String webhookUsername = obj.getWebhookUsername();
if (webhookUsername != null) {
ConfigurationNode webhook = node.node("Webhook");
webhook.node("Username").set(webhookUsername);
webhook.node("AvatarUrl").set(obj.getWebhookAvatarUrl());
ConfigurationNode webhook = node.node(map("Webhook"));
webhook.node(map("Username")).set(webhookUsername);
webhook.node(map("AvatarUrl")).set(obj.getWebhookAvatarUrl());
}
List<DiscordMessageEmbed.Builder> embedBuilders = new ArrayList<>();
obj.getEmbeds().forEach(embed -> embedBuilders.add(embed.toBuilder()));
if (!embedBuilders.isEmpty()) {
node.node("Embeds").setList(DiscordMessageEmbed.Builder.class, embedBuilders);
node.node(map("Embeds")).setList(DiscordMessageEmbed.Builder.class, embedBuilders);
}
node.node("Content").set(obj.getContent());
node.node(map("Content")).set(obj.getContent());
}
}

View File

@ -60,6 +60,9 @@ public final class SendableDiscordMessageUtil {
embeds.add(embed.toJDA());
}
MessageBuilder builder = new MessageBuilder();
message.getContent().ifPresent(builder::setContent);
return new MessageBuilder()
.setContent(message.getContent().orElse(null))
.setEmbeds(embeds)

View File

@ -26,12 +26,14 @@ public class DiscordUserImpl implements DiscordUser {
private final long id;
private final boolean self;
private final boolean bot;
private final String username;
private final String discriminator;
public DiscordUserImpl(User user) {
this.id = user.getIdLong();
this.self = user.getIdLong() == user.getJDA().getSelfUser().getIdLong();
this.bot = user.isBot();
this.username = user.getName();
this.discriminator = user.getDiscriminator();
}
@ -46,6 +48,11 @@ public class DiscordUserImpl implements DiscordUser {
return self;
}
@Override
public boolean isBot() {
return bot;
}
@Override
public @NotNull String getUsername() {
return username;

View File

@ -20,7 +20,9 @@ package com.discordsrv.common.listener;
import com.discordsrv.api.channel.GameChannel;
import com.discordsrv.api.component.EnhancedTextBuilder;
import com.discordsrv.api.discord.api.entity.DiscordUser;
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
import com.discordsrv.api.discord.api.entity.guild.DiscordGuildMember;
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.events.discord.DiscordMessageReceivedEvent;
@ -33,6 +35,9 @@ import com.discordsrv.common.function.OrDefault;
import net.kyori.adventure.text.Component;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
import java.util.Optional;
public class DiscordChatListener extends AbstractListener {
public DiscordChatListener(DiscordSRV discordSRV) {
@ -59,6 +64,9 @@ public class DiscordChatListener extends AbstractListener {
}
DiscordTextChannel channel = event.getChannel();
ReceivedDiscordMessage discordMessage = event.getDiscordMessage();
DiscordUser author = discordMessage.getAuthor();
Optional<DiscordGuildMember> member = discordMessage.getMember();
OrDefault<Pair<GameChannel, BaseChannelConfig>> channelPair = discordSRV.channelConfig().orDefault(channel);
GameChannel gameChannel = channelPair.get(Pair::getKey);
@ -69,20 +77,44 @@ public class DiscordChatListener extends AbstractListener {
OrDefault<? extends BaseChannelConfig> channelConfig = channelPair.map(Pair::getValue);
OrDefault<DiscordToMinecraftChatConfig> chatConfig = channelConfig.map(cfg -> cfg.discordToMinecraft);
DiscordToMinecraftChatConfig.Ignores ignores = chatConfig.get(cfg -> cfg.ignores);
if (ignores != null) {
boolean webhookMessage = discordMessage.isWebhookMessage();
if (ignores.webhooks && webhookMessage) {
return;
} else if (ignores.bots && (author.isBot() && !webhookMessage)) {
return;
}
List<Long> users = ignores.usersAndWebhookIds;
if (users != null && users.contains(author.getId())) {
return;
}
List<Long> roles = ignores.roleIds;
boolean anyMatch = roles != null
? member
.map(m -> m.getRoles().stream().anyMatch(role -> roles.contains(role.getId())))
.orElse(false)
: false;
if (anyMatch) {
return;
}
}
String format = chatConfig.get(cfg -> cfg.format.replace("\\n", "\n"));
if (format == null) {
return;
}
ReceivedDiscordMessage discordMessage = event.getDiscordMessage();
DiscordSRVMinecraftRenderer.inGuildContext(channel.getGuild().getId(), () -> {
Component message = discordSRV.componentFactory().minecraftSerializer().serialize(event.getMessageContent());
EnhancedTextBuilder componentBuilder = discordSRV.componentFactory()
.enhancedBuilder(format)
.addContext(discordMessage, discordMessage.getAuthor())
.addContext(discordMessage, author)
.addReplacement("%message%", message);
discordMessage.getMember().ifPresent(componentBuilder::addContext);
member.ifPresent(componentBuilder::addContext);
gameChannel.sendMessage(componentBuilder.build());
});

View File

@ -55,7 +55,7 @@ public class GameChatListener extends AbstractListener {
OrDefault<BaseChannelConfig> channelConfig = discordSRV.channelConfig().orDefault(gameChannel);
OrDefault<MinecraftToDiscordChatConfig> chatConfig = channelConfig.map(cfg -> cfg.minecraftToDiscord);
SendableDiscordMessage.Builder builder = chatConfig.get(cfg -> cfg.messageFormat);
SendableDiscordMessage.Builder builder = chatConfig.get(cfg -> cfg.format);
if (builder == null) {
return;
}
@ -64,7 +64,7 @@ public class GameChatListener extends AbstractListener {
String serializedMessage = discordSRV.componentFactory().discordSerializer().serialize(message);
SendableDiscordMessage discordMessage = builder.toFormatter()
.addContext(event.getPlayer())
.addContext(event.getPlayer(), gameChannel)
.addReplacement("%message%", serializedMessage)
.build();

View File

@ -35,7 +35,7 @@ public interface IOfflinePlayer extends Identified {
@ApiStatus.NonExtendable
@Placeholder("player_uuid")
@NotNull
default UUID uuid() {
default UUID getUniqueId() {
return identity().uuid();
}
}

View File

@ -18,29 +18,51 @@
package com.discordsrv.common.player;
import com.discordsrv.api.channel.GameChannel;
import com.discordsrv.api.placeholder.annotation.Placeholder;
import com.discordsrv.api.placeholder.util.Placeholders;
import com.discordsrv.api.player.DiscordSRVPlayer;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.command.game.sender.ICommandSender;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public interface IPlayer extends DiscordSRVPlayer, IOfflinePlayer, ICommandSender {
DiscordSRV discordSRV();
@Override
@NotNull
String getUsername();
@Override
@ApiStatus.NonExtendable
default @NotNull UUID uuid() {
default @NotNull UUID getUniqueId() {
return identity().uuid();
}
@NotNull
@Placeholder("player_display_name")
Component displayName();
Component getDisplayName();
@Nullable
@Placeholder("player_avatar_url")
default String getAvatarUrl(GameChannel gameChannel) {
String avatarUrl = discordSRV().channelConfig().orDefault(gameChannel)
.get(cfg -> cfg.avatarUrlProvider);
if (avatarUrl == null) {
return null;
}
return new Placeholders(avatarUrl)
.replace("%uuid%", getUniqueId().toString())
.replace("%username%", getUsername())
.replace("%texture%", "") // TODO
.get();
}
}

View File

@ -18,6 +18,7 @@
package com.discordsrv.sponge.player;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.player.IPlayer;
import com.discordsrv.sponge.SpongeDiscordSRV;
import net.kyori.adventure.identity.Identity;
@ -57,7 +58,12 @@ public class SpongePlayer extends SpongeOfflinePlayer implements IPlayer {
}
@Override
public @NotNull Component displayName() {
public DiscordSRV discordSRV() {
return discordSRV;
}
@Override
public @NotNull Component getDisplayName() {
return player.displayName().get();
}
}

View File

@ -18,6 +18,7 @@
package com.discordsrv.velocity.player;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.player.IPlayer;
import com.discordsrv.velocity.VelocityDiscordSRV;
import com.velocitypowered.api.proxy.Player;
@ -52,6 +53,11 @@ public class VelocityPlayer implements IPlayer {
discordSRV.proxy().getCommandManager().executeAsync(player, command);
}
@Override
public DiscordSRV discordSRV() {
return discordSRV;
}
@Override
public @NotNull String getUsername() {
return player.getUsername();
@ -63,7 +69,7 @@ public class VelocityPlayer implements IPlayer {
}
@Override
public @NotNull Component displayName() {
public @NotNull Component getDisplayName() {
// Use Adventure's Pointer, otherwise username
return player.getOrDefaultFrom(
Identity.DISPLAY_NAME,