DevNatan / inventory-framework

Minecraft Inventory API framework
MIT License
128 stars 22 forks source link

I still don't understand how I create a pagination #441

Closed kaiquyricardo closed 1 year ago

kaiquyricardo commented 1 year ago

@RequiredArgsConstructor public class FriendsView extends View {

private final LobbyPlugin plugin;
private State<Pagination> paginationState;

@Override
public void onInit(ViewConfigBuilder config) {
    config.title("Lista de amigos")
            .size(6)
            .layout(
                    "         ",
                    " OOOOOOO ",
                    " OOOOOOO ",
                    "         ",
                    "         ",
                    "         ")
            .cancelOnClick();
}

@Override
public void onFirstRender(RenderContext render) {
    this.paginationState = paginationState(
            listFriends(render.getPlayer()),
            (item, friends) -> item.withItem(
                    new ItemBuilder(Material.SKULL_ITEM)
                            .name("")
                            .build()
            )
    );
}

private List<Friends> listFriends(Player player) {
    return plugin.getUserCache().getByName(player.getName()).getFriends();
}

ERROR: View is already initialized, please move this method call to class construtor or #onInit.
DevNatan commented 1 year ago

@SrMinister States must be created before view initialization, onRender is called after view initialization. Move the paginationState to class top level as a final value

private final State<Pagination> paginationState = paginationState(
    (context) -> listFriends(context.getPlayer()),
    (item, friend) -> item.withItem(new ItemBuilder(Material.SKULL_ITEM).name("").build())
);

@Override
public void onInit(ViewConfigBuilder config) {
    config.title("Lista de amigos")
            .size(6)
            .layout(
                    "         ",
                    " OOOOOOO ",
                    " OOOOOOO ",
                    "         ",
                    "         ",
                    "         ")
            .cancelOnClick();
}

private List<Friends> listFriends(Player player) {
    return plugin.getUserCache().getByName(player.getName()).getFriends();
}
kaiquyricardo commented 1 year ago

Did you remove the context in the new update?

-> (context) -> Lists.newArrayList(AnimatedHeadsType.values()) not exist context

private final State<Pagination> paginationState = paginationState(
        (context) -> Lists.newArrayList(AnimatedHeadsType.values()),
        (context, item, index, animatedHeadsType) -> item.withItem(
                new ItemBuilder(Material.SKULL_ITEM)
                        .texture(animatedHeadsType.getTexture())
                        .name(animatedHeadsType.getName())
                        .lore(
                                "§7Altere seu chapéu animado",
                                "§7para ficar no estilo.",
                                "",
                                "§aClique para alterar.")
                        .addFlag(ItemFlag.values())
                        .build()
        ).onClick(click -> {
            final Player clicker = click.getPlayer();
            final User user = userState.get(click);

            AnimatedHeadsTask.stop(clicker);
            AnimatedHeadsTask.startTask(clicker, animatedHeadsType);

            MessageProvider.ORB_PICKUP.sendMessage(
                    clicker,
                    "§e§lGG! §eVocê acaba de selecionar o chapéu animado " +
                            animatedHeadsType.getName() +
                            "§e!"
            );

            user.setAnimatedHeads(animatedHeadsType);
            user.setBanner(null);
            user.setHeads(null);
            user.setArmors(null);

            clicker.getInventory().setChestplate(new ItemStack(Material.AIR));
            clicker.getInventory().setLeggings(new ItemStack(Material.AIR));
            clicker.getInventory().setBoots(new ItemStack(Material.AIR));

            click.closeForPlayer();
        })
);
DevNatan commented 1 year ago

@SrMinister paginationState with Function-like as sourceProvider parameter was removed. Use lazyPaginationState instead

kaiquyricardo commented 1 year ago

Is there a way to use the spawner parameter on the current page to identify it as a state on another page?

line -> Arrays.asList(Spawner.values()), (context, builder, i, spawner) -> {

line -> ImmutableMap.of("spawners", spawner)));

private final State<Pagination> paginationState = paginationState(
         Arrays.asList(Spawner.values()),
        (context, builder, i, spawner) -> {
            final double balance = EconomyAPI.ECONOMY.getBalance(context.getPlayer());
            Discount discount = discountState.get(context);

            if (!context.getPlayer().hasPermission(spawner.getPermission())) {
                builder.withItem(
                        new ItemBuilder(Material.BARRIER)
                                .name("§cGerador bloqueado")
                                .lore(
                                        "§7Você não tem permissão para",
                                        "§7adquirir este gerador.")
                                .build());
                return;
            }

            double discountSet = (discount == null ? spawner.getCoin() : spawner.getCoin() - spawner.getCoin() * (discount.getDiscount() / 100));
            int calc = (int) (discount == null ? balance / spawner.getCoin() : balance / discountSet);

            if (discount != null) discount.add(spawner.getCoin());

            builder.withItem(
                    new ItemBuilder(Material.SKULL_ITEM)
                            .texture(spawner.getTexture())
                            .name("§aGerador de " + spawner.getName())
                            .lore(
                                    "§7Tenha a chance de receber",
                                    "§7chaves e bosses ao matar.",
                                    "",
                                    " §fCusto:",
                                    " §8∙ §2$§f" + NumberFormatter.format(discountSet) + " §7(" + NumberFormatter.format((discount == null ? 0 : discount.getDiscount())) + "§7%)",
                                    "",
                                    " §aDrops:",
                                    " §a▎ §fNormal: §7" + spawner.getDrop(),
                                    "",
                                    " §a▴ §fVocê consegue comprar",
                                    "    §7" + NumberFormatter.format(calc) + " §fgeradores deste tipo.",
                                    "",
                                    "§fClique para adquirir.")
                            .build()
            ).onClick(click -> click.openForPlayer(StoreView.class,
                    ImmutableMap.of("spawners", spawner)));
        });
DevNatan commented 1 year ago

@SrMinister Do you mean another view?

See Sharing data between views and Initial State on Wiki.

private final State<Spawner> spawnerState = initialState("spawners"); 
kaiquyricardo commented 1 year ago

ERROR: [19:23:53] [Server thread/ERROR]: Could not pass event InventoryClickEvent to spigot-spawnershop v1.0 org.bukkit.event.EventException: null at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:302) ~[patched_1.8.8.jar:git-PaperSpigot-445] at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:78) ~[patched_1.8.8.jar:git-PaperSpigot-445] at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[patched_1.8.8.jar:git-PaperSpigot-445] at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:517) [patched_1.8.8.jar:git-PaperSpigot-445] at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:502) [patched_1.8.8.jar:git-PaperSpigot-445] at net.minecraft.server.v1_8_R3.PlayerConnection.a(PlayerConnection.java:1657) [patched_1.8.8.jar:git-PaperSpigot-445] at net.minecraft.server.v1_8_R3.PacketPlayInWindowClick.a(SourceFile:31) [patched_1.8.8.jar:git-PaperSpigot-445] at net.minecraft.server.v1_8_R3.PacketPlayInWindowClick.a(SourceFile:9) [patched_1.8.8.jar:git-PaperSpigot-445] at net.minecraft.server.v1_8_R3.PlayerConnectionUtils$1.run(SourceFile:13) [patched_1.8.8.jar:git-PaperSpigot-445] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_362] at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_362] at net.minecraft.server.v1_8_R3.SystemUtils.a(SourceFile:44) [patched_1.8.8.jar:git-PaperSpigot-445] at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:774) [patched_1.8.8.jar:git-PaperSpigot-445] at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:378) [patched_1.8.8.jar:git-PaperSpigot-445] at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:713) [patched_1.8.8.jar:git-PaperSpigot-445] at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:616) [patched_1.8.8.jar:git-PaperSpigot-445] at java.lang.Thread.run(Thread.java:750) [?:1.8.0_362] Caused by: java.lang.NullPointerException at net.hyren.spawnershop.view.StoreView.item(StoreView.java:93) ~[?:?] at net.hyren.spawnershop.view.StoreView.onFirstRender(StoreView.java:51) ~[?:?] at net.hyren.spawnershop.view.StoreView.onFirstRender(StoreView.java:22) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PlatformRenderInterceptor.intercept(PlatformRenderInterceptor.java:16) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PlatformRenderInterceptor.intercept(PlatformRenderInterceptor.java:8) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PipelineContext.loop(PipelineContext.java:43) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PipelineContext.proceed(PipelineContext.java:53) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PipelineContext.execute(PipelineContext.java:59) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.Pipeline.execute(Pipeline.java:112) ~[?:?] at net.hyren.core.spigot.inventory.PlatformView.renderContext(PlatformView.java:295) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PlatformOpenInterceptor.finishOpen(PlatformOpenInterceptor.java:54) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PlatformOpenInterceptor.intercept(PlatformOpenInterceptor.java:28) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PlatformOpenInterceptor.intercept(PlatformOpenInterceptor.java:12) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PipelineContext.loop(PipelineContext.java:43) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PipelineContext.proceed(PipelineContext.java:53) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PipelineContext.execute(PipelineContext.java:59) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.Pipeline.execute(Pipeline.java:119) ~[?:?] at net.hyren.core.spigot.inventory.PlatformView.open(PlatformView.java:132) ~[?:?] at net.hyren.core.spigot.inventory.PlatformView.navigateTo(PlatformView.java:160) ~[?:?] at net.hyren.core.spigot.inventory.context.PlatformConfinedContext.openForPlayer(PlatformConfinedContext.java:25) ~[?:?] at net.hyren.core.spigot.inventory.context.PlatformRenderContext.openForPlayer(PlatformRenderContext.java:316) ~[?:?] at net.hyren.core.spigot.inventory.context.SlotClickContext.openForPlayer(SlotClickContext.java:150) ~[?:?] at net.hyren.spawnershop.view.SpawnersView.lambda$null$0(SpawnersView.java:67) ~[?:?] at net.hyren.core.spigot.inventory.component.ItemComponent.clicked(ItemComponent.java:204) ~[?:?] at net.hyren.core.spigot.inventory.component.PaginationImpl.clicked(PaginationImpl.java:634) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.ItemClickInterceptor.intercept(ItemClickInterceptor.java:35) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.ItemClickInterceptor.intercept(ItemClickInterceptor.java:14) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PipelineContext.loop(PipelineContext.java:43) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PipelineContext.proceed(PipelineContext.java:53) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.PipelineContext.execute(PipelineContext.java:59) ~[?:?] at net.hyren.core.spigot.inventory.pipeline.Pipeline.execute(Pipeline.java:119) ~[?:?] at net.hyren.core.spigot.inventory.IFInventoryListener.onInventoryClick(IFInventoryListener.java:57) ~[?:?] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_362] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_362] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_362] at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_362] at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:300) ~[patched_1.8.8.jar:git-PaperSpigot-445] ... 16 more

kaiquyricardo commented 1 year ago

image image image

DevNatan commented 1 year ago

@SrMinister I'll take a look to find the cause of that NullPointerException

DevNatan commented 1 year ago

@SrMinister By default, the data is not transitioned entirely throughout the stream, that is, opening a screen with A initial data and navigating to B without declaring all data explicitly via openForPlayer, the data from A will not be accessible from B. I I will add an option to make this the default behavior. This is the cause of your error.

You can create a temporary workaround for this replicating the current data using context.getInitialData()

Map<String, Object> data = new HashMap<>();
data.put("spawners", spawner);
data.putAll((Map<String, Object>) click.getInitialData());
click.openForPlayer(StoreView.class, data);
kaiquyricardo commented 1 year ago

I saw that you updated the api, is it now possible to do this instead of creating a map? If so, could you explain it to me using the previous question?

DevNatan commented 1 year ago

I saw that you updated the api, is it now possible to do this instead of creating a map? If so, could you explain it to me using the previous question?

@SrMinister This change was not planned to v3.0.0, will be available in v3.0.1 or v3.1.0 :pray:

kaiquyricardo commented 1 year ago

I cancel the click but I can't move the item in my inventory to drag it to slot 11 where the material is changed, in the past in previous libs I only had to activate the cancel click and nothing else, if I didn't want to drag it so, just add cancelOnClickPickup.

@RequiredArgsConstructor
public class EditWarpView extends View {

    private final EssentialsPlugin plugin;

    private final State<Warp> warpState = initialState("warp");

    @Override
    public void onInit(@NotNull ViewConfigBuilder config) {
        config.title("Edição ▶ Warp · ")
                .cancelOnClick();
    }

    @Override
    public void onOpen(@NotNull OpenContext open) {
        final Warp warp = warpState.get(open);

        open.modifyConfig()
                .title("Edição ▶ Warp · " + warp.getId()
                );
    }

    @Override
    public void onFirstRender(@NotNull RenderContext render) {
        final Warp warp = warpState.get(render);

        render.slot(
                10,
                new ItemBuilder(
                        Material.COMMAND
                ).name(
                        "§eAlterar nome"
                ).lore(
                        "§7Aqui você poderá alterar.",
                        "§7o nome da warp.",
                        "",
                        " §eInformações:",
                        "  §fNome: §7" + (warp.getName() != null ? warp.getName() : "§c???"),
                        "",
                        "§fBotão esquerdo: §7Alterar nome",
                        ""
                ).build()
        ).onClick(click -> {
            final Player player = click.getPlayer();

            MessageProvider.CLICK.sendMessage(
                    player,
                    "",
                    "§e Informe no chat o ´NOME` da warp.",
                    "§7 Para cancelar, digite ´§8cancelar§7´.",
                    ""
            );

            click.closeForPlayer();

            new ChatMonitor(player.getUniqueId(), messageOne -> {
                warp.setName(colorize(messageOne));
                MessageProvider.ORB_PICKUP.sendMessage(
                        player,
                        "§e§lGG! §eNome alterado com sucesso!"
                );

                plugin.getWarpFactory().addName(plugin, warp);

                click.update();
                click.openForPlayer(
                        EditWarpView.class,
                        Collections.singletonMap(
                                "warp",
                                warp
                        ));
            });
        });

        render.slot(
                11,
                new ItemBuilder(
                        warp.getIcon() != null ? warp.getIcon().clone() : new ItemStack(Material.BARRIER)
                ).name(
                        "§eAlterar ícone"
                ).lore(
                        "§7Aqui você poderá alterar.",
                        "§7o ícone da warp.",
                        "",
                        " §eInformações:",
                        "  §fÍcone: §7" + (warp.getIcon() != null ? warp.getIcon().getType().name() : "§c???"),
                        "",
                        "§fArraste o ítem: §7Alterar ícone",
                        ""
                ).build()
        ).onClick(click -> {
            final Player player = click.getPlayer();
            final ItemStack cursor = player.getItemOnCursor().clone();

            if (cursor == null || cursor.getType() == Material.AIR) {

                MessageProvider.ERROR.sendMessage(
                        player,
                        "§c§lEPA! §cVocê precisa arrastar um ítem para alterar o ícone."
                );
                return;
            }

            warp.setIcon(cursor);
            click.update();

            MessageProvider.ORB_PICKUP.sendMessage(
                    player,
                    "§e§lGG! §eÍcone alterado com sucesso!"
            );

            plugin.getWarpFactory().addIcon(plugin, warp);
        });

        render.slot(
                12,
                new ItemBuilder(
                        Material.EMPTY_MAP
                ).name(
                        "§eAlterar coordenadas"
                ).lore(
                        "§7Aqui você poderá alterar.",
                        "§7a coordenada da warp.",
                        "",
                        " §eInformações:",
                        "  §fCoordenadas: §7" + (warp.getLocation() != null ? getFormattedText(LocationSerializer.fromString(warp.getLocation())) : "§c???"),
                        "",
                        "§fBotão esquerdo: §7Alterar localização",
                        ""
                ).build()
        ).onClick(click -> {
            final Player player = click.getPlayer();
            val location = LocationSerializer.serialize(player.getLocation(), true);
            warp.setLocation(location);

            plugin.getWarpFactory().addLocation(plugin, warp);

            MessageProvider.ORB_PICKUP.sendMessage(
                    player,
                    "§e§lGG! §eCoordenada alterada com sucesso!"
            );

            click.update();
            click.openForPlayer(
                    EditWarpView.class,
                    ImmutableMap.of(
                            "warp",
                            warp
                    ));
        });

        render.slot(
                14,
                new ItemBuilder(
                        Material.HOPPER
                ).name(
                        "§eAlterar slot"
                ).lore(
                        "§7Aqui você poderá alterar.",
                        "§7o slot da warp.",
                        "",
                        " §eInformações:",
                        "  §fSlot: §7" + (warp.getSlot() != 0 ? warp.getSlot() : "§c???"),
                        "",
                        "§fBotão esquerdo: §7Alterar slot",
                        ""
                ).build()
        ).onClick(click -> {
            final Player player = click.getPlayer();

            MessageProvider.CLICK.sendMessage(
                    player,
                    "",
                    "§a Informe no chat o ´SLOT´ da warp.",
                    "§7 Para cancelar, digite ´§8cancelar§7´.",
                    ""
            );

            click.closeForPlayer();

            new ChatMonitor(player.getUniqueId(), messageOne -> {
                warp.setSlot(Integer.parseInt(messageOne));

                MessageProvider.ORB_PICKUP.sendMessage(
                        player,
                        "§e§lGG! §eSlot alterado com sucesso!"
                );

                plugin.getWarpFactory().addSlot(plugin, warp);

                click.update();
                click.openForPlayer(
                        EditWarpView.class,
                        ImmutableMap.of(
                                "warp",
                                warp
                        ));
            });
        });

        render.slot(
                15,
                descriptionItem(warp)
        ).onClick(click -> {
            final Player player = click.getPlayer();

            if (click.isLeftClick()) {

                MessageProvider.CLICK.sendMessage(
                        player,
                        "",
                        "§E Informe no chat o ´LORE` da warp.",
                        "§7 Para cancelar, digite ´§8cancelar§7´.",
                        ""
                );

                click.closeForPlayer();
                new ChatMonitor(player.getUniqueId(), messageOne -> {
                    warp.getLore().add(colorize(messageOne));

                    MessageProvider.ORB_PICKUP.sendMessage(
                            player,
                            "§e§lGG! §eLore adicionada com sucesso!"
                    );

                    plugin.getWarpFactory().addLore(plugin, warp);

                    click.update();
                    click.openForPlayer(
                            EditWarpView.class,
                            ImmutableMap.of(
                                    "warp",
                                    warp
                            ));
                });

                return;
            }
            if (click.isRightClick()) {
                plugin.getWarpFactory().removeLore(plugin, warp);

                MessageProvider.ORB_PICKUP.sendMessage(
                        player,
                        "§e§lGG! §eLore removida com sucesso!"
                );
                click.update();
            }

        });
    }

    private ItemStack descriptionItem(Warp warp) {
        val builder = new ItemBuilder(
                Material.PAPER
        ).name(
                "§eAlterar descrição"
        ).lore(
                "§7Aqui você poderá alterar.",
                "§7a lore da warp.",
                "",
                " §eInformações:"
        );

        plugin.getWarpFactory().getLore(plugin, warp.getId()).forEach(builder::addLore);

        return builder.addLore(
                "",
                "§fBotão esquerdo: §7Adicionar lore",
                "§fBotão direito: §7Remover lore",
                ""
        ).build();

    }

    private static String colorize(String text) {
        return text.replace("&", "§");
    }
}
DevNatan commented 1 year ago

@SrMinister Please open a separate issue for this issue https://github.com/DevNatan/inventory-framework/issues/441#issuecomment-1739637918 so we can track it and resolve it better

DevNatan commented 1 year ago

I saw that you updated the api, is it now possible to do this instead of creating a map? If so, could you explain it to me using the previous question?

@SrMinister Fixed in v3.0.1. You must enable a transitiveInitialData option in your ViewFrame/View configuration

Enable it globally

viewFrame.defaultConfig(config -> config.transitiveInitialData(true));

Or per-view

config.transitiveInitialData(true);