use of org.spongepowered.common.interfaces.world.IMixinLocation in project SpongeCommon by SpongePowered.
the class ExplosionState method processBlockCaptures.
@SuppressWarnings({ "unchecked" })
private void processBlockCaptures(List<BlockSnapshot> snapshots, Explosion explosion, 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 (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
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(Sponge.getCauseStackManager().getCurrentCause(), 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);
final Location<World> location = transaction.getOriginal().getLocation().orElse(null);
if (location != null) {
// Cancel any block drops performed, avoids any item drops, regardless
final BlockPos pos = ((IMixinLocation) (Object) location).getBlockPos();
context.getBlockItemDropSupplier().removeAllIfNotEmpty(pos);
context.getBlockEntitySpawnSupplier().removeAllIfNotEmpty(pos);
context.getBlockEntitySpawnSupplier().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);
if (this.tracksBlockSpecificDrops()) {
// 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.common.interfaces.world.IMixinLocation 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.interfaces.world.IMixinLocation in project SpongeCommon by SpongePowered.
the class PlaceBlockPacketState method handleBlockChangeWithUser.
@Override
public void handleBlockChangeWithUser(@Nullable BlockChange blockChange, Transaction<BlockSnapshot> transaction, BasicPacketContext context) {
Player player = Sponge.getCauseStackManager().getCurrentCause().first(Player.class).get();
final Location<World> location = transaction.getFinal().getLocation().get();
BlockPos pos = ((IMixinLocation) (Object) location).getBlockPos();
IMixinChunk spongeChunk = (IMixinChunk) ((WorldServer) location.getExtent()).getChunkFromBlockCoords(pos);
if (blockChange == BlockChange.PLACE) {
spongeChunk.addTrackedBlockPosition((Block) transaction.getFinal().getState().getType(), pos, player, PlayerTracker.Type.OWNER);
}
spongeChunk.addTrackedBlockPosition((Block) transaction.getFinal().getState().getType(), pos, player, PlayerTracker.Type.NOTIFIER);
}
use of org.spongepowered.common.interfaces.world.IMixinLocation in project SpongeCommon by SpongePowered.
the class UseItemPacketState method handleBlockChangeWithUser.
@Override
public void handleBlockChangeWithUser(@Nullable BlockChange blockChange, Transaction<BlockSnapshot> transaction, BasicPacketContext context) {
Player player = context.getSpongePlayer();
BlockPos pos = ((IMixinLocation) (Object) transaction.getFinal().getLocation().get()).getBlockPos();
IMixinChunk spongeChunk = (IMixinChunk) EntityUtil.getMinecraftWorld(player).getChunkFromBlockCoords(pos);
if (blockChange == BlockChange.PLACE) {
spongeChunk.addTrackedBlockPosition((Block) transaction.getFinal().getState().getType(), pos, player, PlayerTracker.Type.OWNER);
}
spongeChunk.addTrackedBlockPosition((Block) transaction.getFinal().getState().getType(), pos, player, PlayerTracker.Type.NOTIFIER);
}
use of org.spongepowered.common.interfaces.world.IMixinLocation in project SpongeCommon by SpongePowered.
the class EntityTickPhaseState method unwind.
@SuppressWarnings("unchecked")
@Override
public void unwind(EntityTickContext phaseContext) {
final Entity tickingEntity = phaseContext.getSource(Entity.class).orElseThrow(TrackingUtil.throwWithContext("Not ticking on an Entity!", phaseContext));
final Optional<User> creator = phaseContext.getOwner();
final Optional<User> notifier = phaseContext.getNotifier();
final User entityCreator = notifier.orElseGet(() -> creator.orElse(null));
try (CauseStackManager.StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
Sponge.getCauseStackManager().pushCause(tickingEntity);
phaseContext.addNotifierAndOwnerToCauseStack();
phaseContext.getCapturedEntitySupplier().acceptAndClearIfNotEmpty(entities -> {
final List<Entity> experience = new ArrayList<Entity>(entities.size());
final List<Entity> nonExp = new ArrayList<Entity>(entities.size());
final List<Entity> breeding = new ArrayList<Entity>(entities.size());
final List<Entity> projectile = new ArrayList<Entity>(entities.size());
for (Entity entity : entities) {
if (entity instanceof EntityXPOrb) {
experience.add(entity);
} else if (tickingEntity instanceof Ageable && tickingEntity.getClass() == entity.getClass()) {
breeding.add(entity);
} else if (entity instanceof Projectile) {
projectile.add(entity);
} else {
nonExp.add(entity);
}
}
if (!experience.isEmpty()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.EXPERIENCE);
if (EntityUtil.isEntityDead(tickingEntity)) {
if (tickingEntity instanceof EntityLivingBase) {
CombatEntry entry = ((EntityLivingBase) tickingEntity).getCombatTracker().getBestCombatEntry();
if (entry != null) {
if (entry.damageSrc != null) {
Sponge.getCauseStackManager().addContext(EventContextKeys.LAST_DAMAGE_SOURCE, (DamageSource) entry.damageSrc);
}
}
}
}
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), experience);
if (!SpongeImpl.postEvent(event)) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
EntityUtil.toMixin(entity).setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
Sponge.getCauseStackManager().removeContext(EventContextKeys.LAST_DAMAGE_SOURCE);
}
if (!breeding.isEmpty()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.BREEDING);
if (tickingEntity instanceof EntityAnimal) {
final EntityPlayer playerInLove = ((EntityAnimal) tickingEntity).getLoveCause();
if (playerInLove != null) {
Sponge.getCauseStackManager().addContext(EventContextKeys.PLAYER, (Player) playerInLove);
}
}
SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), breeding);
if (!SpongeImpl.postEvent(event)) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
EntityUtil.toMixin(entity).setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
Sponge.getCauseStackManager().removeContext(EventContextKeys.PLAYER);
}
if (!projectile.isEmpty()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.PROJECTILE);
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), projectile);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
entity.setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
}
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.PASSIVE);
final SpawnEntityEvent event = SpongeEventFactory.createSpawnEntityEvent(Sponge.getCauseStackManager().getCurrentCause(), nonExp);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
entity.setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
});
phaseContext.getCapturedItemsSupplier().acceptAndClearIfNotEmpty(entities -> {
final ArrayList<Entity> capturedEntities = new ArrayList<>();
for (EntityItem entity : entities) {
capturedEntities.add(EntityUtil.fromNative(entity));
}
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
final DropItemEvent.Custom event = SpongeEventFactory.createDropItemEventCustom(Sponge.getCauseStackManager().getCurrentCause(), capturedEntities);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity entity : event.getEntities()) {
if (entityCreator != null) {
EntityUtil.toMixin(entity).setCreator(entityCreator.getUniqueId());
}
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
});
phaseContext.getCapturedBlockSupplier().acceptAndClearIfNotEmpty(blockSnapshots -> TrackingUtil.processBlockCaptures(blockSnapshots, this, phaseContext));
phaseContext.getBlockItemDropSupplier().acceptIfNotEmpty(map -> {
final List<BlockSnapshot> capturedBlocks = phaseContext.getCapturedBlocks();
for (BlockSnapshot snapshot : capturedBlocks) {
final BlockPos blockPos = ((IMixinLocation) (Object) snapshot.getLocation().get()).getBlockPos();
final Collection<EntityItem> entityItems = map.get(blockPos);
if (!entityItems.isEmpty()) {
Sponge.getCauseStackManager().pushCause(snapshot);
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
final List<Entity> items = entityItems.stream().map(EntityUtil::fromNative).collect(Collectors.toList());
final DropItemEvent.Destruct event = SpongeEventFactory.createDropItemEventDestruct(Sponge.getCauseStackManager().getCurrentCause(), items);
SpongeImpl.postEvent(event);
if (!event.isCancelled()) {
for (Entity entity : event.getEntities()) {
creator.ifPresent(user -> entity.setCreator(user.getUniqueId()));
EntityUtil.getMixinWorld(entity).forceSpawnEntity(entity);
}
}
Sponge.getCauseStackManager().popCause();
}
}
});
phaseContext.getCapturedItemStackSupplier().acceptAndClearIfNotEmpty(drops -> {
final List<EntityItem> items = drops.stream().map(drop -> drop.create(EntityUtil.getMinecraftWorld(tickingEntity))).collect(Collectors.toList());
Sponge.getCauseStackManager().addContext(EventContextKeys.SPAWN_TYPE, InternalSpawnTypes.DROPPED_ITEM);
final List<Entity> entities = (List<Entity>) (List<?>) items;
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);
}
}
}
});
this.fireMovementEvents(EntityUtil.toNative(tickingEntity));
}
}
Aggregations