From 0cf87e37fb11ab43ea3e50169bb34acb2a44d16b Mon Sep 17 00:00:00 2001 From: rafal <63915083+rchomczyk@users.noreply.github.com> Date: Sat, 16 Nov 2024 21:02:27 +0100 Subject: [PATCH] Add an option to use message dispatcher without formatter --- .idea/gradle.xml | 1 + README.md | 20 ++-- .../AdventureMessageDispatcher.java | 22 ++--- .../AdventureTitleMessageDispatcher.java | 29 ++---- .../dispatcher/MessageBaseDispatcher.java | 61 ++++++------ .../message/dispatcher/MessageDispatcher.java | 9 +- .../message/dispatcher/MessageRenderer.java | 92 +++++++++++++++++++ .../src/dev/shiza/honey/ExampleListener.java | 28 +++--- .../src/dev/shiza/honey/ExamplePlugin.java | 5 +- settings.gradle.kts | 2 +- 10 files changed, 170 insertions(+), 99 deletions(-) create mode 100644 honey-common/src/dev/shiza/honey/message/dispatcher/MessageRenderer.java diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 796fbe8..10d2912 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -22,6 +22,7 @@ diff --git a/README.md b/README.md index aa51d0b..e7c4b04 100644 --- a/README.md +++ b/README.md @@ -46,26 +46,26 @@ implementation("dev.shiza:honey:2.0.0") A showcase of how to use *honey*, can be found in [honey-test-plugin](honey-test-plugin) module. ```java -/* for titles::audience */ -dispatcher.createTitle() +// * sending a message as title with all honey features +AdventureMessageDispatcher.createTitle() .recipient(event.getPlayer()) - .title(it -> it.template("Hello!")) - .subtitle(it -> it.template("It is a pleasure to see you there {{player.getName}}") + .title(it -> it.template(formatter, "Hello!")) + .subtitle(it -> it.template(formatter, "It is a pleasure to see you there {{player.getName}}") .variable("player", event.getPlayer())) .times(2, 4, 2) .dispatch(); -/* for chat::audience */ -dispatcher.createChat() +// * sending a message as chat message with all honey features +AdventureMessageDispatcher.createChat() .recipient(Bukkit.getServer()) - .template("{{player.getName}} has joined the server!") + .template(formatter, "{{player.getName}} has joined the server!") .variable("player", event.getPlayer()) .dispatch(); -/* for actionbar::audience */ -dispatcher.createActionBar() +// * sending a message as action bar with predefined message without any placeholder support +AdventureMessageDispatcher.createActionBar() .recipient(event.getPlayer()) - .template("Honey is great, isn't it?") + .template(Component.text("Honey is great, isn't it?")) .dispatch(); ``` diff --git a/honey-common/src/dev/shiza/honey/adventure/message/dispatcher/AdventureMessageDispatcher.java b/honey-common/src/dev/shiza/honey/adventure/message/dispatcher/AdventureMessageDispatcher.java index 8bcdd84..191f60d 100644 --- a/honey-common/src/dev/shiza/honey/adventure/message/dispatcher/AdventureMessageDispatcher.java +++ b/honey-common/src/dev/shiza/honey/adventure/message/dispatcher/AdventureMessageDispatcher.java @@ -1,32 +1,24 @@ package dev.shiza.honey.adventure.message.dispatcher; -import dev.shiza.honey.message.Message; import dev.shiza.honey.message.dispatcher.MessageBaseDispatcher; import dev.shiza.honey.message.dispatcher.MessageDispatcher; import dev.shiza.honey.message.dispatcher.TitleMessageDispatcher; -import dev.shiza.honey.message.formatter.MessageFormatter; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; public final class AdventureMessageDispatcher { - private final MessageFormatter messageFormatter; + private AdventureMessageDispatcher() {} - public AdventureMessageDispatcher(final MessageFormatter messageFormatter) { - this.messageFormatter = messageFormatter; + public static MessageDispatcher createChat() { + return new MessageBaseDispatcher<>(Audience.empty(), Audience::sendMessage); } - public MessageDispatcher createChat() { - return new MessageBaseDispatcher<>( - messageFormatter, Message.blank(), Audience.empty(), Audience::sendMessage); + public static MessageDispatcher createActionBar() { + return new MessageBaseDispatcher<>(Audience.empty(), Audience::sendActionBar); } - public MessageDispatcher createActionBar() { - return new MessageBaseDispatcher<>( - messageFormatter, Message.blank(), Audience.empty(), Audience::sendActionBar); - } - - public TitleMessageDispatcher createTitle() { - return new AdventureTitleMessageDispatcher(messageFormatter); + public static TitleMessageDispatcher createTitle() { + return new AdventureTitleMessageDispatcher(); } } diff --git a/honey-common/src/dev/shiza/honey/adventure/message/dispatcher/AdventureTitleMessageDispatcher.java b/honey-common/src/dev/shiza/honey/adventure/message/dispatcher/AdventureTitleMessageDispatcher.java index f25e33e..79142b4 100644 --- a/honey-common/src/dev/shiza/honey/adventure/message/dispatcher/AdventureTitleMessageDispatcher.java +++ b/honey-common/src/dev/shiza/honey/adventure/message/dispatcher/AdventureTitleMessageDispatcher.java @@ -2,11 +2,9 @@ import com.google.common.collect.ImmutableList; import com.spotify.futures.CompletableFutures; -import dev.shiza.honey.message.Message; import dev.shiza.honey.message.dispatcher.MessageBaseDispatcher; import dev.shiza.honey.message.dispatcher.MessageDispatcher; import dev.shiza.honey.message.dispatcher.TitleMessageDispatcher; -import dev.shiza.honey.message.formatter.MessageFormatter; import java.time.Duration; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -20,41 +18,31 @@ public final class AdventureTitleMessageDispatcher implements TitleMessageDispatcher { - private final MessageFormatter messageFormatter; private final MessageDispatcher times; private final MessageDispatcher title; private final MessageDispatcher subtitle; private final Audience recipient; public AdventureTitleMessageDispatcher( - final MessageFormatter messageFormatter, final MessageDispatcher times, final MessageDispatcher title, final MessageDispatcher subtitle, final Audience recipient) { - this.messageFormatter = messageFormatter; this.times = times; this.title = title; this.subtitle = subtitle; this.recipient = recipient; } - public AdventureTitleMessageDispatcher(final MessageFormatter messageFormatter) { + public AdventureTitleMessageDispatcher() { this( - messageFormatter, new MessageBaseDispatcher<>( - messageFormatter, - Message.blank(), Audience.empty(), (audience, component) -> audience.sendTitlePart(TitlePart.TIMES, Title.DEFAULT_TIMES)), new MessageBaseDispatcher<>( - messageFormatter, - Message.blank(), Audience.empty(), (audience, component) -> audience.sendTitlePart(TitlePart.TITLE, component)), new MessageBaseDispatcher<>( - messageFormatter, - Message.blank(), Audience.empty(), (audience, component) -> audience.sendTitlePart(TitlePart.SUBTITLE, component)), Audience.empty()); @@ -68,31 +56,26 @@ public TitleMessageDispatcher times( Duration.ofSeconds(fadeIn), Duration.ofSeconds(stay), Duration.ofSeconds(fadeOut)); final MessageDispatcher timesDispatcher = new MessageBaseDispatcher<>( - messageFormatter, - Message.blank(), - recipient, - (audience, component) -> audience.sendTitlePart(TitlePart.TIMES, titleTime)); + recipient, (audience, component) -> audience.sendTitlePart(TitlePart.TIMES, titleTime)); return new AdventureTitleMessageDispatcher( - messageFormatter, timesDispatcher, title, subtitle, recipient); + timesDispatcher.template(Component.empty()), title, subtitle, recipient); } @Override public TitleMessageDispatcher title( final UnaryOperator> consumer) { - return new AdventureTitleMessageDispatcher( - messageFormatter, times, consumer.apply(title), subtitle, recipient); + return new AdventureTitleMessageDispatcher(times, consumer.apply(title), subtitle, recipient); } @Override public TitleMessageDispatcher subtitle( final UnaryOperator> consumer) { - return new AdventureTitleMessageDispatcher( - messageFormatter, times, title, consumer.apply(subtitle), recipient); + return new AdventureTitleMessageDispatcher(times, title, consumer.apply(subtitle), recipient); } @Override public TitleMessageDispatcher recipient(final Audience recipient) { - return new AdventureTitleMessageDispatcher(messageFormatter, times, title, subtitle, recipient); + return new AdventureTitleMessageDispatcher(times, title, subtitle, recipient); } @Override diff --git a/honey-common/src/dev/shiza/honey/message/dispatcher/MessageBaseDispatcher.java b/honey-common/src/dev/shiza/honey/message/dispatcher/MessageBaseDispatcher.java index 36e3a5e..f4fe4a5 100644 --- a/honey-common/src/dev/shiza/honey/message/dispatcher/MessageBaseDispatcher.java +++ b/honey-common/src/dev/shiza/honey/message/dispatcher/MessageBaseDispatcher.java @@ -1,6 +1,9 @@ package dev.shiza.honey.message.dispatcher; import dev.shiza.honey.message.Message; +import dev.shiza.honey.message.dispatcher.MessageRenderer.DelegatingMessageRenderer; +import dev.shiza.honey.message.dispatcher.MessageRenderer.FormattingMessageRenderer; +import dev.shiza.honey.message.dispatcher.MessageRenderer.EmptyMessageRenderer; import dev.shiza.honey.message.formatter.MessageFormatter; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; @@ -10,71 +13,69 @@ public final class MessageBaseDispatcher implements MessageDispatcher { - private final MessageFormatter messageFormatter; - private final Message message; + private final MessageRenderer renderer; private final VIEWER recipient; private final BiConsumer deliver; - public MessageBaseDispatcher( - final MessageFormatter messageFormatter, - final Message message, + private MessageBaseDispatcher( + final MessageRenderer renderer, final VIEWER recipient, final BiConsumer deliver) { - this.messageFormatter = messageFormatter; - this.message = message; + this.renderer = renderer; this.recipient = recipient; this.deliver = deliver; } + public MessageBaseDispatcher(final VIEWER recipient, final BiConsumer deliver) { + this(new EmptyMessageRenderer<>(), recipient, deliver); + } + @Override public MessageDispatcher recipient(final VIEWER recipient) { - return new MessageBaseDispatcher<>(messageFormatter, message, recipient, deliver); + return new MessageBaseDispatcher<>(renderer, recipient, deliver); } @Override - public MessageDispatcher template(final String template) { - return new MessageBaseDispatcher<>(messageFormatter, Message.of(template), recipient, deliver); + public MessageDispatcher template( + final MessageFormatter formatter, final String template) { + return new MessageBaseDispatcher<>( + new FormattingMessageRenderer<>(formatter, Message.of(template)), recipient, deliver); } @Override - public MessageDispatcher variable(final String key, final Object value) { + public MessageDispatcher template(final RESULT message) { return new MessageBaseDispatcher<>( - messageFormatter, message.placeholders(it -> it.withValue(key, value)), recipient, deliver); + new DelegatingMessageRenderer<>(message), recipient, deliver); + } + + @Override + public MessageDispatcher variable(final String key, final Object value) { + final MessageRenderer newRenderer = renderer.variable(key, value); + return new MessageBaseDispatcher<>(newRenderer, recipient, deliver); } @Override public MessageDispatcher promisedVariable(final String key, final Object value) { - return new MessageBaseDispatcher<>( - messageFormatter, - message.placeholders(it -> it.withPromisedValue(key, value)), - recipient, - deliver); + final MessageRenderer newRenderer = renderer.promisedVariable(key, value); + return new MessageBaseDispatcher<>(newRenderer, recipient, deliver); } @Override public MessageDispatcher promisedVariable( final String key, final CompletableFuture value) { - return new MessageBaseDispatcher<>( - messageFormatter, - message.placeholders(it -> it.withPromisedValue(key, value)), - recipient, - deliver); + final MessageRenderer newRenderer = renderer.promisedVariable(key, value); + return new MessageBaseDispatcher<>(newRenderer, recipient, deliver); } @Override public void dispatch() { - if (!message.context().getPromisedValues().isEmpty()) { - throw new MessageDispatchingException( - "Cannot dispatch a message with promised values synchronously"); - } - - deliver.accept(recipient, messageFormatter.format(message)); + deliver.accept(recipient, renderer.render()); } @Override public CompletableFuture dispatchAsync() { - return messageFormatter - .formatAsync(message) + return renderer + .renderAsync() .thenAccept(result -> deliver.accept(recipient, result)) .exceptionally( cause -> { diff --git a/honey-common/src/dev/shiza/honey/message/dispatcher/MessageDispatcher.java b/honey-common/src/dev/shiza/honey/message/dispatcher/MessageDispatcher.java index 1fee509..16c758a 100644 --- a/honey-common/src/dev/shiza/honey/message/dispatcher/MessageDispatcher.java +++ b/honey-common/src/dev/shiza/honey/message/dispatcher/MessageDispatcher.java @@ -1,18 +1,23 @@ package dev.shiza.honey.message.dispatcher; +import dev.shiza.honey.message.formatter.MessageFormatter; import java.util.concurrent.CompletableFuture; public interface MessageDispatcher { MessageDispatcher recipient(final VIEWER recipient); - MessageDispatcher template(final String template); + MessageDispatcher template( + final MessageFormatter formatter, final String template); + + MessageDispatcher template(final RESULT message); MessageDispatcher variable(final String key, final Object value); MessageDispatcher promisedVariable(final String key, final Object value); - MessageDispatcher promisedVariable(final String key, final CompletableFuture value); + MessageDispatcher promisedVariable( + final String key, final CompletableFuture value); void dispatch(); diff --git a/honey-common/src/dev/shiza/honey/message/dispatcher/MessageRenderer.java b/honey-common/src/dev/shiza/honey/message/dispatcher/MessageRenderer.java new file mode 100644 index 0000000..eedd4c5 --- /dev/null +++ b/honey-common/src/dev/shiza/honey/message/dispatcher/MessageRenderer.java @@ -0,0 +1,92 @@ +package dev.shiza.honey.message.dispatcher; + +import com.spotify.futures.CompletableFutures; +import dev.shiza.honey.message.Message; +import dev.shiza.honey.message.dispatcher.MessageRenderer.DelegatingMessageRenderer; +import dev.shiza.honey.message.dispatcher.MessageRenderer.FormattingMessageRenderer; +import dev.shiza.honey.message.dispatcher.MessageRenderer.EmptyMessageRenderer; +import dev.shiza.honey.message.formatter.MessageFormatter; +import java.util.concurrent.CompletableFuture; + +public sealed interface MessageRenderer + permits EmptyMessageRenderer, FormattingMessageRenderer, DelegatingMessageRenderer { + + default MessageRenderer variable(final String key, final Object value) { + throw new MessageDispatchingException( + "Cannot add variable to a non-formatting message renderer"); + } + + default MessageRenderer promisedVariable(final String key, final Object value) { + throw new MessageDispatchingException( + "Cannot add promised variable to a non-formatting message renderer"); + } + + default MessageRenderer promisedVariable( + final String key, final CompletableFuture value) { + throw new MessageDispatchingException( + "Cannot add promised variable to a non-formatting message renderer"); + } + + RESULT render(); + + CompletableFuture renderAsync(); + + record EmptyMessageRenderer() implements MessageRenderer { + + @Override + public RESULT render() { + throw new MessageDispatchingException("Cannot render an empty message"); + } + + @Override + public CompletableFuture renderAsync() { + return CompletableFutures.exceptionallyCompletedFuture( + new MessageDispatchingException("Cannot render an empty message")); + } + } + + record FormattingMessageRenderer(MessageFormatter formatter, Message message) + implements MessageRenderer { + + @Override + public MessageRenderer variable(String key, Object value) { + return new FormattingMessageRenderer<>( + formatter, message.placeholders(it -> it.withValue(key, value))); + } + + @Override + public MessageRenderer promisedVariable(String key, Object value) { + return new FormattingMessageRenderer<>( + formatter, message.placeholders(it -> it.withPromisedValue(key, value))); + } + + @Override + public MessageRenderer promisedVariable(String key, CompletableFuture value) { + return new FormattingMessageRenderer<>( + formatter, message.placeholders(it -> it.withPromisedValue(key, value))); + } + + @Override + public RESULT render() { + return formatter.format(message); + } + + @Override + public CompletableFuture renderAsync() { + return formatter.formatAsync(message); + } + } + + record DelegatingMessageRenderer(RESULT result) implements MessageRenderer { + + @Override + public RESULT render() { + return result; + } + + @Override + public CompletableFuture renderAsync() { + return CompletableFuture.completedFuture(result); + } + } +} diff --git a/honey-test-plugin/src/dev/shiza/honey/ExampleListener.java b/honey-test-plugin/src/dev/shiza/honey/ExampleListener.java index 4ceffe9..c7b90a1 100644 --- a/honey-test-plugin/src/dev/shiza/honey/ExampleListener.java +++ b/honey-test-plugin/src/dev/shiza/honey/ExampleListener.java @@ -1,6 +1,9 @@ package dev.shiza.honey; import dev.shiza.honey.adventure.message.dispatcher.AdventureMessageDispatcher; +import dev.shiza.honey.adventure.message.formatter.AdventureMessageFormatter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -8,36 +11,33 @@ final class ExampleListener implements Listener { - private final AdventureMessageDispatcher dispatcher; + private final AdventureMessageFormatter formatter; - ExampleListener(final AdventureMessageDispatcher dispatcher) { - this.dispatcher = dispatcher; + ExampleListener( + final AdventureMessageFormatter formatter) { + this.formatter = formatter; } @EventHandler public void onPlayerJoin(final PlayerJoinEvent event) { - dispatcher - .createTitle() + AdventureMessageDispatcher.createTitle() .recipient(event.getPlayer()) - .title(it -> it.template("Hello!")) + .title(it -> it.template(formatter, "Hello!")) .subtitle( it -> - it.template("It is a pleasure to see you there {{player.getName}}") + it.template(formatter, "It is a pleasure to see you there {{player.getName}}") .variable("player", event.getPlayer())) .times(2, 4, 2) .dispatch(); - dispatcher - .createChat() + AdventureMessageDispatcher.createChat() .recipient(Bukkit.getServer()) - .template("{{player.getName}} has joined the server!") - .variable("player", event.getPlayer()) + .template(Component.text("Somebody joined to the server!").color(NamedTextColor.RED)) .dispatch(); - dispatcher - .createActionBar() + AdventureMessageDispatcher.createActionBar() .recipient(event.getPlayer()) - .template("Honey is great, isn't it?") + .template(formatter, "Honey is great, isn't it?") .dispatch(); } } diff --git a/honey-test-plugin/src/dev/shiza/honey/ExamplePlugin.java b/honey-test-plugin/src/dev/shiza/honey/ExamplePlugin.java index 33ecf05..4ae36f8 100644 --- a/honey-test-plugin/src/dev/shiza/honey/ExamplePlugin.java +++ b/honey-test-plugin/src/dev/shiza/honey/ExamplePlugin.java @@ -1,6 +1,5 @@ package dev.shiza.honey; -import dev.shiza.honey.adventure.message.dispatcher.AdventureMessageDispatcher; import dev.shiza.honey.adventure.message.formatter.AdventureMessageFormatter; import dev.shiza.honey.adventure.message.formatter.AdventureMessageFormatterFactory; import org.bukkit.plugin.java.JavaPlugin; @@ -10,8 +9,6 @@ public final class ExamplePlugin extends JavaPlugin { @Override public void onEnable() { final AdventureMessageFormatter messageFormatter = AdventureMessageFormatterFactory.create(); - final AdventureMessageDispatcher messageDispatcher = - new AdventureMessageDispatcher(messageFormatter); - getServer().getPluginManager().registerEvents(new ExampleListener(messageDispatcher), this); + getServer().getPluginManager().registerEvents(new ExampleListener(messageFormatter), this); } } diff --git a/settings.gradle.kts b/settings.gradle.kts index 40dcb9a..97ac85a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1,4 @@ rootProject.name = "honey" include(":honey-common") // Uncomment in case if you would like to run test plugin -// include(":honey-test-plugin") +include(":honey-test-plugin")