use of org.spongepowered.common.interfaces.world.IMixinLocation in project SpongeCommon by SpongePowered.
the class TrackingUtil method performBlockAdditions.
@SuppressWarnings("rawtypes")
public static boolean performBlockAdditions(List<Transaction<BlockSnapshot>> transactions, IPhaseState<?> phaseState, PhaseContext<?> phaseContext, boolean noCancelledTransactions) {
// 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 = phaseContext.getBlockDropSupplier();
final CapturedMultiMapSupplier<BlockPos, EntityItem> capturedBlockItemEntityDrops = phaseContext.getBlockItemDropSupplier();
final CapturedMultiMapSupplier<BlockPos, net.minecraft.entity.Entity> capturedBlockEntitySpawns = phaseContext.getBlockEntitySpawnSupplier();
for (Transaction<BlockSnapshot> transaction : transactions) {
if (!transaction.isValid()) {
// Rememver that this value needs to be set to false to return because of the fact that
// a transaction was marked as invalid or cancelled. This is used primarily for
// things like portal creation, and if false, removes the portal from the cache
noCancelledTransactions = false;
// 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.NONE);
}
final SpongeBlockSnapshot oldBlockSnapshot = (SpongeBlockSnapshot) transaction.getOriginal();
final SpongeBlockSnapshot newBlockSnapshot = (SpongeBlockSnapshot) transaction.getFinal();
final Location<World> worldLocation = oldBlockSnapshot.getLocation().get();
final IMixinWorldServer mixinWorldServer = (IMixinWorldServer) worldLocation.getExtent();
// Handle item drops captured
final BlockPos pos = ((IMixinLocation) (Object) oldBlockSnapshot.getLocation().get()).getBlockPos();
// This is for pre-merged items
capturedBlockDrops.acceptAndRemoveIfPresent(pos, items -> spawnItemDataForBlockDrops(items, oldBlockSnapshot, phaseContext, phaseState));
// And this is for un-pre-merged items, these will be EntityItems, not ItemDropDatas.
capturedBlockItemEntityDrops.acceptAndRemoveIfPresent(pos, items -> spawnItemEntitiesForBlockDrops(items, oldBlockSnapshot, phaseContext, phaseState));
// This is for entities actually spawned
capturedBlockEntitySpawns.acceptAndRemoveIfPresent(pos, items -> spawnEntitiesForBlock(items, oldBlockSnapshot, phaseContext, phaseState));
final WorldServer worldServer = mixinWorldServer.asMinecraftWorld();
SpongeHooks.logBlockAction(worldServer, oldBlockSnapshot.blockChange, transaction);
final SpongeBlockChangeFlag changeFlag = oldBlockSnapshot.getChangeFlag();
final IBlockState originalState = (IBlockState) oldBlockSnapshot.getState();
final IBlockState newState = (IBlockState) newBlockSnapshot.getState();
// We call onBlockAdded here for blocks without a TileEntity.
// MixinChunk#setBlockState will call onBlockAdded for blocks
// with a TileEntity or when capturing is not being done.
final PhaseTracker phaseTracker = PhaseTracker.getInstance();
if (!SpongeImplHooks.hasBlockTileEntity(newState.getBlock(), newState) && changeFlag.performBlockPhysics() && originalState.getBlock() != newState.getBlock()) {
newState.getBlock().onBlockAdded(worldServer, pos, newState);
final PhaseData peek = phaseTracker.getCurrentPhaseData();
if (peek.state == GeneralPhase.Post.UNWINDING) {
((IPhaseState) peek.state).unwind(peek.context);
}
}
// proxyBlockAccess.proceed();
((IPhaseState) phaseState).handleBlockChangeWithUser(oldBlockSnapshot.blockChange, transaction, phaseContext);
if (changeFlag.isNotifyClients()) {
// Always try to notify clients of the change.
worldServer.notifyBlockUpdate(pos, originalState, newState, changeFlag.getRawFlag());
}
if (changeFlag.updateNeighbors()) {
// Notify neighbors only if the change flag allowed it.
mixinWorldServer.spongeNotifyNeighborsPostBlockChange(pos, originalState, newState, changeFlag);
} else if (changeFlag.notifyObservers()) {
worldServer.updateObservingBlocksAt(pos, newState.getBlock());
}
final PhaseData peek = phaseTracker.getCurrentPhaseData();
if (peek.state == GeneralPhase.Post.UNWINDING) {
((IPhaseState) peek.state).unwind(peek.context);
}
}
return noCancelledTransactions;
}
use of org.spongepowered.common.interfaces.world.IMixinLocation in project SpongeCommon by SpongePowered.
the class GeneralPhase method processBlockTransactionListsPost.
/**
* @param snapshotsToProcess
* @param unwindingState
* @param unwinding
*/
@SuppressWarnings({ "unchecked" })
public static void processBlockTransactionListsPost(PhaseContext<?> postContext, List<BlockSnapshot> snapshotsToProcess, IPhaseState<?> unwindingState, PhaseContext<?> unwinding) {
final List<Transaction<BlockSnapshot>> invalidTransactions = new ArrayList<>();
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 : snapshotsToProcess) {
// 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
postContext.getCapturedBlocksOrEmptyList().clear();
final ChangeBlockEvent[] mainEvents = new ChangeBlockEvent[BlockChange.values().length];
// This likely needs to delegate to the phase in the event we don't use the source object as the main object causing the block changes
// case in point for WorldTick event listeners since the players are captured non-deterministically
// Creates the block events accordingly to the transaction arrays
TrackingUtil.iterateChangeBlockEvents(transactionArrays, blockEvents, mainEvents);
// We create the post event and of course post it in the method, regardless whether any transactions are invalidated or not
final ChangeBlockEvent.Post postEvent = TrackingUtil.throwMultiEventsAndCreatePost(transactionArrays, blockEvents, mainEvents);
if (postEvent == null) {
// Means that we have had no actual block changes apparently?
return;
}
// 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()) {
// 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.
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()) {
invalidTransactions.add(transaction);
}
}
if (!invalidTransactions.isEmpty()) {
// or the events were cancelled), again in reverse order of which they were received.
for (Transaction<BlockSnapshot> transaction : Lists.reverse(invalidTransactions)) {
transaction.getOriginal().restore(true, BlockChangeFlags.NONE);
if (unwindingState.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) {
// Cancel any block drops performed, avoids any item drops, regardless
final BlockPos pos = ((IMixinLocation) (Object) location).getBlockPos();
postContext.getBlockDropSupplier().removeAllIfNotEmpty(pos);
}
}
}
invalidTransactions.clear();
}
performPostBlockAdditions(postContext, postEvent.getTransactions(), unwindingState, unwinding);
}
use of org.spongepowered.common.interfaces.world.IMixinLocation in project SpongeCommon by SpongePowered.
the class DamageEventHandler method generateCauseFor.
public static void generateCauseFor(DamageSource damageSource) {
if (damageSource instanceof EntityDamageSourceIndirect) {
net.minecraft.entity.Entity source = damageSource.getTrueSource();
if (!(source instanceof EntityPlayer) && source != null) {
final IMixinEntity mixinEntity = EntityUtil.toMixin(source);
mixinEntity.getNotifierUser().ifPresent(notifier -> Sponge.getCauseStackManager().addContext(EventContextKeys.NOTIFIER, notifier));
mixinEntity.getCreatorUser().ifPresent(owner -> Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, owner));
}
} else if (damageSource instanceof EntityDamageSource) {
net.minecraft.entity.Entity source = damageSource.getTrueSource();
if (!(source instanceof EntityPlayer) && source != null) {
final IMixinEntity mixinEntity = EntityUtil.toMixin(source);
// TODO only have a UUID, want a user
mixinEntity.getNotifierUser().ifPresent(notifier -> Sponge.getCauseStackManager().addContext(EventContextKeys.NOTIFIER, notifier));
mixinEntity.getCreatorUser().ifPresent(creator -> Sponge.getCauseStackManager().addContext(EventContextKeys.CREATOR, creator));
}
} else if (damageSource instanceof BlockDamageSource) {
Location<org.spongepowered.api.world.World> location = ((BlockDamageSource) damageSource).getLocation();
BlockPos blockPos = ((IMixinLocation) (Object) location).getBlockPos();
final IMixinChunk mixinChunk = (IMixinChunk) ((net.minecraft.world.World) location.getExtent()).getChunkFromBlockCoords(blockPos);
mixinChunk.getBlockNotifier(blockPos).ifPresent(notifier -> Sponge.getCauseStackManager().addContext(EventContextKeys.NOTIFIER, notifier));
mixinChunk.getBlockOwner(blockPos).ifPresent(owner -> Sponge.getCauseStackManager().addContext(EventContextKeys.CREATOR, owner));
}
Sponge.getCauseStackManager().pushCause(damageSource);
}
use of org.spongepowered.common.interfaces.world.IMixinLocation in project SpongeCommon by SpongePowered.
the class CustomExplosionState method processBlockCaptures.
@SuppressWarnings({ "unchecked" })
private void processBlockCaptures(List<BlockSnapshot> snapshots, Explosion explosion, Cause cause, 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 (StackFrame frame = Sponge.getCauseStackManager().pushCauseFrame()) {
if (context.getNotifier().isPresent()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.NOTIFIER, context.getNotifier().get());
}
if (context.getOwner().isPresent()) {
Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, context.getOwner().get());
}
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(cause, 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);
// Cancel any block drops performed, avoids any item drops, regardless
final Location<World> location = transaction.getOriginal().getLocation().orElse(null);
if (location != null) {
final BlockPos pos = ((IMixinLocation) (Object) location).getBlockPos();
context.getBlockItemDropSupplier().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);
// 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 MixinExplosion method doExplosionA.
// TODO fix this whereever it was called from?
// @Override
// public Cause createCause() {
// if (this.createdCause != null) {
// return this.createdCause;
// }
// Object source;
// Object projectileSource = null;
// Object igniter = null;
// if (this.exploder == null) {
// source = getWorld().getBlock(getLocation().getPosition().toInt());
// } else {
// source = this.exploder;
// if (source instanceof Projectile) {
// projectileSource = ((Projectile) this.exploder).getShooter();
// }
//
// // Don't use the exploder itself as igniter
// igniter = getExplosivePlacedBy();
// if (this.exploder == igniter) {
// igniter = null;
// }
// }
//
// final Cause.Builder builder = Cause.source(source);
// if (projectileSource != null) {
// if (igniter != null) {
// builder.named(NamedCause.of("ProjectileSource", projectileSource)).named(NamedCause.of("Igniter", igniter));
// } else {
// builder.named(NamedCause.of("ProjectileSource", projectileSource));
// }
// } else if (igniter != null) {
// builder.named(NamedCause.of("Igniter", igniter));
// }
// if (PhaseTracker.ENABLED) {
// final PhaseData phaseData = PhaseTracker.getInstance().getCurrentPhaseData();
// phaseData.state.getPhase().appendExplosionCause(phaseData);
// }
// return this.createdCause = builder.build();
// }
//
// @Override
// public Cause getCreatedCause() {
// if (this.createdCause == null) {
// createCause();
// }
// return this.createdCause;
// }
/**
* @author gabizou - September 8th, 2016
* @reason Rewrites to use our own hooks that will patch with forge perfectly well,
* and allows for maximal capability.
*/
@Final
@Overwrite
public void doExplosionA() {
// Sponge Start - If the explosion should not break blocks, don't bother calculating it
if (this.shouldBreakBlocks) {
// Sponge End
Set<BlockPos> set = Sets.<BlockPos>newHashSet();
int i = 16;
for (int j = 0; j < 16; ++j) {
for (int k = 0; k < 16; ++k) {
for (int l = 0; l < 16; ++l) {
if (j == 0 || j == 15 || k == 0 || k == 15 || l == 0 || l == 15) {
double d0 = (double) ((float) j / 15.0F * 2.0F - 1.0F);
double d1 = (double) ((float) k / 15.0F * 2.0F - 1.0F);
double d2 = (double) ((float) l / 15.0F * 2.0F - 1.0F);
double d3 = Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
d0 = d0 / d3;
d1 = d1 / d3;
d2 = d2 / d3;
float f = this.size * (0.7F + this.world.rand.nextFloat() * 0.6F);
double d4 = this.x;
double d6 = this.y;
double d8 = this.z;
for (float f1 = 0.3F; f > 0.0F; f -= 0.22500001F) {
BlockPos blockpos = new BlockPos(d4, d6, d8);
IBlockState iblockstate = this.world.getBlockState(blockpos);
if (iblockstate.getMaterial() != Material.AIR) {
float f2 = this.exploder != null ? this.exploder.getExplosionResistance((net.minecraft.world.Explosion) (Object) this, this.world, blockpos, iblockstate) : iblockstate.getBlock().getExplosionResistance((Entity) null);
f -= (f2 + 0.3F) * 0.3F;
}
if (f > 0.0F && (this.exploder == null || this.exploder.canExplosionDestroyBlock((net.minecraft.world.Explosion) (Object) this, this.world, blockpos, iblockstate, f))) {
set.add(blockpos);
}
d4 += d0 * 0.30000001192092896D;
d6 += d1 * 0.30000001192092896D;
d8 += d2 * 0.30000001192092896D;
}
}
}
}
}
this.affectedBlockPositions.addAll(set);
}
// Sponge - Finish if statement
float f3 = this.size * 2.0F;
int k1 = MathHelper.floor(this.x - (double) f3 - 1.0D);
int l1 = MathHelper.floor(this.x + (double) f3 + 1.0D);
int i2 = MathHelper.floor(this.y - (double) f3 - 1.0D);
int i1 = MathHelper.floor(this.y + (double) f3 + 1.0D);
int j2 = MathHelper.floor(this.z - (double) f3 - 1.0D);
int j1 = MathHelper.floor(this.z + (double) f3 + 1.0D);
// Sponge Start - Check if this explosion should damage entities
List<Entity> list = this.shouldDamageEntities ? this.world.getEntitiesWithinAABBExcludingEntity(this.exploder, new AxisAlignedBB((double) k1, (double) i2, (double) j2, (double) l1, (double) i1, (double) j1)) : Collections.emptyList();
// Now we can throw our Detonate Event
final List<Location<World>> blockPositions = new ArrayList<>(this.affectedBlockPositions.size());
final List<org.spongepowered.api.entity.Entity> entities = new ArrayList<>(list.size());
for (BlockPos pos : this.affectedBlockPositions) {
blockPositions.add(new Location<>((World) this.world, pos.getX(), pos.getY(), pos.getZ()));
}
for (Entity entity : list) {
entities.add((org.spongepowered.api.entity.Entity) entity);
}
ExplosionEvent.Detonate detonate = SpongeEventFactory.createExplosionEventDetonate(Sponge.getCauseStackManager().getCurrentCause(), blockPositions, entities, this, (World) this.world);
SpongeImpl.postEvent(detonate);
if (detonate.isCancelled()) {
this.affectedBlockPositions.clear();
return;
}
this.affectedBlockPositions.clear();
if (this.shouldBreakBlocks) {
for (Location<World> worldLocation : detonate.getAffectedLocations()) {
this.affectedBlockPositions.add(((IMixinLocation) (Object) worldLocation).getBlockPos());
}
}
list.clear();
if (this.shouldDamageEntities) {
for (org.spongepowered.api.entity.Entity entity : detonate.getEntities()) {
try {
list.add(EntityUtil.toNative(entity));
} catch (Exception e) {
// Do nothing, a plugin tried to use the wrong entity somehow.
}
}
}
// Sponge End
Vec3d vec3d = new Vec3d(this.x, this.y, this.z);
for (int k2 = 0; k2 < list.size(); ++k2) {
Entity entity = list.get(k2);
if (!entity.isImmuneToExplosions()) {
double d12 = entity.getDistance(this.x, this.y, this.z) / (double) f3;
if (d12 <= 1.0D) {
double d5 = entity.posX - this.x;
double d7 = entity.posY + (double) entity.getEyeHeight() - this.y;
double d9 = entity.posZ - this.z;
double d13 = (double) MathHelper.sqrt(d5 * d5 + d7 * d7 + d9 * d9);
if (d13 != 0.0D) {
d5 = d5 / d13;
d7 = d7 / d13;
d9 = d9 / d13;
double d14 = (double) this.world.getBlockDensity(vec3d, entity.getEntityBoundingBox());
double d10 = (1.0D - d12) * d14;
entity.attackEntityFrom(DamageSource.causeExplosionDamage((net.minecraft.world.Explosion) (Object) this), (float) ((int) ((d10 * d10 + d10) / 2.0D * 7.0D * (double) f3 + 1.0D)));
double d11 = 1.0D;
if (entity instanceof EntityLivingBase) {
d11 = EnchantmentProtection.getBlastDamageReduction((EntityLivingBase) entity, d10);
}
entity.motionX += d5 * d11;
entity.motionY += d7 * d11;
entity.motionZ += d9 * d11;
if (entity instanceof EntityPlayer) {
EntityPlayer entityplayer = (EntityPlayer) entity;
if (!entityplayer.isSpectator() && (!entityplayer.isCreative() || !entityplayer.capabilities.isFlying)) {
this.playerKnockbackMap.put(entityplayer, new Vec3d(d5 * d10, d7 * d10, d9 * d10));
}
}
}
}
}
}
}
Aggregations