diff --git a/api/src/main/java/com/discordsrv/api/DiscordSRVApi.java b/api/src/main/java/com/discordsrv/api/DiscordSRVApi.java index 77ac61b7..92c3bb7c 100644 --- a/api/src/main/java/com/discordsrv/api/DiscordSRVApi.java +++ b/api/src/main/java/com/discordsrv/api/DiscordSRVApi.java @@ -62,6 +62,7 @@ public interface DiscordSRVApi { * DiscordSRV's own placeholder service. * @return the {@link PlaceholderService} instance. */ + @NotNull PlaceholderService placeholderService(); /** diff --git a/api/src/main/java/com/discordsrv/api/placeholder/mapper/ResultMappers.java b/api/src/main/java/com/discordsrv/api/placeholder/mapper/ResultMappers.java index 5d744183..d840b7bb 100644 --- a/api/src/main/java/com/discordsrv/api/placeholder/mapper/ResultMappers.java +++ b/api/src/main/java/com/discordsrv/api/placeholder/mapper/ResultMappers.java @@ -29,7 +29,7 @@ import java.util.function.Supplier; public final class ResultMappers { - private static final ThreadLocal PLAIN_COMPONENTS = new ThreadLocal<>(); + private static final ThreadLocal PLAIN_COMPONENTS = ThreadLocal.withInitial(() -> false); private ResultMappers() {} diff --git a/build.gradle b/build.gradle index f62fb07e..f16f85ce 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ allprojects { } generateRuntimeDownloadResourceForRuntimeDownloadOnly { - file = 'runtimeDownload-' + project.name + '.txt' + file = 'dependencies/runtimeDownload-' + project.name + '.txt' } repositories { diff --git a/common/build.gradle b/common/build.gradle index a77fdfbc..b8d5a657 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -9,12 +9,12 @@ configurations { task generateResourceForH2Driver(type: GenerateDependencyDownloadResourceTask) { var conf = configurations.h2Driver configuration = conf - file = conf.name + '.txt' + file = 'dependencies/' + conf.name + '.txt' } task generateResourceForMySQLDriver(type: GenerateDependencyDownloadResourceTask) { var conf = configurations.mysqlDriver configuration = conf - file = conf.name + '.txt' + file = 'dependencies/' + conf.name + '.txt' } dependencies { diff --git a/common/src/main/java/com/discordsrv/common/AbstractDiscordSRV.java b/common/src/main/java/com/discordsrv/common/AbstractDiscordSRV.java index bb2c72fc..b145a66a 100644 --- a/common/src/main/java/com/discordsrv/common/AbstractDiscordSRV.java +++ b/common/src/main/java/com/discordsrv/common/AbstractDiscordSRV.java @@ -22,7 +22,6 @@ import com.discordsrv.api.discord.connection.DiscordConnectionDetails; import com.discordsrv.api.event.bus.EventBus; import com.discordsrv.api.event.events.lifecycle.DiscordSRVReloadEvent; import com.discordsrv.api.event.events.lifecycle.DiscordSRVShuttingDownEvent; -import com.discordsrv.api.placeholder.PlaceholderService; import com.discordsrv.common.api.util.ApiInstanceUtil; import com.discordsrv.common.channel.ChannelConfigHelper; import com.discordsrv.common.channel.DefaultGlobalChannel; @@ -43,8 +42,9 @@ import com.discordsrv.common.listener.DiscordChatListener; import com.discordsrv.common.listener.GameChatListener; import com.discordsrv.common.logging.DependencyLoggingFilter; import com.discordsrv.common.logging.logger.backend.LoggingBackend; -import com.discordsrv.common.placeholder.PlaceholderServiceImpl; import com.discordsrv.common.placeholder.ComponentResultStringifier; +import com.discordsrv.common.placeholder.PlaceholderServiceImpl; +import com.discordsrv.common.placeholder.context.GlobalTextHandlingContext; import net.dv8tion.jda.api.JDA; import org.jetbrains.annotations.NotNull; @@ -67,7 +67,7 @@ public abstract class AbstractDiscordSRV playerProvider(); diff --git a/common/src/main/java/com/discordsrv/common/component/EnhancedTextBuilderImpl.java b/common/src/main/java/com/discordsrv/common/component/EnhancedTextBuilderImpl.java index 778ed45f..96d4c7b1 100644 --- a/common/src/main/java/com/discordsrv/common/component/EnhancedTextBuilderImpl.java +++ b/common/src/main/java/com/discordsrv/common/component/EnhancedTextBuilderImpl.java @@ -56,21 +56,29 @@ public class EnhancedTextBuilderImpl implements EnhancedTextBuilder { @Override public @NotNull EnhancedTextBuilder addReplacement(Pattern target, Function replacement) { - this.replacements.put(target, replacement); + this.replacements.put(target, wrapFunction(replacement)); return this; } @Override public @NotNull EnhancedTextBuilder applyPlaceholderService() { - this.replacements.put(PlaceholderService.PATTERN, matcher -> { - Object result = discordSRV.placeholderService().getResult(matcher, context); + this.replacements.put(PlaceholderService.PATTERN, wrapFunction( + matcher -> discordSRV.placeholderService().getResult(matcher, context))); + return this; + } + + private Function wrapFunction(Function function) { + return matcher -> { + Object result = function.apply(matcher); if (result instanceof Color) { // Convert Color to something it'll understand return TextColor.color(((Color) result).rgb()); + } else if (result instanceof MinecraftComponent) { + // Convert to adventure component from API + return ComponentUtil.fromAPI((MinecraftComponent) result); } return result; - }); - return this; + }; } @Override diff --git a/common/src/main/java/com/discordsrv/common/component/renderer/DiscordSRVMinecraftRenderer.java b/common/src/main/java/com/discordsrv/common/component/renderer/DiscordSRVMinecraftRenderer.java index 9ae3c2c5..6b1cf3b3 100644 --- a/common/src/main/java/com/discordsrv/common/component/renderer/DiscordSRVMinecraftRenderer.java +++ b/common/src/main/java/com/discordsrv/common/component/renderer/DiscordSRVMinecraftRenderer.java @@ -29,20 +29,29 @@ import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Optional; +import java.util.function.Supplier; public class DiscordSRVMinecraftRenderer extends DefaultMinecraftRenderer { - private static final ThreadLocal GUILD_CONTEXT = new ThreadLocal<>(); + private static final ThreadLocal GUILD_CONTEXT = ThreadLocal.withInitial(() -> 0L); private final DiscordSRV discordSRV; public DiscordSRVMinecraftRenderer(DiscordSRV discordSRV) { this.discordSRV = discordSRV; } - public static void inGuildContext(long guildId, Runnable runnable) { + public static void runInGuildContext(long guildId, Runnable runnable) { + getWithGuildContext(guildId, () -> { + runnable.run(); + return null; + }); + } + + public static T getWithGuildContext(long guildId, Supplier supplier) { GUILD_CONTEXT.set(guildId); - runnable.run(); + T output = supplier.get(); GUILD_CONTEXT.set(0L); + return output; } @Override diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/BaseChannelConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/BaseChannelConfig.java index 8e757b1c..e4256b02 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/BaseChannelConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/BaseChannelConfig.java @@ -18,8 +18,6 @@ package com.discordsrv.common.config.main.channels; -import com.discordsrv.common.config.main.channels.discordtominecraft.DiscordToMinecraftChatConfig; -import com.discordsrv.common.config.main.channels.minecraftodiscord.MinecraftToDiscordChatConfig; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.objectmapping.ConfigSerializable; diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/discordtominecraft/DiscordToMinecraftChatConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/DiscordToMinecraftChatConfig.java similarity index 91% rename from common/src/main/java/com/discordsrv/common/config/main/channels/discordtominecraft/DiscordToMinecraftChatConfig.java rename to common/src/main/java/com/discordsrv/common/config/main/channels/DiscordToMinecraftChatConfig.java index aa7c2c26..7244db47 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/discordtominecraft/DiscordToMinecraftChatConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/DiscordToMinecraftChatConfig.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package com.discordsrv.common.config.main.channels.discordtominecraft; +package com.discordsrv.common.config.main.channels; import org.spongepowered.configurate.objectmapping.ConfigSerializable; import org.spongepowered.configurate.objectmapping.meta.Comment; @@ -31,10 +31,10 @@ import java.util.regex.Pattern; public class DiscordToMinecraftChatConfig { @Comment("The Discord to Minecraft message format for regular users") - public String format = "[ᛩF2Discord&r] [hover:show_text:Tag: %user_tag%&r\\nRoles: %user_roles_, %]%user_color%%user_effective_name%&r » %message%"; + public String format = "[ᛩF2Discord&r] [hover:show_text:Tag: %user_tag%&r\\nRoles: %user_roles_, |text_&7&oNone%%]%user_color%%user_effective_name%&r » %message%"; @Comment("The Discord to Minecraft message format for webhook messages (if enabled)") - public String webhookFormat = "[ᛩF2Discord&r] [hover:show_text:Webhook message]%user_name% » %message%"; + public String webhookFormat = "[ᛩF2Discord&r] [hover:show_text:Webhook message]%user_name%&r » %message%"; @Comment("Users, bots and webhooks to ignore") public Ignores ignores = new Ignores(); diff --git a/common/src/main/java/com/discordsrv/common/config/main/channels/minecraftodiscord/MinecraftToDiscordChatConfig.java b/common/src/main/java/com/discordsrv/common/config/main/channels/MinecraftToDiscordChatConfig.java similarity index 96% rename from common/src/main/java/com/discordsrv/common/config/main/channels/minecraftodiscord/MinecraftToDiscordChatConfig.java rename to common/src/main/java/com/discordsrv/common/config/main/channels/MinecraftToDiscordChatConfig.java index 5ce1e6b5..1c654425 100644 --- a/common/src/main/java/com/discordsrv/common/config/main/channels/minecraftodiscord/MinecraftToDiscordChatConfig.java +++ b/common/src/main/java/com/discordsrv/common/config/main/channels/MinecraftToDiscordChatConfig.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package com.discordsrv.common.config.main.channels.minecraftodiscord; +package com.discordsrv.common.config.main.channels; import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage; import org.spongepowered.configurate.objectmapping.ConfigSerializable; diff --git a/common/src/main/java/com/discordsrv/common/listener/DiscordChatListener.java b/common/src/main/java/com/discordsrv/common/listener/DiscordChatListener.java index 0b464410..6691a1ee 100644 --- a/common/src/main/java/com/discordsrv/common/listener/DiscordChatListener.java +++ b/common/src/main/java/com/discordsrv/common/listener/DiscordChatListener.java @@ -33,7 +33,7 @@ import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.component.renderer.DiscordSRVMinecraftRenderer; import com.discordsrv.common.component.util.ComponentUtil; import com.discordsrv.common.config.main.channels.BaseChannelConfig; -import com.discordsrv.common.config.main.channels.discordtominecraft.DiscordToMinecraftChatConfig; +import com.discordsrv.common.config.main.channels.DiscordToMinecraftChatConfig; import com.discordsrv.common.function.OrDefault; import net.kyori.adventure.text.Component; import org.apache.commons.lang3.tuple.Pair; @@ -105,35 +105,34 @@ public class DiscordChatListener extends AbstractListener { } } - String format = chatConfig.opt(cfg -> webhookMessage ? cfg.format : cfg.webhookFormat) + String format = chatConfig.opt(cfg -> webhookMessage ? cfg.webhookFormat : cfg.format) .map(option -> option.replace("\\n", "\n")) .orElse(null); if (format == null) { return; } - DiscordSRVMinecraftRenderer.inGuildContext(channel.getGuild().getId(), () -> { - Placeholders message = new Placeholders(event.getMessageContent()); - chatConfig.opt(cfg -> cfg.contentRegexFilters) - .ifPresent(filters -> filters.forEach(message::replaceAll)); + Placeholders message = new Placeholders(event.getMessageContent()); + chatConfig.opt(cfg -> cfg.contentRegexFilters) + .ifPresent(filters -> filters.forEach(message::replaceAll)); - Component messageComponent = discordSRV.componentFactory().minecraftSerializer().serialize(message.toString()); + Component messageComponent = DiscordSRVMinecraftRenderer.getWithGuildContext(channel.getGuild().getId(), () -> + discordSRV.componentFactory().minecraftSerializer().serialize(message.toString())); - EnhancedTextBuilder componentBuilder = discordSRV.componentFactory() - .enhancedBuilder(format) - .addContext(discordMessage, author) - .addReplacement("%message%", messageComponent); - member.ifPresent(componentBuilder::addContext); + EnhancedTextBuilder componentBuilder = discordSRV.componentFactory() + .enhancedBuilder(format) + .addContext(discordMessage, author) + .addReplacement("%message%", messageComponent); + member.ifPresent(componentBuilder::addContext); - componentBuilder.applyPlaceholderService(); + componentBuilder.applyPlaceholderService(); - MinecraftComponent component = componentBuilder.build(); - if (ComponentUtil.isEmpty(component)) { - // Empty - return; - } + MinecraftComponent component = componentBuilder.build(); + if (ComponentUtil.isEmpty(component)) { + // Empty + return; + } - gameChannel.sendMessage(component); - }); + gameChannel.sendMessage(component); } } diff --git a/common/src/main/java/com/discordsrv/common/listener/GameChatListener.java b/common/src/main/java/com/discordsrv/common/listener/GameChatListener.java index 5a4c8380..7c9feeb0 100644 --- a/common/src/main/java/com/discordsrv/common/listener/GameChatListener.java +++ b/common/src/main/java/com/discordsrv/common/listener/GameChatListener.java @@ -30,7 +30,7 @@ import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.component.util.ComponentUtil; import com.discordsrv.common.config.main.channels.BaseChannelConfig; import com.discordsrv.common.config.main.channels.ChannelConfig; -import com.discordsrv.common.config.main.channels.minecraftodiscord.MinecraftToDiscordChatConfig; +import com.discordsrv.common.config.main.channels.MinecraftToDiscordChatConfig; import com.discordsrv.common.discord.api.message.ReceivedDiscordMessageClusterImpl; import com.discordsrv.common.function.OrDefault; import net.kyori.adventure.text.Component; diff --git a/common/src/main/java/com/discordsrv/common/placeholder/context/GlobalTextHandlingContext.java b/common/src/main/java/com/discordsrv/common/placeholder/context/GlobalTextHandlingContext.java new file mode 100644 index 00000000..5ab82c76 --- /dev/null +++ b/common/src/main/java/com/discordsrv/common/placeholder/context/GlobalTextHandlingContext.java @@ -0,0 +1,38 @@ +/* + * This file is part of DiscordSRV, licensed under the GPLv3 License + * Copyright (c) 2016-2021 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.discordsrv.common.placeholder.context; + +import com.discordsrv.api.component.MinecraftComponent; +import com.discordsrv.api.placeholder.annotation.Placeholder; +import com.discordsrv.api.placeholder.annotation.PlaceholderRemainder; +import com.discordsrv.common.DiscordSRV; + +public class GlobalTextHandlingContext { + + private final DiscordSRV discordSRV; + + public GlobalTextHandlingContext(DiscordSRV discordSRV) { + this.discordSRV = discordSRV; + } + + @Placeholder("text_") + public MinecraftComponent text(@PlaceholderRemainder String text) { + return discordSRV.componentFactory().enhancedBuilder(text).build(); + } +}