Changes to placeholder stringification, fix PlaceholderAPI integration input/output formats, fix timed updater enable time

This commit is contained in:
Vankka 2023-12-15 22:47:07 +02:00
parent dae2e7232c
commit cf7ee4a914
No known key found for this signature in database
GPG Key ID: 6E50CB7A29B96AD0
12 changed files with 145 additions and 102 deletions

View File

@ -27,7 +27,7 @@ import com.discordsrv.api.component.MinecraftComponentFactory;
import com.discordsrv.api.discord.DiscordAPI;
import com.discordsrv.api.discord.connection.details.DiscordConnectionDetails;
import com.discordsrv.api.event.bus.EventBus;
import com.discordsrv.api.placeholder.DiscordPlaceholders;
import com.discordsrv.api.placeholder.PlainPlaceholderFormat;
import com.discordsrv.api.placeholder.PlaceholderService;
import com.discordsrv.api.player.DiscordSRVPlayer;
import com.discordsrv.api.player.IPlayerProvider;
@ -106,11 +106,11 @@ public interface DiscordSRVApi {
PlaceholderService placeholderService();
/**
* Provides the {@link DiscordPlaceholders} instance.
* @return the {@link DiscordPlaceholders} instance
* Provides the {@link PlainPlaceholderFormat} instance.
* @return the {@link PlainPlaceholderFormat} instance
*/
@NotNull
DiscordPlaceholders discordPlaceholders();
PlainPlaceholderFormat discordPlaceholders();
/**
* A provider for {@link com.discordsrv.api.component.MinecraftComponent}s.

View File

@ -29,7 +29,7 @@ import com.discordsrv.api.discord.entity.message.AllowedMention;
import com.discordsrv.api.discord.entity.message.DiscordMessageEmbed;
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
import com.discordsrv.api.discord.util.DiscordFormattingUtil;
import com.discordsrv.api.placeholder.DiscordPlaceholders;
import com.discordsrv.api.placeholder.PlainPlaceholderFormat;
import com.discordsrv.api.placeholder.FormattedText;
import com.discordsrv.api.placeholder.PlaceholderService;
import com.discordsrv.api.placeholder.util.Placeholders;
@ -358,15 +358,17 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
if (api == null) {
throw new IllegalStateException("DiscordSRVApi not available");
}
this.replacements.put(PlaceholderService.PATTERN,
wrapFunction(matcher -> api.placeholderService().getResultAsPlain(matcher, context)));
this.replacements.put(
PlaceholderService.PATTERN,
wrapFunction(matcher -> api.placeholderService().getResultAsPlain(matcher, context))
);
return this;
}
private Function<Matcher, Object> wrapFunction(Function<Matcher, Object> function) {
return matcher -> {
Object result = function.apply(matcher);
if (result instanceof FormattedText || DiscordPlaceholders.FORMATTING.get() != DiscordPlaceholders.Formatting.NORMAL) {
if (result instanceof FormattedText || PlainPlaceholderFormat.FORMATTING.get() != PlainPlaceholderFormat.Formatting.DISCORD) {
// Process as regular text
return result.toString();
} else if (result instanceof CharSequence) {
@ -413,7 +415,11 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
return output.isEmpty() ? null : output;
};
builder.setContent(discordPlaceholders.apply(builder.getContent()));
PlainPlaceholderFormat.with(
PlainPlaceholderFormat.Formatting.DISCORD,
() -> builder.setContent(discordPlaceholders.apply(builder.getContent()))
);
List<DiscordMessageEmbed> embeds = new ArrayList<>(builder.getEmbeds());
embeds.forEach(builder::removeEmbed);
@ -421,70 +427,67 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
for (DiscordMessageEmbed embed : embeds) {
DiscordMessageEmbed.Builder embedBuilder = embed.toBuilder();
// TODO: check which parts allow formatting more thoroughly
DiscordPlaceholders.with(DiscordPlaceholders.Formatting.PLAIN, () -> {
embedBuilder.setAuthor(
cutToLength(
placeholders.apply(embedBuilder.getAuthorName()),
MessageEmbed.AUTHOR_MAX_LENGTH
),
placeholders.apply(embedBuilder.getAuthorUrl()),
placeholders.apply(embedBuilder.getAuthorImageUrl()));
embedBuilder.setAuthor(
cutToLength(
placeholders.apply(embedBuilder.getAuthorName()),
MessageEmbed.AUTHOR_MAX_LENGTH
),
placeholders.apply(embedBuilder.getAuthorUrl()),
placeholders.apply(embedBuilder.getAuthorImageUrl()));
embedBuilder.setTitle(
cutToLength(
placeholders.apply(embedBuilder.getTitle()),
MessageEmbed.TITLE_MAX_LENGTH
),
placeholders.apply(embedBuilder.getTitleUrl())
);
embedBuilder.setTitle(
cutToLength(
placeholders.apply(embedBuilder.getTitle()),
MessageEmbed.TITLE_MAX_LENGTH
),
placeholders.apply(embedBuilder.getTitleUrl())
);
embedBuilder.setThumbnailUrl(
placeholders.apply(embedBuilder.getThumbnailUrl())
);
embedBuilder.setThumbnailUrl(
placeholders.apply(embedBuilder.getThumbnailUrl())
);
embedBuilder.setImageUrl(
placeholders.apply(embedBuilder.getImageUrl())
);
embedBuilder.setImageUrl(
placeholders.apply(embedBuilder.getImageUrl())
);
embedBuilder.setFooter(
cutToLength(
placeholders.apply(embedBuilder.getFooter()),
MessageEmbed.TEXT_MAX_LENGTH
),
placeholders.apply(embedBuilder.getFooterImageUrl())
);
});
embedBuilder.setFooter(
cutToLength(
placeholders.apply(embedBuilder.getFooter()),
MessageEmbed.TEXT_MAX_LENGTH
),
placeholders.apply(embedBuilder.getFooterImageUrl())
);
embedBuilder.setDescription(
PlainPlaceholderFormat.with(PlainPlaceholderFormat.Formatting.DISCORD, () -> embedBuilder.setDescription(
cutToLength(
discordPlaceholders.apply(embedBuilder.getDescription()),
MessageEmbed.DESCRIPTION_MAX_LENGTH
)
);
));
List<DiscordMessageEmbed.Field> fields = new ArrayList<>(embedBuilder.getFields());
embedBuilder.getFields().clear();
fields.forEach(field -> embedBuilder.addField(
cutToLength(
placeholders.apply(field.getTitle()),
MessageEmbed.TITLE_MAX_LENGTH
),
cutToLength(
placeholders.apply(field.getValue()),
MessageEmbed.VALUE_MAX_LENGTH
),
field.isInline()
));
PlainPlaceholderFormat.with(PlainPlaceholderFormat.Formatting.DISCORD, () ->
fields.forEach(field -> embedBuilder.addField(
cutToLength(
placeholders.apply(field.getTitle()),
MessageEmbed.TITLE_MAX_LENGTH
),
cutToLength(
placeholders.apply(field.getValue()),
MessageEmbed.VALUE_MAX_LENGTH
),
field.isInline()
))
);
builder.addEmbed(embedBuilder.build());
}
DiscordPlaceholders.with(DiscordPlaceholders.Formatting.PLAIN, () -> {
builder.setWebhookUsername(placeholders.apply(builder.getWebhookUsername()));
builder.setWebhookAvatarUrl(placeholders.apply(builder.getWebhookAvatarUrl()));
});
builder.setWebhookUsername(placeholders.apply(builder.getWebhookUsername()));
builder.setWebhookAvatarUrl(placeholders.apply(builder.getWebhookAvatarUrl()));
return builder.build();
}

View File

@ -24,25 +24,35 @@
package com.discordsrv.api.placeholder;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* A helper class to handle replacing placeholders with Discord code blocks.
*/
public interface DiscordPlaceholders {
public interface PlainPlaceholderFormat {
ThreadLocal<Formatting> FORMATTING = ThreadLocal.withInitial(() -> Formatting.NORMAL);
ThreadLocal<Formatting> FORMATTING = ThreadLocal.withInitial(() -> Formatting.PLAIN);
static void with(Formatting formatting, Runnable runnable) {
supplyWith(formatting, () -> {
runnable.run();
return null;
});
}
static <T> T supplyWith(Formatting formatting, Supplier<T> supplier) {
Formatting before = FORMATTING.get();
FORMATTING.set(formatting);
runnable.run();
T value = supplier.get();
FORMATTING.set(before);
return value;
}
enum Formatting {
NORMAL,
PLAIN,
ANSI
DISCORD,
ANSI,
LEGACY
}
String map(String input, Function<String, String> placeholders);

View File

@ -21,6 +21,7 @@ package com.discordsrv.bukkit.integration;
import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.events.placeholder.PlaceholderLookupEvent;
import com.discordsrv.api.placeholder.PlaceholderLookupResult;
import com.discordsrv.api.placeholder.PlainPlaceholderFormat;
import com.discordsrv.api.player.DiscordSRVPlayer;
import com.discordsrv.api.profile.IProfile;
import com.discordsrv.bukkit.BukkitDiscordSRV;
@ -28,6 +29,7 @@ import com.discordsrv.common.module.type.PluginIntegration;
import com.discordsrv.common.player.IOfflinePlayer;
import me.clip.placeholderapi.PlaceholderAPI;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@ -110,7 +112,7 @@ public class PlaceholderAPIIntegration extends PluginIntegration<BukkitDiscordSR
return;
}
event.process(PlaceholderLookupResult.success(result));
event.process(PlaceholderLookupResult.success(BukkitComponentSerializer.legacy().deserialize(result)));
}
public class Expansion extends PlaceholderExpansion {
@ -164,7 +166,10 @@ public class PlaceholderAPIIntegration extends PluginIntegration<BukkitDiscordSR
}
String placeholder = "%" + params + "%";
String result = discordSRV.placeholderService().replacePlaceholders(placeholder, context);
String result = PlainPlaceholderFormat.supplyWith(
PlainPlaceholderFormat.Formatting.LEGACY,
() -> discordSRV.placeholderService().replacePlaceholders(placeholder, context)
);
return placeholder.equals(result) ? null : result;
}
}

View File

@ -20,7 +20,7 @@ package com.discordsrv.common;
import com.discordsrv.api.DiscordSRVApi;
import com.discordsrv.api.module.type.Module;
import com.discordsrv.api.placeholder.DiscordPlaceholders;
import com.discordsrv.api.placeholder.PlainPlaceholderFormat;
import com.discordsrv.common.bootstrap.IBootstrap;
import com.discordsrv.common.channel.ChannelConfigHelper;
import com.discordsrv.common.command.game.GameCommandExecutionHelper;
@ -97,7 +97,7 @@ public interface DiscordSRV extends DiscordSRVApi {
@Override
@NotNull
DiscordPlaceholders discordPlaceholders();
PlainPlaceholderFormat discordPlaceholders();
@Override
@NotNull

View File

@ -38,6 +38,8 @@ public abstract class ServerDiscordSRV<
MC extends MessagesConfig
> extends AbstractDiscordSRV<B, C, CC, MC> {
private boolean serverStarted = false;
public ServerDiscordSRV(B bootstrap) {
super(bootstrap);
}
@ -79,6 +81,12 @@ public abstract class ServerDiscordSRV<
@OverridingMethodsMustInvokeSuper
protected void serverStarted() {
serverStarted = true;
moduleManager().reload();
startedMessage();
}
public boolean isServerStarted() {
return serverStarted;
}
}

View File

@ -21,6 +21,7 @@ package com.discordsrv.common.channel;
import com.discordsrv.api.DiscordSRVApi;
import com.discordsrv.api.discord.connection.jda.errorresponse.ErrorCallbackContext;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.ServerDiscordSRV;
import com.discordsrv.common.config.main.TimedUpdaterConfig;
import com.discordsrv.common.logging.NamedLogger;
import com.discordsrv.common.module.type.AbstractModule;
@ -62,7 +63,9 @@ public class TimedUpdaterModule extends AbstractModule<DiscordSRV> {
return false;
}
return super.isEnabled();
return super.isEnabled() && discordSRV.isReady() &&
(!(discordSRV instanceof ServerDiscordSRV)
|| ((ServerDiscordSRV<?, ?, ?, ?>) discordSRV).isServerStarted());
}
@Override
@ -85,13 +88,6 @@ public class TimedUpdaterModule extends AbstractModule<DiscordSRV> {
}
public void update(TimedUpdaterConfig.UpdaterConfig config) {
try {
// Wait a moment in case we're (re)connecting at the time
discordSRV.waitForStatus(DiscordSRV.Status.CONNECTED, 15, TimeUnit.SECONDS);
} catch (InterruptedException ignored) {
Thread.currentThread().interrupt();
}
JDA jda = discordSRV.jda();
if (jda == null) {
return;
@ -112,8 +108,6 @@ public class TimedUpdaterModule extends AbstractModule<DiscordSRV> {
((TimedUpdaterConfig.TextChannelConfig) config).topicFormat
);
}
}
private void updateChannel(JDA jda, List<Long> channelIds, String nameFormat, String topicFormat) {

View File

@ -11,6 +11,7 @@ import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
import com.discordsrv.api.discord.events.message.DiscordMessageReceiveEvent;
import com.discordsrv.api.discord.util.DiscordFormattingUtil;
import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.placeholder.PlainPlaceholderFormat;
import com.discordsrv.api.placeholder.provider.SinglePlaceholder;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.command.game.GameCommandExecutionHelper;
@ -357,10 +358,16 @@ public class SingleConsoleHandler {
break;
}
String message = discordSRV.placeholderService().replacePlaceholders(
config.appender.lineFormat,
entry,
new SinglePlaceholder("message", parsedMessage)
String message = PlainPlaceholderFormat.supplyWith(
outputMode == ConsoleConfig.OutputMode.PLAIN_CONTENT
? PlainPlaceholderFormat.Formatting.DISCORD
: PlainPlaceholderFormat.Formatting.PLAIN,
() ->
discordSRV.placeholderService().replacePlaceholders(
config.appender.lineFormat,
entry,
new SinglePlaceholder("message", parsedMessage)
)
);
Throwable thrown = entry.throwable();

View File

@ -34,6 +34,7 @@ import com.discordsrv.api.discord.events.message.DiscordMessageUpdateEvent;
import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.events.message.forward.game.AbstractGameMessageForwardedEvent;
import com.discordsrv.api.event.events.message.receive.discord.DiscordChatMessageReceiveEvent;
import com.discordsrv.api.placeholder.PlainPlaceholderFormat;
import com.discordsrv.api.placeholder.provider.SinglePlaceholder;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.config.main.channels.MirroringConfig;
@ -365,6 +366,7 @@ public class DiscordMessageMirroringModule extends AbstractModule<DiscordSRV> {
String content = Objects.requireNonNull(message.getContent())
.replace("[", "\\["); // Block markdown urls
String finalContent;
if (replyMessage != null) {
MessageReference matchingReference = null;
@ -383,19 +385,24 @@ public class DiscordMessageMirroringModule extends AbstractModule<DiscordSRV> {
Long.toUnsignedString(matchingReference.messageId)
) : replyMessage.getJumpUrl();
content = discordSRV.placeholderService()
.replacePlaceholders(
config.replyFormat,
replyMessage.getMember(),
replyMessage.getAuthor(),
new SinglePlaceholder("message_jump_url", jumpUrl),
new SinglePlaceholder("message", content)
);
finalContent = PlainPlaceholderFormat.supplyWith(
PlainPlaceholderFormat.Formatting.DISCORD,
() -> discordSRV.placeholderService()
.replacePlaceholders(
config.replyFormat,
replyMessage.getMember(),
replyMessage.getAuthor(),
new SinglePlaceholder("message_jump_url", jumpUrl),
new SinglePlaceholder("message", content)
)
);
} else {
finalContent = content;
}
SendableDiscordMessage.Builder builder = SendableDiscordMessage.builder()
.setAllowedMentions(Collections.emptyList())
.setContent(content.substring(0, Math.min(content.length(), Message.MAX_CONTENT_LENGTH)))
.setContent(finalContent.substring(0, Math.min(finalContent.length(), Message.MAX_CONTENT_LENGTH)))
.setWebhookUsername(username)
.setWebhookAvatarUrl(
member != null

View File

@ -24,6 +24,7 @@ import com.discordsrv.api.discord.connection.details.DiscordGatewayIntent;
import com.discordsrv.api.discord.connection.details.DiscordMemberCachePolicy;
import com.discordsrv.api.event.bus.EventPriority;
import com.discordsrv.api.event.bus.Subscribe;
import com.discordsrv.api.event.events.lifecycle.DiscordSRVReadyEvent;
import com.discordsrv.api.event.events.lifecycle.DiscordSRVShuttingDownEvent;
import com.discordsrv.api.module.type.Module;
import com.discordsrv.common.DiscordSRV;
@ -183,6 +184,11 @@ public class ModuleManager {
.forEachOrdered(module -> disable(getAbstract(module)));
}
@Subscribe
public void onDiscordSRVReady(DiscordSRVReadyEvent event) {
reload();
}
public List<DiscordSRV.ReloadResult> reload() {
JDAConnectionManager connectionManager = discordSRV.discordConnectionManager();
@ -216,6 +222,7 @@ public class ModuleManager {
}
if (!abstractModule.isEnabled()) {
disable(abstractModule);
continue;
}
try {

View File

@ -18,7 +18,7 @@
package com.discordsrv.common.placeholder;
import com.discordsrv.api.placeholder.DiscordPlaceholders;
import com.discordsrv.api.placeholder.PlainPlaceholderFormat;
import dev.vankka.mcdiscordreserializer.rules.DiscordMarkdownRules;
import dev.vankka.simpleast.core.TextStyle;
import dev.vankka.simpleast.core.node.Node;
@ -32,7 +32,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class DiscordPlaceholdersImpl implements DiscordPlaceholders {
public class DiscordPlaceholdersImpl implements PlainPlaceholderFormat {
private final Parser<Object, Node<Object>, Object> parser;
@ -58,7 +58,7 @@ public class DiscordPlaceholdersImpl implements DiscordPlaceholders {
} else if (node instanceof StyleNode) {
String content = text.toString();
text.setLength(0);
finalText.append(placeholders.apply(content));
PlainPlaceholderFormat.with(Formatting.DISCORD, () -> finalText.append(placeholders.apply(content)));
for (Object style : ((StyleNode<?, ?>) node).getStyles()) {
if (!(style instanceof TextStyle)) {
@ -69,24 +69,23 @@ public class DiscordPlaceholdersImpl implements DiscordPlaceholders {
String childText = ((TextNode<?>) node.getChildren().get(0)).getContent();
if (textStyle.getType() == TextStyle.Type.CODE_STRING) {
DiscordPlaceholders.with(Formatting.PLAIN, () -> finalText.append("`").append(placeholders.apply(childText)).append("`"));
finalText.append("`").append(placeholders.apply(childText)).append("`");
} else if (textStyle.getType() == TextStyle.Type.CODE_BLOCK) {
String language = textStyle.getExtra().get("language");
if (language != null && language.equals("ansi")) {
DiscordPlaceholders.with(Formatting.ANSI, () -> finalText
PlainPlaceholderFormat.with(Formatting.ANSI, () -> finalText
.append("```ansi\n")
.append(placeholders.apply(childText))
.append("```")
);
} else {
DiscordPlaceholders.with(Formatting.PLAIN, () -> finalText
finalText
.append("```")
.append(language != null ? language : "")
.append("\n")
.append(placeholders.apply(childText))
.append("```")
);
.append("```");
}
}
}

View File

@ -19,12 +19,13 @@
package com.discordsrv.common.placeholder.result;
import com.discordsrv.api.component.MinecraftComponent;
import com.discordsrv.api.placeholder.DiscordPlaceholders;
import com.discordsrv.api.placeholder.PlainPlaceholderFormat;
import com.discordsrv.api.placeholder.FormattedText;
import com.discordsrv.api.placeholder.mapper.PlaceholderResultMapper;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.component.util.ComponentUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.jetbrains.annotations.NotNull;
public class ComponentResultStringifier implements PlaceholderResultMapper {
@ -42,15 +43,17 @@ public class ComponentResultStringifier implements PlaceholderResultMapper {
}
if (result instanceof Component) {
Component component = (Component) result;
DiscordPlaceholders.Formatting mappingState = DiscordPlaceholders.FORMATTING.get();
PlainPlaceholderFormat.Formatting mappingState = PlainPlaceholderFormat.FORMATTING.get();
switch (mappingState) {
case ANSI:
return discordSRV.componentFactory().ansiSerializer().serialize(component);
default:
case PLAIN:
return discordSRV.componentFactory().plainSerializer().serialize(component);
default:
case NORMAL:
case DISCORD:
return new FormattedText(discordSRV.componentFactory().discordSerializer().serialize(component));
case ANSI:
return discordSRV.componentFactory().ansiSerializer().serialize(component);
case LEGACY:
return LegacyComponentSerializer.legacySection().serialize(component);
}
}
return null;