use of org.spongepowered.api.data.Transaction 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.api.data.Transaction in project SpongeCommon by SpongePowered.
the class MixinEntityLightningBolt method onStrikeBlock.
private boolean onStrikeBlock(net.minecraft.world.World world, BlockPos pos, IBlockState blockState) {
if (!this.effect && ((World) world).containsBlock(pos.getX(), pos.getY(), pos.getZ())) {
Vector3i pos3i = VecHelper.toVector3i(pos);
Transaction<BlockSnapshot> transaction = new Transaction<BlockSnapshot>(new SpongeBlockSnapshotBuilder().blockState((BlockState) world.getBlockState(pos)).world(((World) world).getProperties()).position(pos3i).build(), new SpongeBlockSnapshotBuilder().blockState((BlockState) blockState).world(((World) world).getProperties()).position(pos3i).build());
if (!this.struckBlocks.contains(transaction)) {
this.struckBlocks.add(transaction);
}
return true;
}
return false;
}
use of org.spongepowered.api.data.Transaction in project SpongeCommon by SpongePowered.
the class MixinEntityFishHook method handleHookRetraction.
/**
* @author Aaron1011 - February 6th, 2015
* @author Minecrell - December 24th, 2016 (Updated to Minecraft 1.11.2)
* @author Minecrell - June 14th, 2017 (Rewritten to handle cases where no items are dropped)
* @reason This needs to handle for both cases where a fish and/or an entity is being caught.
*/
@Overwrite
public int handleHookRetraction() {
if (!this.world.isRemote && this.angler != null) {
int i = 0;
// Sponge start
List<Transaction<ItemStackSnapshot>> transactions;
if (this.ticksCatchable > 0) {
// Moved from below
LootContext.Builder lootcontext$builder = new LootContext.Builder((WorldServer) this.world);
lootcontext$builder.withLuck(this.luck + this.angler.getLuck());
transactions = this.world.getLootTableManager().getLootTableFromLocation(LootTableList.GAMEPLAY_FISHING).generateLootForPools(this.rand, lootcontext$builder.build()).stream().map(s -> {
ItemStackSnapshot snapshot = ((org.spongepowered.api.item.inventory.ItemStack) s).createSnapshot();
return new Transaction<>(snapshot, snapshot);
}).collect(Collectors.toList());
} else {
transactions = new ArrayList<>();
}
Sponge.getCauseStackManager().pushCause(this.angler);
if (SpongeImpl.postEvent(SpongeEventFactory.createFishingEventStop(Sponge.getCauseStackManager().getCurrentCause(), this, transactions))) {
// Event is cancelled
return -1;
}
if (this.caughtEntity != null) {
this.bringInHookedEntity();
this.world.setEntityState((net.minecraft.entity.Entity) (Object) this, (byte) 31);
i = this.caughtEntity instanceof EntityItem ? 3 : 5;
}
// Sponge start - Moved up to event call
if (!transactions.isEmpty()) {
// Use transactions
for (Transaction<ItemStackSnapshot> transaction : transactions) {
if (!transaction.isValid()) {
continue;
}
ItemStack itemstack = (ItemStack) transaction.getFinal().createStack();
// Sponge end
EntityItem entityitem = new EntityItem(this.world, this.posX, this.posY, this.posZ, itemstack);
double d0 = this.angler.posX - this.posX;
double d1 = this.angler.posY - this.posY;
double d2 = this.angler.posZ - this.posZ;
double d3 = MathHelper.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
// double d4 = 0.1D;
entityitem.motionX = d0 * 0.1D;
entityitem.motionY = d1 * 0.1D + MathHelper.sqrt(d3) * 0.08D;
entityitem.motionZ = d2 * 0.1D;
this.world.spawnEntity(entityitem);
this.angler.world.spawnEntity(new EntityXPOrb(this.angler.world, this.angler.posX, this.angler.posY + 0.5D, this.angler.posZ + 0.5D, this.rand.nextInt(6) + 1));
Item item = itemstack.getItem();
if (item == Items.FISH || item == Items.COOKED_FISH) {
this.angler.addStat(StatList.FISH_CAUGHT, 1);
}
}
Sponge.getCauseStackManager().popCause();
// Sponge: Don't lower damage if we've also caught an entity
i = Math.max(i, 1);
}
if (this.inGround) {
i = 2;
}
this.setDead();
return i;
} else {
return 0;
}
}
use of org.spongepowered.api.data.Transaction in project SpongeForge by SpongePowered.
the class SpongeForgeEventFactory method callBlockPlaceEvent.
public static ChangeBlockEvent.Place callBlockPlaceEvent(Event event) {
ChangeBlockEvent.Place spongeEvent = (ChangeBlockEvent.Place) event;
if (spongeEvent.getCause().root() instanceof Player) {
EntityPlayer player = (EntityPlayer) spongeEvent.getCause().first(Player.class).get();
net.minecraft.world.World world = player.world;
final PhaseTracker phaseTracker = PhaseTracker.getInstance();
final PhaseContext<?> currentContext = phaseTracker.getCurrentContext();
PhaseContext<?> target = currentContext;
if (currentContext instanceof UnwindingPhaseContext) {
target = ((UnwindingPhaseContext) currentContext).getUnwindingContext();
}
PacketContext<?> context = target instanceof PacketContext<?> ? (PacketContext<?>) target : null;
Packet<?> contextPacket = context != null ? context.getPacket() : null;
if (contextPacket == null) {
return spongeEvent;
}
if (spongeEvent.getTransactions().size() == 1) {
BlockPos pos = VecHelper.toBlockPos(spongeEvent.getTransactions().get(0).getOriginal().getPosition());
IBlockState state = (IBlockState) spongeEvent.getTransactions().get(0).getOriginal().getState();
net.minecraftforge.common.util.BlockSnapshot blockSnapshot = new net.minecraftforge.common.util.BlockSnapshot(world, pos, state);
IBlockState placedAgainst = Blocks.AIR.getDefaultState();
EnumHand hand = EnumHand.MAIN_HAND;
if (contextPacket instanceof CPacketPlayerTryUseItemOnBlock) {
CPacketPlayerTryUseItemOnBlock packet = (CPacketPlayerTryUseItemOnBlock) contextPacket;
EnumFacing facing = packet.getDirection();
placedAgainst = blockSnapshot.getWorld().getBlockState(blockSnapshot.getPos().offset(facing.getOpposite()));
hand = packet.getHand();
}
BlockEvent.PlaceEvent forgeEvent = new BlockEvent.PlaceEvent(blockSnapshot, placedAgainst, player, hand);
((IMixinEventBus) MinecraftForge.EVENT_BUS).post(forgeEvent, true);
if (forgeEvent.isCanceled()) {
spongeEvent.setCancelled(true);
}
} else {
// multi
Iterator<Transaction<BlockSnapshot>> iterator = spongeEvent.getTransactions().iterator();
List<net.minecraftforge.common.util.BlockSnapshot> blockSnapshots = new ArrayList<>();
while (iterator.hasNext()) {
Transaction<BlockSnapshot> transaction = iterator.next();
Location<World> location = transaction.getOriginal().getLocation().get();
IBlockState state = (IBlockState) transaction.getOriginal().getState();
BlockPos pos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ());
net.minecraftforge.common.util.BlockSnapshot blockSnapshot = new net.minecraftforge.common.util.BlockSnapshot(world, pos, state);
blockSnapshots.add(blockSnapshot);
}
IBlockState placedAgainst = Blocks.AIR.getDefaultState();
EnumHand hand = EnumHand.MAIN_HAND;
if (contextPacket instanceof CPacketPlayerTryUseItemOnBlock) {
CPacketPlayerTryUseItemOnBlock packet = (CPacketPlayerTryUseItemOnBlock) contextPacket;
EnumFacing facing = packet.getDirection();
placedAgainst = blockSnapshots.get(0).getWorld().getBlockState(blockSnapshots.get(0).getPos().offset(facing.getOpposite()));
hand = packet.getHand();
}
BlockEvent.MultiPlaceEvent forgeEvent = new BlockEvent.MultiPlaceEvent(blockSnapshots, placedAgainst, player, hand);
((IMixinEventBus) MinecraftForge.EVENT_BUS).post(forgeEvent, true);
if (forgeEvent.isCanceled()) {
spongeEvent.setCancelled(true);
}
}
}
return spongeEvent;
}
use of org.spongepowered.api.data.Transaction in project SpongeForge by SpongePowered.
the class SpongeForgeEventFactory method createChangeBlockEventPlace.
public static ChangeBlockEvent.Place createChangeBlockEventPlace(BlockEvent.PlaceEvent forgeEvent) {
final BlockPos pos = forgeEvent.getPos();
final net.minecraft.world.World world = forgeEvent.getWorld();
if (world.isRemote) {
return null;
}
final PhaseTracker phaseTracker = PhaseTracker.getInstance();
final PhaseData data = phaseTracker.getCurrentPhaseData();
BlockSnapshot originalSnapshot = ((IMixinBlockSnapshot) forgeEvent.getBlockSnapshot()).createSpongeBlockSnapshot();
BlockSnapshot finalSnapshot = ((BlockState) forgeEvent.getPlacedBlock()).snapshotFor(new Location<>((World) world, VecHelper.toVector3d(pos)));
ImmutableList<Transaction<BlockSnapshot>> blockSnapshots = new ImmutableList.Builder<Transaction<BlockSnapshot>>().add(new Transaction<>(originalSnapshot, finalSnapshot)).build();
User owner = data.context.getOwner().orElse(null);
User notifier = data.context.getNotifier().orElse(null);
EntityPlayer player = forgeEvent.getPlayer();
if (SpongeImplHooks.isFakePlayer(player)) {
Sponge.getCauseStackManager().addContext(EventContextKeys.FAKE_PLAYER, EntityUtil.toPlayer(player));
} else if (Sponge.getCauseStackManager().getCurrentCause() == null) {
Sponge.getCauseStackManager().pushCause(player);
}
if (owner != null) {
Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, owner);
if (Sponge.getCauseStackManager().getCurrentCause() == null) {
Sponge.getCauseStackManager().pushCause(owner);
}
} else {
Sponge.getCauseStackManager().addContext(EventContextKeys.OWNER, (User) player);
if (Sponge.getCauseStackManager().getCurrentCause() == null) {
Sponge.getCauseStackManager().pushCause(player);
}
}
if (notifier != null) {
Sponge.getCauseStackManager().addContext(EventContextKeys.NOTIFIER, notifier);
}
Sponge.getCauseStackManager().addContext(EventContextKeys.PLAYER_PLACE, (World) world);
return SpongeEventFactory.createChangeBlockEventPlace(Sponge.getCauseStackManager().getCurrentCause(), blockSnapshots);
}
Aggregations