diff --git a/api/src/main/java/net/kyori/adventure/text/Component.java b/api/src/main/java/net/kyori/adventure/text/Component.java index 5f8359aef..b03b56584 100644 --- a/api/src/main/java/net/kyori/adventure/text/Component.java +++ b/api/src/main/java/net/kyori/adventure/text/Component.java @@ -1232,58 +1232,70 @@ public interface Component extends ComponentBuilderApplicable, ComponentLike, Ex */ /** - * Creates a virtual component with a value. + * Creates a virtual component. * - * @param virtual the value + * @param the context type + * @param context the context type + * @param renderer the renderer * @return a virtual component - * @since 4.13.0 + * @since 4.14.0 */ - @Contract(value = "_ -> new", pure = true) - static @NotNull VirtualComponent virtual(final @NotNull VirtualComponentHolder virtual) { - requireNonNull(virtual, "virtual"); - return VirtualComponentImpl.createVirtual(virtual); + @Contract(value = "_, _ -> new", pure = true) + static @NotNull VirtualComponent virtual(final @NotNull Class context, final @NotNull VirtualComponentRenderer renderer) { + requireNonNull(context, "context"); + requireNonNull(renderer, "renderer"); + return VirtualComponentImpl.createVirtual(context, renderer); } /** * Creates a virtual component with a value. * - * @param virtual the value + * @param the context type + * @param context the context type + * @param renderer the renderer * @param style the style * @return a virtual component - * @since 4.13.0 + * @since 4.14.0 */ - @Contract(value = "_, _ -> new", pure = true) - static @NotNull VirtualComponent virtual(final @NotNull VirtualComponentHolder virtual, final @NotNull Style style) { - requireNonNull(virtual, "virtual"); - return VirtualComponentImpl.createVirtual(virtual); + @Contract(value = "_, _, _ -> new", pure = true) + static @NotNull VirtualComponent virtual(final @NotNull Class context, final @NotNull VirtualComponentRenderer renderer, final @NotNull Style style) { + requireNonNull(context, "context"); + requireNonNull(renderer, "renderer"); + return VirtualComponentImpl.createVirtual(context, renderer, Collections.emptyList(), style); } /** * Creates a virtual component with a value. * - * @param virtual the value + * @param the context type + * @param context the context type + * @param renderer the renderer * @param style the style elements * @return a virtual component - * @since 4.13.0 + * @since 4.14.0 */ - @Contract(value = "_, _ -> new", pure = true) - static @NotNull VirtualComponent virtual(final @NotNull VirtualComponentHolder virtual, final @NotNull StyleBuilderApplicable... style) { - requireNonNull(virtual, "virtual"); - return VirtualComponentImpl.createVirtual(Collections.emptyList(), Style.style(style), virtual); + @Contract(value = "_, _, _ -> new", pure = true) + static @NotNull VirtualComponent virtual(final @NotNull Class context, final @NotNull VirtualComponentRenderer renderer, final @NotNull StyleBuilderApplicable... style) { + requireNonNull(context, "context"); + requireNonNull(renderer, "renderer"); + return VirtualComponentImpl.createVirtual(context, renderer, Collections.emptyList(), Style.style(style)); } /** * Creates a virtual component with a value. * - * @param virtual the value + * @param the context type + * @param context the context type + * @param renderer the renderer * @param style the style elements * @return a virtual component - * @since 4.13.0 + * @since 4.14.0 */ - @Contract(value = "_, _ -> new", pure = true) - static @NotNull VirtualComponent virtual(final @NotNull VirtualComponentHolder virtual, final @NotNull Iterable style) { - requireNonNull(virtual, "virtual"); - return VirtualComponentImpl.createVirtual(Collections.emptyList(), Style.style(style), virtual); + @Contract(value = "_, _, _ -> new", pure = true) + static @NotNull VirtualComponent virtual(final @NotNull Class context, final @NotNull VirtualComponentRenderer renderer, final @NotNull Iterable style) { + requireNonNull(context, "context"); + requireNonNull(renderer, "renderer"); + return VirtualComponentImpl.createVirtual(context, renderer, Collections.emptyList(), Style.style(style)); } /* diff --git a/api/src/main/java/net/kyori/adventure/text/VirtualComponent.java b/api/src/main/java/net/kyori/adventure/text/VirtualComponent.java index ae18484ca..d057c051f 100644 --- a/api/src/main/java/net/kyori/adventure/text/VirtualComponent.java +++ b/api/src/main/java/net/kyori/adventure/text/VirtualComponent.java @@ -30,14 +30,22 @@ * *

This component type is transient, and not guaranteed to survive during any sort of transformations or serialization.

* - * @since 4.13.0 + * @since 4.14.0 */ public interface VirtualComponent extends TextComponent { /** - * Gets the virtual value holder. + * Gets the renderer context type. * - * @return the virtual value holder - * @since 4.13.0 + * @return the renderer context type + * @since 4.14.0 */ - @NotNull VirtualComponentHolder holder(); + @NotNull Class context(); + + /** + * Gets the renderer. + * + * @return the renderer + * @since 4.14.0 + */ + @NotNull VirtualComponentRenderer renderer(); } diff --git a/api/src/main/java/net/kyori/adventure/text/VirtualComponentImpl.java b/api/src/main/java/net/kyori/adventure/text/VirtualComponentImpl.java index 60dae08aa..511ee354b 100644 --- a/api/src/main/java/net/kyori/adventure/text/VirtualComponentImpl.java +++ b/api/src/main/java/net/kyori/adventure/text/VirtualComponentImpl.java @@ -29,36 +29,43 @@ import org.jetbrains.annotations.NotNull; final class VirtualComponentImpl extends TextComponentImpl implements VirtualComponent { - static VirtualComponent createVirtual(final @NotNull VirtualComponentHolder virtual) { - return new VirtualComponentImpl(Collections.emptyList(), Style.empty(), "", virtual); + static VirtualComponent createVirtual(final @NotNull Class context, final @NotNull VirtualComponentRenderer renderer) { + return createVirtual(context, renderer, Collections.emptyList(), Style.empty()); } - static VirtualComponent createVirtual(final List children, final Style style, final @NotNull VirtualComponentHolder virtual) { + static VirtualComponent createVirtual(final @NotNull Class context, final @NotNull VirtualComponentRenderer renderer, final List children, final Style style) { final List filteredChildren = ComponentLike.asComponents(children, IS_NOT_EMPTY); - return new VirtualComponentImpl(filteredChildren, style, "", virtual); + return new VirtualComponentImpl(filteredChildren, style, "", context, renderer); } - private final VirtualComponentHolder virtual; + private final Class context; + private final VirtualComponentRenderer renderer; - private VirtualComponentImpl(final @NotNull List children, final @NotNull Style style, final @NotNull String content, final @NotNull VirtualComponentHolder virtual) { + private VirtualComponentImpl(final @NotNull List children, final @NotNull Style style, final @NotNull String content, final @NotNull Class context, final @NotNull VirtualComponentRenderer renderer) { super(children, style, content); - this.virtual = virtual; + this.context = context; + this.renderer = renderer; } @Override VirtualComponent create0(final @NotNull List children, final @NotNull Style style, final @NotNull String content) { - return new VirtualComponentImpl(ComponentLike.asComponents(children, IS_NOT_EMPTY), style, content, this.virtual); + return new VirtualComponentImpl(ComponentLike.asComponents(children, IS_NOT_EMPTY), style, content, this.context, this.renderer); } @Override - public @NotNull VirtualComponentHolder holder() { - return this.virtual; + public @NotNull Class context() { + return this.context; + } + + @Override + public @NotNull VirtualComponentRenderer renderer() { + return this.renderer; } @Override public @NotNull String content() { - return this.virtual.fallbackString(); + return this.renderer.fallbackString(); } @Override @@ -67,17 +74,18 @@ VirtualComponent create0(final @NotNull List children, } static final class BuilderImpl extends TextComponentImpl.BuilderImpl { - private final VirtualComponentHolder holder; + private final Class context; + private final VirtualComponentRenderer renderer; BuilderImpl(final VirtualComponent other) { super(other); - - this.holder = other.holder(); + this.context = other.context(); + this.renderer = other.renderer(); } @Override public @NotNull TextComponent build() { - return createVirtual(this.children, this.buildStyle(), this.holder); + return createVirtual(this.context, this.renderer, this.children, this.buildStyle()); } } } diff --git a/api/src/main/java/net/kyori/adventure/text/VirtualComponentHolder.java b/api/src/main/java/net/kyori/adventure/text/VirtualComponentRenderer.java similarity index 79% rename from api/src/main/java/net/kyori/adventure/text/VirtualComponentHolder.java rename to api/src/main/java/net/kyori/adventure/text/VirtualComponentRenderer.java index 5d9505ee5..57802c5a8 100644 --- a/api/src/main/java/net/kyori/adventure/text/VirtualComponentHolder.java +++ b/api/src/main/java/net/kyori/adventure/text/VirtualComponentRenderer.java @@ -29,29 +29,28 @@ /** * A holder for a value. * - * @param the stored value type - * @since 4.13.0 + * @param the context type + * @since 4.14.0 */ -public interface VirtualComponentHolder { +public interface VirtualComponentRenderer { /** - * Gets the stored value. + * Gets the value by rendering using {@code context}. * - * @return the stored value - * @since 4.13.0 + * @param context the context + * @return the rendered value + * @since 4.14.0 */ - @UnknownNullability V unbox(); + @UnknownNullability ComponentLike apply(final @NotNull C context); /** * Get a fallback value for when this component has been serialized without being rendered. * - *

By default, this will be the toString{} of {@link #unbox()}.

+ *

By default, this will be an empty string.

* * @return the fallback string - * @since 4.13.0 + * @since 4.14.0 */ default @NotNull String fallbackString() { - final Object unboxed = this.unbox(); - return unboxed == null ? "" : unboxed.toString(); + return ""; } - } diff --git a/api/src/main/java/net/kyori/adventure/text/renderer/AbstractComponentRenderer.java b/api/src/main/java/net/kyori/adventure/text/renderer/AbstractComponentRenderer.java index 376e511d7..b9377f5d1 100644 --- a/api/src/main/java/net/kyori/adventure/text/renderer/AbstractComponentRenderer.java +++ b/api/src/main/java/net/kyori/adventure/text/renderer/AbstractComponentRenderer.java @@ -34,6 +34,7 @@ import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.VirtualComponent; +import net.kyori.adventure.text.VirtualComponentRenderer; import org.jetbrains.annotations.NotNull; /** @@ -139,9 +140,13 @@ public abstract class AbstractComponentRenderer implements ComponentRenderer< * @param component the component * @param context the context * @return the rendered component - * @since 4.13.0 + * @since 4.14.0 */ + @SuppressWarnings("unchecked") protected @NotNull Component renderVirtual(final @NotNull VirtualComponent component, final @NotNull C context) { + if (component.context().isInstance(context)) { + return ((VirtualComponentRenderer) component.renderer()).apply(context).asComponent(); + } return component; // will be processed as a TextComponent instead } diff --git a/api/src/test/java/net/kyori/adventure/text/ComponentCompactingTest.java b/api/src/test/java/net/kyori/adventure/text/ComponentCompactingTest.java index a5eb07e88..b41474a20 100644 --- a/api/src/test/java/net/kyori/adventure/text/ComponentCompactingTest.java +++ b/api/src/test/java/net/kyori/adventure/text/ComponentCompactingTest.java @@ -420,7 +420,7 @@ void testColorPreservedWithDecorations() { @Test void testVirtualComponentsPreserved() { - final Component expectedComponent = virtual(() -> "meow :3") + final Component expectedComponent = virtual(Object.class, context -> text("meow :3")) .append(text("3")); assertEquals(expectedComponent, expectedComponent.compact()); diff --git a/api/src/test/java/net/kyori/adventure/text/flattener/ComponentFlattenerTest.java b/api/src/test/java/net/kyori/adventure/text/flattener/ComponentFlattenerTest.java index 8c6be6988..b025b1da3 100644 --- a/api/src/test/java/net/kyori/adventure/text/flattener/ComponentFlattenerTest.java +++ b/api/src/test/java/net/kyori/adventure/text/flattener/ComponentFlattenerTest.java @@ -31,7 +31,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.NBTComponent; import net.kyori.adventure.text.TranslatableComponent; -import net.kyori.adventure.text.VirtualComponentHolder; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; @@ -194,7 +193,7 @@ void testKeybind() { @Test void testVirtualComponent() { - this.testFlatten(ComponentFlattener.basic(), Component.virtual((VirtualComponentHolder) () -> "test123")) + this.testFlatten(ComponentFlattener.basic(), Component.virtual(Object.class, context -> Component.text("test123"))) .assertBalanced() .assertPushesAndPops(1) .assertContents("test123");