Search in sources :

Example 21 with PhaseData

use of org.spongepowered.common.event.tracking.PhaseData in project SpongeCommon by SpongePowered.

the class MixinBlockDispenser method onSetInventoryContents.

@Redirect(method = "dispense", at = @At(value = "INVOKE", target = "Lnet/minecraft/tileentity/TileEntityDispenser;setInventorySlotContents(ILnet/minecraft/item/ItemStack;)V"))
public void onSetInventoryContents(TileEntityDispenser dispenser, int index, @Nullable ItemStack stack) {
    final PhaseData phaseData = PhaseTracker.getInstance().getCurrentPhaseData();
    final PhaseContext<?> context = phaseData.context;
    // If we captured nothing, simply set the slot contents and return
    if (context.getCapturedItemsOrEmptyList().isEmpty()) {
        dispenser.setInventorySlotContents(index, stack);
        return;
    }
    final ItemStack dispensedItem = context.getCapturedItems().get(0).getItem();
    final ItemStackSnapshot snapshot = ItemStackUtil.snapshotOf(dispensedItem);
    final List<ItemStackSnapshot> original = new ArrayList<>();
    original.add(snapshot);
    try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        Sponge.getCauseStackManager().pushCause(dispenser);
        final DropItemEvent.Pre dropEvent = SpongeEventFactory.createDropItemEventPre(Sponge.getCauseStackManager().getCurrentCause(), ImmutableList.of(snapshot), original);
        SpongeImpl.postEvent(dropEvent);
        if (dropEvent.isCancelled()) {
            dispenser.setInventorySlotContents(index, (net.minecraft.item.ItemStack) this.originalItem.createStack());
            context.getCapturedItems().clear();
            return;
        }
        if (dropEvent.getDroppedItems().isEmpty()) {
            context.getCapturedItems().clear();
        }
        dispenser.setInventorySlotContents(index, stack);
    }
}
Also used : DropItemEvent(org.spongepowered.api.event.item.inventory.DropItemEvent) PhaseData(org.spongepowered.common.event.tracking.PhaseData) CauseStackManager(org.spongepowered.api.event.CauseStackManager) ArrayList(java.util.ArrayList) ItemStackSnapshot(org.spongepowered.api.item.inventory.ItemStackSnapshot) ItemStack(net.minecraft.item.ItemStack) Redirect(org.spongepowered.asm.mixin.injection.Redirect)

Example 22 with PhaseData

use of org.spongepowered.common.event.tracking.PhaseData in project SpongeCommon by SpongePowered.

the class MixinBlockLeaves method destroy.

/**
 * @author gabizou - August 2nd, 2016
 * @reason Rewrite to handle both drops and the change state for leaves
 * that are considered to be decaying, so the drops do not leak into
 * whatever previous phase is being handled in. Since the issue is that
 * the block change takes place in a different phase (more than likely),
 * the drops are either "lost" or not considered for drops because the
 * blocks didn't change according to whatever previous phase.
 *
 * @param worldIn The world in
 * @param pos The position
 */
@Overwrite
private void destroy(net.minecraft.world.World worldIn, BlockPos pos) {
    final IBlockState state = worldIn.getBlockState(pos);
    // Sponge Start - Cause tracking
    if (!((IMixinWorld) worldIn).isFake()) {
        final PhaseTracker phaseTracker = PhaseTracker.getInstance();
        final PhaseData peek = phaseTracker.getCurrentPhaseData();
        final IPhaseState currentState = peek.state;
        final boolean isWorldGen = currentState.isWorldGeneration();
        final boolean isBlockAlready = phaseTracker.getCurrentState().getPhase() != TrackingPhases.BLOCK;
        try (PhaseContext<?> context = isBlockAlready && !isWorldGen ? BlockPhase.State.BLOCK_DECAY.createPhaseContext().source(LocatableBlock.builder().location(new Location<World>((World) worldIn, pos.getX(), pos.getY(), pos.getZ())).state((BlockState) state).build()).buildAndSwitch() : null) {
            this.dropBlockAsItem(worldIn, pos, state, 0);
            worldIn.setBlockToAir(pos);
        }
        return;
    }
    // Sponge End
    this.dropBlockAsItem(worldIn, pos, state, 0);
    worldIn.setBlockToAir(pos);
}
Also used : IBlockState(net.minecraft.block.state.IBlockState) PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) PhaseData(org.spongepowered.common.event.tracking.PhaseData) IPhaseState(org.spongepowered.common.event.tracking.IPhaseState) Location(org.spongepowered.api.world.Location) Overwrite(org.spongepowered.asm.mixin.Overwrite)

Example 23 with PhaseData

use of org.spongepowered.common.event.tracking.PhaseData in project SpongeCommon by SpongePowered.

the class MixinEntityLivingBase method onDeath.

/**
 * @author blood - May 12th, 2016
 * @author gabizou - June 4th, 2016 - Update for 1.9.4 and Cause Tracker changes
 *
 * @reason SpongeForge requires an overwrite so we do it here instead. This handles all living entity death events
 * (except players). Note should be taken that normally, there are lists for drops captured, however, the drops
 * are retroactively captured by the PhaseTracker and associated through the different phases, depending on
 * how they are handled, so no lists and flags on the entities themselves are needed as they are tracked through
 * the {@link PhaseContext} of the current {@link IPhaseState} at which this method is called. The compatibility
 * for Forge's events to throw are handled specially in SpongeForge.
 */
@Overwrite
public void onDeath(DamageSource cause) {
    // Sponge Start - Call our event, and forge's event
    // This will transitively call the forge event
    SpongeCommonEventFactory.callDestructEntityEventDeath((EntityLivingBase) (Object) this, cause);
    // Double check that the PhaseTracker is already capturing the Death phase
    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
    final boolean isMainThread = !this.world.isRemote || Sponge.isServerAvailable() && Sponge.getServer().isMainThread();
    try (final StackFrame frame = isMainThread ? Sponge.getCauseStackManager().pushCauseFrame() : null) {
        if (!this.world.isRemote) {
            final PhaseData peek = phaseTracker.getCurrentPhaseData();
            final IPhaseState state = peek.state;
            this.tracksEntityDeaths = !phaseTracker.getCurrentState().tracksEntityDeaths() && state != EntityPhase.State.DEATH;
            if (this.tracksEntityDeaths) {
                Sponge.getCauseStackManager().pushCause(this);
                final PhaseContext<?> context = EntityPhase.State.DEATH.createPhaseContext().setDamageSource((org.spongepowered.api.event.cause.entity.damage.source.DamageSource) cause).source(this);
                this.getNotifierUser().ifPresent(context::notifier);
                this.getCreatorUser().ifPresent(context::owner);
                context.buildAndSwitch();
            }
        } else {
            this.tracksEntityDeaths = false;
        }
        // Sponge End
        if (this.dead) {
            // Sponge Start - ensure that we finish the tracker if necessary
            if (this.tracksEntityDeaths && !properlyOverridesOnDeathForCauseTrackerCompletion()) {
                phaseTracker.completePhase(EntityPhase.State.DEATH);
            }
            // Sponge End
            return;
        }
        Entity entity = cause.getTrueSource();
        EntityLivingBase entitylivingbase = this.getAttackingEntity();
        if (this.scoreValue >= 0 && entitylivingbase != null) {
            entitylivingbase.awardKillScore((EntityLivingBase) (Object) this, this.scoreValue, cause);
        }
        if (entity != null) {
            entity.onKillEntity((EntityLivingBase) (Object) this);
        }
        this.dead = true;
        this.getCombatTracker().reset();
        if (!this.world.isRemote) {
            int i = 0;
            if (entity instanceof EntityPlayer) {
                i = EnchantmentHelper.getLootingModifier((EntityLivingBase) entity);
            }
            if (this.canDropLoot() && this.world.getGameRules().getBoolean("doMobLoot")) {
                boolean flag = this.recentlyHit > 0;
                this.dropLoot(flag, i, cause);
            }
        }
        // Sponge Start - Don't send the state if this is a human. Fixes ghost items on client.
        if (!((EntityLivingBase) (Object) this instanceof EntityHuman)) {
            this.world.setEntityState((EntityLivingBase) (Object) this, (byte) 3);
        }
        if (phaseTracker != null && this.tracksEntityDeaths && !properlyOverridesOnDeathForCauseTrackerCompletion()) {
            this.tracksEntityDeaths = false;
            phaseTracker.completePhase(EntityPhase.State.DEATH);
        }
    }
// Sponge End
}
Also used : Entity(net.minecraft.entity.Entity) EntityHuman(org.spongepowered.common.entity.living.human.EntityHuman) PhaseData(org.spongepowered.common.event.tracking.PhaseData) FallingBlockDamageSource(org.spongepowered.api.event.cause.entity.damage.source.FallingBlockDamageSource) DamageSource(net.minecraft.util.DamageSource) IPhaseState(org.spongepowered.common.event.tracking.IPhaseState) 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) Overwrite(org.spongepowered.asm.mixin.Overwrite)

Example 24 with PhaseData

use of org.spongepowered.common.event.tracking.PhaseData in project SpongeCommon by SpongePowered.

the class MixinChunk method onGetEntitiesOfTypeWithinAAAB.

@SuppressWarnings({ "unchecked", "rawtypes" })
@Inject(method = "getEntitiesOfTypeWithinAABB", at = @At(value = "RETURN"))
public void onGetEntitiesOfTypeWithinAAAB(Class<? extends Entity> entityClass, AxisAlignedBB aabb, List listToFill, Predicate<Entity> p_177430_4_, CallbackInfo ci) {
    if (this.world.isRemote || PhaseTracker.getInstance().getCurrentPhaseData().state.ignoresEntityCollisions()) {
        return;
    }
    if (listToFill.size() == 0) {
        return;
    }
    CollideEntityEvent event = SpongeCommonEventFactory.callCollideEntityEvent(this.world, null, listToFill);
    final PhaseData peek = PhaseTracker.getInstance().getCurrentPhaseData();
    if (event == null || event.isCancelled()) {
        if (event == null && !peek.state.isTicking()) {
            return;
        }
        listToFill.clear();
    }
}
Also used : PhaseData(org.spongepowered.common.event.tracking.PhaseData) CollideEntityEvent(org.spongepowered.api.event.entity.CollideEntityEvent) Inject(org.spongepowered.asm.mixin.injection.Inject)

Example 25 with PhaseData

use of org.spongepowered.common.event.tracking.PhaseData in project SpongeCommon by SpongePowered.

the class MixinExplosion method doExplosionB.

/**
 * @author gabizou - March 26th, 2017
 * @reason Since forge will attempt to call the normalized method for modded blocks,
 * we must artificially capture the block position for any block drops or changes during the
 * explosion phase.
 *
 * Does the second part of the explosion (sound, particles, drop spawn)
 */
@Overwrite
public void doExplosionB(boolean spawnParticles) {
    this.world.playSound((EntityPlayer) null, this.x, this.y, this.z, SoundEvents.ENTITY_GENERIC_EXPLODE, SoundCategory.BLOCKS, 4.0F, (1.0F + (this.world.rand.nextFloat() - this.world.rand.nextFloat()) * 0.2F) * 0.7F);
    if (this.size >= 2.0F) {
        if (this.world instanceof WorldServer) {
            ((WorldServer) this.world).spawnParticle(EnumParticleTypes.EXPLOSION_HUGE, this.x, this.y, this.z, 1, 0, 0, 0, 0.1D);
        } else {
            this.world.spawnParticle(EnumParticleTypes.EXPLOSION_HUGE, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D);
        }
    } else {
        if (this.world instanceof WorldServer) {
            ((WorldServer) this.world).spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.x, this.y, this.z, 1, 0, 0, 0, 0.1D);
        } else {
            this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.x, this.y, this.z, 1.0D, 0.0D, 0.0D);
        }
    }
    if (this.shouldBreakBlocks) {
        // Sponge - use 'shouldBreakBlocks' instead of 'damagesTerrain'
        for (BlockPos blockpos : this.affectedBlockPositions) {
            IBlockState iblockstate = this.world.getBlockState(blockpos);
            Block block = iblockstate.getBlock();
            if (spawnParticles) {
                double d0 = (double) ((float) blockpos.getX() + this.world.rand.nextFloat());
                double d1 = (double) ((float) blockpos.getY() + this.world.rand.nextFloat());
                double d2 = (double) ((float) blockpos.getZ() + this.world.rand.nextFloat());
                double d3 = d0 - this.x;
                double d4 = d1 - this.y;
                double d5 = d2 - this.z;
                double d6 = (double) MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5);
                d3 = d3 / d6;
                d4 = d4 / d6;
                d5 = d5 / d6;
                double d7 = 0.5D / (d6 / (double) this.size + 0.1D);
                d7 = d7 * (double) (this.world.rand.nextFloat() * this.world.rand.nextFloat() + 0.3F);
                d3 = d3 * d7;
                d4 = d4 * d7;
                d5 = d5 * d7;
                this.world.spawnParticle(EnumParticleTypes.EXPLOSION_NORMAL, (d0 + this.x) / 2.0D, (d1 + this.y) / 2.0D, (d2 + this.z) / 2.0D, d3, d4, d5, new int[0]);
                this.world.spawnParticle(EnumParticleTypes.SMOKE_NORMAL, d0, d1, d2, d3, d4, d5, new int[0]);
            }
            if (iblockstate.getMaterial() != Material.AIR) {
                if (block.canDropFromExplosion((net.minecraft.world.Explosion) (Object) this)) {
                    // Sponge Start - Track the block position being destroyed
                    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
                    final PhaseData peek = phaseTracker.getCurrentPhaseData();
                    // We need to capture this block position if necessary
                    if (peek.state.requiresBlockPosTracking()) {
                        peek.context.getCaptureBlockPos().setPos(blockpos);
                    }
                    block.dropBlockAsItemWithChance(this.world, blockpos, this.world.getBlockState(blockpos), 1.0F / this.size, 0);
                    // And then un-set the captured block position
                    if (peek.state.requiresBlockPosTracking()) {
                        peek.context.getCaptureBlockPos().setPos(null);
                    }
                }
                // Sponge Start - Track the block position being destroyed
                final PhaseTracker phaseTracker = PhaseTracker.getInstance();
                final PhaseData peek = phaseTracker.getCurrentPhaseData();
                // We need to capture this block position if necessary
                if (peek.state.requiresBlockPosTracking()) {
                    peek.context.getCaptureBlockPos().setPos(blockpos);
                }
                // Because we need to hook into forge.
                SpongeImplHooks.blockExploded(block, this.world, blockpos, (net.minecraft.world.Explosion) (Object) this);
                // And then un-set the captured block position
                if (peek.state.requiresBlockPosTracking()) {
                    peek.context.getCaptureBlockPos().setPos(null);
                }
            // Sponge End
            }
        }
    }
    if (this.causesFire) {
        for (BlockPos blockpos1 : this.affectedBlockPositions) {
            if (this.world.getBlockState(blockpos1).getMaterial() == Material.AIR && this.world.getBlockState(blockpos1.down()).isFullBlock() && this.random.nextInt(3) == 0) {
                // Sponge Start - Track the block position being destroyed
                final PhaseTracker phaseTracker = PhaseTracker.getInstance();
                final PhaseData peek = phaseTracker.getCurrentPhaseData();
                // We need to capture this block position if necessary
                if (peek.state.requiresBlockPosTracking()) {
                    peek.context.getCaptureBlockPos().setPos(blockpos1);
                }
                phaseTracker.setBlockState((IMixinWorldServer) this.world, blockpos1, Blocks.FIRE.getDefaultState(), BlockChangeFlags.ALL);
                // And then un-set the captured block position
                if (peek.state.requiresBlockPosTracking()) {
                    peek.context.getCaptureBlockPos().setPos(null);
                }
            }
        }
    }
}
Also used : IBlockState(net.minecraft.block.state.IBlockState) PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) PhaseData(org.spongepowered.common.event.tracking.PhaseData) Block(net.minecraft.block.Block) IMixinWorldServer(org.spongepowered.common.interfaces.world.IMixinWorldServer) WorldServer(net.minecraft.world.WorldServer) BlockPos(net.minecraft.util.math.BlockPos) Overwrite(org.spongepowered.asm.mixin.Overwrite)

Aggregations

PhaseData (org.spongepowered.common.event.tracking.PhaseData)30 PhaseTracker (org.spongepowered.common.event.tracking.PhaseTracker)22 BlockPos (net.minecraft.util.math.BlockPos)13 IPhaseState (org.spongepowered.common.event.tracking.IPhaseState)10 User (org.spongepowered.api.entity.living.player.User)9 IBlockState (net.minecraft.block.state.IBlockState)8 EntityPlayer (net.minecraft.entity.player.EntityPlayer)8 World (org.spongepowered.api.world.World)8 Overwrite (org.spongepowered.asm.mixin.Overwrite)8 CauseStackManager (org.spongepowered.api.event.CauseStackManager)6 StackFrame (org.spongepowered.api.event.CauseStackManager.StackFrame)6 ItemStack (net.minecraft.item.ItemStack)5 BlockSnapshot (org.spongepowered.api.block.BlockSnapshot)5 Transaction (org.spongepowered.api.data.Transaction)5 BlockState (org.spongepowered.api.block.BlockState)4 Inject (org.spongepowered.asm.mixin.injection.Inject)4 Redirect (org.spongepowered.asm.mixin.injection.Redirect)4 IMixinChunk (org.spongepowered.common.interfaces.IMixinChunk)4 IMixinWorld (org.spongepowered.common.interfaces.world.IMixinWorld)4 Block (net.minecraft.block.Block)3