Search in sources :

Example 11 with PhaseTracker

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

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

the class MixinChunk method setBlockState.

/**
 * @author blood - November 2015
 * @author gabizou - updated April 10th, 2016 - Add cause tracking refactor changes
 *
 * @param pos The position changing
 * @param newState The new state
 * @param currentState The current state - passed in from either chunk or world
 * @param newBlockSnapshot The new snapshot. This can be null when calling {@link MixinChunk#setBlockState(BlockPos, IBlockState)} directly,
 *      as there's no block snapshot to change.
 * @return The changed block state if not null
 */
@Override
@Nullable
public IBlockState setBlockState(BlockPos pos, IBlockState newState, IBlockState currentState, @Nullable BlockSnapshot newBlockSnapshot, BlockChangeFlag flag) {
    int xPos = pos.getX() & 15;
    int yPos = pos.getY();
    int zPos = pos.getZ() & 15;
    int combinedPos = zPos << 4 | xPos;
    if (yPos >= this.precipitationHeightMap[combinedPos] - 1) {
        this.precipitationHeightMap[combinedPos] = -999;
    }
    int currentHeight = this.heightMap[combinedPos];
    // Sponge Start - remove blockstate check as we handle it in world.setBlockState
    // IBlockState iblockstate = this.getBlockState(pos);
    // 
    // if (iblockstate == state) {
    // return null;
    // } else {
    Block newBlock = newState.getBlock();
    Block currentBlock = currentState.getBlock();
    // Sponge End
    ExtendedBlockStorage extendedblockstorage = this.storageArrays[yPos >> 4];
    // Sponge - make this final so we don't change it later
    final boolean requiresNewLightCalculations;
    // Sponge - Forge moves this from
    int newBlockLightOpacity = SpongeImplHooks.getBlockLightOpacity(newState, this.world, pos);
    if (extendedblockstorage == net.minecraft.world.chunk.Chunk.NULL_BLOCK_STORAGE) {
        if (newBlock == Blocks.AIR) {
            return null;
        }
        extendedblockstorage = this.storageArrays[yPos >> 4] = new ExtendedBlockStorage(yPos >> 4 << 4, this.world.provider.hasSkyLight());
        requiresNewLightCalculations = yPos >= currentHeight;
    // Sponge Start - properly initialize variable
    } else {
        requiresNewLightCalculations = false;
    }
    // Sponge end
    // Sponge Start
    final int modifiedY = yPos & 15;
    extendedblockstorage.set(xPos, modifiedY, zPos, newState);
    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
    final PhaseData peek = phaseTracker.getCurrentPhaseData();
    final boolean requiresCapturing = peek.state.requiresBlockCapturing();
    // if (block1 != block) // Sponge - Forge removes this change.
    {
        if (!this.world.isRemote) {
            // Sponge - Forge adds this change for block changes to only fire events when necessary
            if (currentState.getBlock() != newState.getBlock()) {
                currentBlock.breakBlock(this.world, pos, currentState);
            }
            // Sponge - Add several tile entity hook checks. Mainly for forge added hooks, but these
            // still work by themselves in vanilla.
            TileEntity te = this.getTileEntity(pos, EnumCreateEntityType.CHECK);
            if (te != null && SpongeImplHooks.shouldRefresh(te, this.world, pos, currentState, newState)) {
                this.world.removeTileEntity(pos);
            }
        // } else if (currentBlock instanceof ITileEntityProvider) { // Sponge - remove since forge has a special hook we need to add here
        } else if (SpongeImplHooks.hasBlockTileEntity(currentBlock, currentState)) {
            TileEntity tileEntity = this.getTileEntity(pos, EnumCreateEntityType.CHECK);
            // Sponge - Add hook for refreshing, because again, forge hooks.
            if (tileEntity != null && SpongeImplHooks.shouldRefresh(tileEntity, this.world, pos, currentState, newState)) {
                this.world.removeTileEntity(pos);
            }
        }
    }
    final IBlockState blockAfterSet = extendedblockstorage.get(xPos, modifiedY, zPos);
    if (blockAfterSet.getBlock() != newBlock) {
        return null;
    }
    // } else { // Sponge - remove unnecessary else
    if (requiresNewLightCalculations) {
        this.generateSkylightMap();
    } else {
        // int newBlockLightOpacity = state.getLightOpacity(); - Sponge Forge moves this all the way up before tile entities are removed.
        // int postNewBlockLightOpacity = newState.getLightOpacity(this.worldObj, pos); - Sponge use the SpongeImplHooks for forge compatibility
        int postNewBlockLightOpacity = SpongeImplHooks.getBlockLightOpacity(newState, this.world, pos);
        if (newBlockLightOpacity > 0) {
            if (yPos >= currentHeight) {
                this.relightBlock(xPos, yPos + 1, zPos);
            }
        } else if (yPos == currentHeight - 1) {
            this.relightBlock(xPos, yPos, zPos);
        }
        if (newBlockLightOpacity != postNewBlockLightOpacity && (newBlockLightOpacity < postNewBlockLightOpacity || this.getLightFor(EnumSkyBlock.SKY, pos) > 0 || this.getLightFor(EnumSkyBlock.BLOCK, pos) > 0)) {
            this.propagateSkylightOcclusion(xPos, zPos);
        }
    }
    if (!this.world.isRemote && currentBlock != newBlock) {
        // a BlockContainer. Prevents blocks such as TNT from activating when cancelled.
        if (!requiresCapturing || SpongeImplHooks.hasBlockTileEntity(newBlock, newState)) {
            // If it is null, then directly call the onBlockAdded logic.
            if (flag.performBlockPhysics()) {
                newBlock.onBlockAdded(this.world, pos, newState);
            }
        }
    // Sponge end
    }
    // if (block instanceof ITileEntityProvider) { // Sponge
    if (SpongeImplHooks.hasBlockTileEntity(newBlock, newState)) {
        // Sponge End
        TileEntity tileentity = this.getTileEntity(pos, EnumCreateEntityType.CHECK);
        if (tileentity == null) {
            // Sponge Start - use SpongeImplHooks for forge compatibility
            // tileentity = ((ITileEntityProvider)block).createNewTileEntity(this.worldObj, block.getMetaFromState(state)); // Sponge
            tileentity = SpongeImplHooks.createTileEntity(newBlock, this.world, newState);
            final User owner = peek.context.getOwner().orElse(null);
            // This is required for TE's that get created during move such as pistons and ComputerCraft turtles.
            if (owner != null) {
                IMixinChunk spongeChunk = (IMixinChunk) this;
                spongeChunk.addTrackedBlockPosition(newBlock, pos, owner, PlayerTracker.Type.OWNER);
            }
            // Sponge End
            this.world.setTileEntity(pos, tileentity);
        }
        if (tileentity != null) {
            tileentity.updateContainingBlockInfo();
        }
    }
    this.dirty = true;
    return currentState;
}
Also used : TileEntity(net.minecraft.tileentity.TileEntity) IMixinTileEntity(org.spongepowered.common.interfaces.block.tile.IMixinTileEntity) PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) PhaseData(org.spongepowered.common.event.tracking.PhaseData) IBlockState(net.minecraft.block.state.IBlockState) User(org.spongepowered.api.entity.living.player.User) IMixinChunk(org.spongepowered.common.interfaces.IMixinChunk) Block(net.minecraft.block.Block) EnumSkyBlock(net.minecraft.world.EnumSkyBlock) ExtendedBlockStorage(net.minecraft.world.chunk.storage.ExtendedBlockStorage) Nullable(javax.annotation.Nullable)

Example 13 with PhaseTracker

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

the class MixinWorldServer method onFireBlockEvent.

// special handling for Pistons since they use their own event system
@Redirect(method = "sendQueuedBlockEvents", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/WorldServer;fireBlockEvent(Lnet/minecraft/block/BlockEventData;)Z"))
private boolean onFireBlockEvent(net.minecraft.world.WorldServer worldIn, BlockEventData event) {
    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
    final IPhaseState phaseState = phaseTracker.getCurrentState();
    if (phaseState.ignoresBlockEvent()) {
        return fireBlockEvent(event);
    }
    return TrackingUtil.fireMinecraftBlockEvent(worldIn, event);
}
Also used : PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) IPhaseState(org.spongepowered.common.event.tracking.IPhaseState) Redirect(org.spongepowered.asm.mixin.injection.Redirect)

Example 14 with PhaseTracker

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

the class MixinWorldServer method notifyNeighborsOfStateExcept.

/**
 * @author gabizou - March 12th, 2016
 *
 * Technically an overwrite to properly track on *server* worlds.
 */
@Override
public void notifyNeighborsOfStateExcept(BlockPos pos, Block blockType, EnumFacing skipSide) {
    if (!isValid(pos)) {
        return;
    }
    final Chunk chunk = ((IMixinChunkProviderServer) this.getChunkProvider()).getLoadedChunkWithoutMarkingActive(pos.getX() >> 4, pos.getZ() >> 4);
    // Don't let neighbor updates trigger a chunk load ever
    if (chunk == null) {
        return;
    }
    EnumSet<EnumFacing> directions = EnumSet.copyOf(NOTIFY_DIRECTIONS);
    directions.remove(skipSide);
    final NotifyNeighborBlockEvent event = SpongeCommonEventFactory.callNotifyNeighborEvent(this, pos, directions);
    if (event == null || !event.isCancelled()) {
        final PhaseTracker phaseTracker = PhaseTracker.getInstance();
        for (EnumFacing facing : EnumFacing.values()) {
            if (event != null) {
                final Direction direction = DirectionFacingProvider.getInstance().getKey(facing).get();
                if (!event.getNeighbors().keySet().contains(direction)) {
                    continue;
                }
            }
            phaseTracker.notifyBlockOfStateChange(this, pos.offset(facing), blockType, pos);
        }
    }
}
Also used : NotifyNeighborBlockEvent(org.spongepowered.api.event.block.NotifyNeighborBlockEvent) PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) EnumFacing(net.minecraft.util.EnumFacing) IMixinChunk(org.spongepowered.common.interfaces.IMixinChunk) Chunk(net.minecraft.world.chunk.Chunk) IMixinChunkProviderServer(org.spongepowered.common.interfaces.world.gen.IMixinChunkProviderServer) Direction(org.spongepowered.api.util.Direction)

Example 15 with PhaseTracker

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

the class MixinWorldServer method onCallEntityUpdate.

@Override
public void onCallEntityUpdate(net.minecraft.entity.Entity entity) {
    final PhaseTracker phaseTracker = PhaseTracker.getInstance();
    final IPhaseState state = phaseTracker.getCurrentState();
    if (state.alreadyCapturingEntityTicks()) {
        entity.onUpdate();
        return;
    }
    TrackingUtil.tickEntity(entity);
    updateRotation(entity);
}
Also used : PhaseTracker(org.spongepowered.common.event.tracking.PhaseTracker) IPhaseState(org.spongepowered.common.event.tracking.IPhaseState)

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