Search in sources :

Example 26 with Transaction

use of org.spongepowered.api.data.Transaction in project SpongeCommon by SpongePowered.

the class PlaceRecipeTransaction method createInventoryEvent.

@Override
Optional<ClickContainerEvent> createInventoryEvent(final List<SlotTransaction> slotTransactions, final List<Entity> entities, final PhaseContext<@NonNull ?> context, final Cause cause) {
    final SlotTransaction preview = this.getPreviewTransaction(this.craftingInventory.result(), slotTransactions);
    final Transaction<ItemStackSnapshot> cursorTransaction = new Transaction<>(this.originalCursor, ItemStackUtil.snapshotOf(this.player.inventory.getCarried()));
    ClickContainerEvent.Recipe event;
    if (this.shift) {
        event = SpongeEventFactory.createClickContainerEventRecipeAll(cause, (Container) this.menu, this.craftingInventory, cursorTransaction, preview, Optional.of((CraftingRecipe) this.recipe), Optional.empty(), slotTransactions);
    } else {
        event = SpongeEventFactory.createClickContainerEventRecipeSingle(cause, (Container) this.menu, this.craftingInventory, cursorTransaction, preview, Optional.of((CraftingRecipe) this.recipe), Optional.empty(), slotTransactions);
    }
    return Optional.of(event);
}
Also used : Container(org.spongepowered.api.item.inventory.Container) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Transaction(org.spongepowered.api.data.Transaction) ClickContainerEvent(org.spongepowered.api.event.item.inventory.container.ClickContainerEvent) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction)

Example 27 with Transaction

use of org.spongepowered.api.data.Transaction in project SpongeCommon by SpongePowered.

the class SelectTradeTransaction method createInventoryEvent.

@Override
Optional<ClickContainerEvent> createInventoryEvent(final List<SlotTransaction> slotTransactions, final List<Entity> entities, final PhaseContext<@NonNull ?> context, final Cause cause) {
    final ItemStackSnapshot cursorItem = ItemStackUtil.snapshotOf(this.player.inventory.getCarried());
    final Transaction<ItemStackSnapshot> cursorTransaction = new Transaction<>(cursorItem, cursorItem);
    if (this.menu instanceof MerchantMenu) {
        final MerchantOffer offer = ((MerchantMenu) this.menu).getOffers().get(this.tradeItem);
        final ClickContainerEvent.SelectTrade event = SpongeEventFactory.createClickContainerEventSelectTrade(cause, (Container) this.menu, cursorTransaction, Optional.empty(), (TradeOffer) offer, slotTransactions, this.tradeItem);
        return Optional.of(event);
    }
    SpongeCommon.logger().warn("SelectTradeTransaction without MerchantMenu");
    return Optional.empty();
}
Also used : MerchantMenu(net.minecraft.world.inventory.MerchantMenu) MerchantOffer(net.minecraft.world.item.trading.MerchantOffer) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Transaction(org.spongepowered.api.data.Transaction) ClickContainerEvent(org.spongepowered.api.event.item.inventory.container.ClickContainerEvent) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot)

Example 28 with Transaction

use of org.spongepowered.api.data.Transaction in project SpongeCommon by SpongePowered.

the class AbstractFurnaceBlockEntityMixin method impl$throwFuelEventIfOrShrink.

// @Formatter:on
// Shrink Fuel
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;shrink(I)V"))
private void impl$throwFuelEventIfOrShrink(final ItemStack itemStack, final int quantity) {
    final Cause cause = PhaseTracker.getCauseStackManager().currentCause();
    final ItemStackSnapshot fuel = ItemStackUtil.snapshotOf(itemStack);
    final ItemStackSnapshot shrinkedFuel = ItemStackUtil.snapshotOf(ItemStackUtil.cloneDefensive(itemStack, itemStack.getCount() - 1));
    final Transaction<ItemStackSnapshot> transaction = new Transaction<>(fuel, shrinkedFuel);
    final AbstractCookingRecipe recipe = this.impl$getCurrentRecipe();
    final CookingEvent.ConsumeFuel event = SpongeEventFactory.createCookingEventConsumeFuel(cause, (FurnaceBlockEntity) this, Optional.of(fuel), Optional.of((CookingRecipe) recipe), Collections.singletonList(transaction));
    SpongeCommon.post(event);
    if (event.isCancelled()) {
        this.cookingTotalTime = 0;
        return;
    }
    if (!transaction.isValid()) {
        return;
    }
    if (transaction.custom().isPresent()) {
        this.items.set(1, ItemStackUtil.fromSnapshotToNative(transaction.finalReplacement()));
    } else {
        // vanilla
        itemStack.shrink(quantity);
    }
}
Also used : Transaction(org.spongepowered.api.data.Transaction) CookingRecipe(org.spongepowered.api.item.recipe.cooking.CookingRecipe) AbstractCookingRecipe(net.minecraft.world.item.crafting.AbstractCookingRecipe) Cause(org.spongepowered.api.event.Cause) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) AbstractCookingRecipe(net.minecraft.world.item.crafting.AbstractCookingRecipe) CookingEvent(org.spongepowered.api.event.block.entity.CookingEvent) Redirect(org.spongepowered.asm.mixin.injection.Redirect)

Example 29 with Transaction

use of org.spongepowered.api.data.Transaction in project SpongeCommon by SpongePowered.

the class BrewingStandBlockEntityMixin method impl$onConsumeFuel.

// @Formatter:on
@Inject(method = "tick", locals = LocalCapture.CAPTURE_FAILEXCEPTION, slice = @Slice(to = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;isBrewable()Z")), at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/entity/BrewingStandBlockEntity;setChanged()V"))
private void impl$onConsumeFuel(CallbackInfo ci, ItemStack fuelStack) {
    final Cause currentCause = Sponge.server().causeStackManager().currentCause();
    fuelStack.grow(1);
    final ItemStackSnapshot originalStack = ItemStackUtil.snapshotOf(fuelStack);
    fuelStack.shrink(1);
    final Transaction<ItemStackSnapshot> fuelTransaction = new Transaction<>(originalStack, ItemStackUtil.snapshotOf(fuelStack));
    final ItemStackSnapshot ingredientStack = ItemStackUtil.snapshotOf(this.items.get(3));
    final BrewingEvent.ConsumeFuel event = SpongeEventFactory.createBrewingEventConsumeFuel(currentCause, (BrewingStand) this, fuelTransaction, ingredientStack);
    if (Sponge.eventManager().post(event)) {
        fuelStack.grow(1);
        this.fuel = 0;
    } else if (event.fuel().custom().isPresent()) {
        final ItemStackSnapshot finalFuel = event.fuel().finalReplacement();
        this.items.set(4, ItemStackUtil.fromSnapshotToNative(finalFuel));
    }
}
Also used : Transaction(org.spongepowered.api.data.Transaction) BrewingEvent(org.spongepowered.api.event.block.entity.BrewingEvent) Cause(org.spongepowered.api.event.Cause) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) Inject(org.spongepowered.asm.mixin.injection.Inject)

Example 30 with Transaction

use of org.spongepowered.api.data.Transaction in project SpongeCommon by SpongePowered.

the class TrackingUtil method processBlockCaptures.

/**
 * Processes the given list of {@link BlockSnapshot}s and creates and throws and processes
 * the {@link ChangeBlockEvent}s as appropriately determined based on the {@link BlockChange}
 * for each snapshot. If any transactions are invalid or events cancelled, this event
 * returns {@code false} to signify a transaction was cancelled. This return value
 * is used for portal creation.
 *
 * @param snapshots The snapshots to process
 * @param state The phase state that is being processed, used to handle marking notifiers
 *  and block owners
 * @param context The phase context, only used by the phase for handling processes.
 * @return True if no events or transactions were cancelled
 */
@SuppressWarnings({ "unchecked" })
public static boolean processBlockCaptures(List<BlockSnapshot> snapshots, IPhaseState<?> state, PhaseContext<?> context) {
    if (snapshots.isEmpty()) {
        return false;
    }
    ImmutableList<Transaction<BlockSnapshot>>[] transactionArrays = new ImmutableList[EVENT_COUNT];
    ImmutableList.Builder<Transaction<BlockSnapshot>>[] transactionBuilders = new ImmutableList.Builder[EVENT_COUNT];
    for (int i = 0; i < EVENT_COUNT; i++) {
        transactionBuilders[i] = new ImmutableList.Builder<>();
    }
    final List<ChangeBlockEvent> blockEvents = new ArrayList<>();
    for (BlockSnapshot snapshot : snapshots) {
        // This processes each snapshot to assign them to the correct event in the next area, with the
        // correct builder array entry.
        TRANSACTION_PROCESSOR.apply(transactionBuilders).accept(TRANSACTION_CREATION.apply(snapshot));
    }
    for (int i = 0; i < EVENT_COUNT; i++) {
        // Build each event array
        transactionArrays[i] = transactionBuilders[i].build();
    }
    // Clear captured snapshots after processing them
    context.getCapturedBlocksOrEmptyList().clear();
    final ChangeBlockEvent[] mainEvents = new ChangeBlockEvent[BlockChange.values().length];
    // case in point for WorldTick event listeners since the players are captured non-deterministically
    try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        if (context.getNotifier().isPresent()) {
            Sponge.getCauseStackManager().addContext(EventContextKeys.NOTIFIER, context.getNotifier().get());
        }
        if (context.getOwner().isPresent()) {
            Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, context.getOwner().get());
        }
        try {
            state.associateAdditionalCauses(state, context);
        } catch (Exception e) {
        // TODO - this should be a thing to associate additional objects in the cause, or context, but for now it's just a simple
        // try catch to avoid bombing on performing block changes.
        }
        // Creates the block events accordingly to the transaction arrays
        // Needs to throw events
        iterateChangeBlockEvents(transactionArrays, blockEvents, mainEvents);
        // We create the post event and of course post it in the method, regardless whether any transactions are invalidated or not
        final ChangeBlockEvent.Post postEvent = throwMultiEventsAndCreatePost(transactionArrays, blockEvents, mainEvents);
        if (postEvent == null) {
            // Means that we have had no actual block changes apparently?
            return false;
        }
        final List<Transaction<BlockSnapshot>> invalid = new ArrayList<>();
        boolean noCancelledTransactions = true;
        // transactions of the preceeding block events)
        for (ChangeBlockEvent blockEvent : blockEvents) {
            // Need to only check if the event is cancelled, If it is, restore
            if (blockEvent.isCancelled()) {
                noCancelledTransactions = false;
                // Don't restore the transactions just yet, since we're just marking them as invalid for now
                for (Transaction<BlockSnapshot> transaction : Lists.reverse(blockEvent.getTransactions())) {
                    transaction.setValid(false);
                }
            }
        }
        // Finally check the post event
        if (postEvent.isCancelled()) {
            // Of course, if post is cancelled, just mark all transactions as invalid.
            noCancelledTransactions = false;
            for (Transaction<BlockSnapshot> transaction : postEvent.getTransactions()) {
                transaction.setValid(false);
            }
        }
        // Because after, we will restore all the invalid transactions in reverse order.
        for (Transaction<BlockSnapshot> transaction : postEvent.getTransactions()) {
            if (!transaction.isValid()) {
                invalid.add(transaction);
                // Cancel any block drops performed, avoids any item drops, regardless
                final Location<World> location = transaction.getOriginal().getLocation().orElse(null);
                if (location != null) {
                    final BlockPos pos = ((IMixinLocation) (Object) location).getBlockPos();
                    context.getBlockItemDropSupplier().removeAllIfNotEmpty(pos);
                    context.getBlockEntitySpawnSupplier().removeAllIfNotEmpty(pos);
                    context.getBlockEntitySpawnSupplier().removeAllIfNotEmpty(pos);
                }
            }
        }
        if (!invalid.isEmpty()) {
            // We need to set this value and return it to signify that some transactions were cancelled
            noCancelledTransactions = false;
            // or the events were cancelled), again in reverse order of which they were received.
            for (Transaction<BlockSnapshot> transaction : Lists.reverse(invalid)) {
                transaction.getOriginal().restore(true, BlockChangeFlags.NONE);
                if (state.tracksBlockSpecificDrops()) {
                    // Cancel any block drops or harvests for the block change.
                    // This prevents unnecessary spawns.
                    final Location<World> location = transaction.getOriginal().getLocation().orElse(null);
                    if (location != null) {
                        final BlockPos pos = ((IMixinLocation) (Object) location).getBlockPos();
                        context.getBlockDropSupplier().removeAllIfNotEmpty(pos);
                    }
                }
            }
        }
        return performBlockAdditions(postEvent.getTransactions(), state, context, noCancelledTransactions);
    }
}
Also used : StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame) IMixinLocation(org.spongepowered.common.interfaces.world.IMixinLocation) ImmutableList(com.google.common.collect.ImmutableList) SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) BlockSnapshot(org.spongepowered.api.block.BlockSnapshot) ArrayList(java.util.ArrayList) World(org.spongepowered.api.world.World) ChangeBlockEvent(org.spongepowered.api.event.block.ChangeBlockEvent) Transaction(org.spongepowered.api.data.Transaction) CauseStackManager(org.spongepowered.api.event.CauseStackManager) BlockPos(net.minecraft.util.math.BlockPos)

Aggregations

Transaction (org.spongepowered.api.data.Transaction)50 ItemStackSnapshot (org.spongepowered.api.item.inventory.ItemStackSnapshot)32 SlotTransaction (org.spongepowered.api.item.inventory.transaction.SlotTransaction)28 World (org.spongepowered.api.world.World)18 ArrayList (java.util.ArrayList)15 BlockSnapshot (org.spongepowered.api.block.BlockSnapshot)14 CauseStackManager (org.spongepowered.api.event.CauseStackManager)11 Entity (org.spongepowered.api.entity.Entity)10 ClickInventoryEvent (org.spongepowered.api.event.item.inventory.ClickInventoryEvent)10 ChangeBlockEvent (org.spongepowered.api.event.block.ChangeBlockEvent)9 List (java.util.List)8 BlockPos (net.minecraft.util.math.BlockPos)8 SpongeEventFactory (org.spongepowered.api.event.SpongeEventFactory)8 ItemStack (org.spongepowered.api.item.inventory.ItemStack)8 CauseStack (org.lanternpowered.server.event.CauseStack)7 Sponge (org.spongepowered.api.Sponge)7 Player (org.spongepowered.api.entity.living.player.Player)7 SpawnEntityEvent (org.spongepowered.api.event.entity.SpawnEntityEvent)7 ImmutableList (com.google.common.collect.ImmutableList)6 LanternPlayer (org.lanternpowered.server.entity.living.player.LanternPlayer)6