Search in sources :

Example 1 with SpongeBlockSnapshot

use of org.spongepowered.common.block.SpongeBlockSnapshot 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 SpongeBlockSnapshot

use of org.spongepowered.common.block.SpongeBlockSnapshot in project SpongeCommon by SpongePowered.

the class SpongeItemStackBuilder method fromBlockSnapshot.

@Override
public ItemStack.Builder fromBlockSnapshot(BlockSnapshot blockSnapshot) {
    checkNotNull(blockSnapshot, "The snapshot was null!");
    reset();
    final BlockType blockType = blockSnapshot.getState().getType();
    final Optional<ItemType> itemType = blockType.getItem();
    itemType(itemType.orElseThrow(() -> new IllegalArgumentException("ItemType not found for block type: " + blockType.getId())));
    quantity(1);
    if (blockSnapshot instanceof SpongeBlockSnapshot) {
        final Block block = (Block) blockType;
        this.damageValue = block.damageDropped((IBlockState) blockSnapshot.getState());
        final Optional<NBTTagCompound> compound = ((SpongeBlockSnapshot) blockSnapshot).getCompound();
        if (compound.isPresent()) {
            this.compound = new NBTTagCompound();
            this.compound.setTag(NbtDataUtil.BLOCK_ENTITY_TAG, compound.get());
        }
    // todo probably needs more testing, but this'll do donkey...
    } else {
        // TODO handle through the API specifically handling the rest of the data stuff
        blockSnapshot.getContainers().forEach(this::itemData);
    }
    return this;
}
Also used : SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) IBlockState(net.minecraft.block.state.IBlockState) BlockType(org.spongepowered.api.block.BlockType) ItemType(org.spongepowered.api.item.ItemType) NBTTagCompound(net.minecraft.nbt.NBTTagCompound) Block(net.minecraft.block.Block)

Example 3 with SpongeBlockSnapshot

use of org.spongepowered.common.block.SpongeBlockSnapshot in project SpongeCommon by SpongePowered.

the class MixinWorldServer method createSpongeBlockSnapshot.

@Override
public SpongeBlockSnapshot createSpongeBlockSnapshot(IBlockState state, IBlockState extended, BlockPos pos, BlockChangeFlag updateFlag) {
    this.builder.reset();
    this.builder.blockState((BlockState) state).extendedState((BlockState) extended).worldId(this.getUniqueId()).position(VecHelper.toVector3i(pos));
    Optional<UUID> creator = getCreator(pos.getX(), pos.getY(), pos.getZ());
    Optional<UUID> notifier = getNotifier(pos.getX(), pos.getY(), pos.getZ());
    if (creator.isPresent()) {
        this.builder.creator(creator.get());
    }
    if (notifier.isPresent()) {
        this.builder.notifier(notifier.get());
    }
    if (state.getBlock() instanceof ITileEntityProvider) {
        // We MUST only check to see if a TE exists to avoid creating a new one.
        final net.minecraft.tileentity.TileEntity te = this.getChunkFromBlockCoords(pos).getTileEntity(pos, net.minecraft.world.chunk.Chunk.EnumCreateEntityType.CHECK);
        if (te != null) {
            TileEntity tile = (TileEntity) te;
            for (DataManipulator<?, ?> manipulator : ((IMixinCustomDataHolder) tile).getCustomManipulators()) {
                this.builder.add(manipulator);
            }
            NBTTagCompound nbt = new NBTTagCompound();
            // Some mods like OpenComputers assert if attempting to save robot while moving
            try {
                te.writeToNBT(nbt);
                this.builder.unsafeNbt(nbt);
            } catch (Throwable t) {
            // ignore
            }
        }
    }
    return new SpongeBlockSnapshot(this.builder, (SpongeBlockChangeFlag) updateFlag);
}
Also used : NBTTagCompound(net.minecraft.nbt.NBTTagCompound) IMixinCustomDataHolder(org.spongepowered.common.interfaces.data.IMixinCustomDataHolder) TileEntity(org.spongepowered.api.block.tileentity.TileEntity) IMixinTileEntity(org.spongepowered.common.interfaces.block.tile.IMixinTileEntity) SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) ITileEntityProvider(net.minecraft.block.ITileEntityProvider) BlockState(org.spongepowered.api.block.BlockState) IBlockState(net.minecraft.block.state.IBlockState) UUID(java.util.UUID)

Example 4 with SpongeBlockSnapshot

use of org.spongepowered.common.block.SpongeBlockSnapshot in project SpongeCommon by SpongePowered.

the class TransactionSink method logScheduledUpdate.

@SuppressWarnings("ConstantConditions")
default void logScheduledUpdate(final ServerLevel serverWorld, final TickNextTickData<?> data) {
    final WeakReference<ServerLevel> worldRef = new WeakReference<>(serverWorld);
    final Supplier<ServerLevel> worldSupplier = () -> Objects.requireNonNull(worldRef.get(), "ServerWorld dereferenced");
    @Nullable final BlockEntity tileEntity = serverWorld.getBlockEntity(data.pos);
    final BlockState existing = serverWorld.getBlockState(data.pos);
    final SpongeBlockSnapshot original = TrackingUtil.createPooledSnapshot(existing, data.pos, BlockChangeFlags.NONE, Constants.World.DEFAULT_BLOCK_CHANGE_LIMIT, tileEntity, worldSupplier, Optional::empty, Optional::empty);
    original.blockChange = BlockChange.MODIFY;
    final ScheduleUpdateTransaction transaction = new ScheduleUpdateTransaction(original, data);
    this.logTransaction(transaction);
}
Also used : ServerLevel(net.minecraft.server.level.ServerLevel) SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) BlockState(net.minecraft.world.level.block.state.BlockState) Optional(java.util.Optional) ScheduleUpdateTransaction(org.spongepowered.common.event.tracking.context.transaction.block.ScheduleUpdateTransaction) WeakReference(java.lang.ref.WeakReference) Nullable(org.checkerframework.checker.nullness.qual.Nullable) BlockEntity(net.minecraft.world.level.block.entity.BlockEntity) RemoveBlockEntity(org.spongepowered.common.event.tracking.context.transaction.block.RemoveBlockEntity) ReplaceBlockEntity(org.spongepowered.common.event.tracking.context.transaction.block.ReplaceBlockEntity)

Example 5 with SpongeBlockSnapshot

use of org.spongepowered.common.block.SpongeBlockSnapshot in project SpongeCommon by SpongePowered.

the class LevelChunkMixin_Tracker method bridge$createChunkPipeline.

/**
 * Technically a full overwrite for {@link LevelChunk#setBlockState(BlockPos, BlockState, boolean)}
 * and due to Sponge's hijacking of {@link ServerLevel#setBlock(BlockPos, BlockState, int)},
 * it needs to be able to record transactions when necessary. This implementation allows for us to
 * further specify the types of transactions and what proxies are needing to set up where.
 *
 * @param pos The position changing
 * @param newState The new state
 * @param currentState The current state - passed in from either chunk or world
 * @param flag The sponge change flag, converted from an int to a proper struct
 * @return The changed block state if not null
 * @author gabizou - January 13th, 2020 - Minecraft 1.14.3
 */
@Override
@NonNull
public ChunkPipeline bridge$createChunkPipeline(final BlockPos pos, final BlockState newState, final BlockState currentState, final SpongeBlockChangeFlag flag, final int limit) {
    final boolean isFake = ((LevelBridge) this.level).bridge$isFake();
    if (isFake) {
        throw new IllegalStateException("Cannot call ChunkBridge.bridge$buildChunkPipeline in non-Server managed worlds");
    }
    // int i = pos.getX() & 15;
    final int xPos = pos.getX() & 15;
    // int j = pos.getY();
    final int yPos = pos.getY();
    // int k = pos.getZ() & 15;
    final int zPos = pos.getZ() & 15;
    // Sponge - get the moving flag from our flag construct
    LevelChunkSection chunksection = this.sections[yPos >> 4];
    if (chunksection == LevelChunkMixin_Tracker.EMPTY_SECTION) {
        if (newState.isAir()) {
            return ChunkPipeline.nullReturn((LevelChunk) (Object) this, (ServerLevel) this.level);
        }
        chunksection = new LevelChunkSection(yPos >> 4 << 4);
        this.sections[yPos >> 4] = chunksection;
    }
    // Sponge Start - Build out the BlockTransaction
    final PhaseContext<@NonNull ?> context = PhaseTracker.getInstance().getPhaseContext();
    @Nullable final BlockEntity existing = this.shadow$getBlockEntity(pos, LevelChunk.EntityCreationType.CHECK);
    // Build a transaction maybe?
    final WeakReference<ServerLevel> ref = new WeakReference<>((ServerLevel) this.level);
    final SpongeBlockSnapshot snapshot = TrackingUtil.createPooledSnapshot(currentState, pos, flag, limit, existing, () -> Objects.requireNonNull(ref.get(), "ServerWorld dereferenced"), Optional::empty, Optional::empty);
    // Pulled up from below
    final ChangeBlock transaction = context.createTransaction(snapshot, newState, flag);
    snapshot.blockChange = context.associateBlockChangeWithSnapshot(newState, currentState);
    if (((BlockStateBridge) snapshot.state()).bridge$hasTileEntity() && (snapshot.blockChange == BlockChange.BREAK || snapshot.blockChange == BlockChange.MODIFY)) {
        transaction.queuedRemoval = existing;
    }
    final ChunkPipeline.Builder builder = ChunkPipeline.builder().kickOff(transaction).chunk((LevelChunk) (Object) this).chunkSection(chunksection).world((ServerLevel) this.level);
    // Populate the effects
    transaction.populateChunkEffects(builder);
    return builder.build();
}
Also used : ServerLevel(net.minecraft.server.level.ServerLevel) Optional(java.util.Optional) ChangeBlock(org.spongepowered.common.event.tracking.context.transaction.block.ChangeBlock) SpongeBlockSnapshot(org.spongepowered.common.block.SpongeBlockSnapshot) LevelBridge(org.spongepowered.common.bridge.world.level.LevelBridge) LevelChunkSection(net.minecraft.world.level.chunk.LevelChunkSection) WeakReference(java.lang.ref.WeakReference) Nullable(org.checkerframework.checker.nullness.qual.Nullable) ChunkPipeline(org.spongepowered.common.event.tracking.context.transaction.pipeline.ChunkPipeline) BlockEntity(net.minecraft.world.level.block.entity.BlockEntity) MonotonicNonNull(org.checkerframework.checker.nullness.qual.MonotonicNonNull) NonNull(org.checkerframework.checker.nullness.qual.NonNull)

Aggregations

SpongeBlockSnapshot (org.spongepowered.common.block.SpongeBlockSnapshot)20 Optional (java.util.Optional)10 IBlockState (net.minecraft.block.state.IBlockState)6 ServerLevel (net.minecraft.server.level.ServerLevel)6 Nullable (org.checkerframework.checker.nullness.qual.Nullable)6 BlockPos (net.minecraft.core.BlockPos)5 BlockSnapshot (org.spongepowered.api.block.BlockSnapshot)5 LevelChunkBridge (org.spongepowered.common.bridge.world.level.chunk.LevelChunkBridge)5 WeakReference (java.lang.ref.WeakReference)4 BlockEntity (net.minecraft.world.level.block.entity.BlockEntity)4 NonNull (org.checkerframework.checker.nullness.qual.NonNull)4 IMixinWorldServer (org.spongepowered.common.interfaces.world.IMixinWorldServer)4 ArrayList (java.util.ArrayList)3 List (java.util.List)3 UUID (java.util.UUID)3 WorldServer (net.minecraft.world.WorldServer)3 Block (net.minecraft.world.level.block.Block)3 BlockState (net.minecraft.world.level.block.state.BlockState)3 Entity (org.spongepowered.api.entity.Entity)3 SpongeEventFactory (org.spongepowered.api.event.SpongeEventFactory)3