Search in sources :

Example 1 with SpongeBlockChangeFlag

use of org.spongepowered.common.world.SpongeBlockChangeFlag 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;
}
Also used : IMixinEntity(org.spongepowered.common.interfaces.entity.IMixinEntity) TileEntity(org.spongepowered.api.block.tileentity.TileEntity) IMixinTileEntity(org.spongepowered.common.interfaces.block.tile.IMixinTileEntity) Entity(org.spongepowered.api.entity.Entity) SpongeBlockChangeFlag(org.spongepowered.common.world.SpongeBlockChangeFlag) IBlockState(net.minecraft.block.state.IBlockState) IMixinLocation(org.spongepowered.common.interfaces.world.IMixinLocation) SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) BlockSnapshot(org.spongepowered.api.block.BlockSnapshot) IMixinWorldServer(org.spongepowered.common.interfaces.world.IMixinWorldServer) IMixinWorldServer(org.spongepowered.common.interfaces.world.IMixinWorldServer) WorldServer(net.minecraft.world.WorldServer) World(org.spongepowered.api.world.World) SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) BlockPos(net.minecraft.util.math.BlockPos) ItemDropData(org.spongepowered.common.event.tracking.context.ItemDropData) EntityItem(net.minecraft.entity.item.EntityItem)

Example 2 with SpongeBlockChangeFlag

use of org.spongepowered.common.world.SpongeBlockChangeFlag in project SpongeCommon by SpongePowered.

the class PhaseTracker method setBlockState.

public boolean setBlockState(final IMixinWorldServer mixinWorld, final BlockPos pos, final IBlockState newState, BlockChangeFlag flag) {
    final SpongeBlockChangeFlag spongeFlag = (SpongeBlockChangeFlag) flag;
    final net.minecraft.world.World minecraftWorld = mixinWorld.asMinecraftWorld();
    final Chunk chunk = minecraftWorld.getChunkFromBlockCoords(pos);
    // If chunk is empty, we simply return to avoid any further logic.
    if (chunk.isEmpty()) {
        return false;
    }
    final Block block = newState.getBlock();
    // Sponge Start - Up to this point, we've copied exactly what Vanilla minecraft does.
    final IBlockState currentState = chunk.getBlockState(pos);
    if (currentState == newState) {
        // Some micro optimization in case someone is trying to set the new state to the same as current
        return false;
    }
    // Now we need to do some of our own logic to see if we need to capture.
    final PhaseData phaseData = this.stack.peek();
    final IPhaseState<?> phaseState = phaseData.state;
    final boolean isComplete = phaseState == GeneralPhase.State.COMPLETE;
    if (SpongeImpl.getGlobalConfig().getConfig().getPhaseTracker().isVerbose() && isComplete) {
        // The random occurrence that we're told to complete a phase
        // while a world is being changed unknowingly.
        this.printUnexpectedBlockChange();
    }
    if (phaseState.requiresBlockCapturing()) {
        try {
            // of the original method where true means it successfully changed.
            return TrackingUtil.trackBlockChange(this, mixinWorld, chunk, currentState, newState, pos, flag, phaseData.context, phaseState);
        } catch (Exception | NoClassDefFoundError e) {
            this.printBlockTrackingException(phaseData, phaseState, e);
            return false;
        }
    }
    // Sponge End - continue with vanilla mechanics
    IBlockState iblockstate = chunk.setBlockState(pos, newState);
    if (iblockstate == null) {
        return false;
    }
    // else { // Sponge - unnecessary formatting
    if (newState.getLightOpacity() != iblockstate.getLightOpacity() || newState.getLightValue() != iblockstate.getLightValue()) {
        // minecraftWorld.profiler.startSection("checkLight"); // Sponge - we don't need to us the profiler
        minecraftWorld.checkLight(pos);
    // minecraftWorld.profiler.endSection(); // Sponge - We don't need to use the profiler
    }
    if (spongeFlag.isNotifyClients() && chunk.isPopulated()) {
        minecraftWorld.notifyBlockUpdate(pos, iblockstate, newState, spongeFlag.getRawFlag());
    }
    if (spongeFlag.updateNeighbors()) {
        minecraftWorld.notifyNeighborsRespectDebug(pos, iblockstate.getBlock(), true);
        if (newState.hasComparatorInputOverride()) {
            minecraftWorld.updateComparatorOutputLevel(pos, block);
        }
    } else if (!minecraftWorld.isRemote && spongeFlag.notifyObservers()) {
        minecraftWorld.updateObservingBlocksAt(pos, block);
    }
    return true;
// } // Sponge - unnecessary formatting
}
Also used : SpongeBlockChangeFlag(org.spongepowered.common.world.SpongeBlockChangeFlag) IBlockState(net.minecraft.block.state.IBlockState) Chunk(net.minecraft.world.chunk.Chunk) ReportedException(net.minecraft.util.ReportedException) Block(net.minecraft.block.Block)

Example 3 with SpongeBlockChangeFlag

use of org.spongepowered.common.world.SpongeBlockChangeFlag 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);
        });
    }
}
Also used : SpongeBlockChangeFlag(org.spongepowered.common.world.SpongeBlockChangeFlag) Entity(org.spongepowered.api.entity.Entity) IBlockState(net.minecraft.block.state.IBlockState) IMixinLocation(org.spongepowered.common.interfaces.world.IMixinLocation) SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) BlockSnapshot(org.spongepowered.api.block.BlockSnapshot) ArrayList(java.util.ArrayList) IPhaseState(org.spongepowered.common.event.tracking.IPhaseState) IMixinWorldServer(org.spongepowered.common.interfaces.world.IMixinWorldServer) IMixinWorldServer(org.spongepowered.common.interfaces.world.IMixinWorldServer) WorldServer(net.minecraft.world.WorldServer) World(org.spongepowered.api.world.World) SpongeProxyBlockAccess(org.spongepowered.common.world.SpongeProxyBlockAccess) SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) BlockPos(net.minecraft.util.math.BlockPos) ItemDropData(org.spongepowered.common.event.tracking.context.ItemDropData) EntityItem(net.minecraft.entity.item.EntityItem)

Aggregations

IBlockState (net.minecraft.block.state.IBlockState)3 SpongeBlockChangeFlag (org.spongepowered.common.world.SpongeBlockChangeFlag)3 EntityItem (net.minecraft.entity.item.EntityItem)2 BlockPos (net.minecraft.util.math.BlockPos)2 WorldServer (net.minecraft.world.WorldServer)2 BlockSnapshot (org.spongepowered.api.block.BlockSnapshot)2 Entity (org.spongepowered.api.entity.Entity)2 World (org.spongepowered.api.world.World)2 SpongeBlockSnapshot (org.spongepowered.common.block.SpongeBlockSnapshot)2 ItemDropData (org.spongepowered.common.event.tracking.context.ItemDropData)2 IMixinLocation (org.spongepowered.common.interfaces.world.IMixinLocation)2 IMixinWorldServer (org.spongepowered.common.interfaces.world.IMixinWorldServer)2 ArrayList (java.util.ArrayList)1 Block (net.minecraft.block.Block)1 ReportedException (net.minecraft.util.ReportedException)1 Chunk (net.minecraft.world.chunk.Chunk)1 TileEntity (org.spongepowered.api.block.tileentity.TileEntity)1 IPhaseState (org.spongepowered.common.event.tracking.IPhaseState)1 IMixinTileEntity (org.spongepowered.common.interfaces.block.tile.IMixinTileEntity)1 IMixinEntity (org.spongepowered.common.interfaces.entity.IMixinEntity)1