package tc.oc.commons.bukkit.chat; import java.util.List; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.HoverEvent; import org.bukkit.command.CommandSender; import tc.oc.commons.core.chat.Component; import tc.oc.commons.core.chat.Components; /** * Recursively renders any child components that are common to all {@link BaseComponent} * subtypes, which includes the "extra" array, and "hoverEvent.value". Also copies formatting * fields to the rendered component, if it is different from the original. * * Terminal component types should subclass this and implement {@link #renderContent} to render * anything besides these common fields. */ public abstract class BaseComponentRenderer<T extends BaseComponent> implements ComponentRenderer<T> { @Override public BaseComponent render(ComponentRenderContext context, T original, CommandSender viewer) { BaseComponent content = renderContent(context, original, viewer); if(content != original) { // Pass rendered content through the rendering pipeline again, // in case it is composed of more renderable components. content = context.render(content, viewer); } // Render extras List<BaseComponent> extra = original.getExtra() == null ? null : context.render(original.getExtra(), viewer); // If there is a hover event, render its value (which is an array of child components) HoverEvent hoverEvent = original.getHoverEvent(); if(hoverEvent != null && hoverEvent.getValue() != null) { BaseComponent[] value = context.render(hoverEvent.getValue(), viewer); if(value != hoverEvent.getValue()) { hoverEvent = new HoverEvent(hoverEvent.getAction(), value); } } if(content == original && extra == original.getExtra() && hoverEvent == original.getHoverEvent()) { // If content, extras, and hoverEvent were not changed by rendering, // the original component does not need to change. return original; } else if(!original.hasFormatting() && extra == content.getExtra()) { // If the original has no formatting, and rendered content has the same extra as the original, // and extra has no changed, rendered content can be returned on its own return content; } else if(content == original) { // If only child components changed, dupe the original and replace the children original = (T) original.duplicate(); if(extra != null) original.setExtra(extra); original.setHoverEvent(hoverEvent); return original; } else { // Combine the rendered content with the original formatting by wrapping it in a new component. BaseComponent wrapper = new Component().extra(content); Components.copyFormat(original, wrapper); wrapper.setClickEvent(original.getClickEvent()); if(extra != null) { for(BaseComponent c : extra) { wrapper.addExtra(c); } } return wrapper; } } protected abstract BaseComponent renderContent(ComponentRenderContext context, T original, CommandSender viewer); }