use of org.spongepowered.api.event.CauseStackManager.StackFrame in project SpongeCommon by SpongePowered.
the class DropItemWithHotkeyState method createInventoryEvent.
@Override
public ClickInventoryEvent.Drop createInventoryEvent(EntityPlayerMP playerMP, Container openContainer, Transaction<ItemStackSnapshot> transaction, List<SlotTransaction> slotTransactions, List<Entity> capturedEntities, int usedButton) {
try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.DROPPED_ITEM);
Sponge.getCauseStackManager().pushCause(openContainer);
Sponge.getCauseStackManager().pushCause(playerMP);
for (Entity currentEntity : capturedEntities) {
currentEntity.setCreator(playerMP.getUniqueID());
}
// A 'primary click' is used by the game to indicate a single drop (e.g. pressing 'q' without holding
// 'control')
ClickInventoryEvent.Drop event = usedButton == PacketPhase.PACKET_BUTTON_PRIMARY_ID ? SpongeEventFactory.createClickInventoryEventDropSingle(Sponge.getCauseStackManager().getCurrentCause(), transaction, capturedEntities, openContainer, slotTransactions) : SpongeEventFactory.createClickInventoryEventDropFull(Sponge.getCauseStackManager().getCurrentCause(), transaction, capturedEntities, openContainer, slotTransactions);
// the event call, somehow should not release this frame until after the event is posted
return event;
}
}
use of org.spongepowered.api.event.CauseStackManager.StackFrame in project SpongeCommon by SpongePowered.
the class SpongeCommonEventFactory method callDestructEntityEventDeath.
public static DestructEntityEvent.Death callDestructEntityEventDeath(EntityLivingBase entity, DamageSource source) {
final MessageEvent.MessageFormatter formatter = new MessageEvent.MessageFormatter();
MessageChannel originalChannel;
MessageChannel channel;
Text originalMessage;
Optional<User> sourceCreator = Optional.empty();
boolean messageCancelled = false;
if (entity instanceof EntityPlayerMP) {
originalChannel = channel = ((IMixinEntityPlayerMP) entity).getDeathMessageChannel();
} else {
originalChannel = MessageChannel.TO_NONE;
channel = MessageChannel.TO_NONE;
}
if (source instanceof EntityDamageSource) {
EntityDamageSource damageSource = (EntityDamageSource) source;
IMixinEntity spongeEntity = (IMixinEntity) damageSource.getImmediateSource();
if (spongeEntity != null) {
sourceCreator = spongeEntity.getCreatorUser();
}
}
originalMessage = SpongeTexts.toText(entity.getCombatTracker().getDeathMessage());
formatter.getBody().add(new MessageEvent.DefaultBodyApplier(originalMessage));
final boolean isMainThread = Sponge.isServerAvailable() && Sponge.getServer().isMainThread();
// checks need to be made here since entities can die on the client world.
try (final StackFrame frame = isMainThread ? Sponge.getCauseStackManager().pushCauseFrame() : null) {
if (isMainThread) {
Sponge.getCauseStackManager().pushCause(source);
if (sourceCreator.isPresent()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, sourceCreator.get());
}
}
final Cause cause = isMainThread ? Sponge.getCauseStackManager().getCurrentCause() : Cause.of(EventContext.empty(), source);
DestructEntityEvent.Death event = SpongeEventFactory.createDestructEntityEventDeath(cause, originalChannel, Optional.of(channel), formatter, (Living) entity, entity.world.getGameRules().getBoolean("keepInventory"), messageCancelled);
SpongeImpl.postEvent(event);
Text message = event.getMessage();
if (!event.isMessageCancelled() && !message.isEmpty()) {
event.getChannel().ifPresent(eventChannel -> eventChannel.send(entity, event.getMessage()));
}
return event;
}
}
use of org.spongepowered.api.event.CauseStackManager.StackFrame in project SpongeCommon by SpongePowered.
the class SpongeCommonEventFactory method handlePistonEvent.
/**
* This simulates the blocks a piston moves and calls the event for saner
* debugging.
*
* @return if the event was cancelled
*/
public static boolean handlePistonEvent(IMixinWorldServer world, WorldServer.ServerBlockEventList list, Object obj, BlockPos pos, Block blockIn, int eventId, int eventParam) {
boolean extending = (eventId == 0);
final IBlockState blockstate = ((net.minecraft.world.World) world).getBlockState(pos);
EnumFacing direction = blockstate.getValue(BlockDirectional.FACING);
final LocatableBlock locatable = LocatableBlock.builder().location(new Location<>((World) world, pos.getX(), pos.getY(), pos.getZ())).state((BlockState) blockstate).build();
// Sets toss out duplicate values (even though there shouldn't be any)
HashSet<Location<org.spongepowered.api.world.World>> locations = new HashSet<>();
locations.add(new Location<>((World) world, pos.getX(), pos.getY(), pos.getZ()));
BlockPistonStructureHelper movedBlocks = new BlockPistonStructureHelper((WorldServer) world, pos, direction, extending);
// calculates blocks to be moved
movedBlocks.canMove();
Stream.concat(movedBlocks.getBlocksToMove().stream(), movedBlocks.getBlocksToDestroy().stream()).map(block -> new Location<>((World) world, block.getX(), block.getY(), block.getZ())).collect(// SUPER
Collectors.toCollection(() -> locations));
// If the piston is extending and there are no blocks to destroy, add the offset location for protection purposes
if (extending && movedBlocks.getBlocksToDestroy().isEmpty()) {
final List<BlockPos> movedPositions = movedBlocks.getBlocksToMove();
BlockPos offsetPos;
// If there are no blocks to move, add the offset of piston
if (movedPositions.isEmpty()) {
offsetPos = pos.offset(direction);
} else {
// Add the offset of last block set to move
offsetPos = movedPositions.get(movedPositions.size() - 1).offset(direction);
}
locations.add(new Location<>((World) world, offsetPos.getX(), offsetPos.getY(), offsetPos.getZ()));
}
try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
if (extending) {
Sponge.getCauseStackManager().addContext(EventContextKeys.PISTON_EXTEND, world.asSpongeWorld());
} else {
Sponge.getCauseStackManager().addContext(EventContextKeys.PISTON_RETRACT, world.asSpongeWorld());
}
return SpongeCommonEventFactory.callChangeBlockEventPre(world, ImmutableList.copyOf(locations), locatable).isCancelled();
}
}
use of org.spongepowered.api.event.CauseStackManager.StackFrame 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
}
use of org.spongepowered.api.event.CauseStackManager.StackFrame in project SpongeCommon by SpongePowered.
the class BlockEventTickPhaseState method unwind.
@Override
public void unwind(BlockEventTickContext phaseContext) {
final Optional<User> notifier = phaseContext.getNotifier();
final Optional<User> owner = phaseContext.getOwner();
final User entityCreator = notifier.orElseGet(() -> owner.orElse(null));
try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.CUSTOM);
phaseContext.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(blockSnapshots -> TrackingUtil.processBlockCaptures(blockSnapshots, this, phaseContext));
phaseContext.getCapturedItemsSupplier().acceptAndClearIfNotEmpty(items -> {
final ArrayList<Entity> capturedEntities = new ArrayList<>();
for (EntityItem entity : items) {
capturedEntities.add(EntityUtil.fromNative(entity));
}
final SpawnEntityEvent spawnEntityEvent = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), capturedEntities);
SpongeImpl.postEvent(spawnEntityEvent);
for (Entity entity : spawnEntityEvent.getEntities()) {
if (entityCreator != null) {
EntityUtil.toMixin(entity).setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
});
}
}
Aggregations