Search in sources :

Example 36 with PhaseTracker

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

the class MixinBlock method onDropBlockAsItemWithChanceHead.

// This method can be called directly by pistons, mods, etc. so the hook must go here
@Inject(method = "dropBlockAsItemWithChance", at = @At(value = "HEAD"), cancellable = true)
public void onDropBlockAsItemWithChanceHead(net.minecraft.world.World worldIn, BlockPos pos, IBlockState state, float chance, int fortune, CallbackInfo ci) {
    if (!((IMixinWorld) worldIn).isFake()) {
        if (PhaseTracker.getInstance().getCurrentState() == BlockPhase.State.RESTORING_BLOCKS) {
            ci.cancel();
            return;
        }
        final IMixinWorldServer mixinWorld = (IMixinWorldServer) worldIn;
        final PhaseTracker phaseTracker = PhaseTracker.getInstance();
        final IPhaseState<?> currentState = phaseTracker.getCurrentState();
        final boolean shouldEnterBlockDropPhase = !phaseTracker.getCurrentContext().isCapturingBlockItemDrops() && !currentState.alreadyCapturingItemSpawns() && !currentState.isWorldGeneration();
        if (shouldEnterBlockDropPhase) {
            // TODO: Change source to LocatableBlock
            PhaseContext<?> context = BlockPhase.State.BLOCK_DROP_ITEMS.createPhaseContext().source(mixinWorld.createSpongeBlockSnapshot(state, state, pos, BlockChangeFlags.PHYSICS_OBSERVER));
            // unused, to be removed and re-located when phase context is cleaned up
            // .add(NamedCause.of(InternalNamedCauses.General.BLOCK_BREAK_FORTUNE, fortune))
            // .add(NamedCause.of(InternalNamedCauses.General.BLOCK_BREAK_POSITION, pos));
            // use current notifier and owner if available
            User notifier = phaseTracker.getCurrentContext().getNotifier().orElse(null);
            User owner = phaseTracker.getCurrentContext().getOwner().orElse(null);
            if (notifier != null) {
                context.notifier(notifier);
            }
            if (owner != null) {
                context.owner(owner);
            }
            context.buildAndSwitch();
        }
    }
}
Also used : PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) User(org.spongepowered.api.entity.living.player.User) IMixinWorldServer(org.spongepowered.common.interfaces.world.IMixinWorldServer) Inject(org.spongepowered.asm.mixin.injection.Inject)

Example 37 with PhaseTracker

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

the class MixinBlockLeaves method onUpdateDecayState.

@Redirect(method = "updateTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;I)Z"))
public boolean onUpdateDecayState(net.minecraft.world.World worldIn, BlockPos pos, IBlockState state, int flags) {
    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
    final boolean isBlockAlready = phaseTracker.getCurrentState().getPhase() != TrackingPhases.BLOCK;
    final IPhaseState currentState = phaseTracker.getCurrentPhaseData().state;
    final boolean isWorldGen = currentState.isWorldGeneration();
    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) {
        return worldIn.setBlockState(pos, state, flags);
    }
}
Also used : PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) IPhaseState(org.spongepowered.common.event.tracking.IPhaseState) Location(org.spongepowered.api.world.Location) Redirect(org.spongepowered.asm.mixin.injection.Redirect)

Example 38 with PhaseTracker

use of org.spongepowered.common.event.tracking.PhaseTracker 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 39 with PhaseTracker

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

the class MixinBlockStaticLiquid method onSpreadFire.

@Redirect(method = "updateTick", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;)Z"))
private boolean onSpreadFire(World world, BlockPos pos, IBlockState blockState) {
    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
    final PhaseContext<?> context = phaseTracker.getCurrentPhaseData().context;
    try (final CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
        frame.pushCause(pos);
        frame.pushCause(this);
        context.getOwner().ifPresent(owner -> frame.addContext(EventContextKeys.OWNER, owner));
        context.getNotifier().ifPresent(notifier -> frame.addContext(EventContextKeys.NOTIFIER, notifier));
        ChangeBlockEvent.Pre event = SpongeEventFactory.createChangeBlockEventPre(frame.getCurrentCause(), Collections.singletonList(new Location<>((org.spongepowered.api.world.World) world, VecHelper.toVector3i(pos))));
        if (!SpongeImpl.postEvent(event)) {
            phaseTracker.setBlockState((IMixinWorldServer) world, pos, blockState, BlockChangeFlags.ALL);
            return true;
        }
        return false;
    }
}
Also used : ChangeBlockEvent(org.spongepowered.api.event.block.ChangeBlockEvent) PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) CauseStackManager(org.spongepowered.api.event.CauseStackManager) Location(org.spongepowered.api.world.Location) Redirect(org.spongepowered.asm.mixin.injection.Redirect)

Example 40 with PhaseTracker

use of org.spongepowered.common.event.tracking.PhaseTracker 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)

Aggregations

PhaseTracker (org.spongepowered.common.event.tracking.PhaseTracker)67 PhaseData (org.spongepowered.common.event.tracking.PhaseData)22 IPhaseState (org.spongepowered.common.event.tracking.IPhaseState)20 BlockPos (net.minecraft.util.math.BlockPos)15 CauseStackManager (org.spongepowered.api.event.CauseStackManager)15 World (org.spongepowered.api.world.World)12 Redirect (org.spongepowered.asm.mixin.injection.Redirect)12 IBlockState (net.minecraft.block.state.IBlockState)11 EntityPlayer (net.minecraft.entity.player.EntityPlayer)11 User (org.spongepowered.api.entity.living.player.User)11 StackFrame (org.spongepowered.api.event.CauseStackManager.StackFrame)10 Inject (org.spongepowered.asm.mixin.injection.Inject)10 ArrayList (java.util.ArrayList)8 Overwrite (org.spongepowered.asm.mixin.Overwrite)8 IMixinChunk (org.spongepowered.common.interfaces.IMixinChunk)8 BlockSnapshot (org.spongepowered.api.block.BlockSnapshot)7 BlockState (org.spongepowered.api.block.BlockState)6 LocatableBlock (org.spongepowered.api.world.LocatableBlock)6 Location (org.spongepowered.api.world.Location)6 IMixinWorldServer (org.spongepowered.common.interfaces.world.IMixinWorldServer)6