use of org.spongepowered.common.event.tracking.PhaseContext in project SpongeCommon by SpongePowered.
the class PlayerPhase method unwind.
@SuppressWarnings("unchecked")
public void unwind(IPhaseState<?> state, PhaseContext<?> phaseContext) {
// Since currently all we have is PLAYER_LOGOUT, don't care about
// states.
final Player player = phaseContext.getSource(Player.class).orElseThrow(TrackingUtil.throwWithContext("Expected to be processing a player leaving, but we're not!", phaseContext));
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(player);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.DISPENSE);
phaseContext.getCapturedItemsSupplier().acceptAndClearIfNotEmpty(items -> {
final ArrayList<Entity> entities = new ArrayList<>();
for (EntityItem item : items) {
entities.add(EntityUtil.fromNative(item));
}
final DropItemEvent.Dispense dispense = SpongeEventFactory.createDropItemEventDispense(Sponge.getCauseStackManager().getCurrentCause(), entities);
SpongeImpl.postEvent(dispense);
if (!dispense.isCancelled()) {
for (Entity entity : dispense.getEntities()) {
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
});
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.DROPPED_ITEM);
phaseContext.getCapturedItemStackSupplier().acceptAndClearIfNotEmpty(items -> {
final List<EntityItem> drops = items.stream().map(drop -> drop.create(EntityUtil.getMinecraftWorld(player))).collect(Collectors.toList());
final List<Entity> entities = (List<Entity>) (List<?>) drops;
if (!entities.isEmpty()) {
DropItemEvent.Custom event = SpongeEventFactory.createDropItemEventCustom(Sponge.getCauseStackManager().getCurrentCause(), entities);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity droppedItem : event.getEntities()) {
EntityUtil.getMixinWorld(droppedItem).forceSpawnEntity(droppedItem);
}
}
}
});
phaseContext.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(blocks -> TrackingUtil.processBlockCaptures(blocks, state, phaseContext));
}
}
use of org.spongepowered.common.event.tracking.PhaseContext in project SpongeCommon by SpongePowered.
the class ContainerBasedTransaction method generateEvent.
@Override
public Optional<ClickContainerEvent> generateEvent(final PhaseContext<@NonNull ?> context, @Nullable final GameTransaction<@NonNull ?> parent, final ImmutableList<GameTransaction<ClickContainerEvent>> gameTransactions, final Cause currentCause) {
final ImmutableList<ContainerBasedTransaction> containerBasedTransactions = gameTransactions.stream().filter(tx -> tx instanceof ContainerBasedTransaction).map(tx -> (ContainerBasedTransaction) tx).filter(tx -> !tx.used).collect(ImmutableList.toImmutableList());
if (containerBasedTransactions.stream().map(c -> c.isContainerEventAllowed(context)).filter(b -> !b).findAny().orElse(false)) {
SpongeCommon.logger().warn("No event will be fired for existing ContainerBasedTransactions: {}", containerBasedTransactions.size());
return Optional.empty();
}
if (!((TrackedContainerBridge) this.menu).bridge$capturePossible()) {
// if (ContainerBasedTransaction.containersFailedCapture.add(this.menu.getClass())) {
// SpongeCommon.logger()
// .warn("Changes in modded Container were not captured. Inventory events will not fire for this. Container: " + this.menu.getClass());
// }
}
final List<Entity> entities = containerBasedTransactions.stream().map(ContainerBasedTransaction::getEntitiesSpawned).flatMap(List::stream).collect(Collectors.toList());
final List<SlotTransaction> slotTransactions = containerBasedTransactions.stream().map(ContainerBasedTransaction::getSlotTransactions).flatMap(List::stream).collect(Collectors.toList());
if (this.craftingInventory != null) {
// Event with Preview transaction on crafting inventory?
Slot slot = this.craftingInventory.result();
@Nullable final SlotTransaction preview = this.findPreviewTransaction(this.craftingInventory.result(), slotTransactions);
final ItemStackSnapshot previewItem = ItemStackUtil.snapshotOf(this.craftingInventory.peek());
if (preview != null) {
slot = preview.slot();
// Check if preview transaction is correct
if (!preview.defaultReplacement().equals(previewItem)) {
slotTransactions.remove(preview);
slotTransactions.add(new SlotTransaction(slot, preview.original(), previewItem));
}
} else if (!previewItem.isEmpty()) {
slotTransactions.add(new SlotTransaction(slot, previewItem, previewItem));
}
}
for (final ContainerBasedTransaction transaction : containerBasedTransactions) {
transaction.used = true;
}
final Optional<ClickContainerEvent> event = containerBasedTransactions.stream().map(t -> t.createInventoryEvent(slotTransactions, entities, context, currentCause)).filter(Optional::isPresent).map(Optional::get).findFirst();
if (!event.isPresent() && !slotTransactions.isEmpty()) {
SpongeCommon.logger().warn("Logged slot transactions without event! {} {}", gameTransactions.size(), this.menu.getClass().getName(), new Exception(""));
for (final SlotTransaction slotTransaction : slotTransactions) {
SpongeCommon.logger().warn(slotTransaction);
}
}
return event;
}
use of org.spongepowered.common.event.tracking.PhaseContext in project SpongeCommon by SpongePowered.
the class TransactionalCaptureSupplier method generateEventForTransaction.
@SuppressWarnings("unchecked")
private static <E extends Event & Cancellable> void generateEventForTransaction(@NonNull final GameTransaction<E> pointer, @Nullable final GameTransaction<@NonNull ?> parent, final PhaseContext<@NonNull ?> context, final ImmutableList.Builder<EventByTransaction<@NonNull ?>> builder, final ImmutableList<GameTransaction<E>> transactions, final ImmutableMultimap.Builder<TransactionType, ? extends Event> transactionPostEventBuilder) {
final Optional<BiConsumer<PhaseContext<@NonNull ?>, CauseStackManager.StackFrame>> frameMutator = pointer.getFrameMutator(parent);
final PhaseTracker instance = PhaseTracker.getInstance();
try (final CauseStackManager.StackFrame frame = frameMutator.map(mutator -> {
final CauseStackManager.StackFrame transactionFrame = instance.pushCauseFrame();
mutator.accept(context, transactionFrame);
return transactionFrame;
}).orElseGet(instance::pushCauseFrame)) {
final Optional<E> generatedEvent = pointer.generateEvent(context, parent, transactions, instance.currentCause());
generatedEvent.ifPresent(e -> {
final EventByTransaction<E> element = new EventByTransaction<>(e, transactions, parent, pointer);
builder.add(element);
((ImmutableMultimap.Builder) transactionPostEventBuilder).put(pointer.getTransactionType(), e);
});
for (final GameTransaction<E> transaction : transactions) {
if (transaction.sideEffects == null || transaction.sideEffects.isEmpty()) {
continue;
}
generatedEvent.ifPresent(frame::pushCause);
for (final ResultingTransactionBySideEffect sideEffect : transaction.sideEffects) {
if (sideEffect.head == null) {
continue;
}
builder.addAll(TransactionalCaptureSupplier.batchTransactions(sideEffect.head, pointer, context, transactionPostEventBuilder));
}
}
}
}
use of org.spongepowered.common.event.tracking.PhaseContext in project SpongeCommon by SpongePowered.
the class BlockTransactionType method consumeEventsAndMarker.
@Override
protected void consumeEventsAndMarker(PhaseContext<@NonNull ?> context, final Collection<? extends ChangeBlockEvent.All> changeBlockEvents) {
final Multimap<ResourceKey, ChangeBlockEvent.All> eventsByWorld = LinkedListMultimap.create();
changeBlockEvents.forEach(event -> eventsByWorld.put(event.world().key(), event));
eventsByWorld.asMap().forEach((key, events) -> {
final Optional<ServerWorld> serverWorld = ((SpongeServer) SpongeCommon.server()).worldManager().world(key);
if (!serverWorld.isPresent()) {
return;
}
final ListMultimap<BlockPos, SpongeBlockSnapshot> positions = LinkedListMultimap.create();
// Gather transactions that were valid
events.stream().filter(event -> !event.isCancelled()).flatMap(event -> event.transactions().stream()).filter(BlockTransaction::isValid).forEach(transactions -> {
// Then "put" the most recent transactions such that we have a complete rebuild of
// each position according to what originally existed and then
// the ultimate final block on that position
final SpongeBlockSnapshot original = (SpongeBlockSnapshot) transactions.original();
positions.put(original.getBlockPos(), original);
positions.put(original.getBlockPos(), (SpongeBlockSnapshot) transactions.finalReplacement());
});
// just return.
if (positions.isEmpty()) {
return;
}
final ImmutableList<BlockTransactionReceipt> transactions = positions.asMap().values().stream().map(spongeBlockSnapshots -> {
final List<SpongeBlockSnapshot> snapshots = new ArrayList<>(spongeBlockSnapshots);
if (snapshots.isEmpty() || snapshots.size() < 2) {
// Error case
return Optional.<BlockTransactionReceipt>empty();
}
final SpongeBlockSnapshot original = snapshots.get(0);
final SpongeBlockSnapshot result = snapshots.get(snapshots.size() - 1);
final Operation operation = context.getBlockOperation(original, result);
final BlockTransactionReceipt eventTransaction = new BlockTransactionReceipt(original, result, operation);
context.postBlockTransactionApplication(original.blockChange, eventTransaction);
return Optional.of(eventTransaction);
}).filter(Optional::isPresent).map(Optional::get).collect(ImmutableList.toImmutableList());
final Cause cause = PhaseTracker.getInstance().currentCause();
SpongeCommon.post(SpongeEventFactory.createChangeBlockEventPost(cause, transactions, serverWorld.get()));
});
}
use of org.spongepowered.common.event.tracking.PhaseContext in project SpongeCommon by SpongePowered.
the class InventoryBasedTransaction method generateEvent.
@Override
public Optional<ChangeInventoryEvent> generateEvent(final PhaseContext<@NonNull ?> context, @Nullable final GameTransaction<@NonNull ?> parent, final ImmutableList<GameTransaction<ChangeInventoryEvent>> gameTransactions, final Cause currentCause) {
final ImmutableList<InventoryBasedTransaction> containerBasedTransactions = gameTransactions.stream().filter(tx -> tx instanceof InventoryBasedTransaction).map(tx -> (InventoryBasedTransaction) tx).filter(tx -> !tx.used).collect(ImmutableList.toImmutableList());
final List<SlotTransaction> slotTransactions = containerBasedTransactions.stream().map(InventoryBasedTransaction::getSlotTransactions).flatMap(List::stream).collect(Collectors.toList());
for (InventoryBasedTransaction transaction : containerBasedTransactions) {
transaction.used = true;
}
final List<Entity> entities = containerBasedTransactions.stream().map(InventoryBasedTransaction::getEntitiesSpawned).flatMap(List::stream).collect(Collectors.toList());
// TODO on pickup grouping does not work?
final Map<Slot, List<SlotTransaction>> collected = slotTransactions.stream().collect(Collectors.groupingBy(SlotTransaction::slot));
slotTransactions.clear();
collected.values().forEach(list -> {
final SlotTransaction first = list.get(0);
if (list.size() > 1) {
final ItemStackSnapshot last = list.get(list.size() - 1).defaultReplacement();
slotTransactions.add(new SlotTransaction(first.slot(), first.original(), last));
} else {
slotTransactions.add(first);
}
});
return containerBasedTransactions.stream().map(t -> t.createInventoryEvent(slotTransactions, entities, context, currentCause)).filter(Optional::isPresent).map(Optional::get).findFirst();
}
Aggregations