Search in sources :

Example 1 with Transaction

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

the class TrackingUtil method throwMultiEventsAndCreatePost.

public static ChangeBlockEvent.Post throwMultiEventsAndCreatePost(ImmutableList<Transaction<BlockSnapshot>>[] transactionArrays, List<ChangeBlockEvent> blockEvents, ChangeBlockEvent[] mainEvents) {
    if (!blockEvents.isEmpty()) {
        try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
            for (BlockChange blockChange : BlockChange.values()) {
                final ChangeBlockEvent mainEvent = mainEvents[blockChange.ordinal()];
                if (mainEvent != null) {
                    Sponge.getCauseStackManager().pushCause(mainEvent);
                }
            }
            final ImmutableList<Transaction<BlockSnapshot>> transactions = transactionArrays[MULTI_CHANGE_INDEX];
            final ChangeBlockEvent.Post post = SpongeEventFactory.createChangeBlockEventPost(Sponge.getCauseStackManager().getCurrentCause(), transactions);
            SpongeImpl.postEvent(post);
            return post;
        }
    }
    return null;
}
Also used : ChangeBlockEvent(org.spongepowered.api.event.block.ChangeBlockEvent) BlockChange(org.spongepowered.common.world.BlockChange) Transaction(org.spongepowered.api.data.Transaction) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame)

Example 2 with Transaction

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

the class GeneralPhase method processBlockTransactionListsPost.

/**
 *  @param snapshotsToProcess
 * @param unwindingState
 * @param unwinding
 */
@SuppressWarnings({ "unchecked" })
public static void processBlockTransactionListsPost(PhaseContext<?> postContext, List<BlockSnapshot> snapshotsToProcess, IPhaseState<?> unwindingState, PhaseContext<?> unwinding) {
    final List<Transaction<BlockSnapshot>> invalidTransactions = new ArrayList<>();
    ImmutableList<Transaction<BlockSnapshot>>[] transactionArrays = new ImmutableList[TrackingUtil.EVENT_COUNT];
    ImmutableList.Builder<Transaction<BlockSnapshot>>[] transactionBuilders = new ImmutableList.Builder[TrackingUtil.EVENT_COUNT];
    for (int i = 0; i < TrackingUtil.EVENT_COUNT; i++) {
        transactionBuilders[i] = new ImmutableList.Builder<>();
    }
    final List<ChangeBlockEvent> blockEvents = new ArrayList<>();
    for (BlockSnapshot snapshot : snapshotsToProcess) {
        // This processes each snapshot to assign them to the correct event in the next area, with the
        // correct builder array entry.
        TrackingUtil.TRANSACTION_PROCESSOR.apply(transactionBuilders).accept(TrackingUtil.TRANSACTION_CREATION.apply(snapshot));
    }
    for (int i = 0; i < TrackingUtil.EVENT_COUNT; i++) {
        // Build each event array
        transactionArrays[i] = transactionBuilders[i].build();
    }
    // Clear captured snapshots after processing them
    postContext.getCapturedBlocksOrEmptyList().clear();
    final ChangeBlockEvent[] mainEvents = new ChangeBlockEvent[BlockChange.values().length];
    // This likely needs to delegate to the phase in the event we don't use the source object as the main object causing the block changes
    // case in point for WorldTick event listeners since the players are captured non-deterministically
    // Creates the block events accordingly to the transaction arrays
    TrackingUtil.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 = TrackingUtil.throwMultiEventsAndCreatePost(transactionArrays, blockEvents, mainEvents);
    if (postEvent == null) {
        // Means that we have had no actual block changes apparently?
        return;
    }
    // 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()) {
            // 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.
        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()) {
            invalidTransactions.add(transaction);
        }
    }
    if (!invalidTransactions.isEmpty()) {
        // or the events were cancelled), again in reverse order of which they were received.
        for (Transaction<BlockSnapshot> transaction : Lists.reverse(invalidTransactions)) {
            transaction.getOriginal().restore(true, BlockChangeFlags.NONE);
            if (unwindingState.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) {
                    // Cancel any block drops performed, avoids any item drops, regardless
                    final BlockPos pos = ((IMixinLocation) (Object) location).getBlockPos();
                    postContext.getBlockDropSupplier().removeAllIfNotEmpty(pos);
                }
            }
        }
        invalidTransactions.clear();
    }
    performPostBlockAdditions(postContext, postEvent.getTransactions(), unwindingState, unwinding);
}
Also used : IMixinLocation(org.spongepowered.common.interfaces.world.IMixinLocation) ImmutableList(com.google.common.collect.ImmutableList) ArrayList(java.util.ArrayList) SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) BlockSnapshot(org.spongepowered.api.block.BlockSnapshot) World(org.spongepowered.api.world.World) ChangeBlockEvent(org.spongepowered.api.event.block.ChangeBlockEvent) Transaction(org.spongepowered.api.data.Transaction) BlockPos(net.minecraft.util.math.BlockPos)

Example 3 with Transaction

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

the class EnchantItemPacketState method unwind.

@Override
public void unwind(InventoryPacketContext context) {
    // TODO - Pre changes of merging PacketFunction into the phase states, enchantments did NOT have any processing....
    final EntityPlayerMP player = context.getPacketPlayer();
    // The server will disable the player's crafting after receiving a
    // client packet
    // that did not pass validation (server click item != packet click item)
    // The server then sends a SPacketConfirmTransaction and waits for a
    // CPacketConfirmTransaction to re-enable crafting confirming that the
    // client
    // acknowledged the denied transaction.
    // To detect when this happens, we turn off capturing so we can avoid
    // firing
    // invalid events.
    // See MixinNetHandlerPlayServer processClickWindow redirect for rest of
    // fix.
    // --bloodmc
    final IMixinContainer mixinContainer = ContainerUtil.toMixin(player.openContainer);
    if (!mixinContainer.capturingInventory()) {
        mixinContainer.getCapturedTransactions().clear();
        return;
    }
    // TODO clear this shit out of the context
    final CPacketEnchantItem packetIn = context.getPacket();
    final ItemStackSnapshot lastCursor = context.getCursor();
    final ItemStackSnapshot newCursor = ItemStackUtil.snapshotOf(player.inventory.getItemStack());
    final Transaction<ItemStackSnapshot> transaction = new Transaction<>(lastCursor, newCursor);
    final net.minecraft.inventory.Container openContainer = player.openContainer;
    final List<SlotTransaction> slotTransactions = mixinContainer.getCapturedTransactions();
    final int usedButton = packetIn.getButton();
    final List<Entity> capturedItems = new ArrayList<>();
    for (EntityItem entityItem : context.getCapturedItems()) {
        capturedItems.add(EntityUtil.fromNative(entityItem));
    }
    try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().pushCause(player);
        Sponge.getCauseStackManager().pushCause(openContainer);
        final ClickInventoryEvent inventoryEvent;
        inventoryEvent = this.createInventoryEvent(player, ContainerUtil.fromNative(openContainer), transaction, Lists.newArrayList(slotTransactions), capturedItems, usedButton);
        // If this happens and we captured no entities, avoid firing events
        if (mixinContainer.getCapturedTransactions().isEmpty() && capturedItems.isEmpty()) {
            mixinContainer.setCaptureInventory(false);
            return;
        }
        if (inventoryEvent != null) {
            // Don't fire inventory drop events when there are no entities
            if (inventoryEvent instanceof AffectEntityEvent && ((AffectEntityEvent) inventoryEvent).getEntities().isEmpty()) {
                slotTransactions.clear();
                mixinContainer.setCaptureInventory(false);
                return;
            }
            // packet has everything we want.
            if (!(inventoryEvent instanceof ClickInventoryEvent.Drag)) {
                PacketPhaseUtil.validateCapturedTransactions(packetIn.getWindowId(), openContainer, inventoryEvent.getTransactions());
            }
            SpongeImpl.postEvent(inventoryEvent);
            if (inventoryEvent.isCancelled() || PacketPhaseUtil.allTransactionsInvalid(inventoryEvent.getTransactions())) {
                if (inventoryEvent instanceof ClickInventoryEvent.Drop) {
                    capturedItems.clear();
                }
                // Restore cursor
                PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getOriginal());
                // Restore target slots
                PacketPhaseUtil.handleSlotRestore(player, openContainer, inventoryEvent.getTransactions(), true);
            } else {
                PacketPhaseUtil.handleSlotRestore(player, openContainer, inventoryEvent.getTransactions(), false);
                // Handle cursor
                if (!inventoryEvent.getCursorTransaction().isValid()) {
                    PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getOriginal());
                } else if (inventoryEvent.getCursorTransaction().getCustom().isPresent()) {
                    PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getFinal());
                } else if (inventoryEvent instanceof ClickInventoryEvent.Drag) {
                    int increment;
                    increment = slotTransactions.stream().filter((t) -> !t.isValid()).mapToInt((t) -> t.getFinal().getQuantity()).sum();
                    final ItemStack cursor = inventoryEvent.getCursorTransaction().getFinal().createStack();
                    cursor.setQuantity(cursor.getQuantity() + increment);
                    PacketPhaseUtil.handleCustomCursor(player, cursor.createSnapshot());
                } else if (inventoryEvent instanceof ClickInventoryEvent.Double && !(inventoryEvent instanceof ClickInventoryEvent.Shift)) {
                    int decrement;
                    decrement = slotTransactions.stream().filter((t) -> !t.isValid()).mapToInt((t) -> t.getOriginal().getQuantity()).sum();
                    final ItemStack cursor = inventoryEvent.getCursorTransaction().getFinal().createStack();
                    cursor.setQuantity(cursor.getQuantity() - decrement);
                    PacketPhaseUtil.handleCustomCursor(player, cursor.createSnapshot());
                }
                if (inventoryEvent instanceof SpawnEntityEvent) {
                    processSpawnedEntities(player, (SpawnEntityEvent) inventoryEvent);
                } else if (!context.getCapturedEntitySupplier().isEmpty()) {
                    SpawnEntityEvent spawnEntityEvent = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), context.getCapturedEntities());
                    SpongeImpl.postEvent(spawnEntityEvent);
                    if (!spawnEntityEvent.isCancelled()) {
                        processSpawnedEntities(player, spawnEntityEvent);
                    }
                }
            }
        }
    }
    slotTransactions.clear();
    mixinContainer.setCaptureInventory(false);
}
Also used : CPacketEnchantItem(net.minecraft.network.play.client.CPacketEnchantItem) EntityItem(net.minecraft.entity.item.EntityItem) SpongeImpl(org.spongepowered.common.SpongeImpl) SpongeEventFactory(org.spongepowered.api.event.SpongeEventFactory) CPacketEnchantItem(net.minecraft.network.play.client.CPacketEnchantItem) Sponge(org.spongepowered.api.Sponge) SpawnEntityEvent(org.spongepowered.api.event.entity.SpawnEntityEvent) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) Entity(org.spongepowered.api.entity.Entity) ItemStackUtil(org.spongepowered.common.item.inventory.util.ItemStackUtil) EntityPlayerMP(net.minecraft.entity.player.EntityPlayerMP) EntityUtil(org.spongepowered.common.entity.EntityUtil) ArrayList(java.util.ArrayList) ContainerUtil(org.spongepowered.common.item.inventory.util.ContainerUtil) ItemStack(org.spongepowered.api.item.inventory.ItemStack) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) List(java.util.List) Lists(com.google.common.collect.Lists) AffectEntityEvent(org.spongepowered.api.event.entity.AffectEntityEvent) IMixinContainer(org.spongepowered.common.interfaces.IMixinContainer) CauseStackManager(org.spongepowered.api.event.CauseStackManager) ClickInventoryEvent(org.spongepowered.api.event.item.inventory.ClickInventoryEvent) Transaction(org.spongepowered.api.data.Transaction) Entity(org.spongepowered.api.entity.Entity) ArrayList(java.util.ArrayList) CauseStackManager(org.spongepowered.api.event.CauseStackManager) EntityItem(net.minecraft.entity.item.EntityItem) ClickInventoryEvent(org.spongepowered.api.event.item.inventory.ClickInventoryEvent) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) SpawnEntityEvent(org.spongepowered.api.event.entity.SpawnEntityEvent) IMixinContainer(org.spongepowered.common.interfaces.IMixinContainer) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Transaction(org.spongepowered.api.data.Transaction) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) EntityPlayerMP(net.minecraft.entity.player.EntityPlayerMP) AffectEntityEvent(org.spongepowered.api.event.entity.AffectEntityEvent) ItemStack(org.spongepowered.api.item.inventory.ItemStack)

Example 4 with Transaction

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

the class SpongeCommonEventFactory method callChangeBlockEventModifyLiquidMix.

public static ChangeBlockEvent.Modify callChangeBlockEventModifyLiquidMix(net.minecraft.world.World worldIn, BlockPos pos, IBlockState state, @Nullable Object source) {
    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
    final PhaseData data = phaseTracker.getCurrentPhaseData();
    BlockState fromState = BlockUtil.fromNative(worldIn.getBlockState(pos));
    BlockState toState = BlockUtil.fromNative(state);
    User owner = data.context.getOwner().orElse(null);
    User notifier = data.context.getNotifier().orElse(null);
    if (source == null) {
        // If source is null the source is the block itself
        source = LocatableBlock.builder().state(fromState).world(((World) worldIn)).position(pos.getX(), pos.getY(), pos.getZ()).build();
    }
    try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().pushCause(source);
        Sponge.getCauseStackManager().addContext(EventContextKeys.LIQUID_MIX, (World) worldIn);
        if (owner != null) {
            Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, owner);
        }
        if (notifier != null) {
            Sponge.getCauseStackManager().addContext(EventContextKeys.NOTIFIER, notifier);
        }
        WorldProperties world = ((World) worldIn).getProperties();
        Vector3i position = new Vector3i(pos.getX(), pos.getY(), pos.getZ());
        Transaction<BlockSnapshot> transaction = new Transaction<>(BlockSnapshot.builder().blockState(fromState).world(world).position(position).build(), BlockSnapshot.builder().blockState(toState).world(world).position(position).build());
        ChangeBlockEvent.Modify event = SpongeEventFactory.createChangeBlockEventModify(Sponge.getCauseStackManager().getCurrentCause(), Collections.singletonList(transaction));
        SpongeImpl.postEvent(event);
        return event;
    }
}
Also used : PhaseData(org.spongepowered.common.event.tracking.PhaseData) User(org.spongepowered.api.entity.living.player.User) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame) BlockSnapshot(org.spongepowered.api.block.BlockSnapshot) World(org.spongepowered.api.world.World) ChangeBlockEvent(org.spongepowered.api.event.block.ChangeBlockEvent) PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) BlockState(org.spongepowered.api.block.BlockState) IBlockState(net.minecraft.block.state.IBlockState) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Transaction(org.spongepowered.api.data.Transaction) CauseStackManager(org.spongepowered.api.event.CauseStackManager) Vector3i(com.flowpowered.math.vector.Vector3i) WorldProperties(org.spongepowered.api.world.storage.WorldProperties)

Example 5 with Transaction

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

the class PlaceRecipePacketState method unwind.

@Override
public void unwind(InventoryPacketContext context) {
    CPacketPlaceRecipe packet = context.getPacket();
    boolean shift = packet.func_194319_c();
    IRecipe recipe = packet.func_194317_b();
    final EntityPlayerMP player = context.getPacketPlayer();
    ((IMixinContainer) player.openContainer).detectAndSendChanges(true);
    ((IMixinContainer) player.openContainer).setCaptureInventory(false);
    ((IMixinContainer) player.openContainer).setFirePreview(true);
    Inventory craftInv = ((Inventory) player.openContainer).query(QueryOperationTypes.INVENTORY_TYPE.of(CraftingInventory.class));
    if (!(craftInv instanceof CraftingInventory)) {
        SpongeImpl.getLogger().warn("Detected crafting without a InventoryCrafting!? Crafting Event will not fire.");
        return;
    }
    List<SlotTransaction> previewTransactions = ((IMixinContainer) player.openContainer).getPreviewTransactions();
    if (previewTransactions.isEmpty()) {
        CraftingOutput slot = ((CraftingInventory) craftInv).getResult();
        SlotTransaction st = new SlotTransaction(slot, ItemStackSnapshot.NONE, ItemStackUtil.snapshotOf(slot.peek().orElse(ItemStack.empty())));
        previewTransactions.add(st);
    }
    SpongeCommonEventFactory.callCraftEventPre(player, ((CraftingInventory) craftInv), previewTransactions.get(0), ((CraftingRecipe) recipe), player.openContainer, previewTransactions);
    previewTransactions.clear();
    final Entity spongePlayer = EntityUtil.fromNative(player);
    try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        frame.pushCause(spongePlayer);
        frame.pushCause(player.openContainer);
        List<SlotTransaction> transactions = ((IMixinContainer) player.openContainer).getCapturedTransactions();
        ItemStackSnapshot cursor = ItemStackUtil.snapshotOf(player.inventory.getItemStack());
        Transaction<ItemStackSnapshot> cursorTransaction = new Transaction<>(cursor, cursor);
        ClickInventoryEvent event;
        if (shift) {
            event = SpongeEventFactory.createClickInventoryEventShiftPrimary(frame.getCurrentCause(), cursorTransaction, ((Container) player.openContainer), transactions);
        } else {
            event = SpongeEventFactory.createClickInventoryEventPrimary(frame.getCurrentCause(), cursorTransaction, ((Container) player.openContainer), transactions);
        }
        SpongeImpl.postEvent(event);
        if (event.isCancelled() || !event.getCursorTransaction().isValid()) {
            PacketPhaseUtil.handleCustomCursor(player, event.getCursorTransaction().getOriginal());
        } else {
            PacketPhaseUtil.handleCustomCursor(player, event.getCursorTransaction().getFinal());
        }
        PacketPhaseUtil.handleSlotRestore(player, player.openContainer, event.getTransactions(), event.isCancelled());
        event.getTransactions().clear();
    }
}
Also used : CraftingInventory(org.spongepowered.api.item.inventory.crafting.CraftingInventory) Entity(org.spongepowered.api.entity.Entity) IRecipe(net.minecraft.item.crafting.IRecipe) CraftingOutput(org.spongepowered.api.item.inventory.crafting.CraftingOutput) CraftingRecipe(org.spongepowered.api.item.recipe.crafting.CraftingRecipe) ClickInventoryEvent(org.spongepowered.api.event.item.inventory.ClickInventoryEvent) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) IMixinContainer(org.spongepowered.common.interfaces.IMixinContainer) SlotTransaction(org.spongepowered.api.item.inventory.transaction.SlotTransaction) Transaction(org.spongepowered.api.data.Transaction) CauseStackManager(org.spongepowered.api.event.CauseStackManager) CPacketPlaceRecipe(net.minecraft.network.play.client.CPacketPlaceRecipe) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) EntityPlayerMP(net.minecraft.entity.player.EntityPlayerMP) Inventory(org.spongepowered.api.item.inventory.Inventory) CraftingInventory(org.spongepowered.api.item.inventory.crafting.CraftingInventory)

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