mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2024-12-26 17:18:29 +01:00
More progress on placeholders & Minecraft -> Discord chat
This commit is contained in:
parent
3fb79cc50c
commit
ff8385dfda
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||||
|
* Copyright (c) 2016-2021 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.discordsrv.api.component;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public interface EnhancedTextBuilder {
|
||||||
|
|
||||||
|
EnhancedTextBuilder addContext(Object... context);
|
||||||
|
|
||||||
|
default EnhancedTextBuilder addReplacement(String target, Object replacement) {
|
||||||
|
return addReplacement(Pattern.compile(target, Pattern.LITERAL), replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
default EnhancedTextBuilder addReplacement(Pattern target, Object replacement) {
|
||||||
|
return addReplacement(target, matcher -> replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
default EnhancedTextBuilder addReplacement(String target, Supplier<Object> replacement) {
|
||||||
|
return addReplacement(Pattern.compile(target, Pattern.LITERAL), replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
default EnhancedTextBuilder addReplacement(Pattern target, Supplier<Object> replacement) {
|
||||||
|
return addReplacement(target, matcher -> replacement.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
default EnhancedTextBuilder addReplacement(String target, Function<Matcher, Object> replacement) {
|
||||||
|
return addReplacement(Pattern.compile(target, Pattern.LITERAL), replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnhancedTextBuilder addReplacement(Pattern target, Function<Matcher, Object> replacement);
|
||||||
|
|
||||||
|
MinecraftComponent build();
|
||||||
|
}
|
@ -66,7 +66,7 @@ public interface MinecraftComponent {
|
|||||||
*
|
*
|
||||||
* @param gsonSerializerClass the gson serializer class
|
* @param gsonSerializerClass the gson serializer class
|
||||||
* @return a adapter that will convert to/from relocated or unrelocated adventure classes to/from json
|
* @return a adapter that will convert to/from relocated or unrelocated adventure classes to/from json
|
||||||
* @throws IllegalArgumentException if the provided class is not a Adventure GsonComponentSerializer
|
* @throws IllegalArgumentException if the provided class is not an Adventure GsonComponentSerializer
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
Adapter adventureAdapter(@NotNull Class<?> gsonSerializerClass);
|
Adapter adventureAdapter(@NotNull Class<?> gsonSerializerClass);
|
||||||
@ -96,7 +96,7 @@ public interface MinecraftComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Adventure adapter, converts from/to given adventure components from/to json.
|
* An Adventure adapter, converts from/to given adventure components from/to json.
|
||||||
*/
|
*/
|
||||||
interface Adapter {
|
interface Adapter {
|
||||||
|
|
||||||
|
@ -39,4 +39,6 @@ public interface MinecraftComponentFactory {
|
|||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
MinecraftComponent empty();
|
MinecraftComponent empty();
|
||||||
|
|
||||||
|
EnhancedTextBuilder enhancedBuilder(String content);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import com.discordsrv.api.discord.api.entity.channel.DiscordDMChannel;
|
|||||||
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
||||||
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
||||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||||
|
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||||
import com.discordsrv.api.discord.api.entity.user.DiscordUser;
|
import com.discordsrv.api.discord.api.entity.user.DiscordUser;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -37,6 +38,8 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public interface DiscordAPI {
|
public interface DiscordAPI {
|
||||||
|
|
||||||
|
SendableDiscordMessage.Formatter format(SendableDiscordMessage.Builder message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a Discord message channel by id, the provided entity can be cached and will not update if it changes on Discord.
|
* Gets a Discord message channel by id, the provided entity can be cached and will not update if it changes on Discord.
|
||||||
* @param id the id for the message channel
|
* @param id the id for the message channel
|
||||||
|
@ -29,6 +29,10 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message that can be sent to Discord.
|
* A message that can be sent to Discord.
|
||||||
@ -190,5 +194,33 @@ public interface SendableDiscordMessage {
|
|||||||
SendableDiscordMessage build();
|
SendableDiscordMessage build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Formatter {
|
||||||
|
|
||||||
|
Formatter addContext(Object... context);
|
||||||
|
|
||||||
|
default Formatter addReplacement(String target, Object replacement) {
|
||||||
|
return addReplacement(Pattern.compile(target, Pattern.LITERAL), replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
default Formatter addReplacement(Pattern target, Object replacement) {
|
||||||
|
return addReplacement(target, matcher -> replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
default Formatter addReplacement(String target, Supplier<Object> replacement) {
|
||||||
|
return addReplacement(Pattern.compile(target, Pattern.LITERAL), replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
default Formatter addReplacement(Pattern target, Supplier<Object> replacement) {
|
||||||
|
return addReplacement(target, matcher -> replacement.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
default Formatter addReplacement(String target, Function<Matcher, Object> replacement) {
|
||||||
|
return addReplacement(Pattern.compile(target, Pattern.LITERAL), replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter addReplacement(Pattern target, Function<Matcher, Object> replacement);
|
||||||
|
|
||||||
|
SendableDiscordMessage build();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage {
|
|||||||
return webhookAvatarUrl;
|
return webhookAvatarUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class BuilderImpl implements Builder {
|
public static class BuilderImpl implements SendableDiscordMessage.Builder {
|
||||||
|
|
||||||
private String content;
|
private String content;
|
||||||
private final List<DiscordMessageEmbed> embeds = new ArrayList<>();
|
private final List<DiscordMessageEmbed> embeds = new ArrayList<>();
|
||||||
|
@ -24,43 +24,32 @@
|
|||||||
package com.discordsrv.api.event.events.message.send.game;
|
package com.discordsrv.api.event.events.message.send.game;
|
||||||
|
|
||||||
import com.discordsrv.api.channel.GameChannel;
|
import com.discordsrv.api.channel.GameChannel;
|
||||||
|
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||||
import com.discordsrv.api.event.events.Cancellable;
|
import com.discordsrv.api.event.events.Cancellable;
|
||||||
import com.discordsrv.api.event.events.Processable;
|
import com.discordsrv.api.event.events.Processable;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public abstract class AbstractGameMessageSendEvent implements Cancellable, Processable {
|
public abstract class AbstractGameMessageSendEvent implements Cancellable, Processable {
|
||||||
|
|
||||||
private String discordMessage;
|
private SendableDiscordMessage discordMessage;
|
||||||
private String discordUsername;
|
|
||||||
private GameChannel targetChannel;
|
private GameChannel targetChannel;
|
||||||
private boolean cancelled;
|
private boolean cancelled;
|
||||||
private boolean processed;
|
private boolean processed;
|
||||||
|
|
||||||
public AbstractGameMessageSendEvent(@NotNull String discordMessage, @Nullable String discordUsername, @NotNull GameChannel targetChannel) {
|
public AbstractGameMessageSendEvent(@NotNull SendableDiscordMessage discordMessage, @NotNull GameChannel targetChannel) {
|
||||||
this.discordMessage = discordMessage;
|
this.discordMessage = discordMessage;
|
||||||
this.discordUsername = discordUsername;
|
|
||||||
this.targetChannel = targetChannel;
|
this.targetChannel = targetChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public String getDiscordMessage() {
|
public SendableDiscordMessage getDiscordMessage() {
|
||||||
return discordMessage;
|
return discordMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDiscordMessage(@NotNull String discordMessage) {
|
public void setDiscordMessage(@NotNull SendableDiscordMessage discordMessage) {
|
||||||
this.discordMessage = discordMessage;
|
this.discordMessage = discordMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String getDiscordUsername() {
|
|
||||||
return discordUsername;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDiscordUsername(@Nullable String discordUsername) {
|
|
||||||
this.discordUsername = discordUsername;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public GameChannel getTargetChannel() {
|
public GameChannel getTargetChannel() {
|
||||||
return targetChannel;
|
return targetChannel;
|
||||||
|
@ -24,12 +24,12 @@
|
|||||||
package com.discordsrv.api.event.events.message.send.game;
|
package com.discordsrv.api.event.events.message.send.game;
|
||||||
|
|
||||||
import com.discordsrv.api.channel.GameChannel;
|
import com.discordsrv.api.channel.GameChannel;
|
||||||
|
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public class ChatMessageSendEvent extends AbstractGameMessageSendEvent {
|
public class ChatMessageSendEvent extends AbstractGameMessageSendEvent {
|
||||||
|
|
||||||
public ChatMessageSendEvent(@NotNull String discordMessage, @Nullable String discordUsername, @NotNull GameChannel targetChannel) {
|
public ChatMessageSendEvent(@NotNull SendableDiscordMessage discordMessage, @NotNull GameChannel targetChannel) {
|
||||||
super(discordMessage, discordUsername, targetChannel);
|
super(discordMessage, targetChannel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ public class PlaceholderLookupResult {
|
|||||||
public static final PlaceholderLookupResult UNKNOWN_PLACEHOLDER = new PlaceholderLookupResult(Type.UNKNOWN_PLACEHOLDER);
|
public static final PlaceholderLookupResult UNKNOWN_PLACEHOLDER = new PlaceholderLookupResult(Type.UNKNOWN_PLACEHOLDER);
|
||||||
|
|
||||||
public static PlaceholderLookupResult success(Object result) {
|
public static PlaceholderLookupResult success(Object result) {
|
||||||
return new PlaceholderLookupResult(String.valueOf(result));
|
return new PlaceholderLookupResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlaceholderLookupResult newLookup(String placeholder, Set<Object> extras) {
|
public static PlaceholderLookupResult newLookup(String placeholder, Set<Object> extras) {
|
||||||
@ -40,7 +40,7 @@ public class PlaceholderLookupResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final Type type;
|
private final Type type;
|
||||||
private final String value;
|
private final Object value;
|
||||||
private final Set<Object> extras;
|
private final Set<Object> extras;
|
||||||
|
|
||||||
protected PlaceholderLookupResult(Type type) {
|
protected PlaceholderLookupResult(Type type) {
|
||||||
@ -49,7 +49,7 @@ public class PlaceholderLookupResult {
|
|||||||
this.extras = null;
|
this.extras = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected PlaceholderLookupResult(String value) {
|
protected PlaceholderLookupResult(Object value) {
|
||||||
this.type = Type.SUCCESS;
|
this.type = Type.SUCCESS;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.extras = null;
|
this.extras = null;
|
||||||
@ -65,7 +65,7 @@ public class PlaceholderLookupResult {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
public Object getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the DiscordSRV API, licensed under the MIT License
|
||||||
|
* Copyright (c) 2016-2021 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.discordsrv.api.placeholder;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface PlaceholderResultConverter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a successful placeholder lookup result into a {@link String}.
|
||||||
|
* @param result the result
|
||||||
|
* @return the result in {@link String} form
|
||||||
|
*/
|
||||||
|
String convertPlaceholderResult(@NotNull Object result);
|
||||||
|
}
|
@ -23,7 +23,10 @@
|
|||||||
|
|
||||||
package com.discordsrv.api.placeholder;
|
package com.discordsrv.api.placeholder;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public interface PlaceholderService {
|
public interface PlaceholderService {
|
||||||
@ -38,9 +41,16 @@ public interface PlaceholderService {
|
|||||||
*/
|
*/
|
||||||
Pattern RECURSIVE_PATTERN = Pattern.compile("(\\{)(.+)(})");
|
Pattern RECURSIVE_PATTERN = Pattern.compile("(\\{)(.+)(})");
|
||||||
|
|
||||||
PlaceholderLookupResult lookupPlaceholder(String placeholder, Set<Object> context);
|
void addResultConverter(@NotNull PlaceholderResultConverter resultConverter);
|
||||||
PlaceholderLookupResult lookupPlaceholder(String placeholder, Object... context);
|
void removeResultConverter(@NotNull PlaceholderResultConverter resultConverter);
|
||||||
|
|
||||||
|
String replacePlaceholders(@NotNull String placeholder, @NotNull Set<Object> context);
|
||||||
|
String replacePlaceholders(@NotNull String placeholder, @NotNull Object... context);
|
||||||
|
|
||||||
|
PlaceholderLookupResult lookupPlaceholder(@NotNull String placeholder, @NotNull Set<Object> context);
|
||||||
|
PlaceholderLookupResult lookupPlaceholder(@NotNull String placeholder, @NotNull Object... context);
|
||||||
|
|
||||||
|
Object getResult(@NotNull Matcher matcher, @NotNull Set<Object> context);
|
||||||
|
String getResultAsString(@NotNull Matcher matcher, @NotNull Set<Object> context);
|
||||||
|
|
||||||
String replacePlaceholders(String placeholder, Set<Object> context);
|
|
||||||
String replacePlaceholders(String placeholder, Object... context);
|
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,11 @@ import net.kyori.adventure.identity.Identity;
|
|||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.serializer.craftbukkit.BukkitComponentSerializer;
|
import net.kyori.adventure.text.serializer.craftbukkit.BukkitComponentSerializer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
@SuppressWarnings("NullableProblems") // BukkitOfflinePlayer nullability
|
||||||
public class BukkitPlayer extends BukkitOfflinePlayer implements IPlayer {
|
public class BukkitPlayer extends BukkitOfflinePlayer implements IPlayer {
|
||||||
|
|
||||||
private static final Method DISPLAY_NAME_METHOD; // Paper 1.16+
|
private static final Method DISPLAY_NAME_METHOD; // Paper 1.16+
|
||||||
@ -72,12 +74,13 @@ public class BukkitPlayer extends BukkitOfflinePlayer implements IPlayer {
|
|||||||
|
|
||||||
@SuppressWarnings("deprecation") // Paper
|
@SuppressWarnings("deprecation") // Paper
|
||||||
@Override
|
@Override
|
||||||
public Component displayName() {
|
public @NotNull Component displayName() {
|
||||||
if (DISPLAY_NAME_METHOD != null) {
|
if (DISPLAY_NAME_METHOD != null) {
|
||||||
try {
|
try {
|
||||||
return ComponentUtil.fromUnrelocated(DISPLAY_NAME_METHOD.invoke(player));
|
return ComponentUtil.fromUnrelocated(DISPLAY_NAME_METHOD.invoke(player));
|
||||||
} catch (Throwable ignored) {}
|
} catch (Throwable ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the legacy method
|
// Use the legacy method
|
||||||
return BukkitComponentSerializer.legacy().deserialize(player.getDisplayName());
|
return BukkitComponentSerializer.legacy().deserialize(player.getDisplayName());
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ public class BungeePlayer implements IPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component displayName() {
|
public @NotNull Component displayName() {
|
||||||
return BungeeComponentUtil.fromLegacy(player.getDisplayName());
|
return BungeeComponentUtil.fromLegacy(player.getDisplayName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ import com.discordsrv.common.listener.DefaultChatListener;
|
|||||||
import com.discordsrv.common.logging.DependencyLoggingFilter;
|
import com.discordsrv.common.logging.DependencyLoggingFilter;
|
||||||
import com.discordsrv.common.logging.logger.backend.LoggingBackend;
|
import com.discordsrv.common.logging.logger.backend.LoggingBackend;
|
||||||
import com.discordsrv.common.placeholder.PlaceholderServiceImpl;
|
import com.discordsrv.common.placeholder.PlaceholderServiceImpl;
|
||||||
|
import com.discordsrv.common.placeholder.converter.ComponentResultConverter;
|
||||||
import net.dv8tion.jda.api.JDA;
|
import net.dv8tion.jda.api.JDA;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
|
|||||||
protected final void load() {
|
protected final void load() {
|
||||||
this.eventBus = new EventBusImpl(this);
|
this.eventBus = new EventBusImpl(this);
|
||||||
this.placeholderService = new PlaceholderServiceImpl(this);
|
this.placeholderService = new PlaceholderServiceImpl(this);
|
||||||
this.componentFactory = new ComponentFactory();
|
this.componentFactory = new ComponentFactory(this);
|
||||||
this.discordAPI = new DiscordAPIImpl(this);
|
this.discordAPI = new DiscordAPIImpl(this);
|
||||||
this.discordConnectionDetails = new DiscordConnectionDetailsImpl(this);
|
this.discordConnectionDetails = new DiscordConnectionDetailsImpl(this);
|
||||||
}
|
}
|
||||||
@ -239,6 +240,9 @@ public abstract class AbstractDiscordSRV<C extends MainConfig, CC extends Connec
|
|||||||
discordConnectionManager = new JDAConnectionManager(this);
|
discordConnectionManager = new JDAConnectionManager(this);
|
||||||
discordConnectionManager.connect().join();
|
discordConnectionManager.connect().join();
|
||||||
|
|
||||||
|
// Placeholder result converters
|
||||||
|
placeholderService().addResultConverter(new ComponentResultConverter());
|
||||||
|
|
||||||
// Register PlayerProvider listeners
|
// Register PlayerProvider listeners
|
||||||
playerProvider().subscribe();
|
playerProvider().subscribe();
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import com.discordsrv.api.channel.GameChannel;
|
|||||||
import com.discordsrv.api.event.events.channel.GameChannelLookupEvent;
|
import com.discordsrv.api.event.events.channel.GameChannelLookupEvent;
|
||||||
import com.discordsrv.common.DiscordSRV;
|
import com.discordsrv.common.DiscordSRV;
|
||||||
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
||||||
import com.discordsrv.common.config.main.channels.ChannelConfigHolder;
|
|
||||||
import com.discordsrv.common.function.OrDefault;
|
import com.discordsrv.common.function.OrDefault;
|
||||||
import com.github.benmanes.caffeine.cache.CacheLoader;
|
import com.github.benmanes.caffeine.cache.CacheLoader;
|
||||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||||
@ -55,7 +54,7 @@ public class ChannelConfig {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, ChannelConfigHolder> channels() {
|
private Map<String, BaseChannelConfig> channels() {
|
||||||
return discordSRV.config().channels;
|
return discordSRV.config().channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,12 +63,12 @@ public class ChannelConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public OrDefault<BaseChannelConfig> orDefault(String ownerName, String channelName) {
|
public OrDefault<BaseChannelConfig> orDefault(String ownerName, String channelName) {
|
||||||
ChannelConfigHolder defaultConfig = channels().computeIfAbsent(
|
BaseChannelConfig defaultConfig = channels().computeIfAbsent(
|
||||||
"default", key -> new ChannelConfigHolder(new BaseChannelConfig()));
|
"default", key -> new BaseChannelConfig());
|
||||||
|
|
||||||
return new OrDefault<>(
|
return new OrDefault<>(
|
||||||
get(ownerName, channelName),
|
get(ownerName, channelName),
|
||||||
defaultConfig.get()
|
defaultConfig
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,15 +78,15 @@ public class ChannelConfig {
|
|||||||
|
|
||||||
public BaseChannelConfig get(String ownerName, String channelName) {
|
public BaseChannelConfig get(String ownerName, String channelName) {
|
||||||
if (ownerName != null) {
|
if (ownerName != null) {
|
||||||
ChannelConfigHolder config = channels().get(ownerName + ":" + channelName);
|
BaseChannelConfig config = channels().get(ownerName + ":" + channelName);
|
||||||
if (config != null) {
|
if (config != null) {
|
||||||
return config.get();
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameChannel gameChannel = channels.get(channelName);
|
GameChannel gameChannel = channels.get(channelName);
|
||||||
if (gameChannel != null && gameChannel.getOwnerName().equals(ownerName)) {
|
if (gameChannel != null && gameChannel.getOwnerName().equals(ownerName)) {
|
||||||
config = channels().get(channelName);
|
config = channels().get(channelName);
|
||||||
return config != null ? config.get() : null;
|
return config;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,27 @@
|
|||||||
|
|
||||||
package com.discordsrv.common.component;
|
package com.discordsrv.common.component;
|
||||||
|
|
||||||
|
import com.discordsrv.api.component.EnhancedTextBuilder;
|
||||||
import com.discordsrv.api.component.MinecraftComponent;
|
import com.discordsrv.api.component.MinecraftComponent;
|
||||||
import com.discordsrv.api.component.MinecraftComponentFactory;
|
import com.discordsrv.api.component.MinecraftComponentFactory;
|
||||||
|
import com.discordsrv.common.DiscordSRV;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
public class ComponentFactory implements MinecraftComponentFactory {
|
public class ComponentFactory implements MinecraftComponentFactory {
|
||||||
|
|
||||||
|
private final DiscordSRV discordSRV;
|
||||||
|
|
||||||
|
public ComponentFactory(DiscordSRV discordSRV) {
|
||||||
|
this.discordSRV = discordSRV;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull MinecraftComponent empty() {
|
public @NotNull MinecraftComponent empty() {
|
||||||
return MinecraftComponentImpl.empty();
|
return MinecraftComponentImpl.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnhancedTextBuilder enhancedBuilder(String content) {
|
||||||
|
return new EnhancedTextBuilderImpl(discordSRV, content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.discordsrv.common.component;
|
||||||
|
|
||||||
|
import com.discordsrv.api.component.EnhancedTextBuilder;
|
||||||
|
import com.discordsrv.api.component.MinecraftComponent;
|
||||||
|
import com.discordsrv.api.placeholder.PlaceholderService;
|
||||||
|
import com.discordsrv.common.DiscordSRV;
|
||||||
|
import com.discordsrv.common.component.util.ComponentUtil;
|
||||||
|
import dev.vankka.enhancedlegacytext.EnhancedComponentBuilder;
|
||||||
|
import dev.vankka.enhancedlegacytext.EnhancedLegacyText;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class EnhancedTextBuilderImpl implements EnhancedTextBuilder {
|
||||||
|
|
||||||
|
private final Set<Object> context = new HashSet<>();
|
||||||
|
private final Map<Pattern, Function<Matcher, Object>> replacements = new HashMap<>();
|
||||||
|
|
||||||
|
private final DiscordSRV discordSRV;
|
||||||
|
private final String enhancedFormat;
|
||||||
|
|
||||||
|
public EnhancedTextBuilderImpl(DiscordSRV discordSRV, String enhancedFormat) {
|
||||||
|
this.discordSRV = discordSRV;
|
||||||
|
this.enhancedFormat = enhancedFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnhancedTextBuilder addContext(Object... context) {
|
||||||
|
this.context.addAll(Arrays.asList(context));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnhancedTextBuilder addReplacement(Pattern target, Function<Matcher, Object> replacement) {
|
||||||
|
this.replacements.put(target, replacement);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MinecraftComponent build() {
|
||||||
|
EnhancedComponentBuilder builder = EnhancedLegacyText.get()
|
||||||
|
.buildComponent(enhancedFormat);
|
||||||
|
|
||||||
|
replacements.forEach(builder::replaceAll);
|
||||||
|
builder.replaceAll(PlaceholderService.PATTERN,
|
||||||
|
matcher -> discordSRV.placeholderService().getResult(matcher, context));
|
||||||
|
|
||||||
|
Component component = builder.build();
|
||||||
|
return ComponentUtil.toAPI(component);
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,8 @@ import org.spongepowered.configurate.objectmapping.meta.Comment;
|
|||||||
public class ConnectionConfig implements Config {
|
public class ConnectionConfig implements Config {
|
||||||
|
|
||||||
public static final String FILE_NAME = "connections.yaml";
|
public static final String FILE_NAME = "connections.yaml";
|
||||||
|
|
||||||
|
@Override
|
||||||
public final String getFileName() {
|
public final String getFileName() {
|
||||||
return FILE_NAME;
|
return FILE_NAME;
|
||||||
}
|
}
|
||||||
@ -37,5 +39,6 @@ public class ConnectionConfig implements Config {
|
|||||||
|
|
||||||
@Comment("Don't know what this is? Neither do I")
|
@Comment("Don't know what this is? Neither do I")
|
||||||
public String token = "Token here";
|
public String token = "Token here";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ import com.discordsrv.common.config.Config;
|
|||||||
import com.discordsrv.common.config.annotation.DefaultOnly;
|
import com.discordsrv.common.config.annotation.DefaultOnly;
|
||||||
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
||||||
import com.discordsrv.common.config.main.channels.ChannelConfig;
|
import com.discordsrv.common.config.main.channels.ChannelConfig;
|
||||||
import com.discordsrv.common.config.main.channels.ChannelConfigHolder;
|
|
||||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -32,13 +31,15 @@ import java.util.Map;
|
|||||||
public class MainConfig implements Config {
|
public class MainConfig implements Config {
|
||||||
|
|
||||||
public static final String FILE_NAME = "config.yaml";
|
public static final String FILE_NAME = "config.yaml";
|
||||||
|
|
||||||
|
@Override
|
||||||
public final String getFileName() {
|
public final String getFileName() {
|
||||||
return FILE_NAME;
|
return FILE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@DefaultOnly("default")
|
@DefaultOnly("default")
|
||||||
public Map<String, ChannelConfigHolder> channels = new HashMap<String, ChannelConfigHolder>() {{
|
public Map<String, BaseChannelConfig> channels = new HashMap<String, BaseChannelConfig>() {{
|
||||||
put("default", new ChannelConfigHolder(new BaseChannelConfig()));
|
put("default", new BaseChannelConfig());
|
||||||
put("global", new ChannelConfigHolder(new ChannelConfig()));
|
put("global", new ChannelConfig());
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,50 @@
|
|||||||
package com.discordsrv.common.config.main.channels;
|
package com.discordsrv.common.config.main.channels;
|
||||||
|
|
||||||
import com.discordsrv.common.config.main.channels.minecraftodiscord.MinecraftToDiscordChatConfig;
|
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;
|
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||||
|
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
||||||
|
import org.spongepowered.configurate.serialize.SerializationException;
|
||||||
|
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
@ConfigSerializable
|
@ConfigSerializable
|
||||||
public class BaseChannelConfig {
|
public class BaseChannelConfig {
|
||||||
|
|
||||||
public MinecraftToDiscordChatConfig minecraftToDiscord = new MinecraftToDiscordChatConfig();
|
public MinecraftToDiscordChatConfig minecraftToDiscord = new MinecraftToDiscordChatConfig();
|
||||||
|
|
||||||
|
|
||||||
|
public static class Serializer implements TypeSerializer<BaseChannelConfig> {
|
||||||
|
|
||||||
|
private final ObjectMapper.Factory mapperFactory;
|
||||||
|
|
||||||
|
public Serializer(ObjectMapper.Factory mapperFactory) {
|
||||||
|
this.mapperFactory = mapperFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseChannelConfig deserialize(Type type, ConfigurationNode node) throws SerializationException {
|
||||||
|
return (BaseChannelConfig) mapperFactory.asTypeSerializer()
|
||||||
|
.deserialize(
|
||||||
|
"default".equals(node.key()) ? BaseChannelConfig.class : ChannelConfig.class,
|
||||||
|
node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(Type type, @Nullable BaseChannelConfig obj, ConfigurationNode node) throws SerializationException {
|
||||||
|
if (obj == null) {
|
||||||
|
node.set(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapperFactory.asTypeSerializer().serialize(
|
||||||
|
"default".equals(node.key()) ? BaseChannelConfig.class : ChannelConfig.class,
|
||||||
|
obj,
|
||||||
|
node
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ package com.discordsrv.common.config.main.channels;
|
|||||||
|
|
||||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||||
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
import org.spongepowered.configurate.objectmapping.meta.Comment;
|
||||||
import org.spongepowered.configurate.objectmapping.meta.Setting;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
@ -31,8 +30,6 @@ import java.util.List;
|
|||||||
@ConfigSerializable
|
@ConfigSerializable
|
||||||
public class ChannelConfig extends BaseChannelConfig {
|
public class ChannelConfig extends BaseChannelConfig {
|
||||||
|
|
||||||
protected static final String CHANNEL_IDS_OPTION_NAME = "ChannelIds";
|
|
||||||
|
|
||||||
public ChannelConfig() {
|
public ChannelConfig() {
|
||||||
// Clear everything besides channelIds by default (these will be filled back in by Configurate if they are in the config itself)
|
// Clear everything besides channelIds by default (these will be filled back in by Configurate if they are in the config itself)
|
||||||
for (Field field : getClass().getFields()) {
|
for (Field field : getClass().getFields()) {
|
||||||
@ -50,7 +47,6 @@ public class ChannelConfig extends BaseChannelConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Setting(CHANNEL_IDS_OPTION_NAME)
|
|
||||||
@Comment("The channels this in-game channel will forward to in Discord")
|
@Comment("The channels this in-game channel will forward to in Discord")
|
||||||
public List<String> channelIds = new ArrayList<>(Collections.singletonList("channel-id-here"));
|
public List<String> channelIds = new ArrayList<>(Collections.singletonList("channel-id-here"));
|
||||||
|
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.discordsrv.common.config.main.channels;
|
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
|
||||||
import org.spongepowered.configurate.ConfigurationNode;
|
|
||||||
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
|
||||||
import org.spongepowered.configurate.serialize.SerializationException;
|
|
||||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A bit of a trick to have two different types in the same map with Configurate.
|
|
||||||
*/
|
|
||||||
public class ChannelConfigHolder {
|
|
||||||
|
|
||||||
private final BaseChannelConfig obj;
|
|
||||||
|
|
||||||
public ChannelConfigHolder(BaseChannelConfig obj) {
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseChannelConfig get() {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Serializer implements TypeSerializer<ChannelConfigHolder> {
|
|
||||||
|
|
||||||
private final ObjectMapper.Factory mapperFactory;
|
|
||||||
|
|
||||||
public Serializer(ObjectMapper.Factory mapperFactory) {
|
|
||||||
this.mapperFactory = mapperFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ChannelConfigHolder deserialize(Type type, ConfigurationNode node) throws SerializationException {
|
|
||||||
boolean channelsNotPresent = node.node(ChannelConfig.CHANNEL_IDS_OPTION_NAME).empty();
|
|
||||||
BaseChannelConfig channelConfig = (BaseChannelConfig) mapperFactory
|
|
||||||
.get(channelsNotPresent ? BaseChannelConfig.class : ChannelConfig.class)
|
|
||||||
.load(node);
|
|
||||||
return new ChannelConfigHolder(channelConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void serialize(Type type, @Nullable ChannelConfigHolder obj, ConfigurationNode node) throws SerializationException {
|
|
||||||
map(obj != null ? obj.get() : null, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private <T extends BaseChannelConfig> void map(BaseChannelConfig obj, ConfigurationNode node) throws SerializationException {
|
|
||||||
mapperFactory
|
|
||||||
.get((Class<T>) (obj instanceof ChannelConfig ? ChannelConfig.class : BaseChannelConfig.class))
|
|
||||||
.save((T) obj, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,8 +28,6 @@ public class MinecraftToDiscordChatConfig {
|
|||||||
@Setting("Format")
|
@Setting("Format")
|
||||||
public SendableDiscordMessage.Builder messageFormat = SendableDiscordMessage.builder()
|
public SendableDiscordMessage.Builder messageFormat = SendableDiscordMessage.builder()
|
||||||
.setWebhookUsername("%player_display_name%")
|
.setWebhookUsername("%player_display_name%")
|
||||||
.setContent("%player_message%");// TODO
|
.setContent("%message%");// TODO
|
||||||
|
|
||||||
@Setting("UseWebhooks")
|
|
||||||
public boolean useWebhooks = false;
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ import com.discordsrv.common.config.manager.loader.YamlConfigLoaderProvider;
|
|||||||
import com.discordsrv.common.config.manager.manager.TranslatedConfigManager;
|
import com.discordsrv.common.config.manager.manager.TranslatedConfigManager;
|
||||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||||
|
|
||||||
public abstract class ConnectionConfigManager<C extends ConnectionConfig> extends TranslatedConfigManager<C, YamlConfigurationLoader> implements YamlConfigLoaderProvider {
|
public abstract class ConnectionConfigManager<C extends ConnectionConfig>
|
||||||
|
extends TranslatedConfigManager<C, YamlConfigurationLoader>
|
||||||
|
implements YamlConfigLoaderProvider {
|
||||||
|
|
||||||
public ConnectionConfigManager(DiscordSRV discordSRV) {
|
public ConnectionConfigManager(DiscordSRV discordSRV) {
|
||||||
super(discordSRV);
|
super(discordSRV);
|
||||||
|
@ -18,22 +18,12 @@
|
|||||||
|
|
||||||
package com.discordsrv.common.config.manager;
|
package com.discordsrv.common.config.manager;
|
||||||
|
|
||||||
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
|
|
||||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
|
||||||
import com.discordsrv.common.DiscordSRV;
|
import com.discordsrv.common.DiscordSRV;
|
||||||
import com.discordsrv.common.config.main.MainConfig;
|
import com.discordsrv.common.config.main.MainConfig;
|
||||||
import com.discordsrv.common.config.main.channels.ChannelConfigHolder;
|
|
||||||
import com.discordsrv.common.config.manager.loader.YamlConfigLoaderProvider;
|
import com.discordsrv.common.config.manager.loader.YamlConfigLoaderProvider;
|
||||||
import com.discordsrv.common.config.manager.manager.TranslatedConfigManager;
|
import com.discordsrv.common.config.manager.manager.TranslatedConfigManager;
|
||||||
import com.discordsrv.common.config.serializer.ColorSerializer;
|
|
||||||
import com.discordsrv.common.config.serializer.DiscordMessageEmbedSerializer;
|
|
||||||
import com.discordsrv.common.config.serializer.SendableDiscordMessageSerializer;
|
|
||||||
import org.spongepowered.configurate.ConfigurationOptions;
|
|
||||||
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
|
||||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
|
|
||||||
public abstract class MainConfigManager<C extends MainConfig>
|
public abstract class MainConfigManager<C extends MainConfig>
|
||||||
extends TranslatedConfigManager<C, YamlConfigurationLoader>
|
extends TranslatedConfigManager<C, YamlConfigurationLoader>
|
||||||
implements YamlConfigLoaderProvider {
|
implements YamlConfigLoaderProvider {
|
||||||
@ -46,17 +36,4 @@ public abstract class MainConfigManager<C extends MainConfig>
|
|||||||
protected String fileName() {
|
protected String fileName() {
|
||||||
return MainConfig.FILE_NAME;
|
return MainConfig.FILE_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConfigurationOptions defaultOptions() {
|
|
||||||
return super.defaultOptions()
|
|
||||||
.serializers(builder -> {
|
|
||||||
ObjectMapper.Factory objectMapper = defaultObjectMapper();
|
|
||||||
builder.register(Color.class, new ColorSerializer());
|
|
||||||
builder.register(ChannelConfigHolder.class, new ChannelConfigHolder.Serializer(objectMapper));
|
|
||||||
builder.register(DiscordMessageEmbed.Builder.class, new DiscordMessageEmbedSerializer());
|
|
||||||
builder.register(DiscordMessageEmbed.Field.class, new DiscordMessageEmbedSerializer.FieldSerializer());
|
|
||||||
builder.register(SendableDiscordMessage.Builder.class, new SendableDiscordMessageSerializer());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,15 @@
|
|||||||
|
|
||||||
package com.discordsrv.common.config.manager.manager;
|
package com.discordsrv.common.config.manager.manager;
|
||||||
|
|
||||||
|
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
|
||||||
|
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||||
import com.discordsrv.common.DiscordSRV;
|
import com.discordsrv.common.DiscordSRV;
|
||||||
import com.discordsrv.common.config.annotation.DefaultOnly;
|
import com.discordsrv.common.config.annotation.DefaultOnly;
|
||||||
|
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
||||||
import com.discordsrv.common.config.manager.loader.ConfigLoaderProvider;
|
import com.discordsrv.common.config.manager.loader.ConfigLoaderProvider;
|
||||||
|
import com.discordsrv.common.config.serializer.ColorSerializer;
|
||||||
|
import com.discordsrv.common.config.serializer.DiscordMessageEmbedSerializer;
|
||||||
|
import com.discordsrv.common.config.serializer.SendableDiscordMessageSerializer;
|
||||||
import com.discordsrv.common.exception.ConfigException;
|
import com.discordsrv.common.exception.ConfigException;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||||
@ -31,7 +37,9 @@ import org.spongepowered.configurate.loader.AbstractConfigurationLoader;
|
|||||||
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
import org.spongepowered.configurate.objectmapping.ConfigSerializable;
|
||||||
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
import org.spongepowered.configurate.objectmapping.ObjectMapper;
|
||||||
import org.spongepowered.configurate.serialize.SerializationException;
|
import org.spongepowered.configurate.serialize.SerializationException;
|
||||||
|
import org.spongepowered.configurate.util.NamingSchemes;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -73,31 +81,40 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
|
|||||||
|
|
||||||
public ConfigurationOptions defaultOptions() {
|
public ConfigurationOptions defaultOptions() {
|
||||||
return ConfigurationOptions.defaults()
|
return ConfigurationOptions.defaults()
|
||||||
.shouldCopyDefaults(false);
|
.shouldCopyDefaults(false)
|
||||||
}
|
.implicitInitialization(false)
|
||||||
|
.serializers(builder -> {
|
||||||
protected ObjectMapper.Factory.Builder objectMapperBuilder() {
|
ObjectMapper.Factory objectMapper = configObjectMapper();
|
||||||
return ObjectMapper.factoryBuilder();
|
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());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationOptions configNodeOptions() {
|
public ConfigurationOptions configNodeOptions() {
|
||||||
return defaultOptions();
|
return defaultOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ObjectMapper.Factory.Builder configObjectMapperBuilder() {
|
|
||||||
return objectMapperBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjectMapper.Factory configObjectMapper() {
|
|
||||||
return configObjectMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConfigurationOptions defaultNodeOptions() {
|
public ConfigurationOptions defaultNodeOptions() {
|
||||||
return defaultOptions();
|
return defaultOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ObjectMapper.Factory.Builder configObjectMapperBuilder() {
|
||||||
|
return objectMapperBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
protected ObjectMapper.Factory.Builder defaultObjectMapperBuilder() {
|
protected ObjectMapper.Factory.Builder defaultObjectMapperBuilder() {
|
||||||
return configObjectMapperBuilder()
|
return objectMapperBuilder()
|
||||||
.addProcessor(DefaultOnly.class, (data, value) -> (value1, destination) -> {
|
.addProcessor(DefaultOnly.class, (data, value) -> (value1, destination) -> {
|
||||||
String[] children = data.value();
|
String[] children = data.value();
|
||||||
boolean whitelist = data.whitelist();
|
boolean whitelist = data.whitelist();
|
||||||
@ -131,6 +148,10 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ObjectMapper.Factory configObjectMapper() {
|
||||||
|
return configObjectMapper;
|
||||||
|
}
|
||||||
|
|
||||||
public ObjectMapper.Factory defaultObjectMapper() {
|
public ObjectMapper.Factory defaultObjectMapper() {
|
||||||
return defaultObjectMapper;
|
return defaultObjectMapper;
|
||||||
}
|
}
|
||||||
@ -190,14 +211,19 @@ public abstract class ConfigurateConfigManager<T, LT extends AbstractConfigurati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public void save() throws ConfigException {
|
public void save() throws ConfigException {
|
||||||
try {
|
try {
|
||||||
CommentedConfigurationNode node = loader.createNode();
|
CommentedConfigurationNode node = loader.createNode();
|
||||||
node.set(configuration);
|
save(configuration, (Class<T>) configuration.getClass(), node);
|
||||||
loader.save(node);
|
loader.save(node);
|
||||||
} catch (ConfigurateException e) {
|
} catch (ConfigurateException e) {
|
||||||
throw new ConfigException("Failed to load configuration", e);
|
throw new ConfigException("Failed to load configuration", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void save(T config, Class<T> clazz, CommentedConfigurationNode node) throws SerializationException {
|
||||||
|
configObjectMapper().get(clazz).save(config, node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,8 @@ import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
|||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
public abstract class TranslatedConfigManager<T extends Config, LT extends AbstractConfigurationLoader<CommentedConfigurationNode>> extends ConfigurateConfigManager<T, LT> {
|
public abstract class TranslatedConfigManager<T extends Config, LT extends AbstractConfigurationLoader<CommentedConfigurationNode>>
|
||||||
|
extends ConfigurateConfigManager<T, LT> {
|
||||||
|
|
||||||
public TranslatedConfigManager(DiscordSRV discordSRV) {
|
public TranslatedConfigManager(DiscordSRV discordSRV) {
|
||||||
super(discordSRV);
|
super(discordSRV);
|
||||||
@ -55,6 +56,7 @@ public abstract class TranslatedConfigManager<T extends Config, LT extends Abstr
|
|||||||
return translation;
|
return translation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void translate() throws ConfigException {
|
public void translate() throws ConfigException {
|
||||||
T config = config();
|
T config = config();
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
@ -70,7 +72,8 @@ public abstract class TranslatedConfigManager<T extends Config, LT extends Abstr
|
|||||||
translation = translation.node(config.getFileName());
|
translation = translation.node(config.getFileName());
|
||||||
|
|
||||||
CommentedConfigurationNode node = loader().createNode();
|
CommentedConfigurationNode node = loader().createNode();
|
||||||
node.set(config);
|
save(config, (Class<T>) config.getClass(), node);
|
||||||
|
//node.set(config);
|
||||||
translateNode(node, translation, translation.node("_comments"));
|
translateNode(node, translation, translation.node("_comments"));
|
||||||
} catch (ConfigurateException e) {
|
} catch (ConfigurateException e) {
|
||||||
throw new ConfigException(e);
|
throw new ConfigException(e);
|
||||||
|
@ -45,7 +45,9 @@ public class SendableDiscordMessageSerializer implements TypeSerializer<Sendable
|
|||||||
|
|
||||||
ConfigurationNode webhook = node.node("Webhook");
|
ConfigurationNode webhook = node.node("Webhook");
|
||||||
String webhookUsername = webhook.node("Username").getString();
|
String webhookUsername = webhook.node("Username").getString();
|
||||||
if (webhook.node("Enabled").getBoolean(webhook.node("Enable").getBoolean(webhookUsername != null))) {
|
if (webhook.node("Enabled").getBoolean(
|
||||||
|
webhook.node("Enable").getBoolean(
|
||||||
|
webhookUsername != null))) {
|
||||||
builder.setWebhookUsername(webhookUsername);
|
builder.setWebhookUsername(webhookUsername);
|
||||||
builder.setWebhookAvatarUrl(webhook.node("AvatarUrl").getString());
|
builder.setWebhookAvatarUrl(webhook.node("AvatarUrl").getString());
|
||||||
}
|
}
|
||||||
@ -82,7 +84,9 @@ public class SendableDiscordMessageSerializer implements TypeSerializer<Sendable
|
|||||||
|
|
||||||
List<DiscordMessageEmbed.Builder> embedBuilders = new ArrayList<>();
|
List<DiscordMessageEmbed.Builder> embedBuilders = new ArrayList<>();
|
||||||
obj.getEmbeds().forEach(embed -> embedBuilders.add(embed.toBuilder()));
|
obj.getEmbeds().forEach(embed -> embedBuilders.add(embed.toBuilder()));
|
||||||
node.setList(DiscordMessageEmbed.Builder.class, embedBuilders);
|
if (!embedBuilders.isEmpty()) {
|
||||||
|
node.node("Embeds").setList(DiscordMessageEmbed.Builder.class, embedBuilders);
|
||||||
|
}
|
||||||
|
|
||||||
node.node("Content").set(obj.getContent());
|
node.node("Content").set(obj.getContent());
|
||||||
}
|
}
|
||||||
|
@ -25,18 +25,22 @@ import com.discordsrv.api.discord.api.entity.channel.DiscordDMChannel;
|
|||||||
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
import com.discordsrv.api.discord.api.entity.channel.DiscordMessageChannel;
|
||||||
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
||||||
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
import com.discordsrv.api.discord.api.entity.guild.DiscordGuild;
|
||||||
|
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||||
import com.discordsrv.api.discord.api.entity.user.DiscordUser;
|
import com.discordsrv.api.discord.api.entity.user.DiscordUser;
|
||||||
import com.discordsrv.api.discord.api.exception.NotReadyException;
|
import com.discordsrv.api.discord.api.exception.NotReadyException;
|
||||||
import com.discordsrv.api.discord.api.exception.UnknownChannelException;
|
import com.discordsrv.api.discord.api.exception.UnknownChannelException;
|
||||||
import com.discordsrv.common.DiscordSRV;
|
import com.discordsrv.common.DiscordSRV;
|
||||||
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
||||||
import com.discordsrv.common.config.main.channels.ChannelConfig;
|
import com.discordsrv.common.config.main.channels.ChannelConfig;
|
||||||
import com.discordsrv.common.config.main.channels.ChannelConfigHolder;
|
|
||||||
import com.discordsrv.common.discord.api.channel.DiscordDMChannelImpl;
|
import com.discordsrv.common.discord.api.channel.DiscordDMChannelImpl;
|
||||||
import com.discordsrv.common.discord.api.channel.DiscordTextChannelImpl;
|
import com.discordsrv.common.discord.api.channel.DiscordTextChannelImpl;
|
||||||
import com.discordsrv.common.discord.api.guild.DiscordGuildImpl;
|
import com.discordsrv.common.discord.api.guild.DiscordGuildImpl;
|
||||||
|
import com.discordsrv.common.discord.api.message.SendableDiscordMessageFormatterImpl;
|
||||||
import com.discordsrv.common.discord.api.user.DiscordUserImpl;
|
import com.discordsrv.common.discord.api.user.DiscordUserImpl;
|
||||||
import com.github.benmanes.caffeine.cache.*;
|
import com.github.benmanes.caffeine.cache.AsyncCacheLoader;
|
||||||
|
import com.github.benmanes.caffeine.cache.AsyncLoadingCache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Expiry;
|
||||||
|
import com.github.benmanes.caffeine.cache.RemovalListener;
|
||||||
import net.dv8tion.jda.api.JDA;
|
import net.dv8tion.jda.api.JDA;
|
||||||
import net.dv8tion.jda.api.entities.TextChannel;
|
import net.dv8tion.jda.api.entities.TextChannel;
|
||||||
import net.dv8tion.jda.api.entities.User;
|
import net.dv8tion.jda.api.entities.User;
|
||||||
@ -72,6 +76,11 @@ public class DiscordAPIImpl implements DiscordAPI {
|
|||||||
return cachedClients.get(channelId);
|
return cachedClients.get(channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SendableDiscordMessage.Formatter format(SendableDiscordMessage.Builder message) {
|
||||||
|
return new SendableDiscordMessageFormatterImpl(discordSRV, message);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Optional<? extends DiscordMessageChannel> getMessageChannelById(@NotNull String id) {
|
public @NotNull Optional<? extends DiscordMessageChannel> getMessageChannelById(@NotNull String id) {
|
||||||
Optional<DiscordTextChannel> textChannel = getTextChannelById(id);
|
Optional<DiscordTextChannel> textChannel = getTextChannelById(id);
|
||||||
@ -163,8 +172,7 @@ public class DiscordAPIImpl implements DiscordAPI {
|
|||||||
private class WebhookCacheExpiry implements Expiry<String, WebhookClient> {
|
private class WebhookCacheExpiry implements Expiry<String, WebhookClient> {
|
||||||
|
|
||||||
private boolean isConfiguredChannel(String channelId) {
|
private boolean isConfiguredChannel(String channelId) {
|
||||||
for (ChannelConfigHolder value : discordSRV.config().channels.values()) {
|
for (BaseChannelConfig config : discordSRV.config().channels.values()) {
|
||||||
BaseChannelConfig config = value.get();
|
|
||||||
if (config instanceof ChannelConfig
|
if (config instanceof ChannelConfig
|
||||||
&& ((ChannelConfig) config).channelIds.contains(channelId)) {
|
&& ((ChannelConfig) config).channelIds.contains(channelId)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -23,11 +23,11 @@ import club.minnced.discord.webhook.receive.ReadonlyMessage;
|
|||||||
import club.minnced.discord.webhook.receive.ReadonlyUser;
|
import club.minnced.discord.webhook.receive.ReadonlyUser;
|
||||||
import club.minnced.discord.webhook.send.WebhookEmbed;
|
import club.minnced.discord.webhook.send.WebhookEmbed;
|
||||||
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
import com.discordsrv.api.discord.api.entity.channel.DiscordTextChannel;
|
||||||
import com.discordsrv.api.discord.api.exception.UnknownChannelException;
|
|
||||||
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
|
import com.discordsrv.api.discord.api.entity.message.DiscordMessageEmbed;
|
||||||
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
import com.discordsrv.api.discord.api.entity.message.ReceivedDiscordMessage;
|
||||||
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||||
import com.discordsrv.api.discord.api.entity.message.impl.SendableDiscordMessageImpl;
|
import com.discordsrv.api.discord.api.entity.message.impl.SendableDiscordMessageImpl;
|
||||||
|
import com.discordsrv.api.discord.api.exception.UnknownChannelException;
|
||||||
import com.discordsrv.common.DiscordSRV;
|
import com.discordsrv.common.DiscordSRV;
|
||||||
import net.dv8tion.jda.api.entities.Message;
|
import net.dv8tion.jda.api.entities.Message;
|
||||||
import net.dv8tion.jda.api.entities.MessageEmbed;
|
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.discordsrv.common.discord.api.message;
|
||||||
|
|
||||||
|
import com.discordsrv.api.discord.api.entity.message.SendableDiscordMessage;
|
||||||
|
import com.discordsrv.api.placeholder.PlaceholderService;
|
||||||
|
import com.discordsrv.common.DiscordSRV;
|
||||||
|
import com.discordsrv.common.placeholder.converter.ComponentResultConverter;
|
||||||
|
import com.discordsrv.common.string.util.Placeholders;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class SendableDiscordMessageFormatterImpl implements SendableDiscordMessage.Formatter {
|
||||||
|
|
||||||
|
private final Set<Object> context = new HashSet<>();
|
||||||
|
private final Map<Pattern, Function<Matcher, Object>> replacements = new HashMap<>();
|
||||||
|
|
||||||
|
private final DiscordSRV discordSRV;
|
||||||
|
private final SendableDiscordMessage.Builder builder;
|
||||||
|
|
||||||
|
public SendableDiscordMessageFormatterImpl(DiscordSRV discordSRV, SendableDiscordMessage.Builder builder) {
|
||||||
|
this.discordSRV = discordSRV;
|
||||||
|
this.builder = builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SendableDiscordMessage.Formatter addContext(Object... context) {
|
||||||
|
this.context.addAll(Arrays.asList(context));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SendableDiscordMessage.Formatter addReplacement(Pattern target, Function<Matcher, Object> replacement) {
|
||||||
|
this.replacements.put(target, replacement);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SendableDiscordMessage build() {
|
||||||
|
Function<String, String> placeholders = input -> {
|
||||||
|
if (input == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Placeholders(input)
|
||||||
|
.addAll(replacements)
|
||||||
|
.replaceAll(PlaceholderService.PATTERN,
|
||||||
|
matcher -> discordSRV.placeholderService().getResultAsString(matcher, context))
|
||||||
|
.get();
|
||||||
|
};
|
||||||
|
|
||||||
|
ComponentResultConverter.plain(() ->
|
||||||
|
builder.setWebhookUsername(placeholders.apply(builder.getWebhookUsername())));
|
||||||
|
builder.setContent(placeholders.apply(builder.getContent()));
|
||||||
|
|
||||||
|
// TODO: rest of the content, escaping unwanted characters
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
@ -28,8 +28,9 @@ import com.discordsrv.common.DiscordSRV;
|
|||||||
import com.discordsrv.common.component.util.ComponentUtil;
|
import com.discordsrv.common.component.util.ComponentUtil;
|
||||||
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
||||||
import com.discordsrv.common.config.main.channels.ChannelConfig;
|
import com.discordsrv.common.config.main.channels.ChannelConfig;
|
||||||
|
import com.discordsrv.common.config.main.channels.minecraftodiscord.MinecraftToDiscordChatConfig;
|
||||||
import com.discordsrv.common.function.OrDefault;
|
import com.discordsrv.common.function.OrDefault;
|
||||||
import com.discordsrv.common.player.util.PlayerUtil;
|
import dev.vankka.mcdiscordreserializer.discord.DiscordSerializer;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -49,23 +50,23 @@ public class DefaultChatListener extends AbstractListener {
|
|||||||
|
|
||||||
GameChannel gameChannel = event.getGameChannel();
|
GameChannel gameChannel = event.getGameChannel();
|
||||||
Component message = ComponentUtil.fromAPI(event.message());
|
Component message = ComponentUtil.fromAPI(event.message());
|
||||||
Component displayName = PlayerUtil.displayName(event.getPlayer());
|
|
||||||
|
|
||||||
OrDefault<BaseChannelConfig> channelConfig = discordSRV.channelConfig().orDefault(gameChannel);
|
OrDefault<BaseChannelConfig> channelConfig = discordSRV.channelConfig().orDefault(gameChannel);
|
||||||
|
OrDefault<MinecraftToDiscordChatConfig> chatConfig = channelConfig.map(cfg -> cfg.minecraftToDiscord);
|
||||||
|
|
||||||
// Component discordMessage = EnhancedLegacyText.get().buildComponent(channelConfig.map(cfg -> cfg.minecraftToDiscord).get(cfg -> cfg.messageFormat))
|
SendableDiscordMessage.Builder builder = chatConfig.get(cfg -> cfg.messageFormat);
|
||||||
// .replace("%message%", message)
|
if (builder == null) {
|
||||||
// .replace("%player_display_name%", displayName)
|
return;
|
||||||
// .build();
|
}
|
||||||
//
|
|
||||||
// String username = new Placeholders(channelConfig.map(cfg -> cfg.minecraftToDiscord).get(cfg -> cfg.usernameFormat))
|
SendableDiscordMessage discordMessage = discordSRV.discordAPI().format(builder)
|
||||||
// .replace("%player_display_name%", () -> PlainTextComponentSerializer.plainText().serialize(displayName))
|
.addContext(event.getPlayer())
|
||||||
// .get();
|
.addReplacement("%message%", DiscordSerializer.INSTANCE.serialize(message))
|
||||||
|
.build();
|
||||||
|
|
||||||
discordSRV.eventBus().publish(
|
discordSRV.eventBus().publish(
|
||||||
new ChatMessageSendEvent(
|
new ChatMessageSendEvent(
|
||||||
null,
|
discordMessage,
|
||||||
null,
|
|
||||||
gameChannel
|
gameChannel
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -86,13 +87,7 @@ public class DefaultChatListener extends AbstractListener {
|
|||||||
|
|
||||||
for (String channelId : channelIds) {
|
for (String channelId : channelIds) {
|
||||||
discordSRV.discordAPI().getTextChannelById(channelId).ifPresent(textChannel ->
|
discordSRV.discordAPI().getTextChannelById(channelId).ifPresent(textChannel ->
|
||||||
textChannel.sendMessage(
|
textChannel.sendMessage(event.getDiscordMessage()));
|
||||||
SendableDiscordMessage.builder()
|
|
||||||
.setWebhookUsername(event.getDiscordUsername())
|
|
||||||
.setContent(event.getDiscordMessage())
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package com.discordsrv.common.placeholder;
|
|||||||
import com.discordsrv.api.event.events.placeholder.PlaceholderLookupEvent;
|
import com.discordsrv.api.event.events.placeholder.PlaceholderLookupEvent;
|
||||||
import com.discordsrv.api.placeholder.Placeholder;
|
import com.discordsrv.api.placeholder.Placeholder;
|
||||||
import com.discordsrv.api.placeholder.PlaceholderLookupResult;
|
import com.discordsrv.api.placeholder.PlaceholderLookupResult;
|
||||||
|
import com.discordsrv.api.placeholder.PlaceholderResultConverter;
|
||||||
import com.discordsrv.api.placeholder.PlaceholderService;
|
import com.discordsrv.api.placeholder.PlaceholderService;
|
||||||
import com.discordsrv.common.DiscordSRV;
|
import com.discordsrv.common.DiscordSRV;
|
||||||
import com.discordsrv.common.placeholder.provider.AnnotationPlaceholderProvider;
|
import com.discordsrv.common.placeholder.provider.AnnotationPlaceholderProvider;
|
||||||
@ -29,11 +30,13 @@ import com.github.benmanes.caffeine.cache.CacheLoader;
|
|||||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -42,6 +45,7 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
|||||||
|
|
||||||
private final DiscordSRV discordSRV;
|
private final DiscordSRV discordSRV;
|
||||||
private final LoadingCache<Class<?>, Set<PlaceholderProvider>> classProviders;
|
private final LoadingCache<Class<?>, Set<PlaceholderProvider>> classProviders;
|
||||||
|
private final Set<PlaceholderResultConverter> converters = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
public PlaceholderServiceImpl(DiscordSRV discordSRV) {
|
public PlaceholderServiceImpl(DiscordSRV discordSRV) {
|
||||||
this.discordSRV = discordSRV;
|
this.discordSRV = discordSRV;
|
||||||
@ -58,13 +62,20 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlaceholderLookupResult lookupPlaceholder(String placeholder, Object... context) {
|
public PlaceholderLookupResult lookupPlaceholder(@NotNull String placeholder, Object... context) {
|
||||||
return lookupPlaceholder(placeholder, getArrayAsSet(context));
|
return lookupPlaceholder(placeholder, getArrayAsSet(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlaceholderLookupResult lookupPlaceholder(String placeholder, Set<Object> context) {
|
public PlaceholderLookupResult lookupPlaceholder(@NotNull String placeholder, @NotNull Set<Object> context) {
|
||||||
for (Object o : context) {
|
for (Object o : context) {
|
||||||
|
if (o instanceof PlaceholderProvider) {
|
||||||
|
PlaceholderLookupResult result = ((PlaceholderProvider) o).lookup(placeholder, context);
|
||||||
|
if (result.getType() != PlaceholderLookupResult.Type.UNKNOWN_PLACEHOLDER) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Set<PlaceholderProvider> providers = classProviders.get(o.getClass());
|
Set<PlaceholderProvider> providers = classProviders.get(o.getClass());
|
||||||
if (providers == null) {
|
if (providers == null) {
|
||||||
continue;
|
continue;
|
||||||
@ -88,35 +99,108 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String replacePlaceholders(String input, Object... context) {
|
public String replacePlaceholders(@NotNull String input, Object... context) {
|
||||||
return replacePlaceholders(input, getArrayAsSet(context));
|
return replacePlaceholders(input, getArrayAsSet(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String replacePlaceholders(String input, Set<Object> context) {
|
public void addResultConverter(@NotNull PlaceholderResultConverter resultConverter) {
|
||||||
return processReplacement(PATTERN, input, context);
|
converters.add(resultConverter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String processReplacement(Pattern pattern, String input, Set<Object> context) {
|
@Override
|
||||||
|
public void removeResultConverter(@NotNull PlaceholderResultConverter resultConverter) {
|
||||||
|
converters.remove(resultConverter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String replacePlaceholders(@NotNull String input, @NotNull Set<Object> context) {
|
||||||
|
return getReplacement(PATTERN, input, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getReplacement(Pattern pattern, String input, Set<Object> context) {
|
||||||
Matcher matcher = pattern.matcher(input);
|
Matcher matcher = pattern.matcher(input);
|
||||||
|
|
||||||
String output = input;
|
String output = input;
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String placeholder = matcher.group(2);
|
String placeholder = matcher.group(2);
|
||||||
String originalPlaceholder = placeholder;
|
PlaceholderLookupResult result = resolve(placeholder, context);
|
||||||
|
output = updateContent(result, placeholder, matcher, output);
|
||||||
// Recursive
|
|
||||||
placeholder = processReplacement(RECURSIVE_PATTERN, placeholder, context);
|
|
||||||
|
|
||||||
PlaceholderLookupResult result = lookupPlaceholder(placeholder, context);
|
|
||||||
output = updateBasedOnResult(result, input, originalPlaceholder, matcher);
|
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String updateBasedOnResult(
|
@Override
|
||||||
PlaceholderLookupResult result, String input, String originalPlaceholder, Matcher matcher) {
|
public Object getResult(@NotNull Matcher matcher, @NotNull Set<Object> context) {
|
||||||
String output = input;
|
if (matcher.groupCount() < 3) {
|
||||||
|
throw new IllegalStateException("Matcher must have atleast 3 groups");
|
||||||
|
}
|
||||||
|
String placeholder = matcher.group(2);
|
||||||
|
PlaceholderLookupResult result = resolve(matcher, context);
|
||||||
|
return getResultRepresentation(result, placeholder, matcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getResultAsString(@NotNull Matcher matcher, @NotNull Set<Object> context) {
|
||||||
|
Object result = getResult(matcher, context);
|
||||||
|
return getResultAsString(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getResultAsString(Object result) {
|
||||||
|
if (result == null) {
|
||||||
|
return "null";
|
||||||
|
} else if (result instanceof String) {
|
||||||
|
return (String) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String output = null;
|
||||||
|
for (PlaceholderResultConverter converter : converters) {
|
||||||
|
output = converter.convertPlaceholderResult(result);
|
||||||
|
if (output != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (output == null) {
|
||||||
|
output = String.valueOf(result);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlaceholderLookupResult resolve(Matcher matcher, Set<Object> context) {
|
||||||
|
return resolve(matcher.group(2), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlaceholderLookupResult resolve(String placeholder, Set<Object> context) {
|
||||||
|
// Recursive
|
||||||
|
placeholder = getReplacement(RECURSIVE_PATTERN, placeholder, context);
|
||||||
|
|
||||||
|
return lookupPlaceholder(placeholder, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String updateContent(
|
||||||
|
PlaceholderLookupResult result, String placeholder, Matcher matcher, String input) {
|
||||||
|
Object representation = getResultRepresentation(result, placeholder, matcher);
|
||||||
|
|
||||||
|
String output = getResultAsString(representation);
|
||||||
|
for (PlaceholderResultConverter converter : converters) {
|
||||||
|
output = converter.convertPlaceholderResult(representation);
|
||||||
|
if (output != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (output == null) {
|
||||||
|
output = String.valueOf(representation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pattern.compile(
|
||||||
|
matcher.group(1) + placeholder + matcher.group(3),
|
||||||
|
Pattern.LITERAL
|
||||||
|
)
|
||||||
|
.matcher(input)
|
||||||
|
.replaceFirst(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getResultRepresentation(PlaceholderLookupResult result, String placeholder, Matcher matcher) {
|
||||||
while (result != null) {
|
while (result != null) {
|
||||||
PlaceholderLookupResult.Type type = result.getType();
|
PlaceholderLookupResult.Type type = result.getType();
|
||||||
if (type == PlaceholderLookupResult.Type.UNKNOWN_PLACEHOLDER) {
|
if (type == PlaceholderLookupResult.Type.UNKNOWN_PLACEHOLDER) {
|
||||||
@ -124,7 +208,7 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean newLookup = false;
|
boolean newLookup = false;
|
||||||
String replacement = null;
|
Object replacement = null;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
replacement = result.getValue();
|
replacement = result.getValue();
|
||||||
@ -136,27 +220,18 @@ public class PlaceholderServiceImpl implements PlaceholderService {
|
|||||||
replacement = "Error";
|
replacement = "Error";
|
||||||
break;
|
break;
|
||||||
case NEW_LOOKUP:
|
case NEW_LOOKUP:
|
||||||
// prevent infinite recursion
|
result = lookupPlaceholder((String) result.getValue(), result.getExtras());
|
||||||
if (result.getValue().equals(originalPlaceholder)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result = lookupPlaceholder(result.getValue(), result.getExtras());
|
|
||||||
newLookup = true;
|
newLookup = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (replacement != null) {
|
if (replacement != null) {
|
||||||
output = Pattern.compile(
|
return replacement;
|
||||||
matcher.group(1)
|
|
||||||
+ originalPlaceholder
|
|
||||||
+ matcher.group(3),
|
|
||||||
Pattern.LITERAL
|
|
||||||
).matcher(output).replaceFirst(replacement);
|
|
||||||
}
|
}
|
||||||
if (!newLookup) {
|
if (!newLookup) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output;
|
return matcher.group(1) + placeholder + matcher.group(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ClassProviderLoader implements CacheLoader<Class<?>, Set<PlaceholderProvider>> {
|
private static class ClassProviderLoader implements CacheLoader<Class<?>, Set<PlaceholderProvider>> {
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.discordsrv.common.placeholder.converter;
|
||||||
|
|
||||||
|
import com.discordsrv.api.component.MinecraftComponent;
|
||||||
|
import com.discordsrv.api.placeholder.PlaceholderResultConverter;
|
||||||
|
import com.discordsrv.common.component.util.ComponentUtil;
|
||||||
|
import dev.vankka.mcdiscordreserializer.discord.DiscordSerializer;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class ComponentResultConverter implements PlaceholderResultConverter {
|
||||||
|
|
||||||
|
private static final ThreadLocal<Boolean> PLAIN_CONTEXT = new ThreadLocal<>();
|
||||||
|
|
||||||
|
public static void plain(Runnable runnable) {
|
||||||
|
PLAIN_CONTEXT.set(true);
|
||||||
|
runnable.run();
|
||||||
|
PLAIN_CONTEXT.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String convertPlaceholderResult(@NotNull Object result) {
|
||||||
|
if (result instanceof MinecraftComponent) {
|
||||||
|
result = ComponentUtil.fromAPI((MinecraftComponent) result);
|
||||||
|
}
|
||||||
|
if (result instanceof Component) {
|
||||||
|
Component component = (Component) result;
|
||||||
|
if (PLAIN_CONTEXT.get()) {
|
||||||
|
return PlainTextComponentSerializer.plainText()
|
||||||
|
.serialize(component);
|
||||||
|
} else {
|
||||||
|
return DiscordSerializer.INSTANCE
|
||||||
|
.serialize(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,6 @@ import com.discordsrv.api.placeholder.Placeholder;
|
|||||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
import com.discordsrv.api.player.DiscordSRVPlayer;
|
||||||
import com.discordsrv.common.command.game.sender.ICommandSender;
|
import com.discordsrv.common.command.game.sender.ICommandSender;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@ -40,12 +39,8 @@ public interface IPlayer extends DiscordSRVPlayer, IOfflinePlayer, ICommandSende
|
|||||||
return identity().uuid();
|
return identity().uuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Placeholder("player_display_name")
|
||||||
Component displayName();
|
Component displayName();
|
||||||
|
|
||||||
@ApiStatus.NonExtendable
|
|
||||||
@Placeholder("player_display_name")
|
|
||||||
default String plainDisplayName() {
|
|
||||||
return PlainTextComponentSerializer.plainText()
|
|
||||||
.serialize(displayName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.discordsrv.common.player.util;
|
|
||||||
|
|
||||||
import com.discordsrv.api.player.DiscordSRVPlayer;
|
|
||||||
import com.discordsrv.common.player.IPlayer;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
|
|
||||||
public final class PlayerUtil {
|
|
||||||
|
|
||||||
private PlayerUtil() {}
|
|
||||||
|
|
||||||
public static Component displayName(DiscordSRVPlayer player) {
|
|
||||||
if (player instanceof IPlayer) {
|
|
||||||
return ((IPlayer) player).displayName();
|
|
||||||
} else {
|
|
||||||
return Component.text(player.getUsername());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
package com.discordsrv.common.string.util;
|
package com.discordsrv.common.string.util;
|
||||||
|
|
||||||
import javax.annotation.CheckReturnValue;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -28,54 +28,55 @@ import java.util.regex.Pattern;
|
|||||||
public class Placeholders {
|
public class Placeholders {
|
||||||
|
|
||||||
private final String inputText;
|
private final String inputText;
|
||||||
private final Map<Pattern, Supplier<String>> replacements = new HashMap<>();
|
private final Map<Pattern, Function<Matcher, Object>> replacements = new HashMap<>();
|
||||||
|
|
||||||
public Placeholders(String inputText) {
|
public Placeholders(String inputText) {
|
||||||
this.inputText = inputText;
|
this.inputText = inputText;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckReturnValue
|
public Placeholders addAll(Map<Pattern, Function<Matcher, Object>> replacements) {
|
||||||
public Placeholders replace(String replace, String replacement) {
|
replacements.forEach(this.replacements::put);
|
||||||
return replace(replace, () -> replacement);
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckReturnValue
|
public Placeholders replace(String target, Object replacement) {
|
||||||
public Placeholders replaceAll(String regex, String replacement) {
|
return replace(target, matcher -> replacement);
|
||||||
return replaceAll(regex, () -> replacement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckReturnValue
|
public Placeholders replaceAll(Pattern pattern, Object replacement) {
|
||||||
public Placeholders replaceAll(Pattern pattern, String replacement) {
|
return replaceAll(pattern, matcher -> replacement);
|
||||||
return replaceAll(pattern, () -> replacement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckReturnValue
|
public Placeholders replace(String target, Supplier<Object> replacement) {
|
||||||
public Placeholders replace(String replace, Supplier<String> replacement) {
|
return replaceAll(Pattern.compile(target, Pattern.LITERAL), matcher -> replacement);
|
||||||
return replaceAll(Pattern.compile(replace, Pattern.LITERAL), replacement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckReturnValue
|
public Placeholders replaceAll(Pattern pattern, Supplier<Object> replacement) {
|
||||||
public Placeholders replaceAll(String regex, Supplier<String> replacement) {
|
return replaceAll(pattern, matcher -> replacement);
|
||||||
return replaceAll(Pattern.compile(regex), replacement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@CheckReturnValue
|
public Placeholders replace(String target, Function<Matcher, Object> replacement) {
|
||||||
public Placeholders replaceAll(Pattern pattern, Supplier<String> replacement) {
|
return replaceAll(Pattern.compile(target, Pattern.LITERAL), replacement);
|
||||||
replacements.put(pattern, replacement);
|
}
|
||||||
|
|
||||||
|
public Placeholders replaceAll(Pattern pattern, Function<Matcher, Object> replacement) {
|
||||||
|
this.replacements.put(pattern, replacement);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String get() {
|
public String get() {
|
||||||
String input = inputText;
|
String input = inputText;
|
||||||
for (Map.Entry<Pattern, Supplier<String>> entry : replacements.entrySet()) {
|
for (Map.Entry<Pattern, Function<Matcher, Object>> entry : replacements.entrySet()) {
|
||||||
Pattern pattern = entry.getKey();
|
Pattern pattern = entry.getKey();
|
||||||
Matcher matcher = pattern.matcher(input);
|
Matcher matcher = pattern.matcher(input);
|
||||||
if (!matcher.find()) {
|
if (!matcher.find()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Supplier<String> replacement = entry.getValue();
|
Function<Matcher, Object> replacement = entry.getValue();
|
||||||
input = matcher.replaceAll(replacement.get());
|
Object value = replacement.apply(matcher);
|
||||||
|
|
||||||
|
input = matcher.replaceAll(String.valueOf(value));
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import com.discordsrv.bukkit.config.connection.BukkitConnectionConfig;
|
|||||||
import com.discordsrv.bukkit.config.main.BukkitConfig;
|
import com.discordsrv.bukkit.config.main.BukkitConfig;
|
||||||
import com.discordsrv.common.config.Config;
|
import com.discordsrv.common.config.Config;
|
||||||
import com.discordsrv.common.config.annotation.Untranslated;
|
import com.discordsrv.common.config.annotation.Untranslated;
|
||||||
import com.discordsrv.common.config.main.channels.ChannelConfigHolder;
|
import com.discordsrv.common.config.main.channels.BaseChannelConfig;
|
||||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||||
import org.spongepowered.configurate.ConfigurateException;
|
import org.spongepowered.configurate.ConfigurateException;
|
||||||
import org.spongepowered.configurate.ConfigurationNode;
|
import org.spongepowered.configurate.ConfigurationNode;
|
||||||
@ -75,9 +75,9 @@ public final class DiscordSRVTranslation {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
ChannelConfigHolder.Serializer channelSerializer = new ChannelConfigHolder.Serializer(objectMapper);
|
BaseChannelConfig.Serializer channelSerializer = new BaseChannelConfig.Serializer(objectMapper);
|
||||||
CommentedConfigurationNode node = CommentedConfigurationNode.root(ConfigurationOptions.defaults()
|
CommentedConfigurationNode node = CommentedConfigurationNode.root(ConfigurationOptions.defaults()
|
||||||
.serializers(builder -> builder.register(ChannelConfigHolder.class, channelSerializer)));
|
.serializers(builder -> builder.register(BaseChannelConfig.class, channelSerializer)));
|
||||||
for (Config config : CONFIG_INSTANCES) {
|
for (Config config : CONFIG_INSTANCES) {
|
||||||
ConfigurationNode section = node.node(config.getFileName());
|
ConfigurationNode section = node.node(config.getFileName());
|
||||||
ConfigurationNode configSection = section.copy();
|
ConfigurationNode configSection = section.copy();
|
||||||
|
@ -22,6 +22,7 @@ import com.discordsrv.common.player.IPlayer;
|
|||||||
import com.discordsrv.sponge.SpongeDiscordSRV;
|
import com.discordsrv.sponge.SpongeDiscordSRV;
|
||||||
import net.kyori.adventure.identity.Identity;
|
import net.kyori.adventure.identity.Identity;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.spongepowered.api.command.exception.CommandException;
|
import org.spongepowered.api.command.exception.CommandException;
|
||||||
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ public class SpongePlayer extends SpongeOfflinePlayer implements IPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component displayName() {
|
public @NotNull Component displayName() {
|
||||||
return player.displayName().get();
|
return player.displayName().get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ public class VelocityPlayer implements IPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component displayName() {
|
public @NotNull Component displayName() {
|
||||||
// Use Adventure's Pointer, otherwise username
|
// Use Adventure's Pointer, otherwise username
|
||||||
return player.getOrDefaultFrom(
|
return player.getOrDefaultFrom(
|
||||||
Identity.DISPLAY_NAME,
|
Identity.DISPLAY_NAME,
|
||||||
|
Loading…
Reference in New Issue
Block a user