use of org.spongepowered.common.event.tracking.context.ItemDropData in project SpongeCommon by SpongePowered.
the class CommandState method unwind.
@Override
public void unwind(CommandPhaseContext phaseContext) {
Optional<EntityPlayer> playerSource = phaseContext.getSource(EntityPlayer.class);
if (playerSource.isPresent()) {
// Post event for inventory changes
((IMixinInventoryPlayer) playerSource.get().inventory).setCapture(false);
List<SlotTransaction> list = ((IMixinInventoryPlayer) playerSource.get().inventory).getCapturedTransactions();
if (!list.isEmpty()) {
ChangeInventoryEvent event = SpongeEventFactory.createChangeInventoryEvent(Sponge.getCauseStackManager().getCurrentCause(), ((Inventory) playerSource.get().inventory), list);
SpongeImpl.postEvent(event);
PacketPhaseUtil.handleSlotRestore(playerSource.get(), null, list, event.isCancelled());
list.clear();
}
}
final CommandSource sender = phaseContext.getSource(CommandSource.class).orElseThrow(TrackingUtil.throwWithContext("Expected to be capturing a Command Sender, but none found!", phaseContext));
phaseContext.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(list -> TrackingUtil.processBlockCaptures(list, this, phaseContext));
try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(sender);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.PLACEMENT);
phaseContext.getCapturedEntitySupplier().acceptAndClearIfNotEmpty(entities -> {
// TODO the entity spawn causes are not likely valid,
// need to investigate further.
final SpawnEntityEvent spawnEntityEvent = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), entities);
SpongeImpl.postEvent(spawnEntityEvent);
if (!spawnEntityEvent.isCancelled()) {
final boolean isPlayer = sender instanceof Player;
final Player player = isPlayer ? (Player) sender : null;
for (Entity entity : spawnEntityEvent.getEntities()) {
if (isPlayer) {
EntityUtil.toMixin(entity).setCreator(player.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
});
}
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(sender);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
phaseContext.getCapturedEntityDropSupplier().acceptIfNotEmpty(uuidItemStackMultimap -> {
for (Map.Entry<UUID, Collection<ItemDropData>> entry : uuidItemStackMultimap.asMap().entrySet()) {
final UUID key = entry.getKey();
@Nullable net.minecraft.entity.Entity foundEntity = null;
for (WorldServer worldServer : WorldManager.getWorlds()) {
final net.minecraft.entity.Entity entityFromUuid = worldServer.getEntityFromUuid(key);
if (entityFromUuid != null) {
foundEntity = entityFromUuid;
break;
}
}
final Optional<Entity> affectedEntity = Optional.ofNullable((Entity) foundEntity);
if (!affectedEntity.isPresent()) {
continue;
}
final Collection<ItemDropData> itemStacks = entry.getValue();
if (itemStacks.isEmpty()) {
return;
}
final List<ItemDropData> items = new ArrayList<>();
items.addAll(itemStacks);
itemStacks.clear();
final WorldServer minecraftWorld = EntityUtil.getMinecraftWorld(affectedEntity.get());
if (!items.isEmpty()) {
final List<Entity> itemEntities = items.stream().map(data -> data.create(minecraftWorld)).map(EntityUtil::fromNative).collect(Collectors.toList());
Sponge.getCauseStackManager().pushCause(affectedEntity.get());
final DropItemEvent.Destruct destruct = SpongeEventFactory.createDropItemEventDestruct(Sponge.getCauseStackManager().getCurrentCause(), itemEntities);
SpongeImpl.postEvent(destruct);
Sponge.getCauseStackManager().popCause();
if (!destruct.isCancelled()) {
final boolean isPlayer = sender instanceof Player;
final Player player = isPlayer ? (Player) sender : null;
for (Entity entity : destruct.getEntities()) {
if (isPlayer) {
EntityUtil.toMixin(entity).setCreator(player.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
}
}
});
}
}
use of org.spongepowered.common.event.tracking.context.ItemDropData in project SpongeCommon by SpongePowered.
the class GeneralPhase method performPostBlockAdditions.
@SuppressWarnings("unchecked")
private static void performPostBlockAdditions(PhaseContext<?> postContext, List<Transaction<BlockSnapshot>> transactions, IPhaseState<?> unwindingState, PhaseContext<?> unwindingPhaseContext) {
// We have to use a proxy so that our pending changes are notified such that any accessors from block
// classes do not fail on getting the incorrect block state from the IBlockAccess
final SpongeProxyBlockAccess proxyBlockAccess = new SpongeProxyBlockAccess(transactions);
final CapturedMultiMapSupplier<BlockPos, ItemDropData> capturedBlockDrops = postContext.getBlockDropSupplier();
final CapturedMultiMapSupplier<BlockPos, EntityItem> capturedBlockItemEntityDrops = postContext.getBlockItemDropSupplier();
for (Transaction<BlockSnapshot> transaction : transactions) {
if (!transaction.isValid()) {
// Don't use invalidated block transactions during notifications, these only need to be restored
continue;
}
// Handle custom replacements
if (transaction.getCustom().isPresent()) {
transaction.getFinal().restore(true, BlockChangeFlags.ALL);
}
final SpongeBlockSnapshot oldBlockSnapshot = (SpongeBlockSnapshot) transaction.getOriginal();
final SpongeBlockSnapshot newBlockSnapshot = (SpongeBlockSnapshot) transaction.getFinal();
// Handle item drops captured
final Location<World> worldLocation = oldBlockSnapshot.getLocation().get();
final IMixinWorldServer mixinWorldServer = (IMixinWorldServer) worldLocation.getExtent();
final BlockPos pos = ((IMixinLocation) (Object) worldLocation).getBlockPos();
capturedBlockDrops.acceptAndRemoveIfPresent(pos, items -> TrackingUtil.spawnItemDataForBlockDrops(items, oldBlockSnapshot, unwindingPhaseContext, unwindingState));
capturedBlockItemEntityDrops.acceptAndRemoveIfPresent(pos, items -> TrackingUtil.spawnItemEntitiesForBlockDrops(items, oldBlockSnapshot, unwindingPhaseContext, unwindingState));
final WorldServer worldServer = mixinWorldServer.asMinecraftWorld();
SpongeHooks.logBlockAction(worldServer, oldBlockSnapshot.blockChange, transaction);
final SpongeBlockChangeFlag spongeFlag = oldBlockSnapshot.getChangeFlag();
final int updateFlag = spongeFlag.getRawFlag();
final IBlockState originalState = (IBlockState) oldBlockSnapshot.getState();
final IBlockState newState = (IBlockState) newBlockSnapshot.getState();
// Containers get placed automatically
final CapturedSupplier<BlockSnapshot> capturedBlockSupplier = postContext.getCapturedBlockSupplier();
if (spongeFlag.performBlockPhysics() && originalState.getBlock() != newState.getBlock() && !SpongeImplHooks.hasBlockTileEntity(newState.getBlock(), newState)) {
newState.getBlock().onBlockAdded(worldServer, pos, newState);
postContext.getCapturedEntitySupplier().acceptAndClearIfNotEmpty(entities -> {
final ArrayList<Entity> capturedEntities = new ArrayList<>(entities);
((IPhaseState) unwindingState).postProcessSpawns(unwindingPhaseContext, capturedEntities);
});
capturedBlockSupplier.acceptAndClearIfNotEmpty(blocks -> {
final List<BlockSnapshot> blockSnapshots = new ArrayList<>(blocks);
processBlockTransactionListsPost(postContext, blockSnapshots, unwindingState, unwindingPhaseContext);
});
}
proxyBlockAccess.proceed();
((IPhaseState) unwindingState).handleBlockChangeWithUser(oldBlockSnapshot.blockChange, transaction, unwindingPhaseContext);
if (spongeFlag.isNotifyClients()) {
// Since notifyBlockUpdate is basically to tell clients that the block position has changed,
// we need to respect that flag
worldServer.notifyBlockUpdate(pos, originalState, newState, updateFlag);
}
if (spongeFlag.updateNeighbors()) {
// Notify neighbors only if the change flag allowed it.
mixinWorldServer.spongeNotifyNeighborsPostBlockChange(pos, originalState, newState, spongeFlag);
} else if (spongeFlag.notifyObservers()) {
worldServer.updateObservingBlocksAt(pos, newState.getBlock());
}
capturedBlockSupplier.acceptAndClearIfNotEmpty(blocks -> {
final List<BlockSnapshot> blockSnapshots = new ArrayList<>(blocks);
blocks.clear();
processBlockTransactionListsPost(postContext, blockSnapshots, unwindingState, unwindingPhaseContext);
});
}
}
use of org.spongepowered.common.event.tracking.context.ItemDropData in project SpongeCommon by SpongePowered.
the class InteractEntityPacketState method unwind.
@Override
public void unwind(BasicPacketContext phaseContext) {
final EntityPlayerMP player = phaseContext.getPacketPlayer();
final CPacketUseEntity useEntityPacket = phaseContext.getPacket();
final net.minecraft.entity.Entity entity = useEntityPacket.getEntityFromWorld(player.world);
if (entity == null) {
// Something happened?
return;
}
final World spongeWorld = EntityUtil.getSpongeWorld(player);
EntityUtil.toMixin(entity).setNotifier(player.getUniqueID());
phaseContext.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(blocks -> {
final PrettyPrinter printer = new PrettyPrinter(80);
printer.add("Processing Interact Entity").centre().hr();
printer.add("The blocks captured are:");
for (BlockSnapshot blockSnapshot : blocks) {
printer.add(" Block: %s", blockSnapshot);
}
printer.trace(System.err);
});
phaseContext.getCapturedEntitySupplier().acceptAndClearIfNotEmpty(entities -> {
final PrettyPrinter printer = new PrettyPrinter(80);
printer.add("Processing Interact Entity").centre().hr();
printer.add("The entities captured are:");
for (Entity capturedEntity : entities) {
printer.add(" Entity: %s", capturedEntity);
}
printer.trace(System.err);
});
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(player);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.PLACEMENT);
phaseContext.getCapturedItemsSupplier().acceptAndClearIfNotEmpty(entities -> {
final List<Entity> items = entities.stream().map(EntityUtil::fromNative).collect(Collectors.toList());
SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), items);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
processSpawnedEntities(player, event);
}
});
}
phaseContext.getCapturedEntityDropSupplier().acceptIfNotEmpty(map -> {
final PrettyPrinter printer = new PrettyPrinter(80);
printer.add("Processing Interact Entity").centre().hr();
printer.add("The item stacks captured are: ");
for (Map.Entry<UUID, Collection<ItemDropData>> entry : map.asMap().entrySet()) {
printer.add(" - Entity with UUID: %s", entry.getKey());
for (ItemDropData stack : entry.getValue()) {
printer.add(" - %s", stack);
}
}
printer.trace(System.err);
});
phaseContext.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(snapshots -> TrackingUtil.processBlockCaptures(snapshots, this, phaseContext));
}
use of org.spongepowered.common.event.tracking.context.ItemDropData in project SpongeCommon by SpongePowered.
the class ContainerUtil method performBlockInventoryDrops.
/**
* Replacement helper method for {@link MixinInventoryHelper#spongeDropInventoryItems(World, double, double, double, IInventory)}
* to perform cause tracking related drops. This is specific for blocks, not for any other cases.
*
* @param worldServer The world server
* @param x the x position
* @param y the y position
* @param z the z position
* @param inventory The inventory to drop items from
*/
public static void performBlockInventoryDrops(WorldServer worldServer, double x, double y, double z, IInventory inventory) {
final PhaseData currentPhase = PhaseTracker.getInstance().getCurrentPhaseData();
final IPhaseState currentState = currentPhase.state;
if (currentState.tracksBlockSpecificDrops()) {
final PhaseContext<?> context = currentPhase.context;
if (!currentState.ignoresItemPreMerging() && SpongeImpl.getGlobalConfig().getConfig().getOptimizations().doDropsPreMergeItemDrops()) {
// Add itemstack to pre merge list
final Multimap<BlockPos, ItemDropData> multimap = context.getBlockDropSupplier().get();
final BlockPos pos = new BlockPos(x, y, z);
final Collection<ItemDropData> itemStacks = multimap.get(pos);
for (int i = 0; i < inventory.getSizeInventory(); i++) {
final net.minecraft.item.ItemStack itemStack = inventory.getStackInSlot(i);
if (!itemStack.isEmpty()) {
SpongeImplHooks.addItemStackToListForSpawning(itemStacks, ItemDropData.item(itemStack).position(VecHelper.toVector3d(pos)).build());
}
}
} else {
// Don't do pre-merging - directly spawn in item
final Multimap<BlockPos, EntityItem> multimap = context.getBlockItemDropSupplier().get();
final BlockPos pos = new BlockPos(x, y, z);
final Collection<EntityItem> itemStacks = multimap.get(pos);
for (int j = 0; j < inventory.getSizeInventory(); j++) {
final net.minecraft.item.ItemStack itemStack = inventory.getStackInSlot(j);
if (!itemStack.isEmpty()) {
float f = RANDOM.nextFloat() * 0.8F + 0.1F;
float f1 = RANDOM.nextFloat() * 0.8F + 0.1F;
float f2 = RANDOM.nextFloat() * 0.8F + 0.1F;
while (!itemStack.isEmpty()) {
int i = RANDOM.nextInt(21) + 10;
EntityItem entityitem = new EntityItem(worldServer, x + f, y + f1, z + f2, itemStack.splitStack(i));
entityitem.motionX = RANDOM.nextGaussian() * 0.05;
entityitem.motionY = RANDOM.nextGaussian() * 0.05 + 0.2;
entityitem.motionZ = RANDOM.nextGaussian() * 0.05;
itemStacks.add(entityitem);
}
}
}
}
return;
}
// Finally, just default to spawning the entities normally, regardless of the case.
for (int i = 0; i < inventory.getSizeInventory(); i++) {
final net.minecraft.item.ItemStack itemStack = inventory.getStackInSlot(i);
if (!itemStack.isEmpty()) {
InventoryHelper.spawnItemStack(worldServer, x, y, z, itemStack);
}
}
}
use of org.spongepowered.common.event.tracking.context.ItemDropData in project SpongeCommon by SpongePowered.
the class EntityUtil method entityOnDropItem.
/**
* A simple redirected static util method for {@link Entity#entityDropItem(ItemStack, float)}
* for easy debugging.
* @param entity
* @param itemStack
* @param offsetY
* @return
*/
public static EntityItem entityOnDropItem(Entity entity, ItemStack itemStack, float offsetY) {
final IMixinEntity mixinEntity = EntityUtil.toMixin(entity);
final IMixinEntityPlayer mixinPlayer = entity instanceof Player ? (IMixinEntityPlayer) entity : null;
// Now the real fun begins.
final ItemStack item;
final double posX = entity.posX;
final double posY = entity.posY + offsetY;
final double posZ = entity.posZ;
if (itemStack.isEmpty()) {
return null;
}
// FIRST we want to throw the DropItemEvent.PRE
final ItemStackSnapshot snapshot = ItemStackUtil.snapshotOf(itemStack);
final List<ItemStackSnapshot> original = new ArrayList<>();
original.add(snapshot);
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(entity);
final DropItemEvent.Pre dropEvent = SpongeEventFactory.createDropItemEventPre(Sponge.getCauseStackManager().getCurrentCause(), ImmutableList.of(snapshot), original);
SpongeImpl.postEvent(dropEvent);
if (dropEvent.isCancelled()) {
if (mixinPlayer != null) {
mixinPlayer.shouldRestoreInventory(true);
}
return null;
}
if (dropEvent.getDroppedItems().isEmpty()) {
return null;
}
// SECOND throw the ConstructEntityEvent
Transform<World> suggested = new Transform<>(mixinEntity.getWorld(), new Vector3d(posX, entity.posY + offsetY, posZ));
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.DROPPED_ITEM);
ConstructEntityEvent.Pre event = SpongeEventFactory.createConstructEntityEventPre(Sponge.getCauseStackManager().getCurrentCause(), EntityTypes.ITEM, suggested);
SpongeImpl.postEvent(event);
item = event.isCancelled() ? null : ItemStackUtil.fromSnapshotToNative(dropEvent.getDroppedItems().get(0));
if (item == null) {
if (mixinPlayer != null) {
mixinPlayer.shouldRestoreInventory(true);
}
return null;
}
final PhaseData peek = PhaseTracker.getInstance().getCurrentPhaseData();
final IPhaseState currentState = peek.state;
final PhaseContext<?> phaseContext = peek.context;
if (item.isEmpty()) {
return null;
}
if (!currentState.ignoresItemPreMerging() && SpongeImpl.getGlobalConfig().getConfig().getOptimizations().doDropsPreMergeItemDrops()) {
if (currentState.tracksEntitySpecificDrops()) {
final Multimap<UUID, ItemDropData> multimap = phaseContext.getCapturedEntityDropSupplier().get();
final Collection<ItemDropData> itemStacks = multimap.get(entity.getUniqueID());
SpongeImplHooks.addItemStackToListForSpawning(itemStacks, ItemDropData.item(item).position(new Vector3d(posX, posY, posZ)).build());
return null;
}
final List<ItemDropData> itemStacks = phaseContext.getCapturedItemStackSupplier().get();
SpongeImplHooks.addItemStackToListForSpawning(itemStacks, ItemDropData.item(item).position(new Vector3d(posX, posY, posZ)).build());
return null;
}
EntityItem entityitem = new EntityItem(entity.world, posX, posY, posZ, item);
entityitem.setDefaultPickupDelay();
// FIFTH - Capture the entity maybe?
if (currentState.doesCaptureEntityDrops()) {
if (currentState.tracksEntitySpecificDrops()) {
// We are capturing per entity drop
phaseContext.getCapturedEntityItemDropSupplier().get().put(entity.getUniqueID(), entityitem);
} else {
// We are adding to a general list - usually for EntityPhase.State.DEATH
phaseContext.getCapturedItemsSupplier().get().add(entityitem);
}
// Return the item, even if it wasn't spawned in the world.
return entityitem;
}
// FINALLY - Spawn the entity in the world if all else didn't fail
entity.world.spawnEntity(entityitem);
return entityitem;
}
}
Aggregations