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;
}
}
}
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;
}
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);
}
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);
}
}
}
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);
}
Aggregations