Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sellable Menu Kit field changes when two or more references of the class are created (with GitHub)

I have been experiencing an odd bug in my Spigot/Bukkit plugin lately which totally does not make any sense. Please note that this question may be long due to the fact that the project I am working on is fairly big and since the source code (provided below) contains classes that will not be included here I will try my best to describe my problem.

In Minecraft, using Bukkit API you can create graphical menus (GUI's) in which you can place items in certain slots and when clicked, you can adjust your functionality.

In my case, I have created the Menu foundation class which contains basic methods for the creation of such a menu. Then, the PurchaseMenu which extends the Menu class is used to trigger functionality in specific locations to simulate a transaction for product that can be clicked from the menu.

In depth, the menu I will include contains "Kit" displays (like game classes) that when one Left-Click's the display the player can buy it, or if it's already bought, the player will just select that kit for use. When one Right-Clicks's the display, the player can level up the kit up to 3.

In both cases a transaction menu must be popped up in order to buy or level up the clicked kit. My design is really straight forward, by passing the clicked kit from the constructor on each PurchaseMenu class.

The problem on all the above is that the Kit is passed correctly from the constructor, but the kit that is actually being bought or level up is a random one (obviously not, but haven't found any evidence yet) and that usually happens after some tries.

My Design:

  • Each Menu class contains two methods. InventoryClick is called when a menu display is clicked (interacted). InventoryConstruct is called when a menu is being created (opened).
  • The Purchase Menu class contains two methods as well. PurchaseProduct is called when a display is purchased successfully. PrePaymentChecks is necessary checks that need to be ran before the purchase.

My questions:

  • How do I patch that problem, and save the correct Kit in a private field of the class?
  • How can I improve my design (approach) in certain projects to avoid such problems?

Any form of help is appreciated, I hope I described my problem in detail, if you require any further source code, please post a comment below.

Update

Because of the fact that the question will be more than 30k characters, I uploaded the whole project into a Git repository.

https://github.com/parat26/core

Menu.java: https://github.com/parat26/core/blob/master/src/src/ares/core/menu/Menu.java

PurchaseMenu.java:https://github.com/parat26/core/blob/master/src/src/ares/core/menu/PurchaseMenu.java

BattleOptionsMenu.java: https://github.com/parat26/core/blob/master/src/src/ares/core/menu/type/MenuBattleOptions.java

PurchaseMenuKit.java: https://github.com/parat26/core/blob/master/src/src/ares/core/menu/type/PurchaseMenuKit.java

like image 915
Thanos Paravantis Avatar asked Mar 27 '15 22:03

Thanos Paravantis


1 Answers

Try changing PurchaseMenu.object to final and see what the output is. Also, System.out.println() is your friend.

I do not suggest you use Object for your kit as it may be changing the object when you set object to sellableKit. Make an interface called Sellable<T> so that you can enforce the type (called Strong Typing) with:

private final ItemStack item;
protected final Sellable<? super Kit> kit;
private final GoldCurrency currency;

public PurchaseMenu(String menuName, ItemStack sellableItem, Sellable<? super Kit> sellableKit, GoldCurrency currencyType)
{
    super(Material.STONE, menuName, 54);

    item = sellableItem;
    kit = sellableKit;
    currency = currencyType;

    DependOnEvents(true);
}

Making those fields final also is good practice since it doesn't appear that you are setting those fields after object creation and lets anyone know immediately those objects will never change. It should also enlighten the situation since a final object cannot be changed.

You should remove the private Kit kit; field from BuyKitOwnershipMenu since your just making a copy of the object. Your PurchaseProduct() method can be changed to

@Override
    public void PurchaseProduct(GoldCurrency currency, Client client)
    {
        client.getManager().setKitOwned(kit, true);
    }

Since kit is now protected and in the super class.

like image 133
AMDG Avatar answered Sep 18 '22 00:09

AMDG