kangarko / Foundation

Foundation™ helps you create highly customized Minecraft plugins (based on Spigot/Paper API) that support multiple MC versions.

Home Page:https://mineacademy.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

1.20.1: Previous menu title shows when you click a button which animates the title, then you go back to the previous menu before the title reverts

MrCrazys opened this issue · comments

I am using the following code:

package me.mrcrazys.simplemenus.settings;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.inventory.ItemStack;
import org.mineacademy.fo.Common;
import org.mineacademy.fo.MathUtil;
import org.mineacademy.fo.Valid;
import org.mineacademy.fo.collection.SerializedMap;
import org.mineacademy.fo.menu.Menu;
import org.mineacademy.fo.menu.button.Button;
import org.mineacademy.fo.menu.model.ItemCreator;
import org.mineacademy.fo.model.ConfigSerializable;
import org.mineacademy.fo.remain.CompColor;
import org.mineacademy.fo.remain.CompItemFlag;
import org.mineacademy.fo.remain.CompMaterial;
import org.mineacademy.fo.settings.ConfigItems;
import org.mineacademy.fo.settings.YamlConfig;

import java.util.*;
import java.util.Map.Entry;

@Getter
public class MenuData extends YamlConfig {

    private static final ConfigItems<MenuData> MENUS = ConfigItems.fromFile("", "menus.yml", MenuData.class);

    private final String name;

    private String title;
    private List<String> info;
    private int size;
    private int infoButtonPosition;
    private List<ButtonData> buttons;

    private MenuData(final String name) {
        this.name = name;

        this.setPathPrefix(name);
        this.loadConfiguration(NO_DEFAULT, "menus.yml");
    }

    @Override
    protected void onLoad() {
        this.title = this.getString("Title");
        this.info = this.getStringList("Info");
        this.size = (int) MathUtil.calculate(this.getString("Size"));
        this.infoButtonPosition = this.getInteger("Info_Button_Position", this.size - 9);
        this.buttons = this.loadButtons();
    }

    private List<ButtonData> loadButtons() {
        final List<ButtonData> buttons = new ArrayList<>();

        for (final Entry<String, Object> entry : this.getMap("Buttons", String.class, Object.class).entrySet()) {
            final String buttonName = entry.getKey();
            final SerializedMap buttonSettings = SerializedMap.of(entry.getValue());

            buttons.add(ButtonData.deserialize(buttonSettings, buttonName));
        }

        return buttons;
    }

    public void displayTo(final Player player) {
        this.toMenu().displayTo(player);
    }

    public Menu toMenu() {
        return this.toMenu(null);
    }

    public Menu toMenu(final Menu parent) {
        final Map<Integer, Button> buttons = this.getButtons();

        return new Menu(parent) {

            {
                this.setTitle(MenuData.this.title);
                this.setSize(MenuData.this.size);
            }

            @Override
            protected List<Button> getButtonsToAutoRegister() {
                return new ArrayList<>(buttons.values());
            }

            @Override
            public ItemStack getItemAt(final int slot) {
                if (buttons.containsKey(slot))
                    return buttons.get(slot).getItem();

                return NO_ITEM;
            }

            @Override
            protected String[] getInfo() {
                return Valid.isNullOrEmpty(MenuData.this.info) ? null : Common.toArray(MenuData.this.info);
            }

            @Override
            protected int getInfoButtonPosition() {
                return super.getInfoButtonPosition();
            }
        };
    }

    public Map<Integer, Button> getButtons() {
        final Map<Integer, Button> buttons = new HashMap<>();

        for (final ButtonData data : this.buttons)
            buttons.put(data.getSlot(), new Button() {

                @Override
                public void onClickedInMenu(final Player player, final Menu menu, final ClickType click) {
                    if (data.getPlayerCommands() != null && !data.getPlayerCommands().isEmpty())
                        data.getPlayerCommands().forEach(player::chat);

                    if (data.getTitleAnimation() != null)
                        menu.animateTitle(data.getTitleAnimation());

                    if (data.isCopyItem())
                        player.getInventory().addItem(this.getItem());

                    if (data.getMenuToOpen() != null) {
                        final MenuData otherMenu = MenuData.findMenu(data.getMenuToOpen());

                        if (otherMenu == null)
                            menu.animateTitle("Invalid menu: " + data.getMenuToOpen());
                        else
                            otherMenu.toMenu(menu).displayTo(player);
                    }
                }

                @Override
                public ItemStack getItem() {
                    return ItemCreator.of(data.getMaterial(), data.getDisplayName(), data.getLore())
                            .amount(data.getAmount())
                            .hideTags(data.isHideTags())
                            .flags(data.getFlags().toArray(new CompItemFlag[0]))
                            .modelData(data.getCustomModelData())
                            .color(data.getColor())
                            .skullOwner(data.getSkullOwner())
                            .skullUrl(data.getSkullUrl())
                            .unbreakable(data.isUnbreakable())
                            .glow(data.isGlow())
                            .bookTitle(data.getBookTitle())
                            .bookAuthor(data.getBookAuthor())
                            .make();
                }
            });

        return buttons;
    }

    @Getter
    @ToString
    @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
    private static class ButtonData implements ConfigSerializable {

        private final String name;

        private int slot;
        private CompMaterial material;
        private String displayName;
        private List<String> lore;
        private int amount;
        private boolean hideTags;
        private Set<CompItemFlag> flags;
        private int customModelData;
        private CompColor color;
        private String skullOwner;
        private String skullUrl;
        private boolean unbreakable;
        private boolean glow;
        private String bookTitle;
        private String bookAuthor;

        private List<String> playerCommands;
        private String titleAnimation;
        private String menuToOpen;
        private boolean copyItem;

        @Override
        public SerializedMap serialize() {
            return null;
        }

        public static ButtonData deserialize(final SerializedMap map, final String buttonName) {
            final ButtonData button = new ButtonData(buttonName);

            map.setRemoveOnGet(true);

            button.slot = map.containsKey("Slot") ? (int) MathUtil.calculate(map.getString("Slot")) : -1;
            Valid.checkBoolean(button.slot != -1, "Missing 'Slot' key from button: " + map);

            button.material = map.getMaterial("Material");
            Valid.checkNotNull(button.material, "Missing 'Material' key from button: " + map);

            button.displayName = map.getString("Title");
            Valid.checkNotNull(button.displayName, "Missing 'Title' key from button: " + map);

            button.lore = map.getStringList("Lore");
            Valid.checkNotNull(button.lore, "Missing 'Lore' key from button: " + map);

            button.amount = map.getInteger("Amount", 1);
            button.hideTags = map.getBoolean("Hide_Tags", false);
            button.flags = map.getSet("Flags", CompItemFlag.class);
            button.customModelData = map.getInteger("Custom_Model_Data", 0);
            button.color = CompColor.fromName(map.containsKey("Color") ? map.getString("Color") : "");
            button.skullOwner = map.getString("Skull_Owner");
            button.skullUrl = map.getString("Skull_URL");
            button.unbreakable = map.getBoolean("Unbreakable", false);
            button.glow = map.getBoolean("Glow", false);
            button.bookTitle = map.getString("Book_Title");
            button.bookAuthor = map.getString("Book_Author");

            final SerializedMap click = map.getMap("Click");
            click.setRemoveOnGet(true);

            button.playerCommands = click.getStringList("Player_Command");
            button.titleAnimation = click.getString("Animate");
            button.menuToOpen = click.getString("Menu");
            button.copyItem = click.getBoolean("Copy_Item", false);

            Valid.checkBoolean(click.isEmpty(), "Found unrecognized button click settings: " + click);
            Valid.checkBoolean(map.isEmpty(), "Found unrecognized button settings: " + map);

            return button;
        }
    }

    public static MenuData findMenu(final String name) {
        return MENUS.findItem(name);
    }

    public static void loadMenus() {
        MENUS.loadItems();
    }

    public static Set<String> getMenuNames() {
        return MENUS.getItemNames();
    }
}

The menus.yml files looks like:

Main_Menu:
  Title: "Custom Menu"
  Size: "9 * 3"
  Buttons:
    Time:
      Slot: "9 * 1 + 3"
      Material: CLOCK
      Title: "Change Time"
      Lore:
        - ""
        - "Click this button"
        - "to change the time"
        - "to day in your world."
      Click:
        Player_Command: "/time set 1000"
        Animate: "Time has been set to a day!"
    Egg:
      Slot: "9 * 1 + 5"
      Material: SHEEP_SPAWN_EGG
      Title: "Open Egg Menu"
      Lore:
        - ""
        - "Click this button"
        - "to open another menu."
      Click:
        Menu: Test_Menu
    Button:
      Slot: "9 * 1 + 7"
      Material: DIAMOND_SWORD
      Title: "Sword"
      Unbreakable: true
      Lore:
        - ""
        - "This is a sword!"
    Skull:
      Slot: "9 * 1 + 1"
      Amount: 64
      Material: LEATHER_HELMET
      Title: "Player Head"
      Hide_Tags: true
      Lore:
        - ""
        - "This is a helmet!"

Second_Menu:
  Title: "Second Menu"
  Size: "9 * 2"
  Info:
    - "This menu shows example"
    - "of getting buttons"
    - "as items."
  Buttons:
    Mob_Egg:
      Slot: "4"
      Material: ZOMBIE_SPAWN_EGG
      Title: "Zombie Spawn Egg"
      Lore:
        - ""
        - "Click to get this"
        - "item to your inventory!"
      Click:
        Copy_Item: true
        Animate: "Item copied to inventory!"

Test_Menu:
  Title: "Test Menu"
  Size: 54
  Info:
    - "This is a test menu!"
  Buttons:
    First:
      Slot: 8 * 3
      Material: BEDROCK
      Title: "Test Item"
      Lore:
        - ""
        - "This is a test item."
      Click:
        Animate: "You clicked the test item!"

When I open Test_Menu using the button from Main_Menu, click the Bedrock and then click on the Return button before the title finishes animating, the animated title still shows in the menu I return to, but then when the title reverts, it reverts to the title of the menu which I clicked the button that caused the title to animate.

I know this might be confusing, so please let me know if you need me to elaborate.

Thanks,

MrCrazys

Looks like a logic issue where the animation keeps the old title, and when the animation is finished the title is restored to the old one. You would need to keep the proper title somewhere else outside of the animation and then run a task 1 or two ticks later to manually "fix" the title.