I’ll do my best to make this understandable (it’s a lot of custom code).
So first, the event listener:
@Listener
public void onClick(ClickInventoryEvent event, @First Player player){
ItemStackSnapshot itemStack = event.getCursorTransaction().getFinal();
if(itemStack.get(AtlasKeys.CLICK_ACTION).isPresent()){
if(itemStack.get(AtlasKeys.CLICK_ACTION).get().perform(event, AtlasInventory.ClickType.getClickTypeFor(event), player,
event.getTransactions().get(0), itemStack, null)){
event.setCancelled(true);
}
}
}
As far as I can tell, everything here, including the custom Data, works well except when trying to cancel the event. If I comment that out, the error doesn’t get thrown.
Here’s the external method which I call in the above code:
@Override
public boolean perform(ClickInventoryEvent event, AtlasInventory.ClickType clickType, Player player,
SlotTransaction slotTransaction, ItemStackSnapshot item, AtlasInventory atlasInventory) {
/**
* Return TRUE if event should be cancelled.
*/
Formatter.debug("1");
Slot slot = slotTransaction.getSlot();
int index = slot.getInventoryProperty(SlotIndex.class).get().getValue();
if(clickType == AtlasInventory.ClickType.PRIMARY){
Formatter.debug("2");
if(!item.get(AtlasKeys.CURRENT_PRICE).isPresent()){
Formatter.debug("3");
return true;
}
double price = item.get(AtlasKeys.CURRENT_PRICE).get();
TransactionService transactionService = AtlasCore.INSTANCE.getEconomyService().getTransactionService();
Optional<Account> account = transactionService.findAccount(player.getUniqueId());
if(!account.isPresent()){
Formatter.debug("4");
return true;
}
EconomyEvent.PlayerBuyItem.Pre e = new EconomyEvent.PlayerBuyItem.Pre(account.get(), event.getCursorTransaction().getFinal());
Sponge.getEventManager().post(e);
if(!e.isCancelled()){
if(!transactionService.withdraw(player.getUniqueId(), price)){
Formatter.debug("5");
return true;
}
//We've now withdrawn the money needed for this item.
if(item.get(AtlasKeys.SUPPLY).get() > 1){
vItem.decreaseSupply(1);
Formatter.debug("6");
return true;
} else {
vItem.setSupply(0);
Formatter.debug("7");
return false;
}
}
}
return true;
}
From what I can tell with my debug messages, it gets through all this code fine. I’m wanting this to get to debug number 6 and it does that (all the correct messages leading up to that point are printed in console). It just has something to do with canceling this event and I cannot figure it out.
I’ll provide my DataManipulator code below, although no errors are being thrown when offering or getting my custom data from the ItemStack, so I am to assume that’s working fine. But nonetheless, I’ll provide it. Thanks for the help!
My mutable AbstractData:
public class VendorShopItemData extends AbstractData<VendorShopItemData, ImmutableVendorShopItemData> {
private AtlasInventory.ClickAction itemClickAction;
private double currentPrice;
private double vendorPrice;
private int supply;
public VendorShopItemData(){
this(0, 0, 0, null);
}
public VendorShopItemData(double currentPrices, double vendorPrice, int supply, AtlasInventory.ClickAction clickAction) {
this.itemClickAction = clickAction;
this.currentPrice = currentPrices;
this.vendorPrice = vendorPrice;
this.supply = supply;
registerGettersAndSetters();
}
public AtlasInventory.ClickAction getItemClickAction() {
return itemClickAction;
}
public double getCurrentPrice() {
return currentPrice;
}
public double getVendorPrice() {
return vendorPrice;
}
public int getSupply() {
return supply;
}
public void setItemClickAction(AtlasInventory.ClickAction itemClickAction) {
this.itemClickAction = itemClickAction;
}
public void setCurrentPrice(double currentPrice) {
this.currentPrice = currentPrice;
}
public void setVendorPrice(double vendorPrice) {
this.vendorPrice = vendorPrice;
}
public void setSupply(int supply) {
this.supply = supply;
}
protected Value<AtlasInventory.ClickAction> clickAction(){
return this.itemClickAction == null ? null : Sponge.getRegistry().getValueFactory().createValue(AtlasKeys.CLICK_ACTION, this.itemClickAction);
}
protected Value<Double> currentPrice() {
return Sponge.getRegistry().getValueFactory().createValue(AtlasKeys.CURRENT_PRICE, this.currentPrice);
}
protected Value<Double> vendorPrice() {
return Sponge.getRegistry().getValueFactory().createValue(AtlasKeys.VENDOR_PRICE, this.vendorPrice);
}
protected Value<Integer> supply(){
return Sponge.getRegistry().getValueFactory().createValue(AtlasKeys.SUPPLY, this.supply);
}
@Override
protected void registerGettersAndSetters() {
registerFieldGetter(AtlasKeys.CLICK_ACTION, this::getItemClickAction);
registerFieldSetter(AtlasKeys.CLICK_ACTION, this::setItemClickAction);
registerKeyValue(AtlasKeys.CLICK_ACTION, this::clickAction);
registerFieldGetter(AtlasKeys.CURRENT_PRICE, this::getCurrentPrice);
registerFieldSetter(AtlasKeys.CURRENT_PRICE, this::setCurrentPrice);
registerKeyValue(AtlasKeys.CURRENT_PRICE, this::currentPrice);
registerFieldGetter(AtlasKeys.VENDOR_PRICE, this::getVendorPrice);
registerFieldSetter(AtlasKeys.VENDOR_PRICE, this::setVendorPrice);
registerKeyValue(AtlasKeys.VENDOR_PRICE, this::vendorPrice);
registerFieldGetter(AtlasKeys.SUPPLY, this::getSupply);
registerFieldSetter(AtlasKeys.SUPPLY, this::setSupply);
registerKeyValue(AtlasKeys.SUPPLY, this::supply);
}
@Override
public Optional<VendorShopItemData> fill(DataHolder dataHolder) {
return Optional.ofNullable(dataHolder.get(VendorShopItemData.class).orElse(null));
}
@Override
public Optional<VendorShopItemData> fill(DataHolder dataHolder, MergeFunction overlap) {
VendorShopItemData vendorShopItemData = overlap.merge(this, dataHolder.get(VendorShopItemData.class).orElse(null));
setItemClickAction(vendorShopItemData.getItemClickAction());
setCurrentPrice(vendorShopItemData.getCurrentPrice());
setVendorPrice(vendorShopItemData.getVendorPrice());
setSupply(vendorShopItemData.getSupply());
return Optional.of(this);
}
@Override
public Optional<VendorShopItemData> from(DataContainer container) {
if(container.contains(AtlasKeys.CLICK_ACTION, AtlasKeys.INITIAL_PRICE, AtlasKeys.CURRENT_PRICE,
AtlasKeys.VENDOR_PRICE, AtlasKeys.SUPPLY)){
setItemClickAction((AtlasInventory.ClickAction) container.get(AtlasKeys.CLICK_ACTION.getQuery()).get());
setCurrentPrice(container.getDouble(AtlasKeys.CURRENT_PRICE.getQuery()).get());
setVendorPrice(container.getDouble(AtlasKeys.VENDOR_PRICE.getQuery()).get());
setSupply(container.getInt(AtlasKeys.SUPPLY.getQuery()).get());
return Optional.of(this);
}
return Optional.empty();
}
@Override
public VendorShopItemData copy() {
return new VendorShopItemData(getCurrentPrice(), getVendorPrice(), getSupply(), getItemClickAction());
}
@Override
public ImmutableVendorShopItemData asImmutable() {
return new ImmutableVendorShopItemData();
}
@Override
public int getContentVersion() {
return 1;
}
}
My Immutable AbstractData:
public class ImmutableVendorShopItemData extends AbstractImmutableData<ImmutableVendorShopItemData, VendorShopItemData> {
private final AtlasInventory.ClickAction itemClickAction;
private final double currentPrice;
private final double vendorPrice;
private final int supply;
public ImmutableVendorShopItemData(){
this(null, 0, 0, 0);
}
public ImmutableVendorShopItemData(AtlasInventory.ClickAction clickAction, double currentPrice, double vendorPrice, int supply) {
this.itemClickAction = clickAction;
this.currentPrice = currentPrice;
this.vendorPrice = vendorPrice;
this.supply = supply;
registerGetters();
}
public AtlasInventory.ClickAction getItemClickAction() {
return itemClickAction;
}
public double getCurrentPrice() {
return currentPrice;
}
public double getVendorPrice() {
return vendorPrice;
}
public int getSupply() {
return supply;
}
protected ImmutableValue<AtlasInventory.ClickAction> clickAction(){
return Sponge.getRegistry().getValueFactory()
.createValue(AtlasKeys.CLICK_ACTION, this.itemClickAction)
.asImmutable();
}
protected ImmutableValue<Double> currentPrices() {
return Sponge.getRegistry().getValueFactory().createValue(AtlasKeys.CURRENT_PRICE, this.currentPrice).asImmutable();
}
protected ImmutableValue<Double> vendorPrices() {
return Sponge.getRegistry().getValueFactory().createValue(AtlasKeys.VENDOR_PRICE, this.vendorPrice).asImmutable();
}
protected ImmutableValue<Integer> supply(){
return Sponge.getRegistry().getValueFactory().createValue(AtlasKeys.SUPPLY, this.supply).asImmutable();
}
@Override
protected void registerGetters() {
registerFieldGetter(AtlasKeys.CLICK_ACTION, this::getItemClickAction);
registerKeyValue(AtlasKeys.CLICK_ACTION, this::clickAction);
registerFieldGetter(AtlasKeys.CURRENT_PRICE, this::getCurrentPrice);
registerKeyValue(AtlasKeys.CURRENT_PRICE, this::currentPrices);
registerFieldGetter(AtlasKeys.VENDOR_PRICE, this::getVendorPrice);
registerKeyValue(AtlasKeys.VENDOR_PRICE, this::vendorPrices);
registerFieldGetter(AtlasKeys.SUPPLY, this::getSupply);
registerKeyValue(AtlasKeys.SUPPLY, this::supply);
}
@Override
public VendorShopItemData asMutable() {
return new VendorShopItemData(currentPrice, vendorPrice, supply, null);
}
@Override
public int getContentVersion() {
return 1;
}
@Override
public DataContainer toContainer(){
return super.toContainer().set(AtlasKeys.CLICK_ACTION.getQuery(), this.itemClickAction)
.set(AtlasKeys.CURRENT_PRICE.getQuery(), this.currentPrice)
.set(AtlasKeys.VENDOR_PRICE.getQuery(), this.vendorPrice)
.set(AtlasKeys.SUPPLY.getQuery(), this.supply);
}
}
My Builder for this data:
public class VendorShopItemDataBuilder extends AbstractDataBuilder<VendorShopItemData> implements DataManipulatorBuilder<VendorShopItemData, ImmutableVendorShopItemData> {
public VendorShopItemDataBuilder() {
super(VendorShopItemData.class, 1);
}
@Override
public VendorShopItemData create() {
return new VendorShopItemData(0, 0, 0, null);
}
@Override
public Optional<VendorShopItemData> createFrom(DataHolder dataHolder) {
return create().fill(dataHolder);
}
@Override
protected Optional<VendorShopItemData> buildContent(DataView container) throws InvalidDataException {
return create().from(container.getContainer());
}
}
And now my Keys:
public class AtlasKeys {
public static final Key<Value<AtlasInventory.ClickAction>> CLICK_ACTION = Key.builder()
.type(new TypeToken<Value<AtlasInventory.ClickAction>>(){})
.id("click_action")
.name("Click Action")
.query(DataQuery.of(".", "click.action"))
.build();
/**
* This is the initial price an item started selling at when it first entered a {@link com.atlas.atlascore.economy.ai.Market}.
*/
public static final Key<Value<Double>> INITIAL_PRICE = Key.builder()
.type(new TypeToken<Value<Double>>(){})
.id("initial_price")
.name("Initial Price")
.query(DataQuery.of(".", "initial.price"))
.build();
/**
* This is the price a {@link com.atlas.atlascore.economy.ai.vendor.Vendor} is selling a particular item.
*/
public static final Key<Value<Double>> VENDOR_PRICE = Key.builder()
.type(new TypeToken<Value<Double>>(){})
.id("vendor_price")
.name("Vendor Price")
.query(DataQuery.of(".", "vendor.price"))
.build();
/**
* This is the current average price of an item among all Vendors within a given {@link com.atlas.atlascore.economy.ai.Market}.
*/
public static final Key<Value<Double>> CURRENT_PRICE = Key.builder()
.type(new TypeToken<Value<Double>>(){})
.id("current_price")
.name("Current Price")
.query(DataQuery.of(".", "current.price"))
.build();
/**
* This is the supply of a {@link com.atlas.atlascore.economy.ai.vendor.VendorItem}
* that a {@link com.atlas.atlascore.economy.ai.vendor.Vendor} has.
*/
public static final Key<Value<Integer>> SUPPLY = Key.builder()
.type(TypeTokens.INTEGER_VALUE_TOKEN)
.id("supply")
.name("Supply")
.query(DataQuery.of("", "supply"))
.build();
}
Finally, the registration in GamePreInitializationEvent:
private void registerData(){
DataRegistration.builder()
.dataName("Vendor Shop Item Data")
.manipulatorId("vendor_shop_item_data")
.dataClass(VendorShopItemData.class)
.immutableClass(ImmutableVendorShopItemData.class)
.builder(new VendorShopItemDataBuilder())
.buildAndRegister(pluginContainer);
}