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