diff --git a/api/src/main/java/com/discordsrv/api/discord/api/entity/message/impl/SendableDiscordMessageImpl.java b/api/src/main/java/com/discordsrv/api/discord/api/entity/message/impl/SendableDiscordMessageImpl.java index ab5fcbca..6148806c 100644 --- a/api/src/main/java/com/discordsrv/api/discord/api/entity/message/impl/SendableDiscordMessageImpl.java +++ b/api/src/main/java/com/discordsrv/api/discord/api/entity/message/impl/SendableDiscordMessageImpl.java @@ -247,7 +247,7 @@ public class SendableDiscordMessageImpl implements SendableDiscordMessage { .addAll(replacements); // Empty string -> null - String output = placeholderUtil.get(); + String output = placeholderUtil.toString(); return output.isEmpty() ? null : output; }; builder.setContent(placeholders.apply(builder.getContent())); diff --git a/api/src/main/java/com/discordsrv/api/placeholder/util/Placeholders.java b/api/src/main/java/com/discordsrv/api/placeholder/util/Placeholders.java index ef4c2b54..8c64d5c0 100644 --- a/api/src/main/java/com/discordsrv/api/placeholder/util/Placeholders.java +++ b/api/src/main/java/com/discordsrv/api/placeholder/util/Placeholders.java @@ -78,8 +78,9 @@ public class Placeholders { return this; } + @Override @NotNull - public String get() { + public String toString() { String input = inputText; for (Map.Entry> entry : replacements.entrySet()) { Pattern pattern = entry.getKey(); diff --git a/api/src/test/java/com/discordsrv/api/placeholder/util/PlaceholdersTest.java b/api/src/test/java/com/discordsrv/api/placeholder/util/PlaceholdersTest.java new file mode 100644 index 00000000..3511c6a9 --- /dev/null +++ b/api/src/test/java/com/discordsrv/api/placeholder/util/PlaceholdersTest.java @@ -0,0 +1,18 @@ +package com.discordsrv.api.placeholder.util; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PlaceholdersTest { + + @Test + public void orderTest() { + Placeholders placeholders = new Placeholders("a"); + + placeholders.replace("b", "c"); + placeholders.replace("a", "b"); + + assertEquals("b", placeholders.toString()); + } +} diff --git a/common/src/main/java/com/discordsrv/common/listener/DiscordChatListener.java b/common/src/main/java/com/discordsrv/common/listener/DiscordChatListener.java index a3400c34..155650ab 100644 --- a/common/src/main/java/com/discordsrv/common/listener/DiscordChatListener.java +++ b/common/src/main/java/com/discordsrv/common/listener/DiscordChatListener.java @@ -115,7 +115,7 @@ public class DiscordChatListener extends AbstractListener { chatConfig.opt(cfg -> cfg.contentRegexFilters) .ifPresent(filters -> filters.forEach(message::replaceAll)); - Component messageComponent = discordSRV.componentFactory().minecraftSerializer().serialize(message.get()); + Component messageComponent = discordSRV.componentFactory().minecraftSerializer().serialize(message.toString()); EnhancedTextBuilder componentBuilder = discordSRV.componentFactory() .enhancedBuilder(format) diff --git a/common/src/main/java/com/discordsrv/common/listener/GameChatListener.java b/common/src/main/java/com/discordsrv/common/listener/GameChatListener.java index 6a4c5e10..5a4c8380 100644 --- a/common/src/main/java/com/discordsrv/common/listener/GameChatListener.java +++ b/common/src/main/java/com/discordsrv/common/listener/GameChatListener.java @@ -69,7 +69,7 @@ public class GameChatListener extends AbstractListener { SendableDiscordMessage.Formatter formatter = builder.toFormatter() .addContext(event.getPlayer(), gameChannel) - .addReplacement("%message%", serializedMessage.get()); + .addReplacement("%message%", serializedMessage.toString()); formatter.applyPlaceholderService(); diff --git a/common/src/main/java/com/discordsrv/common/placeholder/PlaceholderServiceImpl.java b/common/src/main/java/com/discordsrv/common/placeholder/PlaceholderServiceImpl.java index 3c6458b8..eef73896 100644 --- a/common/src/main/java/com/discordsrv/common/placeholder/PlaceholderServiceImpl.java +++ b/common/src/main/java/com/discordsrv/common/placeholder/PlaceholderServiceImpl.java @@ -23,6 +23,7 @@ import com.discordsrv.api.placeholder.annotation.Placeholder; import com.discordsrv.api.placeholder.PlaceholderLookupResult; import com.discordsrv.api.placeholder.PlaceholderResultStringifier; import com.discordsrv.api.placeholder.PlaceholderService; +import com.discordsrv.api.placeholder.annotation.PlaceholderRemainder; import com.discordsrv.common.DiscordSRV; import com.discordsrv.common.placeholder.provider.AnnotationPlaceholderProvider; import com.discordsrv.common.placeholder.provider.PlaceholderProvider; @@ -35,6 +36,7 @@ import org.jetbrains.annotations.NotNull; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; import java.util.*; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.TimeUnit; @@ -80,7 +82,7 @@ public class PlaceholderServiceImpl implements PlaceholderService { } } - Set providers = classProviders.get(o.getClass()); + Set providers = classProviders.get(o instanceof Class ? (Class) o : o.getClass()); if (providers == null) { continue; } @@ -256,8 +258,18 @@ public class PlaceholderServiceImpl implements PlaceholderService { continue; } + boolean startsWith = !annotation.relookup().isEmpty(); + if (!startsWith) { + for (Parameter parameter : method.getParameters()) { + if (parameter.getAnnotation(PlaceholderRemainder.class) != null) { + startsWith = true; + break; + } + } + } + boolean isStatic = Modifier.isStatic(method.getModifiers()); - providers.add(new AnnotationPlaceholderProvider(annotation, isStatic ? null : clazz, method)); + providers.add(new AnnotationPlaceholderProvider(annotation, isStatic ? null : clazz, startsWith, method)); } for (Field field : clazz.getFields()) { Placeholder annotation = field.getAnnotation(Placeholder.class); @@ -266,7 +278,7 @@ public class PlaceholderServiceImpl implements PlaceholderService { } boolean isStatic = Modifier.isStatic(field.getModifiers()); - providers.add(new AnnotationPlaceholderProvider(annotation, isStatic ? null : clazz, field)); + providers.add(new AnnotationPlaceholderProvider(annotation, isStatic ? null : clazz, !annotation.relookup().isEmpty(), field)); } } diff --git a/common/src/main/java/com/discordsrv/common/placeholder/provider/AnnotationPlaceholderProvider.java b/common/src/main/java/com/discordsrv/common/placeholder/provider/AnnotationPlaceholderProvider.java index ae01bd8f..23a01795 100644 --- a/common/src/main/java/com/discordsrv/common/placeholder/provider/AnnotationPlaceholderProvider.java +++ b/common/src/main/java/com/discordsrv/common/placeholder/provider/AnnotationPlaceholderProvider.java @@ -34,18 +34,21 @@ public class AnnotationPlaceholderProvider implements PlaceholderProvider { private final Class type; private final Method method; + private final boolean startsWith; private final Field field; - public AnnotationPlaceholderProvider(Placeholder annotation, Class type, Method method) { + public AnnotationPlaceholderProvider(Placeholder annotation, Class type, boolean startsWith, Method method) { this.annotation = annotation; this.type = type; + this.startsWith = startsWith; this.method = method; this.field = null; } - public AnnotationPlaceholderProvider(Placeholder annotation, Class type, Field field) { + public AnnotationPlaceholderProvider(Placeholder annotation, Class type, boolean startsWith, Field field) { this.annotation = annotation; this.type = type; + this.startsWith = startsWith; this.method = null; this.field = field; } @@ -54,7 +57,7 @@ public class AnnotationPlaceholderProvider implements PlaceholderProvider { public @NotNull PlaceholderLookupResult lookup(@NotNull String placeholder, @NotNull Set context) { String annotationPlaceholder = annotation.value(); if (annotationPlaceholder.isEmpty() - || !placeholder.startsWith(annotationPlaceholder) + || !(startsWith ? placeholder.startsWith(annotationPlaceholder) : placeholder.equals(annotationPlaceholder)) || (type != null && context.isEmpty())) { return PlaceholderLookupResult.UNKNOWN_PLACEHOLDER; } diff --git a/common/src/main/java/com/discordsrv/common/player/IPlayer.java b/common/src/main/java/com/discordsrv/common/player/IPlayer.java index 990f288c..13aeabe0 100644 --- a/common/src/main/java/com/discordsrv/common/player/IPlayer.java +++ b/common/src/main/java/com/discordsrv/common/player/IPlayer.java @@ -62,7 +62,7 @@ public interface IPlayer extends DiscordSRVPlayer, IOfflinePlayer, ICommandSende .replace("%uuid%", getUniqueId().toString()) .replace("%username%", getUsername()) .replace("%texture%", "") // TODO - .get(); + .toString(); } } diff --git a/common/src/test/java/com/discordsrv/common/MockDiscordSRV.java b/common/src/test/java/com/discordsrv/common/MockDiscordSRV.java new file mode 100644 index 00000000..0bee0f27 --- /dev/null +++ b/common/src/test/java/com/discordsrv/common/MockDiscordSRV.java @@ -0,0 +1,67 @@ +package com.discordsrv.common; + +import com.discordsrv.common.config.connection.ConnectionConfig; +import com.discordsrv.common.config.main.MainConfig; +import com.discordsrv.common.config.manager.ConnectionConfigManager; +import com.discordsrv.common.config.manager.MainConfigManager; +import com.discordsrv.common.console.Console; +import com.discordsrv.common.logging.logger.Logger; +import com.discordsrv.common.logging.logger.impl.JavaLoggerImpl; +import com.discordsrv.common.player.provider.AbstractPlayerProvider; +import com.discordsrv.common.scheduler.Scheduler; +import com.discordsrv.common.scheduler.StandardScheduler; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; + +public class MockDiscordSRV extends AbstractDiscordSRV { + + public static final MockDiscordSRV INSTANCE = new MockDiscordSRV(); + + private final Scheduler scheduler = new StandardScheduler(this); + private final Logger logger = JavaLoggerImpl.getRoot(); + + public MockDiscordSRV() { + load(); + } + + @Override + public Logger logger() { + return logger; + } + + @Override + public Path dataDirectory() { + return null; + } + + @Override + public Scheduler scheduler() { + return scheduler; + } + + @Override + public Console console() { + return null; + } + + @Override + public String version() { + return null; + } + + @Override + public @NotNull AbstractPlayerProvider playerProvider() { + return null; + } + + @Override + public ConnectionConfigManager connectionConfigManager() { + return null; + } + + @Override + public MainConfigManager configManager() { + return null; + } +} diff --git a/common/src/test/java/com/discordsrv/common/event/bus/EventBusTest.java b/common/src/test/java/com/discordsrv/common/event/bus/EventBusTest.java new file mode 100644 index 00000000..39c6c171 --- /dev/null +++ b/common/src/test/java/com/discordsrv/common/event/bus/EventBusTest.java @@ -0,0 +1,43 @@ +package com.discordsrv.common.event.bus; + +import com.discordsrv.api.event.bus.EventBus; +import com.discordsrv.api.event.bus.Subscribe; +import com.discordsrv.api.event.events.Event; +import com.discordsrv.common.MockDiscordSRV; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class EventBusTest { + + private static final Listener listener = new Listener(); + private static final EventBus eventBus = MockDiscordSRV.INSTANCE.eventBus(); + + @BeforeAll + public static void subscribe() { + eventBus.subscribe(listener); + } + + @AfterAll + public static void unsubscribe() { + eventBus.unsubscribe(listener); + } + + @Test + public void publishTest() { + eventBus.publish(new Event() {}); + assertTrue(listener.reached); + } + + public static class Listener { + + public boolean reached = false; + + @Subscribe + public void onEvent(Event event) { + reached = true; + } + } +} diff --git a/common/src/test/java/com/discordsrv/common/placeholder/PlaceholderServiceTest.java b/common/src/test/java/com/discordsrv/common/placeholder/PlaceholderServiceTest.java new file mode 100644 index 00000000..43815792 --- /dev/null +++ b/common/src/test/java/com/discordsrv/common/placeholder/PlaceholderServiceTest.java @@ -0,0 +1,62 @@ +package com.discordsrv.common.placeholder; + +import com.discordsrv.api.placeholder.PlaceholderService; +import com.discordsrv.api.placeholder.annotation.Placeholder; +import com.discordsrv.common.MockDiscordSRV; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PlaceholderServiceTest { + + private PlaceholderService service = MockDiscordSRV.INSTANCE.placeholderService(); + + @Test + public void staticFieldTest() { + assertEquals("a", service.replacePlaceholders("%static_field%", PlaceholderContext.class)); + } + + @Test + public void staticMethodTest() { + assertEquals("b", service.replacePlaceholders("%static_method%", PlaceholderContext.class)); + } + + @Test + public void objectFieldTest() { + assertEquals("c", service.replacePlaceholders("%object_field%", new PlaceholderContext())); + } + + @Test + public void objectMethodTest() { + assertEquals("d", service.replacePlaceholders("%object_method%", new PlaceholderContext())); + } + + @Test + public void staticMethodWithContextTest() { + assertEquals("e", service.replacePlaceholders("%static_method_with_context%", PlaceholderContext.class, "e")); + } + + public static class PlaceholderContext { + + @Placeholder("static_field") + public static String STATIC_FIELD = "a"; + + @Placeholder("static_method") + public static String staticMethod() { + return "b"; + } + + @Placeholder("object_field") + public String localField = "c"; + + @Placeholder("object_method") + public String objectMethod() { + return "d"; + } + + @Placeholder("static_method_with_context") + public static String objectMethodWithContext(String output) { + return output; + } + } +}