use of org.spongepowered.api.event.entity.SpawnEntityEvent in project SpongeCommon by SpongePowered.
the class DeathPhase method unwind.
@Override
public void unwind(BasicEntityContext context) {
final Entity dyingEntity = context.getSource(Entity.class).orElseThrow(TrackingUtil.throwWithContext("Dying entity not found!", context));
final DamageSource damageSource = context.getDamageSource();
try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(damageSource);
Sponge.getCauseStackManager().pushCause(dyingEntity);
final boolean isPlayer = dyingEntity instanceof EntityPlayer;
final EntityPlayer entityPlayer = isPlayer ? (EntityPlayer) dyingEntity : null;
final Optional<User> notifier = context.getNotifier();
final Optional<User> owner = context.getOwner();
final User entityCreator = notifier.orElseGet(() -> owner.orElse(null));
context.getCapturedEntitySupplier().acceptAndClearIfNotEmpty(entities -> {
// Separate experience orbs from other entity drops
final List<Entity> experience = entities.stream().filter(entity -> entity instanceof ExperienceOrb).collect(Collectors.toList());
if (!experience.isEmpty()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.EXPERIENCE);
final SpawnEntityEvent spawnEntityEvent = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), experience);
SpongeImpl.postEvent(spawnEntityEvent);
if (!spawnEntityEvent.isCancelled()) {
for (Entity entity : spawnEntityEvent.getEntities()) {
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
}
// Now process other entities, this is separate from item drops specifically
final List<Entity> other = entities.stream().filter(entity -> !(entity instanceof ExperienceOrb)).collect(Collectors.toList());
if (!other.isEmpty()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.ENTITY_DEATH);
final SpawnEntityEvent spawnEntityEvent = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), experience);
SpongeImpl.postEvent(spawnEntityEvent);
if (!spawnEntityEvent.isCancelled()) {
for (Entity entity : spawnEntityEvent.getEntities()) {
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
}
});
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
// This allows mods such as Draconic Evolution to add items to the drop list
if (context.getCapturedEntityItemDropSupplier().isEmpty() && context.getCapturedEntityDropSupplier().isEmpty()) {
final ArrayList<Entity> entities = new ArrayList<>();
final DropItemEvent.Destruct destruct = SpongeEventFactory.createDropItemEventDestruct(frame.getCurrentCause(), entities);
SpongeImpl.postEvent(destruct);
if (!destruct.isCancelled()) {
for (Entity entity : destruct.getEntities()) {
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
return;
}
context.getCapturedEntityItemDropSupplier().acceptAndRemoveIfPresent(dyingEntity.getUniqueId(), items -> {
final ArrayList<Entity> entities = new ArrayList<>();
for (EntityItem item : items) {
entities.add(EntityUtil.fromNative(item));
}
if (isPlayer) {
// Forge and Vanilla always clear items on player death BEFORE drops occur
// This will also provide the highest compatibility with mods such as Tinkers Construct
entityPlayer.inventory.clear();
}
final DropItemEvent.Destruct destruct = SpongeEventFactory.createDropItemEventDestruct(Sponge.getCauseStackManager().getCurrentCause(), entities);
SpongeImpl.postEvent(destruct);
if (!destruct.isCancelled()) {
for (Entity entity : destruct.getEntities()) {
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
// Note: If cancelled, the items do not spawn in the world and are NOT copied back to player inventory.
// This avoids many issues with mods such as Tinkers Construct's soulbound items.
});
// Note that this is only used if and when item pre-merging is enabled. Which is never enabled in forge.
context.getCapturedEntityDropSupplier().acceptAndRemoveIfPresent(dyingEntity.getUniqueId(), itemStacks -> {
final List<ItemDropData> items = new ArrayList<>();
items.addAll(itemStacks);
if (!items.isEmpty()) {
final net.minecraft.entity.Entity minecraftEntity = EntityUtil.toNative(dyingEntity);
final List<Entity> itemEntities = items.stream().map(data -> data.create((WorldServer) minecraftEntity.world)).map(EntityUtil::fromNative).collect(Collectors.toList());
if (isPlayer) {
// Forge and Vanilla always clear items on player death BEFORE drops occur
// This will also provide the highest compatibility with mods such as Tinkers Construct
entityPlayer.inventory.clear();
}
final DropItemEvent.Destruct destruct = SpongeEventFactory.createDropItemEventDestruct(Sponge.getCauseStackManager().getCurrentCause(), itemEntities);
SpongeImpl.postEvent(destruct);
if (!destruct.isCancelled()) {
for (Entity entity : destruct.getEntities()) {
if (entityCreator != null) {
EntityUtil.toMixin(entity).setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
// Note: If cancelled, the items do not spawn in the world and are NOT copied back to player inventory.
// This avoids many issues with mods such as Tinkers Construct's soulbound items.
}
});
}
}
use of org.spongepowered.api.event.entity.SpawnEntityEvent in project SpongeCommon by SpongePowered.
the class DeathUpdateState method unwind.
@Override
public void unwind(BasicEntityContext context) {
final Entity dyingEntity = context.getSource(Entity.class).orElseThrow(TrackingUtil.throwWithContext("Dying entity not found!", context));
context.getCapturedItemsSupplier().acceptAndClearIfNotEmpty(items -> {
final DamageSource damageSource = context.getDamageSource();
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(dyingEntity);
Sponge.getCauseStackManager().pushCause(damageSource);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.DROPPED_ITEM);
final ArrayList<Entity> entities = new ArrayList<>();
for (EntityItem item : items) {
entities.add(EntityUtil.fromNative(item));
}
final DropItemEvent.Destruct destruct = SpongeEventFactory.createDropItemEventDestruct(Sponge.getCauseStackManager().getCurrentCause(), entities);
SpongeImpl.postEvent(destruct);
if (!destruct.isCancelled()) {
for (Entity entity : destruct.getEntities()) {
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
}
});
context.getCapturedEntitySupplier().acceptAndClearIfNotEmpty(entities -> {
final List<Entity> experience = entities.stream().filter(entity -> entity instanceof ExperienceOrb).collect(Collectors.toList());
if (!experience.isEmpty()) {
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(dyingEntity);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.EXPERIENCE);
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), experience);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity entity : event.getEntities()) {
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
}
}
final List<Entity> other = entities.stream().filter(entity -> !(entity instanceof ExperienceOrb)).collect(Collectors.toList());
if (!other.isEmpty()) {
try (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(dyingEntity);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.ENTITY_DEATH);
final SpawnEntityEvent event1 = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), other);
SpongeImpl.postEvent(event1);
if (!event1.isCancelled()) {
for (Entity entity : event1.getEntities()) {
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
}
}
});
context.getCapturedEntityDropSupplier().acceptIfNotEmpty(map -> {
if (map.isEmpty()) {
return;
}
final PrettyPrinter printer = new PrettyPrinter(80);
printer.add("Processing Entity Death Updates Spawning").centre().hr();
printer.add("Entity Dying: " + dyingEntity);
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);
});
context.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(blocks -> TrackingUtil.processBlockCaptures(blocks, this, context));
}
use of org.spongepowered.api.event.entity.SpawnEntityEvent in project SpongeCommon by SpongePowered.
the class ExplosionState method spawnEntityOrCapture.
@Override
public boolean spawnEntityOrCapture(ExplosionContext context, Entity entity, int chunkX, int chunkZ) {
return context.getBlockPosition().map(blockPos -> {
// TODO - this needs to be guaranteed. can't be bothered to figure out why it isn't
final Multimap<BlockPos, net.minecraft.entity.Entity> blockPosEntityMultimap = context.getBlockEntitySpawnSupplier().get();
final Multimap<BlockPos, EntityItem> blockPosEntityItemMultimap = context.getBlockItemDropSupplier().get();
if (entity instanceof EntityItem) {
blockPosEntityItemMultimap.put(blockPos, (EntityItem) entity);
} else {
blockPosEntityMultimap.put(blockPos, (net.minecraft.entity.Entity) entity);
}
return true;
}).orElseGet(() -> {
final ArrayList<Entity> entities = new ArrayList<>(1);
entities.add(entity);
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), entities);
SpongeImpl.postEvent(event);
if (!event.isCancelled() && event.getEntities().size() > 0) {
for (Entity item : event.getEntities()) {
((IMixinWorldServer) item.getWorld()).forceSpawnEntity(item);
}
return true;
}
return false;
});
}
use of org.spongepowered.api.event.entity.SpawnEntityEvent in project SpongeCommon by SpongePowered.
the class GeneralGenerationPhaseState method spawnEntityOrCapture.
@Override
public boolean spawnEntityOrCapture(G context, Entity entity, int chunkX, int chunkZ) {
final ArrayList<Entity> entities = new ArrayList<>(1);
entities.add(entity);
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
frame.pushCause(entity.getLocation().getExtent());
frame.addContext(EventContextKeys.SPAWN_TYPE, SpawnTypes.WORLD_SPAWNER);
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEventSpawner(frame.getCurrentCause(), entities);
SpongeImpl.postEvent(event);
if (!event.isCancelled() && event.getEntities().size() > 0) {
for (Entity item : event.getEntities()) {
((IMixinWorldServer) item.getWorld()).forceSpawnEntity(item);
}
return true;
}
return false;
}
}
use of org.spongepowered.api.event.entity.SpawnEntityEvent in project SpongeCommon by SpongePowered.
the class EnchantItemPacketState method unwind.
@Override
public void unwind(InventoryPacketContext context) {
// TODO - Pre changes of merging PacketFunction into the phase states, enchantments did NOT have any processing....
final EntityPlayerMP player = context.getPacketPlayer();
// The server will disable the player's crafting after receiving a
// client packet
// that did not pass validation (server click item != packet click item)
// The server then sends a SPacketConfirmTransaction and waits for a
// CPacketConfirmTransaction to re-enable crafting confirming that the
// client
// acknowledged the denied transaction.
// To detect when this happens, we turn off capturing so we can avoid
// firing
// invalid events.
// See MixinNetHandlerPlayServer processClickWindow redirect for rest of
// fix.
// --bloodmc
final IMixinContainer mixinContainer = ContainerUtil.toMixin(player.openContainer);
if (!mixinContainer.capturingInventory()) {
mixinContainer.getCapturedTransactions().clear();
return;
}
// TODO clear this shit out of the context
final CPacketEnchantItem packetIn = context.getPacket();
final ItemStackSnapshot lastCursor = context.getCursor();
final ItemStackSnapshot newCursor = ItemStackUtil.snapshotOf(player.inventory.getItemStack());
final Transaction<ItemStackSnapshot> transaction = new Transaction<>(lastCursor, newCursor);
final net.minecraft.inventory.Container openContainer = player.openContainer;
final List<SlotTransaction> slotTransactions = mixinContainer.getCapturedTransactions();
final int usedButton = packetIn.getButton();
final List<Entity> capturedItems = new ArrayList<>();
for (EntityItem entityItem : context.getCapturedItems()) {
capturedItems.add(EntityUtil.fromNative(entityItem));
}
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(player);
Sponge.getCauseStackManager().pushCause(openContainer);
final ClickInventoryEvent inventoryEvent;
inventoryEvent = this.createInventoryEvent(player, ContainerUtil.fromNative(openContainer), transaction, Lists.newArrayList(slotTransactions), capturedItems, usedButton);
// If this happens and we captured no entities, avoid firing events
if (mixinContainer.getCapturedTransactions().isEmpty() && capturedItems.isEmpty()) {
mixinContainer.setCaptureInventory(false);
return;
}
if (inventoryEvent != null) {
// Don't fire inventory drop events when there are no entities
if (inventoryEvent instanceof AffectEntityEvent && ((AffectEntityEvent) inventoryEvent).getEntities().isEmpty()) {
slotTransactions.clear();
mixinContainer.setCaptureInventory(false);
return;
}
// packet has everything we want.
if (!(inventoryEvent instanceof ClickInventoryEvent.Drag)) {
PacketPhaseUtil.validateCapturedTransactions(packetIn.getWindowId(), openContainer, inventoryEvent.getTransactions());
}
SpongeImpl.postEvent(inventoryEvent);
if (inventoryEvent.isCancelled() || PacketPhaseUtil.allTransactionsInvalid(inventoryEvent.getTransactions())) {
if (inventoryEvent instanceof ClickInventoryEvent.Drop) {
capturedItems.clear();
}
// Restore cursor
PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getOriginal());
// Restore target slots
PacketPhaseUtil.handleSlotRestore(player, openContainer, inventoryEvent.getTransactions(), true);
} else {
PacketPhaseUtil.handleSlotRestore(player, openContainer, inventoryEvent.getTransactions(), false);
// Handle cursor
if (!inventoryEvent.getCursorTransaction().isValid()) {
PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getOriginal());
} else if (inventoryEvent.getCursorTransaction().getCustom().isPresent()) {
PacketPhaseUtil.handleCustomCursor(player, inventoryEvent.getCursorTransaction().getFinal());
} else if (inventoryEvent instanceof ClickInventoryEvent.Drag) {
int increment;
increment = slotTransactions.stream().filter((t) -> !t.isValid()).mapToInt((t) -> t.getFinal().getQuantity()).sum();
final ItemStack cursor = inventoryEvent.getCursorTransaction().getFinal().createStack();
cursor.setQuantity(cursor.getQuantity() + increment);
PacketPhaseUtil.handleCustomCursor(player, cursor.createSnapshot());
} else if (inventoryEvent instanceof ClickInventoryEvent.Double && !(inventoryEvent instanceof ClickInventoryEvent.Shift)) {
int decrement;
decrement = slotTransactions.stream().filter((t) -> !t.isValid()).mapToInt((t) -> t.getOriginal().getQuantity()).sum();
final ItemStack cursor = inventoryEvent.getCursorTransaction().getFinal().createStack();
cursor.setQuantity(cursor.getQuantity() - decrement);
PacketPhaseUtil.handleCustomCursor(player, cursor.createSnapshot());
}
if (inventoryEvent instanceof SpawnEntityEvent) {
processSpawnedEntities(player, (SpawnEntityEvent) inventoryEvent);
} else if (!context.getCapturedEntitySupplier().isEmpty()) {
SpawnEntityEvent spawnEntityEvent = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), context.getCapturedEntities());
SpongeImpl.postEvent(spawnEntityEvent);
if (!spawnEntityEvent.isCancelled()) {
processSpawnedEntities(player, spawnEntityEvent);
}
}
}
}
}
slotTransactions.clear();
mixinContainer.setCaptureInventory(false);
}
Aggregations