inventory-framework icon indicating copy to clipboard operation
inventory-framework copied to clipboard

More detailed exception message

Open github-actions[bot] opened this issue 1 year ago • 0 comments

https://github.com/DevNatan/inventory-framework/blob/53b12b8df5ae63457daae03256dd66f74ba683ae/inventory-framework-platform/src/main/java/me/devnatan/inventoryframework/context/DefaultPublicSlotComponentRenderer.java#L235


package me.devnatan.inventoryframework.context;

import static me.devnatan.inventoryframework.utils.SlotConverter.convertSlot;

import java.util.function.BiConsumer;
import java.util.function.Supplier;
import me.devnatan.inventoryframework.InventoryFrameworkException;
import me.devnatan.inventoryframework.ViewType;
import me.devnatan.inventoryframework.VirtualView;
import me.devnatan.inventoryframework.component.Component;
import me.devnatan.inventoryframework.component.ComponentBuilder;
import me.devnatan.inventoryframework.component.ItemComponentBuilder;
import me.devnatan.inventoryframework.component.PlatformComponentBuilder;
import me.devnatan.inventoryframework.internal.LayoutSlot;
import me.devnatan.inventoryframework.utils.SlotConverter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

@SuppressWarnings("unchecked")
public final class DefaultPublicSlotComponentRenderer<CONTEXT, BUILDER extends ComponentBuilder, ITEM>
        implements PublicSlotComponentRenderer<CONTEXT, BUILDER, ITEM> {

    private final VirtualView root;
    private final IFRenderContext renderContext;
    private final Supplier<BUILDER> builderFactory;

    public DefaultPublicSlotComponentRenderer(
            VirtualView root, IFRenderContext renderContext, Supplier<BUILDER> builderFactory) {
        this.root = root;
        this.renderContext = renderContext;
        this.builderFactory = builderFactory;
    }

    private ItemComponentBuilder createRegisteredBuilder() {
        final BUILDER builder = builderFactory.get();
        if (!(builder instanceof ItemComponentBuilder))
            throw new IllegalArgumentException(
                    "slot(int) is only available in builders that extends ItemComponentBuilder");
        renderContext.getNotRenderedComponents().add(builder);
        return (ItemComponentBuilder) builder;
    }

    /**
     * Creates a new item builder without a specified slot.
     * <p>
     * This function is for creating items whose slot is set dynamically during item rendering.
     * <pre>{@code
     * unsetSlot().onRender(render -> {
     *     render.setItem(...);
     *     render.setSlot(...);
     * });
     * }</pre>
     *
     * <p><b><i> This API is experimental and is not subject to the general compatibility guarantees
     * such API may be changed or may be removed completely in any further release. </i></b>
     *
     * @return An item builder to configure the item.
     */
    @ApiStatus.Experimental
    public BUILDER unsetSlot() {
        return (BUILDER) createRegisteredBuilder();
    }

    /**
     * Adds an item to a specific slot in the context container.
     *
     * @param slot The slot in which the item will be positioned.
     * @return An item builder to configure the item.
     */
    public @NotNull BUILDER slot(int slot) {
        return (BUILDER) createRegisteredBuilder().withPosition(slot);
    }

    /**
     * Adds an item at the specific column and ROW (X, Y) in that context's container.
     *
     * @param row    The row (Y) in which the item will be positioned.
     * @param column The column (X) in which the item will be positioned.
     * @return An item builder to configure the item.
     */
    @NotNull
    public final BUILDER slot(int row, int column) {
        checkAlignedContainerTypeForSlotAssignment();
        return slot(convertSlot(
                row,
                column,
                renderContext.getContainer().getRowsCount(),
                renderContext.getContainer().getColumnsCount()));
    }

    @SuppressWarnings("unchecked")
    @Override
    public BUILDER slot(int slot, ITEM item) {
        return (BUILDER) createRegisteredBuilder().withPosition(slot).withPlatformItem(item);
    }

    @Override
    public BUILDER slot(int row, int column, ITEM item) {
        return slot(
                SlotConverter.convertSlot(
                        row,
                        column,
                        renderContext.getContainer().getRowsCount(),
                        renderContext.getContainer().getColumnsCount()),
                item);
    }

    @Override
    public <T extends PlatformComponentBuilder<T, CONTEXT>> void slot(int slot, T builder) {
        slotComponent(slot, builder);
    }

    @Override
    public <T extends PlatformComponentBuilder<T, CONTEXT>> void slot(int row, int column, T builder) {
        slotComponent(
                SlotConverter.convertSlot(
                        row,
                        column,
                        renderContext.getContainer().getRowsCount(),
                        renderContext.getContainer().getColumnsCount()),
                builder);
    }

    /**
     * Sets an item in the first slot of this context's container.
     *
     * @return An item builder to configure the item.
     */
    public BUILDER firstSlot() {
        return slot(renderContext.getContainer().getFirstSlot());
    }

    @Override
    public BUILDER firstSlot(ITEM item) {
        return slot(renderContext.getContainer().getFirstSlot(), item);
    }

    @Override
    public <T extends PlatformComponentBuilder<T, CONTEXT>> void firstSlot(T builder) {
        slotComponent(renderContext.getContainer().getFirstSlot(), builder);
    }

    /**
     * Sets an item in the last slot of this context's container.
     *
     * @return An item builder to configure the item.
     */
    public BUILDER lastSlot() {
        return slot(renderContext.getContainer().getLastSlot());
    }

    @Override
    public BUILDER lastSlot(ITEM item) {
        return slot(renderContext.getContainer().getLastSlot(), item);
    }

    @Override
    public <T extends PlatformComponentBuilder<T, CONTEXT>> void lastSlot(T builder) {
        slotComponent(renderContext.getContainer().getLastSlot(), builder);
    }

    /**
     * <p><b><i> This API is experimental and is not subject to the general compatibility guarantees
     * such API may be changed or may be removed completely in any further release. </i></b>
     */
    @ApiStatus.Experimental
    public BUILDER resultSlot() {
        final ViewType containerType = renderContext.getContainer().getType();
        final int[] resultSlots = containerType.getResultSlots();
        if (resultSlots == null) throw new InventoryFrameworkException("No result slots available: " + containerType);

        if (resultSlots.length > 1)
            throw new InventoryFrameworkException("#resultSlot() do not support types with more than one result slot.");

        return slot(resultSlots[0]);
    }

    @Override
    public BUILDER resultSlot(ITEM item) {
        return null;
    }

    /**
     * Adds an item in the next available slot of this context's container.
     *
     * @return An item builder to configure the item.
     */
    public BUILDER availableSlot() {
        final BUILDER builder = builderFactory.get();
        renderContext.getAvailableSlotFactories().add((index, slot) -> {
            ((ItemComponentBuilder) builder).setPosition(slot);
            return builder;
        });
        return builder;
    }

    /**
     * Adds an item in the next available slot of this context's container.
     *
     * <pre>{@code
     * availableSlot((index, builder) -> builder.withItem(...));
     * }</pre>
     *
     * @param factory A factory to create the item builder to configure the item.
     *                The first parameter is the iteration index of the available slot.
     */
    public void availableSlot(@NotNull BiConsumer<Integer, BUILDER> factory) {
        renderContext.getAvailableSlotFactories().add((index, slot) -> {
            final BUILDER builder = builderFactory.get();
            ((ItemComponentBuilder) builder).setPosition(slot);
            factory.accept(index, builder);
            return builder;
        });
    }

    @Override
    public <T extends PlatformComponentBuilder<T, CONTEXT>> void availableSlot(T builder) {}

    @Override
    public BUILDER availableSlot(ITEM item) {
        final BUILDER builder = builderFactory.get();
        renderContext.getAvailableSlotFactories().add((index, slot) -> ((ItemComponentBuilder) builder)
                .withPlatformItem(item)
                .withPosition(slot));
        return builder;
    }

    /**
     * Defines the item that will represent a character provided in the context layout.
     *
     * @param character The layout character target.
     * @return An item builder to configure the item.
     */
    public BUILDER layoutSlot(char character) {
        // TODO More detailed exception message
        final LayoutSlot layoutSlot = renderContext.getLayoutSlots().stream()
                .filter(value -> value.getCharacter() == character)
                .findFirst()
                .orElseThrow(() -> new InventoryFrameworkException("Missing layout character: " + character));

        final BUILDER builder = builderFactory.get();
        renderContext.getLayoutSlots().add(layoutSlot.withBuilderFactory($ -> builder));
        return builder;
    }

    @SuppressWarnings("unchecked")
    @Override
    public BUILDER layoutSlot(char character, ITEM item) {
        return (BUILDER) ((ItemComponentBuilder) layoutSlot(character)).withPlatformItem(item);
    }

    /**
     * Defines the item that will represent a character provided in the context layout.
     *
     * <pre>{@code
     * layoutSlot('F', (index, builder) -> builder.withItem(...));
     * }</pre>
     *
     * @param character The layout character target.
     */
    public void layoutSlot(char character, @NotNull BiConsumer<Integer, BUILDER> factory) {
        // TODO More detailed exception message
        final LayoutSlot layoutSlot = renderContext.getLayoutSlots().stream()
                .filter(value -> value.getCharacter() == character)
                .findFirst()
                .orElseThrow(() -> new InventoryFrameworkException("Missing layout character: " + character));

        renderContext.getLayoutSlots().add(layoutSlot.withBuilderFactory(index -> {
            final BUILDER builder = builderFactory.get();
            factory.accept(index, builder);
            return builder;
        }));
    }

    @Override
    public <T extends PlatformComponentBuilder<T, CONTEXT>> void layoutSlotComponent(char character, T builder) {
        final LayoutSlot layoutSlot = renderContext.getLayoutSlots().stream()
                .filter(value -> value.getCharacter() == character)
                .findFirst()
                .orElseThrow(() -> new InventoryFrameworkException("Missing layout character: " + character));

        renderContext.getLayoutSlots().add(layoutSlot.withComponentFactory(index -> {
            final Component component = builder.buildComponent(root);
            component.setHandle(builder.buildHandle());
            return component;
        }));
    }
    // endregion

    // region Component Assignment Methods
    private <B extends PlatformComponentBuilder<B, CONTEXT>> void slotComponent(int position, B builder) {
        if (position > 0 && builder instanceof ItemComponentBuilder)
            ((ItemComponentBuilder) builder).setPosition(position);

        final Component component = builder.buildComponent(root);
        component.setHandle(builder.buildHandle());
        renderContext.addComponent(component);
    }
    // endregion

    // region Internals
    /**
     * Throws an {@link IllegalStateException} if container type is not aligned.
     */
    private void checkAlignedContainerTypeForSlotAssignment() {
        if (!renderContext.getContainer().getType().isAligned())
            throw new IllegalStateException(String.format(
                    "Non-aligned container type %s cannot use row-column slots, use absolute %s instead",
                    renderContext.getContainer().getType().getIdentifier(), "#slot(n)"));
    }
    // endregion
}

github-actions[bot] avatar Dec 12 '23 23:12 github-actions[bot]