GUIMenu (Per Item Click and Updating Menus)

Discussion in 'Resources' started by DevRosemberg, Jun 17, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    DevRosemberg

    Hello everyone, DevRo_ here and today I bring you a new way of creating per-player Inventory Menus which contain:
    • Per Item Click
    • Updating Menus
    • Simple Setup.
    There are three classes to this:
    • GUIButton (The Button class which is an interface containing a boolean for the player when the button is clicked).
    • GUIMenu (The actual menu class which allows you to create simple menus).
    • GUIUpdatingMenu (The class which allows you to create updating menus every a certain amount of time).
    GUIButton:
    Code:java
    1. public interface GUIButton {
    2. public boolean onClick(Player player);
    3. }


    GUIMenu:
    Code:java
    1. public class GUIMenu implements Listener {
    2. private String name;
    3. private int size;
    4. private Player player;
    5. private boolean willClose = false;
    6.  
    7. private HashMap<Integer, GUIButton> buttons = new HashMap<Integer, GUIButton>();
    8.  
    9. private HashMap<Integer, ItemStack> options = new HashMap<Integer, ItemStack>();
    10.  
    11. public GUIMenu(String name, int size, Player player) {
    12. this.name = name;
    13. this.size = size;
    14. this.player = player;
    15.  
    16. Testing.getInstance().getServer().getPluginManager().registerEvents(this, Testing.getInstance());
    17. }
    18.  
    19. public GUIMenu setOption(int postition, ItemStack stack, String name, List<String> description, GUIButton button) {
    20. buttons.put(postition, button);
    21. options.put(postition, setNameAndLore(stack, name, description));
    22.  
    23. return this;
    24. }
    25.  
    26. public void setWillClose(boolean willClose) {
    27. this.willClose = willClose;
    28. }
    29.  
    30. public void open() {
    31. Inventory inv = Testing.getInstance().getServer().createInventory(player, size, name);
    32.  
    33. for (int i = 0; i < buttons.size(); i++) {
    34. if (options.get(i) != null) {
    35. inv.setItem(i, options.get(i));
    36. }
    37. }
    38.  
    39. player.openInventory(inv);
    40. }
    41.  
    42. @EventHandler
    43. public void onClick(InventoryClickEvent event) {
    44. if (event.getInventory().getTitle().equals(name)) {
    45. event.setCancelled(true);
    46. int slot = event.getRawSlot();
    47. if (slot >= 0 && slot < size) {
    48. for (Integer ig : buttons.keySet()) {
    49. if (ig == slot) {
    50. buttons.get(ig).onClick(player, options.get(ig).getItemMeta().getDisplayName());
    51. }
    52. }
    53. }
    54.  
    55. if (willClose) {
    56. final Player clicker = (Player) event.getWhoClicked();
    57.  
    58. Testing.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(Testing.getInstance(), new Runnable() {
    59. public void run() {
    60. clicker.closeInventory();
    61. }
    62. }, 1L);
    63.  
    64. unload();
    65. }
    66. }
    67. }
    68.  
    69. @EventHandler
    70. public void onClose(InventoryCloseEvent event) {
    71. if (event.getInventory().getTitle().equals(name)) {
    72. unload();
    73. }
    74. }
    75.  
    76. private void unload() {
    77. HandlerList.unregisterAll(this);
    78.  
    79. options = null;
    80. buttons = null;
    81.  
    82. name = null;
    83. player = null;
    84. }
    85.  
    86. private ItemStack setNameAndLore(ItemStack item, String name, List<String> lore) {
    87. ItemMeta meta = item.getItemMeta();
    88. meta.setDisplayName(ChatColor.RESET + name);
    89. meta.setLore(lore);
    90. item.setItemMeta(meta);
    91. return (item);
    92. }
    93. }


    GUIUpdatingMenu:
    Code:java
    1. public class GUIUpdatingMenu implements Listener {
    2. private String name;
    3. private int size;
    4. private Player player;
    5. private int delay;
    6. private boolean willClose = false;
    7.  
    8. private HashMap<String, Integer> updater = new HashMap<String, Integer>();
    9.  
    10. private HashMap<Integer, GUIButton> buttons = new HashMap<Integer, GUIButton>();
    11.  
    12. private HashMap<Integer, ItemStack> options = new HashMap<Integer, ItemStack>();
    13.  
    14. public GUIUpdatingMenu(String name, int size, Player player, int delayUpdateInSeconds) {
    15. this.name = name;
    16. this.size = size;
    17. this.player = player;
    18. this.delay = delayUpdateInSeconds;
    19.  
    20. Testing.getInstance().getServer().getPluginManager().registerEvents(this, Testing.getInstance());
    21. }
    22.  
    23. public GUIUpdatingMenu setItem(int postition, ItemStack stack, String name, List<String> description, GUIButton button) {
    24. buttons.put(postition, button);
    25. options.put(postition, setNameAndLore(stack, name, description));
    26.  
    27. return this;
    28. }
    29.  
    30. public void setWillClose(boolean willClose) {
    31. this.willClose = willClose;
    32. }
    33.  
    34. public void open() {
    35. Inventory inv = Testing.getInstance().getServer().createInventory(player, size, name);
    36.  
    37. for (int i = 0; i < buttons.size(); i++) {
    38. if (options.get(i) != null) {
    39. inv.setItem(i, options.get(i));
    40. }
    41. }
    42.  
    43. player.openInventory(inv);
    44. }
    45.  
    46. @EventHandler
    47. public void onClick(InventoryClickEvent event) {
    48. if (event.getInventory().getTitle().equals(name)) {
    49. event.setCancelled(true);
    50. int slot = event.getRawSlot();
    51. if (slot >= 0 && slot < size) {
    52. for (Integer ig : buttons.keySet()) {
    53. if (ig == slot) {
    54. buttons.get(ig).onClick(player, options.get(ig).getItemMeta().getDisplayName());
    55. }
    56. }
    57. }
    58.  
    59. if (willClose) {
    60. final Player clicker = (Player) event.getWhoClicked();
    61.  
    62. Testing.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(Testing.getInstance(), new Runnable() {
    63. public void run() {
    64. clicker.closeInventory();
    65. }
    66. }, 1L);
    67.  
    68. unload();
    69. }
    70. }
    71. }
    72.  
    73. @EventHandler
    74. public void onOpen(InventoryOpenEvent event) {
    75. if (event.getInventory().getName().equals(name)) {
    76. final Inventory inventory = event.getInventory();
    77.  
    78. BukkitTask update = new BukkitRunnable(){
    79. @Override
    80. public void run() {
    81. for (int i = 0; i < buttons.size(); i++) {
    82. inventory.setItem(i, options.get(i));
    83. }
    84. }
    85. }.runTaskTimer(Testing.getInstance(),0, this.delay * 20);
    86.  
    87. updater.put(event.getPlayer().getName(), update.getTaskId());
    88. }
    89. }
    90.  
    91. @EventHandler
    92. public void onInventoryClose(InventoryCloseEvent event) {
    93. if (event.getInventory().getTitle().equals(name)) {
    94. if (updater.containsKey((event.getPlayer().getName()))) {
    95. Bukkit.getScheduler().cancelTask(updater.get(event.getPlayer().getName()));
    96. updater.remove(event.getPlayer().getName());
    97. }
    98.  
    99. unload();
    100. }
    101. }
    102.  
    103. private ItemStack setNameAndLore(ItemStack item, String name, List<String> lore) {
    104. ItemMeta meta = item.getItemMeta();
    105. meta.setDisplayName(ChatColor.RESET + name);
    106. meta.setLore(lore);
    107. item.setItemMeta(meta);
    108. return (item);
    109. }
    110.  
    111. private void unload() {
    112. HandlerList.unregisterAll(this);
    113.  
    114. options = null;
    115. buttons = null;
    116.  
    117. name = null;
    118. player = null;
    119.  
    120. delay = 0;
    121. updater = null;
    122. }
    123. }


    If you like this resource go and take a look at nisovin‘s Class which is simpler than mine and which I based mine of.

    Thanks for taking the time for reading,

    ~ Erik.
     
  2. Offline

    Onlineids

  3. Offline

    DevRosemberg

    Onlineids Thanks. I just realized i forgot to include something like #setClose(boolean close); which ill add in a bit.
     
  4. Offline

    DSH105

    Why are you storing the player object (and not removing/nullifying where appropriate)? :(
     
  5. Offline

    darkness1999

    DevRosemberg
    Your way of using my updating menu code looks nice :p
     
  6. Offline

    DevRosemberg

  7. Offline

    garbagemule

    Kudos for trying to make a resource that attempts to actually reduce the amount of work necessary to create these inventory menus :p A few points:
    • You're working in a reactive, publish/subscribe based world of event-driven programming. Why on earth would you choose to implement a polling timer to continuously overwrite the inventory when you can just update it when new items are added or changed (i.e. when necessary)?
    • The singleton pattern is useful for situations where tight coupling is not an issue. With a library or generic resource like this, coupling your alleged "reusable code" to your specific plugin is a Very Bad Thing. Resources should be provided in a state that allow others to simply copy and paste, not copy, paste and resolve compiler errors. Use dependency injection by making a plugin setter, or take a plugin instance in the constructor.
    • Show people how to use your resource. No matter how simple it is, the source code itself is not an acceptable replacement for documentation of the component. You post your resource to help people, so go all the way. Help them get started, don't force them to parse your source code.
    All you need to do now to make this resource truly useful is to provide a means of specifying menus and templates in a markup language and loading and populating them from code (like layouts in Android!) :)
     
    Skyost, drtshock, mbaxter and 4 others like this.
  8. Offline

    chasechocolate

    I *think* that by making the class implement Listener, when you unregister one menu it will unregister all other ones. Might want to test that out.
     
    DSH105 and drtshock like this.
  9. Offline

    ChipDev

    So, this is what some save been looking for... updating menus! (Updating lores, ex: mineplex, hypixel..)
     
  10. Offline

    DevRosemberg

    garbagemule When did i state the topic/resource was fully done? I've found some bugs which i am going to fix soon, provide examples. You aswell stated that this is sort of not worth using which already some people have commented possitively aside from you. Please refrain from critizising people like this because i could go and critizise anything that you have made simply stating that it is a Very Bad Thing™ (even though it may not in the case of MoA).

    chasechocolate No, its unregistering the listener from THAT menu. Not the rest.
     
  11. Offline

    garbagemule

    DevRosemberg
    I'm sorry you took offense from my constructive criticism, but I have nothing to apologize for. First of all, I am not criticizing you, I'm criticizing your work. The tone in your response borders hysteria. Don't take constructive criticism personally, because you will never improve if you do. The only feedback you can truly benefit from is the kind that points out issues, because it allows you to take a step back and reflect on what you can do better - you can always do better. If you only ever absorb positive feedback, you're going to end up on X-Factor making a fool out of yourself, claiming that "everyone else thinks I'm good" when the judges point out that your performance was abysmal. Your work is not perfect, I'm helping you realize it so you can do better, if you so desire.

    Secondly, I never said your work was "not worth using". I said that to make it truly useful, you could implement something that would actually set it apart from all the other "inventory menu" resources already available, because right now, someone looking for this kind of resource has little reason to pick yours over anyone else's. No one (that I know of) has implemented support for markup templates (an idea I've toyed around with for months now, but haven't had the time to look into), but there is no doubt that if implemented properly, they would be insanely useful. No one likes UI programming, that's why Android, iOS, WPF, etc. have support for markup languages.

    Finally, and most importantly, the Resources section is a place for people to post stuff that could be useful to others. When you post your work here, you are automatically inviting people to review and comment, to make suggestions for improvements, and to voice their opinions on your work, such that it can become as useful as possible. You post your work here to share it with the community for the sake of helping and enabling, not to fish for compliments or ego boosts. I'm not saying you're doing the latter, but your flailing makes it a bit too tempting to assume it. If I make a suggestion for improvements or call out an issue, your rational options are:
    • Refute my arguments or engage in debate for the sake of a compromise.
    • Accept my arguments and make the suggested changes (or ask for help with it), or suggest that someone else takes on the job of making a different or augmented solution.
    You can also choose to completely ignore me, which is of course a bit rude, but it's still better than taking things personally and lashing out. No one here is out to get you, so put your fists down, take a step back, and re-read my post with the knowledge that I am only trying to help :)
     
  12. Offline

    DevRosemberg

    garbagemule I trully appreciate that you are trying to help. I may as well look into Markup Templates when i have some time. I don't have enough time at this moment to continue updating it as some things have come up.
     
Thread Status:
Not open for further replies.

Share This Page