Search in sources :

Example 6 with Transaction

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

the class CustomExplosionState method processBlockCaptures.

@SuppressWarnings({ "unchecked" })
private void processBlockCaptures(List<BlockSnapshot> snapshots, Explosion explosion, Cause cause, PhaseContext<?> context) {
    if (snapshots.isEmpty()) {
        return;
    }
    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 : snapshots) {
        // 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
    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 (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 {
            this.associateAdditionalCauses(this, 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);
        // Copied from TrackingUtil#throwMultiEventsAndCreatePost
        for (BlockChange blockChange : BlockChange.values()) {
            final ChangeBlockEvent mainEvent = mainEvents[blockChange.ordinal()];
            if (mainEvent != null) {
                Sponge.getCauseStackManager().pushCause(mainEvent);
            }
        }
        final ImmutableList<Transaction<BlockSnapshot>> transactions = transactionArrays[TrackingUtil.MULTI_CHANGE_INDEX];
        final ExplosionEvent.Post postEvent = SpongeEventFactory.createExplosionEventPost(cause, explosion, transactions);
        if (postEvent == null) {
            // Means that we have had no actual block changes apparently?
            return;
        }
        SpongeImpl.postEvent(postEvent);
        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);
                }
            }
        }
        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);
                // 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);
                }
            }
        }
        TrackingUtil.performBlockAdditions(postEvent.getTransactions(), this, context, noCancelledTransactions);
    }
}
Also used : ImmutableList(com.google.common.collect.ImmutableList) ExplosionEvent(org.spongepowered.api.event.world.ExplosionEvent) ArrayList(java.util.ArrayList) World(org.spongepowered.api.world.World) ChangeBlockEvent(org.spongepowered.api.event.block.ChangeBlockEvent) BlockChange(org.spongepowered.common.world.BlockChange) BlockPos(net.minecraft.util.math.BlockPos) IMixinLocation(org.spongepowered.common.interfaces.world.IMixinLocation) BlockSnapshot(org.spongepowered.api.block.BlockSnapshot) Transaction(org.spongepowered.api.data.Transaction) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame)

Example 7 with Transaction

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

the class MixinEntityLightningBolt method onStrikeBlock.

private boolean onStrikeBlock(net.minecraft.world.World world, BlockPos pos, IBlockState blockState) {
    if (!this.effect && ((World) world).containsBlock(pos.getX(), pos.getY(), pos.getZ())) {
        Vector3i pos3i = VecHelper.toVector3i(pos);
        Transaction<BlockSnapshot> transaction = new Transaction<BlockSnapshot>(new SpongeBlockSnapshotBuilder().blockState((BlockState) world.getBlockState(pos)).world(((World) world).getProperties()).position(pos3i).build(), new SpongeBlockSnapshotBuilder().blockState((BlockState) blockState).world(((World) world).getProperties()).position(pos3i).build());
        if (!this.struckBlocks.contains(transaction)) {
            this.struckBlocks.add(transaction);
        }
        return true;
    }
    return false;
}
Also used : Transaction(org.spongepowered.api.data.Transaction) SpongeBlockSnapshotBuilder(org.spongepowered.common.block.SpongeBlockSnapshotBuilder) Vector3i(com.flowpowered.math.vector.Vector3i) BlockSnapshot(org.spongepowered.api.block.BlockSnapshot) World(org.spongepowered.api.world.World)

Example 8 with Transaction

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

the class MixinEntityFishHook method handleHookRetraction.

/**
 * @author Aaron1011 - February 6th, 2015
 * @author Minecrell - December 24th, 2016 (Updated to Minecraft 1.11.2)
 * @author Minecrell - June 14th, 2017 (Rewritten to handle cases where no items are dropped)
 * @reason This needs to handle for both cases where a fish and/or an entity is being caught.
 */
@Overwrite
public int handleHookRetraction() {
    if (!this.world.isRemote && this.angler != null) {
        int i = 0;
        // Sponge start
        List<Transaction<ItemStackSnapshot>> transactions;
        if (this.ticksCatchable > 0) {
            // Moved from below
            LootContext.Builder lootcontext$builder = new LootContext.Builder((WorldServer) this.world);
            lootcontext$builder.withLuck(this.luck + this.angler.getLuck());
            transactions = this.world.getLootTableManager().getLootTableFromLocation(LootTableList.GAMEPLAY_FISHING).generateLootForPools(this.rand, lootcontext$builder.build()).stream().map(s -> {
                ItemStackSnapshot snapshot = ((org.spongepowered.api.item.inventory.ItemStack) s).createSnapshot();
                return new Transaction<>(snapshot, snapshot);
            }).collect(Collectors.toList());
        } else {
            transactions = new ArrayList<>();
        }
        Sponge.getCauseStackManager().pushCause(this.angler);
        if (SpongeImpl.postEvent(SpongeEventFactory.createFishingEventStop(Sponge.getCauseStackManager().getCurrentCause(), this, transactions))) {
            // Event is cancelled
            return -1;
        }
        if (this.caughtEntity != null) {
            this.bringInHookedEntity();
            this.world.setEntityState((net.minecraft.entity.Entity) (Object) this, (byte) 31);
            i = this.caughtEntity instanceof EntityItem ? 3 : 5;
        }
        // Sponge start - Moved up to event call
        if (!transactions.isEmpty()) {
            // Use transactions
            for (Transaction<ItemStackSnapshot> transaction : transactions) {
                if (!transaction.isValid()) {
                    continue;
                }
                ItemStack itemstack = (ItemStack) transaction.getFinal().createStack();
                // Sponge end
                EntityItem entityitem = new EntityItem(this.world, this.posX, this.posY, this.posZ, itemstack);
                double d0 = this.angler.posX - this.posX;
                double d1 = this.angler.posY - this.posY;
                double d2 = this.angler.posZ - this.posZ;
                double d3 = MathHelper.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
                // double d4 = 0.1D;
                entityitem.motionX = d0 * 0.1D;
                entityitem.motionY = d1 * 0.1D + MathHelper.sqrt(d3) * 0.08D;
                entityitem.motionZ = d2 * 0.1D;
                this.world.spawnEntity(entityitem);
                this.angler.world.spawnEntity(new EntityXPOrb(this.angler.world, this.angler.posX, this.angler.posY + 0.5D, this.angler.posZ + 0.5D, this.rand.nextInt(6) + 1));
                Item item = itemstack.getItem();
                if (item == Items.FISH || item == Items.COOKED_FISH) {
                    this.angler.addStat(StatList.FISH_CAUGHT, 1);
                }
            }
            Sponge.getCauseStackManager().popCause();
            // Sponge: Don't lower damage if we've also caught an entity
            i = Math.max(i, 1);
        }
        if (this.inGround) {
            i = 2;
        }
        this.setDead();
        return i;
    } else {
        return 0;
    }
}
Also used : LootContext(net.minecraft.world.storage.loot.LootContext) Item(net.minecraft.item.Item) EntityItem(net.minecraft.entity.item.EntityItem) Transaction(org.spongepowered.api.data.Transaction) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) ItemStack(net.minecraft.item.ItemStack) EntityItem(net.minecraft.entity.item.EntityItem) EntityXPOrb(net.minecraft.entity.item.EntityXPOrb) Overwrite(org.spongepowered.asm.mixin.Overwrite)

Example 9 with Transaction

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

the class SpongeForgeEventFactory method callBlockPlaceEvent.

public static ChangeBlockEvent.Place callBlockPlaceEvent(Event event) {
    ChangeBlockEvent.Place spongeEvent = (ChangeBlockEvent.Place) event;
    if (spongeEvent.getCause().root() instanceof Player) {
        EntityPlayer player = (EntityPlayer) spongeEvent.getCause().first(Player.class).get();
        net.minecraft.world.World world = player.world;
        final PhaseTracker phaseTracker = PhaseTracker.getInstance();
        final PhaseContext<?> currentContext = phaseTracker.getCurrentContext();
        PhaseContext<?> target = currentContext;
        if (currentContext instanceof UnwindingPhaseContext) {
            target = ((UnwindingPhaseContext) currentContext).getUnwindingContext();
        }
        PacketContext<?> context = target instanceof PacketContext<?> ? (PacketContext<?>) target : null;
        Packet<?> contextPacket = context != null ? context.getPacket() : null;
        if (contextPacket == null) {
            return spongeEvent;
        }
        if (spongeEvent.getTransactions().size() == 1) {
            BlockPos pos = VecHelper.toBlockPos(spongeEvent.getTransactions().get(0).getOriginal().getPosition());
            IBlockState state = (IBlockState) spongeEvent.getTransactions().get(0).getOriginal().getState();
            net.minecraftforge.common.util.BlockSnapshot blockSnapshot = new net.minecraftforge.common.util.BlockSnapshot(world, pos, state);
            IBlockState placedAgainst = Blocks.AIR.getDefaultState();
            EnumHand hand = EnumHand.MAIN_HAND;
            if (contextPacket instanceof CPacketPlayerTryUseItemOnBlock) {
                CPacketPlayerTryUseItemOnBlock packet = (CPacketPlayerTryUseItemOnBlock) contextPacket;
                EnumFacing facing = packet.getDirection();
                placedAgainst = blockSnapshot.getWorld().getBlockState(blockSnapshot.getPos().offset(facing.getOpposite()));
                hand = packet.getHand();
            }
            BlockEvent.PlaceEvent forgeEvent = new BlockEvent.PlaceEvent(blockSnapshot, placedAgainst, player, hand);
            ((IMixinEventBus) MinecraftForge.EVENT_BUS).post(forgeEvent, true);
            if (forgeEvent.isCanceled()) {
                spongeEvent.setCancelled(true);
            }
        } else {
            // multi
            Iterator<Transaction<BlockSnapshot>> iterator = spongeEvent.getTransactions().iterator();
            List<net.minecraftforge.common.util.BlockSnapshot> blockSnapshots = new ArrayList<>();
            while (iterator.hasNext()) {
                Transaction<BlockSnapshot> transaction = iterator.next();
                Location<World> location = transaction.getOriginal().getLocation().get();
                IBlockState state = (IBlockState) transaction.getOriginal().getState();
                BlockPos pos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
                net.minecraftforge.common.util.BlockSnapshot blockSnapshot = new net.minecraftforge.common.util.BlockSnapshot(world, pos, state);
                blockSnapshots.add(blockSnapshot);
            }
            IBlockState placedAgainst = Blocks.AIR.getDefaultState();
            EnumHand hand = EnumHand.MAIN_HAND;
            if (contextPacket instanceof CPacketPlayerTryUseItemOnBlock) {
                CPacketPlayerTryUseItemOnBlock packet = (CPacketPlayerTryUseItemOnBlock) contextPacket;
                EnumFacing facing = packet.getDirection();
                placedAgainst = blockSnapshots.get(0).getWorld().getBlockState(blockSnapshots.get(0).getPos().offset(facing.getOpposite()));
                hand = packet.getHand();
            }
            BlockEvent.MultiPlaceEvent forgeEvent = new BlockEvent.MultiPlaceEvent(blockSnapshots, placedAgainst, player, hand);
            ((IMixinEventBus) MinecraftForge.EVENT_BUS).post(forgeEvent, true);
            if (forgeEvent.isCanceled()) {
                spongeEvent.setCancelled(true);
            }
        }
    }
    return spongeEvent;
}
Also used : EnumFacing(net.minecraft.util.EnumFacing) ArrayList(java.util.ArrayList) UnwindingPhaseContext(org.spongepowered.common.event.tracking.phase.general.UnwindingPhaseContext) World(org.spongepowered.api.world.World) IMixinWorld(org.spongepowered.common.interfaces.world.IMixinWorld) ChangeBlockEvent(org.spongepowered.api.event.block.ChangeBlockEvent) EnumHand(net.minecraft.util.EnumHand) BlockPos(net.minecraft.util.math.BlockPos) Player(org.spongepowered.api.entity.living.player.Player) EntityPlayer(net.minecraft.entity.player.EntityPlayer) IBlockState(net.minecraft.block.state.IBlockState) IMixinBlockSnapshot(org.spongepowered.mod.interfaces.IMixinBlockSnapshot) BlockSnapshot(org.spongepowered.api.block.BlockSnapshot) CPacketPlayerTryUseItemOnBlock(net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock) IMixinEventBus(org.spongepowered.mod.interfaces.IMixinEventBus) PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) Transaction(org.spongepowered.api.data.Transaction) EntityPlayer(net.minecraft.entity.player.EntityPlayer) ChangeBlockEvent(org.spongepowered.api.event.block.ChangeBlockEvent) BlockEvent(net.minecraftforge.event.world.BlockEvent) InteractBlockEvent(org.spongepowered.api.event.block.InteractBlockEvent) NotifyNeighborBlockEvent(org.spongepowered.api.event.block.NotifyNeighborBlockEvent)

Example 10 with Transaction

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

the class SpongeForgeEventFactory method createChangeBlockEventPlace.

public static ChangeBlockEvent.Place createChangeBlockEventPlace(BlockEvent.PlaceEvent forgeEvent) {
    final BlockPos pos = forgeEvent.getPos();
    final net.minecraft.world.World world = forgeEvent.getWorld();
    if (world.isRemote) {
        return null;
    }
    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
    final PhaseData data = phaseTracker.getCurrentPhaseData();
    BlockSnapshot originalSnapshot = ((IMixinBlockSnapshot) forgeEvent.getBlockSnapshot()).createSpongeBlockSnapshot();
    BlockSnapshot finalSnapshot = ((BlockState) forgeEvent.getPlacedBlock()).snapshotFor(new Location<>((World) world, VecHelper.toVector3d(pos)));
    ImmutableList<Transaction<BlockSnapshot>> blockSnapshots = new ImmutableList.Builder<Transaction<BlockSnapshot>>().add(new Transaction<>(originalSnapshot, finalSnapshot)).build();
    User owner = data.context.getOwner().orElse(null);
    User notifier = data.context.getNotifier().orElse(null);
    EntityPlayer player = forgeEvent.getPlayer();
    if (SpongeImplHooks.isFakePlayer(player)) {
        Sponge.getCauseStackManager().addContext(EventContextKeys.FAKE_PLAYER, EntityUtil.toPlayer(player));
    } else if (Sponge.getCauseStackManager().getCurrentCause() == null) {
        Sponge.getCauseStackManager().pushCause(player);
    }
    if (owner != null) {
        Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, owner);
        if (Sponge.getCauseStackManager().getCurrentCause() == null) {
            Sponge.getCauseStackManager().pushCause(owner);
        }
    } else {
        Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, (User) player);
        if (Sponge.getCauseStackManager().getCurrentCause() == null) {
            Sponge.getCauseStackManager().pushCause(player);
        }
    }
    if (notifier != null) {
        Sponge.getCauseStackManager().addContext(EventContextKeys.NOTIFIER, notifier);
    }
    Sponge.getCauseStackManager().addContext(EventContextKeys.PLAYER_PLACE, (World) world);
    return SpongeEventFactory.createChangeBlockEventPlace(Sponge.getCauseStackManager().getCurrentCause(), blockSnapshots);
}
Also used : PhaseData(org.spongepowered.common.event.tracking.PhaseData) User(org.spongepowered.api.entity.living.player.User) IMixinBlockSnapshot(org.spongepowered.mod.interfaces.IMixinBlockSnapshot) BlockSnapshot(org.spongepowered.api.block.BlockSnapshot) World(org.spongepowered.api.world.World) IMixinWorld(org.spongepowered.common.interfaces.world.IMixinWorld) PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) BlockState(org.spongepowered.api.block.BlockState) IBlockState(net.minecraft.block.state.IBlockState) Transaction(org.spongepowered.api.data.Transaction) EntityPlayer(net.minecraft.entity.player.EntityPlayer) BlockPos(net.minecraft.util.math.BlockPos) IMixinBlockSnapshot(org.spongepowered.mod.interfaces.IMixinBlockSnapshot)

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