MinusKube / SmartInvs

Advanced Inventory API for your Minecraft Bukkit plugins.
https://minuskube.gitbook.io/smartinvs/
Apache License 2.0
262 stars 65 forks source link

Feature for InventoryContents #94

Closed portlek closed 4 years ago

portlek commented 4 years ago

I encountered a difficulty using your library.

Opening an inventory for each situation is causing difficulties for users. For example;

Let's take this situation that I want to create an inventory that has a few items that I can edit to an Object in my plugin. I want to add an agreement inventory for modifying/removing the Object so, in this case I have to create agreement inventories for each item to accept/reject this modifying/removing. I solved this difficulty with; MY_PLUGIN_INSTANCE.acceptReject.get(player.getUniqueId()) The whole initiating method is that;

@Override
public void init(Player player, InventoryContents inventoryContents) {
    Optional.ofNullable(elements.get("empty-slots")).ifPresent(fileElement ->
        fileElement.fill(inventoryContents)
    );
    Optional.ofNullable(Vote.getAPI().acceptReject.get(player.getUniqueId())).ifPresent(entry -> {
        Optional.ofNullable(elements.get("accept")).ifPresent(fileElement ->
            fileElement.insert(inventoryContents, event -> {
                event.setCancelled(true);
                entry.getKey().accept(event);
            })
        );
        Optional.ofNullable(elements.get("reject")).ifPresent(fileElement ->
            fileElement.insert(inventoryContents, event -> {
                event.setCancelled(true);
                entry.getValue().accept(event);
            })
        );
    });
    Vote.getAPI().acceptReject.remove(player.getUniqueId());
}

The acceptReject map is storing the runnables with the player unique id for getting the different situations. When I click to modifying/removing the Object, I have to add the runnables to acceptReject map like that;

event -> {
    event.setCancelled(true);

    final Optional<Reward> rewardOptional = Vote.getAPI().rewards.findRewardById(rewardId);

    if (!rewardOptional.isPresent()) {
        Vote.getAPI().menus.rewardsMenu.open((Player) event.getWhoClicked());
        return;
    }

    if (event.isLeftClick()) {
        Vote.getAPI().menus.openEditRewardMenu(
            (Player) event.getWhoClicked(),
            rewardOptional.get()
        );
    } else if (event.isRightClick()) {
        Vote.getAPI().acceptReject.put(event.getWhoClicked().getUniqueId(),
            new MapEntry<>(
                accept -> {
                    Vote.getAPI().rewards.remove(rewardOptional.get());
                    Vote.getAPI().menus.rewardsMenu.open((Player) accept.getWhoClicked());
                },
                reject ->
                    Vote.getAPI().menus.rewardsMenu.open((Player) reject.getWhoClicked())
            ));
        Vote.getAPI().menus.acceptMenu.open((Player) event.getWhoClicked());
    }
}

This code is just Consumer<InventoryClickEvent> consumer of a Clickable Item.

My suggestion to solve this difficulty is when I want to open an inventory for each situation we can add Properties, that we can get with InventoryContests, with each player's values. InventoryContests already has property methods. However, the methods can add properties when you opened your inventory and using it's InventoryContests My solution code is for this situation is like that(SmartInventory.class);

public Inventory open(Player player, int page) {
  // The old method can be stay here with an empty properties map.
  return open(player, page, new HashMap<>());
}

public Inventory open(Player player, int page, Map<String, Object> properties) {
  Optional<SmartInventory> oldInv = this.manager.getInventory(player);
  oldInv.ifPresent((inv) -> {
    inv.getListeners().stream().filter((listener) -> {
      return listener.getType() == InventoryCloseEvent.class;
    }).forEach((listener) -> {
      listener.accept(new InventoryCloseEvent(player.getOpenInventory()));
    });
    this.manager.setInventory(player, (SmartInventory)null);
  });
  InventoryContents contents = new Impl(this, player, properties);
  // Adding optional properties before the menu opens.
  properties.forEach(contents::setProperty)
  contents.pagination().page(page);
  this.manager.setContents(player, contents);
  this.provider.init(player, contents);
  InventoryOpener opener = (InventoryOpener)this.manager.findOpener(this.type).orElseThrow(() -> {
    return new IllegalStateException("No opener found for the inventory type " + this.type.name());
  });
  Inventory handle = opener.open(this, player);
  this.manager.setInventory(player, this);
  return handle;
}
portlek commented 4 years ago

It will be fixed when 1.3.0 sorry, I didn't see it.