Search in sources :

Example 11 with StackFrame

use of org.spongepowered.api.event.CauseStackManager.StackFrame in project SpongeCommon by SpongePowered.

the class SpongeCommonEventFactory method handleCollideBlockEvent.

public static boolean handleCollideBlockEvent(Block block, net.minecraft.world.World world, BlockPos pos, IBlockState state, net.minecraft.entity.Entity entity, Direction direction) {
    if (pos.getY() <= 0) {
        return false;
    }
    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
    try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().pushCause(entity);
        if (!(entity instanceof EntityPlayer)) {
            IMixinEntity spongeEntity = (IMixinEntity) entity;
            Optional<User> user = spongeEntity.getCreatorUser();
            if (user.isPresent()) {
                Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, user.get());
            }
        }
        // TODO: Add target side support
        CollideBlockEvent event = SpongeEventFactory.createCollideBlockEvent(Sponge.getCauseStackManager().getCurrentCause(), (BlockState) state, new Location<>((World) world, VecHelper.toVector3d(pos)), direction);
        boolean cancelled = SpongeImpl.postEvent(event);
        if (!cancelled) {
            IMixinEntity spongeEntity = (IMixinEntity) entity;
            if (!pos.equals(spongeEntity.getLastCollidedBlockPos())) {
                final PhaseData peek = phaseTracker.getCurrentPhaseData();
                final Optional<User> notifier = peek.context.getNotifier();
                if (notifier.isPresent()) {
                    IMixinChunk spongeChunk = (IMixinChunk) world.getChunkFromBlockCoords(pos);
                    spongeChunk.addTrackedBlockPosition(block, pos, notifier.get(), PlayerTracker.Type.NOTIFIER);
                }
            }
        }
        return cancelled;
    }
}
Also used : PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) User(org.spongepowered.api.entity.living.player.User) PhaseData(org.spongepowered.common.event.tracking.PhaseData) IMixinChunk(org.spongepowered.common.interfaces.IMixinChunk) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame) EntityPlayer(net.minecraft.entity.player.EntityPlayer) IMixinEntity(org.spongepowered.common.interfaces.entity.IMixinEntity) World(org.spongepowered.api.world.World) CollideBlockEvent(org.spongepowered.api.event.block.CollideBlockEvent)

Example 12 with StackFrame

use of org.spongepowered.api.event.CauseStackManager.StackFrame in project SpongeCommon by SpongePowered.

the class SpongeCommonEventFactory method callInventoryPickupEvent.

public static ItemStack callInventoryPickupEvent(IInventory inventory, EntityItem item, ItemStack stack) {
    try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        frame.pushCause(inventory);
        ItemStackSnapshot snapshot = ItemStackUtil.snapshotOf(stack);
        ChangeInventoryEvent.Pickup.Pre event = SpongeEventFactory.createChangeInventoryEventPickupPre(frame.getCurrentCause(), Optional.empty(), Collections.singletonList(snapshot), snapshot, ((Item) item), ((Inventory) inventory));
        SpongeImpl.postEvent(event);
        if (event.isCancelled()) {
            return stack;
        }
        int size = inventory.getSizeInventory();
        ItemStack[] prevInventory = new ItemStack[size];
        for (int i = 0; i < size; i++) {
            prevInventory[i] = inventory.getStackInSlot(i);
        }
        if (event.getCustom().isPresent()) {
            if (event.getCustom().get().isEmpty()) {
                return ItemStack.EMPTY;
            }
            boolean fullTransfer = true;
            for (ItemStackSnapshot snap : event.getCustom().get()) {
                ItemStack stackToAdd = ItemStackUtil.fromSnapshotToNative(snap);
                ItemStack remaining = TileEntityHopper.putStackInInventoryAllSlots(null, inventory, stackToAdd, null);
                if (!remaining.isEmpty()) {
                    fullTransfer = false;
                    break;
                }
            }
            if (!fullTransfer) {
                for (int i = 0; i < prevInventory.length; i++) {
                    inventory.setInventorySlotContents(i, prevInventory[i]);
                }
                return stack;
            }
            if (callInventoryPickupEvent(inventory, prevInventory)) {
                return ItemStack.EMPTY;
            }
            return stack;
        } else {
            ItemStack remainder = TileEntityHopper.putStackInInventoryAllSlots(null, inventory, stack, null);
            if (callInventoryPickupEvent(inventory, prevInventory)) {
                return remainder;
            }
            return stack;
        }
    }
}
Also used : EntityItem(net.minecraft.entity.item.EntityItem) Item(org.spongepowered.api.entity.Item) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) ItemStack(net.minecraft.item.ItemStack) IMixinInventory(org.spongepowered.common.interfaces.IMixinInventory) OrderedInventory(org.spongepowered.api.item.inventory.type.OrderedInventory) CraftingInventory(org.spongepowered.api.item.inventory.crafting.CraftingInventory) CarriedInventory(org.spongepowered.api.item.inventory.type.CarriedInventory) Inventory(org.spongepowered.api.item.inventory.Inventory) CustomInventory(org.spongepowered.common.item.inventory.custom.CustomInventory) IInventory(net.minecraft.inventory.IInventory)

Example 13 with StackFrame

use of org.spongepowered.api.event.CauseStackManager.StackFrame in project SpongeCommon by SpongePowered.

the class MixinEntityLivingBase method attackEntityFrom.

/**
 * @author bloodmc - November 22, 2015
 * @author gabizou - Updated April 11th, 2016 - Update for 1.9 changes
 * @author Aaron1011 - Updated Nov 11th, 2016 - Update for 1.11 changes
 *
 * @reason Reroute damageEntity calls to our hook in order to prevent damage.
 */
@Override
@Overwrite
public boolean attackEntityFrom(DamageSource source, float amount) {
    // Sponge start - Add certain hooks for necessities
    this.lastDamageSource = source;
    if (source == null) {
        Thread.dumpStack();
    }
    // Sponge - This hook is for forge use mainly
    if (!hookModAttack((EntityLivingBase) (Object) this, source, amount))
        return false;
    // Sponge end
    if (this.isEntityInvulnerable(source)) {
        return false;
    } else if (this.world.isRemote) {
        return false;
    } else {
        this.idleTime = 0;
        // has already been set to zero if Keys#HEALTH or SpongeHealthData is set to zero.
        if (this.getHealth() <= 0.0F && source != DamageSourceRegistryModule.IGNORED_DAMAGE_SOURCE) {
            return false;
        } else if (source.isFireDamage() && this.isPotionActive(MobEffects.FIRE_RESISTANCE)) {
            return false;
        } else {
            // Sponge - ignore as this is handled in our damageEntityHookge
            // if (false && (source == DamageSource.anvil || source == DamageSource.fallingBlock)
            // && this.getEquipmentInSlot(4) != null) {
            // this.getEquipmentInSlot(4).damageItem((int) (amount * 4.0F + this.rand.nextFloat() * amount * 2.0F),
            // (EntityLivingBase) (Object) this);
            // amount *= 0.75F;
            // }
            // Sponge End
            // Sponge - set the 'shield blocking ran' flag to the proper value, since
            // we comment out the logic below
            boolean flag = amount > 0.0F && this.canBlockDamageSource(source);
            // Sponge start - this is handled in our damageEntityHook
            /*boolean flag = false;

                if (amount > 0.0F && this.canBlockDamageSource(source)) {
                    this.damageShield(amount);

                    if (!source.isProjectile())
                    {
                        Entity entity = source.getSourceOfDamage();

                        if (entity instanceof EntityLivingBase)
                        {
                            this.blockUsingShield((EntityLivingBase)entity);
                        }
                    }

                    flag = true;
                }*/
            // Sponge end
            this.limbSwingAmount = 1.5F;
            boolean flag1 = true;
            if ((float) this.hurtResistantTime > (float) this.maxHurtResistantTime / 2.0F) {
                if (amount <= this.lastDamage) {
                    // Technically, this is wrong since 'amount' won't be 0 if a shield is used. However, we need damageEntityHook so that we process the shield, so we leave it as-is
                    return false;
                }
                // Sponge start - reroute to our damage hook
                if (!this.damageEntityHook(source, amount - this.lastDamage)) {
                    return false;
                }
                // Sponge end
                this.lastDamage = amount;
                flag1 = false;
            } else {
                // Sponge start - reroute to our damage hook
                if (!this.damageEntityHook(source, amount)) {
                    return false;
                }
                this.lastDamage = amount;
                this.hurtResistantTime = this.maxHurtResistantTime;
                // this.damageEntity(source, amount); // handled above
                // Sponge end
                this.hurtTime = this.maxHurtTime = 10;
            }
            this.attackedAtYaw = 0.0F;
            net.minecraft.entity.Entity entity = source.getTrueSource();
            if (entity != null) {
                if (entity instanceof EntityLivingBase) {
                    this.setRevengeTarget((EntityLivingBase) entity);
                }
                if (entity instanceof EntityPlayer) {
                    this.recentlyHit = 100;
                    this.attackingPlayer = (EntityPlayer) entity;
                } else if (entity instanceof EntityWolf) {
                    EntityWolf entityWolf = (EntityWolf) entity;
                    if (entityWolf.isTamed()) {
                        this.recentlyHit = 100;
                        this.attackingPlayer = null;
                    }
                }
            }
            if (flag1) {
                if (flag) {
                    this.world.setEntityState((EntityLivingBase) (Object) this, (byte) 29);
                } else if (source instanceof net.minecraft.util.EntityDamageSource && ((net.minecraft.util.EntityDamageSource) source).getIsThornsDamage()) {
                    this.world.setEntityState((EntityLivingBase) (Object) this, (byte) 33);
                } else {
                    this.world.setEntityState((EntityLivingBase) (Object) this, (byte) 2);
                }
                if (source != DamageSource.DROWN && !flag) {
                    // Sponge - remove 'amount > 0.0F' - it's redundant in Vanilla, and breaks our handling of shields
                    this.markVelocityChanged();
                }
                if (entity != null) {
                    double d1 = entity.posX - this.posX;
                    double d0;
                    for (d0 = entity.posZ - this.posZ; d1 * d1 + d0 * d0 < 1.0E-4D; d0 = (Math.random() - Math.random()) * 0.01D) {
                        d1 = (Math.random() - Math.random()) * 0.01D;
                    }
                    this.attackedAtYaw = (float) (MathHelper.atan2(d0, d1) * 180.0D / Math.PI - (double) this.rotationYaw);
                    this.knockBack(entity, 0.4F, d1, d0);
                } else {
                    this.attackedAtYaw = (float) ((Math.random() * 2.0D) * 180);
                }
            }
            if (this.getHealth() <= 0.0F) {
                if (!this.checkTotemDeathProtection(source)) {
                    SoundEvent soundevent = this.getDeathSound();
                    if (flag1 && soundevent != null) {
                        this.playSound(soundevent, this.getSoundVolume(), this.getSoundPitch());
                    }
                    // Sponge Start - notify the cause tracker
                    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
                    try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
                        final boolean enterDeathPhase = !phaseTracker.getCurrentState().tracksEntityDeaths();
                        if (enterDeathPhase) {
                            Sponge.getCauseStackManager().pushCause(this);
                        }
                        try (final PhaseContext<?> context = !enterDeathPhase ? null : EntityPhase.State.DEATH.createPhaseContext().source(this).setDamageSource((org.spongepowered.api.event.cause.entity.damage.source.DamageSource) source).owner(this::getCreatorUser).notifier(this::getNotifierUser).buildAndSwitch()) {
                            this.onDeath(source);
                        }
                    }
                }
            // Sponge End
            } else if (flag1) {
                this.playHurtSound(source);
            }
            if (// Sponge - remove 'amount > 0.0F'
            !flag) {
                this.lastDamageSource = source;
                this.lastDamageStamp = this.world.getTotalWorldTime();
            }
            // Sponge - remove 'amount > 0.0F'
            return !flag;
        }
    }
}
Also used : Entity(net.minecraft.entity.Entity) SoundEvent(net.minecraft.util.SoundEvent) PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame) IMixinEntityLivingBase(org.spongepowered.common.interfaces.entity.IMixinEntityLivingBase) EntityLivingBase(net.minecraft.entity.EntityLivingBase) EntityPlayer(net.minecraft.entity.player.EntityPlayer) DamageObject(org.spongepowered.common.event.damage.DamageObject) EntityWolf(net.minecraft.entity.passive.EntityWolf) Overwrite(org.spongepowered.asm.mixin.Overwrite)

Example 14 with StackFrame

use of org.spongepowered.api.event.CauseStackManager.StackFrame 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 15 with StackFrame

use of org.spongepowered.api.event.CauseStackManager.StackFrame in project SpongeCommon by SpongePowered.

the class DimensionTickPhaseState method unwind.

@Override
public void unwind(DimensionContext phaseContext) {
    try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.PLACEMENT);
        phaseContext.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(blockSnapshots -> {
            TrackingUtil.processBlockCaptures(blockSnapshots, this, phaseContext);
        });
        phaseContext.getCapturedEntitySupplier().acceptAndClearIfNotEmpty(entities -> {
            final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), entities);
            SpongeImpl.postEvent(event);
            if (!event.isCancelled()) {
                for (Entity entity : event.getEntities()) {
                    EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
                }
            }
        });
        phaseContext.getCapturedItemsSupplier().acceptAndClearIfNotEmpty(entities -> {
            final ArrayList<Entity> capturedEntities = new ArrayList<>();
            for (EntityItem entity : entities) {
                capturedEntities.add(EntityUtil.fromNative(entity));
            }
            final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), capturedEntities);
            SpongeImpl.postEvent(event);
            if (!event.isCancelled()) {
                for (Entity entity : event.getEntities()) {
                    EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
                }
            }
        });
    }
}
Also used : Entity(org.spongepowered.api.entity.Entity) StackFrame(org.spongepowered.api.event.CauseStackManager.StackFrame) ArrayList(java.util.ArrayList) SpawnEntityEvent(org.spongepowered.api.event.entity.SpawnEntityEvent) EntityItem(net.minecraft.entity.item.EntityItem)

Aggregations

StackFrame (org.spongepowered.api.event.CauseStackManager.StackFrame)36 Entity (org.spongepowered.api.entity.Entity)18 ArrayList (java.util.ArrayList)15 SpawnEntityEvent (org.spongepowered.api.event.entity.SpawnEntityEvent)13 User (org.spongepowered.api.entity.living.player.User)12 EntityItem (net.minecraft.entity.item.EntityItem)11 EntityPlayer (net.minecraft.entity.player.EntityPlayer)8 TileEntity (org.spongepowered.api.block.tileentity.TileEntity)8 IMixinEntity (org.spongepowered.common.interfaces.entity.IMixinEntity)6 ItemStack (net.minecraft.item.ItemStack)5 BlockPos (net.minecraft.util.math.BlockPos)5 WorldServer (net.minecraft.world.WorldServer)5 LocatableBlock (org.spongepowered.api.world.LocatableBlock)5 IMixinTileEntity (org.spongepowered.common.interfaces.block.tile.IMixinTileEntity)5 List (java.util.List)4 UUID (java.util.UUID)4 Collectors (java.util.stream.Collectors)4 EntityLivingBase (net.minecraft.entity.EntityLivingBase)4 EntityPlayerMP (net.minecraft.entity.player.EntityPlayerMP)4 Sponge (org.spongepowered.api.Sponge)4