XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

MyDimension

【Java】我的维度模组

公开
关注 0 Fork 0 Star 0
UTF-8
package com.xfestudio.mydimension.builder;

import com.xfestudio.mydimension.MyDimension;
import com.xfestudio.mydimension.builder.history.BuilderHistoryData;
import com.xfestudio.mydimension.builder.history.BuilderTransaction;
import com.xfestudio.mydimension.builder.history.WorldDelta;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.CandleBlock;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.GameMasterBlock;
import net.minecraft.world.level.block.SeaPickleBlock;
import net.minecraft.world.level.block.SlabBlock;
import net.minecraft.world.level.block.SnowLayerBlock;
import net.minecraft.world.level.block.TurtleEggBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.SlabType;
import net.minecraft.world.level.border.WorldBorder;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.ToolAction;
import net.minecraftforge.common.ToolActions;
import net.minecraftforge.common.util.BlockSnapshot;
import net.minecraftforge.event.level.BlockEvent;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.Map;

/** Server-authoritative execution for layer jobs and material-waiting retries. */
public final class BuilderOperationManager {
    /** Conservative upper bound for one ordinary state-only delta plus its small item ledger share. */
    private static final long ORDINARY_HISTORY_ENTRY_BYTES = 4_096L;
    /** Used only when a mod advertises a BE but cannot create a prediction instance safely. */
    private static final long UNKNOWN_BLOCK_ENTITY_BYTES = 256L * 1_024L;
    /**
     * Structural block entities whose first ticker invocation is a bounded, non-processing
     * initialization pass. Keep this deliberately explicit: ticking an arbitrary newly placed
     * furnace or modded machine here could advance recipes, consume fuel, or emit side effects.
     */
    private static final ResourceLocation CREATE_ITEM_VAULT =
            new ResourceLocation("create", "item_vault");

    private BuilderOperationManager() {
    }

    public static Result executeSurface(ServerPlayer player, ItemStack scepter, BlockHitResult hit) {
        return executeSurface(player, scepter, hit, false);
    }

    /** Used by the C2S handler after {@link BuilderReachValidator#validatedHit} already ray-validated it. */
    public static Result executeValidatedSurface(ServerPlayer player, ItemStack scepter, BlockHitResult hit) {
        return executeSurface(player, scepter, hit, true);
    }

    private static Result executeSurface(ServerPlayer player, ItemStack scepter, BlockHitResult hit,
                                         boolean reachAlreadyValidated) {
        if (!BuilderRuntime.settings().enabled()) return Result.disabled();
        if (PendingBuildData.get(player.getServer()).get(player.getUUID()) != null
                || com.xfestudio.mydimension.builder.blueprint.BlueprintTaskManager.get(player.getServer())
                .hasActive(player.getUUID())) {
            return Result.rejected("message.mydimension.builder.active_task_exists");
        }
        BuilderMode mode = RealmwrightData.mode(scepter);
        ServerLevel level = player.serverLevel();
        if (!reachAlreadyValidated && !validReachAndSight(player, hit)) {
            return Result.rejected("message.mydimension.builder.out_of_reach");
        }

        int requested = mode == BuilderMode.BUILD
                ? RealmwrightData.buildLimit(scepter, BuilderRuntime.settings().maxBuildLimit())
                : RealmwrightData.demolishLimit(scepter, BuilderRuntime.settings().maxDemolishLimit());
        int hardLimit = mode == BuilderMode.BUILD
                ? BuilderRuntime.settings().maxBuildLimit() : BuilderRuntime.settings().maxDemolishLimit();
        int limit = Math.max(1, Math.min(requested, hardLimit));
        ItemStack offhand = player.getOffhandItem();
        BlockState override = offhand.getItem() instanceof BlockItem blockItem
                ? blockItem.getBlock().defaultBlockState() : null;
        SurfacePlanner.Plan plan = SurfacePlanner.plan(level, hit.getBlockPos(), hit.getDirection(), mode,
                RealmwrightData.matchMode(scepter), limit, override,
                mode == BuilderMode.BUILD && RealmwrightData.allowsReplacement(scepter));
        if (plan.candidates().isEmpty()) return Result.rejected("message.mydimension.builder.nothing_to_do");
        List<SurfacePlanner.Candidate> locked = lockSurfaceStates(player, plan.candidates(),
                hit.getDirection(), mode);
        return executeImmediateSurface(player, scepter, mode, locked, hit.getDirection(),
                UUID.randomUUID(), plan.truncated(), RealmwrightData.recordsHistory(scepter), false, false);
    }

    public static Result resumePending(ServerPlayer player, ItemStack scepter) {
        PendingBuildData data = PendingBuildData.get(player.getServer());
        PendingBuildData.Task task = data.get(player.getUUID());
        if (task == null || !task.scepterId().equals(RealmwrightData.id(scepter))) {
            return Result.rejected("message.mydimension.builder.no_pending_task");
        }
        if (!task.dimension().equals(player.level().dimension())) {
            return Result.rejected("message.mydimension.builder.pending_other_dimension");
        }
        if (task.type() == BuilderTransaction.Type.BLUEPRINT) {
            com.xfestudio.mydimension.builder.blueprint.BlueprintTaskManager.resume(player, scepter, task);
            return new Result(0, task.missing().size(), 0, false, null, true);
        }
        List<SurfacePlanner.Candidate> candidates = task.missing().stream()
                .map(entry -> new SurfacePlanner.Candidate(entry.pos(), entry.pos(), entry.state(), 0)).toList();
        BuilderMode mode = task.type() == BuilderTransaction.Type.DEMOLISH
                ? BuilderMode.DEMOLISH : BuilderMode.BUILD;
        boolean captureHistory = task.resolveRecordHistory(RealmwrightData.recordsHistory(scepter));
        return executeImmediateSurface(player, scepter, mode, candidates, Direction.UP,
                task.transactionId(), false, captureHistory, true, task.soundPlayed());
    }

    /**
     * Executes an entire manually requested surface in this server task.  History
     * capture is an explicit per-scepter opt-in; with it disabled this path never
     * serializes block entities or constructs a transaction ledger.
     */
    private static Result executeImmediateSurface(ServerPlayer player, ItemStack scepter,
                                                  BuilderMode mode,
                                                  List<SurfacePlanner.Candidate> candidates,
                                                  Direction face, UUID transactionId,
                                                  boolean truncated, boolean captureHistory,
                                                  boolean continuation, boolean soundAlreadyPlayed) {
        BuilderTransaction.Type type = mode == BuilderMode.BUILD
                ? BuilderTransaction.Type.BUILD : BuilderTransaction.Type.DEMOLISH;
        if (captureHistory && continuation
                && !validateContinuationPrefix(player, scepter, transactionId)) {
            return new Result(0, 0, 0, truncated,
                    "message.mydimension.builder.continuation_world_conflict", true);
        }
        if (captureHistory && !prepareHistory(player, scepter, transactionId, type,
                candidates, face, false, Map.of())) {
            return new Result(0, 0, 0, truncated,
                    "message.mydimension.builder.history_budget_exceeded", true);
        }

        Execution execution = mode == BuilderMode.BUILD
                ? build(player, scepter, candidates, face, transactionId, false, Map.of(), captureHistory)
                : demolish(player, scepter, candidates, transactionId, captureHistory);
        if (captureHistory) refreshFinalAfterImages(player.serverLevel(), execution);
        boolean committed = !captureHistory
                || recordTransaction(player, scepter, type, transactionId, execution);
        if (!committed) {
            return new Result(execution.changedCount, execution.missing.size(), execution.blocked,
                    truncated, null, true);
        }
        if (shouldRefreshMergedHistory(captureHistory, continuation, committed)) {
            // Appending a continuation can update connection-aware states in the
            // already recorded prefix (fences, walls, redstone, and similar).
            // Refresh the combined transaction, not merely this resume batch.
            BuilderHistoryData.get(player.getServer()).refreshAppliedAfter(player.getUUID(),
                    RealmwrightData.id(scepter), transactionId, player.serverLevel());
        }
        boolean soundPlayed = soundAlreadyPlayed;
        if (!soundPlayed && execution.sound != null) {
            playOperationSound(player, execution.sound);
            soundPlayed = true;
        }

        PendingBuildData pending = PendingBuildData.get(player.getServer());
        PendingBuildData.Task previous = continuation ? pending.get(player.getUUID()) : null;
        boolean matchingContinuation = previous != null
                && previous.transactionId().equals(transactionId)
                && previous.scepterId().equals(RealmwrightData.id(scepter));
        PendingCounts counts = pendingCounts(matchingContinuation,
                matchingContinuation ? previous.completed() : 0,
                matchingContinuation ? previous.total() : 0,
                execution.changedCount, execution.missing.size());
        pending.remove(player.getUUID());
        if (!execution.missing.isEmpty()) {
            pending.put(player.getUUID(), new PendingBuildData.Task(RealmwrightData.id(scepter),
                    transactionId, player.level().dimension(), type, captureHistory, true,
                    soundPlayed, counts.completed(), counts.total(), execution.missing,
                    System.currentTimeMillis()));
        }
        player.displayClientMessage(Component.translatable("message.mydimension.builder.result",
                execution.changedCount, execution.missing.size(), execution.blocked), true);
        // With history disabled and no pending cells, the world and inventories already synchronize
        // through vanilla. Avoid rebuilding/sorting history, resolving every anchor and emitting an
        // empty workflow preview after every ordinary click.
        boolean synchronizeBuilderState = shouldSynchronizeBuilderState(
                captureHistory, execution.missing.size());
        return new Result(execution.changedCount, execution.missing.size(), execution.blocked,
                truncated, null, synchronizeBuilderState);
    }

    static boolean shouldRefreshMergedHistory(boolean captureHistory, boolean continuation,
                                              boolean committed) {
        return captureHistory && continuation && committed;
    }

    static boolean shouldSynchronizeBuilderState(boolean captureHistory, int missingBlocks) {
        return captureHistory || missingBlocks > 0;
    }

    private static boolean validateContinuationPrefix(ServerPlayer player, ItemStack scepter,
                                                      UUID transactionId) {
        BuilderHistoryData history = BuilderHistoryData.get(player.getServer());
        BuilderTransaction prefix = history.peekUndo(player.getUUID(), RealmwrightData.id(scepter));
        if (prefix == null || !prefix.id().equals(transactionId)) return true;
        if (prefix.matchesAppliedAfter(player.serverLevel())) return true;
        history.conflictApplied(player.getUUID(), RealmwrightData.id(scepter), transactionId);
        return false;
    }

    private static int saturatedCount(int left, int right) {
        return (int) Math.min(Integer.MAX_VALUE, (long) Math.max(0, left) + Math.max(0, right));
    }

    static PendingCounts pendingCounts(boolean matchingContinuation, int previousCompleted,
                                       int previousTotal, int changed, int missing) {
        int completed = matchingContinuation
                ? saturatedCount(previousCompleted, changed) : Math.max(0, changed);
        int total = matchingContinuation ? Math.max(0, previousTotal)
                : saturatedCount(changed, missing);
        return new PendingCounts(completed, Math.max(completed, total));
    }

    record PendingCounts(int completed, int total) {
    }

    public static boolean cancelPending(ServerPlayer player, ItemStack scepter) {
        boolean activeBlueprint = com.xfestudio.mydimension.builder.blueprint.BlueprintTaskManager
                .get(player.getServer()).cancel(player, scepter);
        PendingBuildData data = PendingBuildData.get(player.getServer());
        PendingBuildData.Task task = data.get(player.getUUID());
        if (task == null || !task.scepterId().equals(RealmwrightData.id(scepter))) {
            return activeBlueprint;
        }
        data.remove(player.getUUID());
        return true;
    }

    /** Locks BlockItem placement semantics once for every target in this click. */
    static List<SurfacePlanner.Candidate> lockSurfaceStates(ServerPlayer player,
                                                            List<SurfacePlanner.Candidate> candidates,
                                                            Direction face, BuilderMode mode) {
        if (mode != BuilderMode.BUILD || !(player.getOffhandItem().getItem() instanceof BlockItem)) {
            return List.copyOf(candidates);
        }
        List<SurfacePlanner.Candidate> locked = new ArrayList<>(candidates.size());
        for (SurfacePlanner.Candidate candidate : candidates) {
            locked.add(new SurfacePlanner.Candidate(candidate.reference(), candidate.target(),
                    desiredState(player, candidate, face), candidate.distance()));
        }
        return List.copyOf(locked);
    }

    private static Execution build(ServerPlayer player, ItemStack scepter,
                                   List<SurfacePlanner.Candidate> candidates, Direction face,
                                   UUID transactionId, boolean allowOffhandOverride,
                                   Map<BlockPos, net.minecraft.nbt.CompoundTag> blockEntityTags,
                                   boolean captureHistory) {
        ServerLevel level = player.serverLevel();
        Execution result = new Execution(player.getOffhandItem().copy(), captureHistory,
                OperationSoundKind.PLACE);
        List<BuildAttempt> attempts = new ArrayList<>();
        ItemStack placementSource = player.getOffhandItem().copy();
        boolean free = isFree(player);
        boolean allowReplacement = RealmwrightData.allowsReplacement(scepter);
        for (SurfacePlanner.Candidate candidate : candidates) {
            try {
                BlockPos pos = candidate.target();
                BlockState desired = allowOffhandOverride ? desiredState(player, candidate, face)
                        : candidate.desiredState();
                BlockState existing = level.getBlockState(pos);
                if (existing.equals(desired)) continue;
                // Keep this pass cheap.  The authoritative collision/envelope check runs exactly
                // once immediately before the edit, after any earlier mod callbacks in this batch.
                if (!validStaticBuildEnvelope(player, pos, desired, existing, allowReplacement)) {
                    result.blocked++;
                    continue;
                }
                ItemStack cost = constructionCost(desired);
                if (cost.isEmpty()) {
                    result.blocked++;
                    continue;
                }
                ItemStack placementStack = placementStack(placementSource, desired, cost);
                attempts.add(new BuildAttempt(candidate, desired, cost, placementStack,
                        blockEntityTags.get(pos)));
            } catch (Throwable throwable) {
                result.blocked++;
                MyDimension.LOGGER.warn("Builder rejected a placement candidate after a mod callback failed",
                        throwable);
            }
        }

        Map<BlockPos, WorldDelta.Snapshot> batchBeforeImages = Map.of();
        if (captureHistory) {
            try {
                batchBeforeImages = snapshotBuildBatchArea(level, attempts);
            } catch (Throwable throwable) {
                result.blocked += attempts.size();
                MyDimension.LOGGER.warn("Builder rejected a build batch because its neighbour history "
                        + "could not be captured", throwable);
                return result;
            }
        }

        // Aggregate each ItemKey before touching remote handlers. This is what prevents a large storage
        // network from being scanned once per target block.
        List<SupplyPool> pools = new ArrayList<>();
        if (!free) {
            for (BuildAttempt attempt : attempts) {
                List<Item> fallbacks = BuilderBlockCompatibility.constructionFallbacks(attempt.desired);
                SupplyPool pool = findPool(pools, attempt.cost, fallbacks);
                if (pool == null) {
                    pool = new SupplyPool(attempt.cost.copyWithCount(1), fallbacks);
                    pools.add(pool);
                }
                pool.requested += attempt.cost.getCount();
            }
            // Reserve every target's exact item before requesting any substitution. Thus ordinary dirt
            // targets keep first claim on dirt, while grass targets consume grass blocks whenever present.
            for (SupplyPool pool : pools) {
                extractSupply(player, scepter, pool, pool.template, pool.requested);
            }
            for (SupplyPool pool : pools) {
                for (Item fallback : pool.fallbacks) {
                    int missing = pool.requested - pool.available();
                    if (missing <= 0) break;
                    extractSupply(player, scepter, pool, new ItemStack(fallback), missing);
                }
            }
        }

        List<BuildAttempt> unresolved = processWithSingleRetry(attempts,
                attempt -> placeBuildAttempt(player, pools, free, result, attempt, allowReplacement));
        result.blocked += unresolved.size();
        stabilizeBuildBatch(level, result.successfulBuildPositions, captureHistory);
        if (captureHistory && !captureStableBuildHistory(level, batchBeforeImages, result)) {
            restoreSnapshotsWithoutDrops(level, batchBeforeImages);
            for (SupplyPool pool : pools) pool.resetAvailable();
            result.changed.clear();
            result.missing.clear();
            result.credits.clear();
            result.replacementDrops.clear();
            result.successfulBuildPositions.clear();
            result.sound = null;
            result.blocked += result.changedCount;
            result.changedCount = 0;
        }
        List<ItemStack> unusedSupplies = new ArrayList<>();
        for (SupplyPool pool : pools) {
            unusedSupplies.addAll(pool.unusedStacks());
        }
        if (!unusedSupplies.isEmpty()) {
            dropOverflow(player, transactionId, BuilderMaterials.insert(player, scepter, unusedSupplies));
        }
        if (!result.replacementDrops.isEmpty()) {
            settleBuildReplacementDrops(player, scepter, transactionId, result.replacementDrops);
        }
        result.offhandAfter = player.getOffhandItem().copy();
        return result;
    }

    private static void extractSupply(ServerPlayer player, ItemStack scepter, SupplyPool pool,
                                      ItemStack requested, int amount) {
        if (amount <= 0 || requested.isEmpty()) return;
        try {
            BuilderMaterials.Extraction extraction = BuilderMaterials.extract(player, scepter, requested, amount);
            pool.addReserve(requested, extraction.count());
        } catch (Throwable throwable) {
            MyDimension.LOGGER.warn("Builder material extraction failed; this item is left pending", throwable);
        }
    }

    private static ItemStack placementStack(ItemStack offhand, BlockState desired, ItemStack cost) {
        if (offhand.getItem() instanceof BlockItem blockItem
                && blockItem.getBlock() == desired.getBlock()) {
            return offhand.copyWithCount(1);
        }
        return cost.copyWithCount(1);
    }

    private static Map<BlockPos, WorldDelta.Snapshot> snapshotBuildBatchArea(
            ServerLevel level, List<BuildAttempt> attempts) {
        List<BlockPos> targets = attempts.stream().map(attempt -> attempt.candidate.target()).toList();
        Map<BlockPos, WorldDelta.Snapshot> snapshots = new java.util.LinkedHashMap<>();
        for (BlockPos pos : buildStabilizationPositions(targets)) {
            if (level.hasChunkAt(pos)) snapshots.put(pos, WorldDelta.snapshot(level, pos));
        }
        return snapshots;
    }

    /** Target and direct-neighbour set used by the post-placement compatibility pass. */
    static List<BlockPos> buildStabilizationPositions(Iterable<BlockPos> targets) {
        java.util.LinkedHashSet<BlockPos> positions = new java.util.LinkedHashSet<>();
        for (BlockPos target : targets) {
            BlockPos immutable = target.immutable();
            positions.add(immutable);
            for (Direction direction : Direction.values()) {
                positions.add(immutable.relative(direction).immutable());
            }
        }
        return List.copyOf(positions);
    }

    /** Each directed target/source pair appears once even when two successful targets touch. */
    static List<NeighborNotification> buildNeighborNotifications(Iterable<BlockPos> targets) {
        java.util.LinkedHashSet<BlockPos> uniqueTargets = new java.util.LinkedHashSet<>();
        targets.forEach(pos -> uniqueTargets.add(pos.immutable()));
        java.util.LinkedHashSet<NeighborNotification> notifications = new java.util.LinkedHashSet<>();
        for (BlockPos target : uniqueTargets) {
            for (Direction direction : Direction.values()) {
                BlockPos neighbour = target.relative(direction).immutable();
                notifications.add(new NeighborNotification(target, neighbour));
                notifications.add(new NeighborNotification(neighbour, target));
            }
        }
        return List.copyOf(notifications);
    }

    /**
     * Completes the normal BlockItem neighbour lifecycle once per deduplicated batch area. This is
     * intentionally after all placements so multiblocks such as Create vaults see their complete
     * neighbourhood, while the ordinary per-block protection event remains authoritative.
     */
    static void stabilizeBuildBatch(ServerLevel level, Iterable<BlockPos> successfulTargets,
                                    boolean initializeFreshBlockEntities) {
        java.util.LinkedHashSet<BlockPos> targetSet = new java.util.LinkedHashSet<>();
        successfulTargets.forEach(pos -> targetSet.add(pos.immutable()));
        List<BlockPos> targets = List.copyOf(targetSet);
        if (targets.isEmpty()) return;
        List<BlockPos> affected = buildStabilizationPositions(targets);
        Map<BlockPos, BlockState> beforeStates = new java.util.LinkedHashMap<>();
        Map<BlockPos, BlockEntitySyncState> beforeBlockEntities = new java.util.LinkedHashMap<>();

        for (BlockPos pos : affected) {
            if (!validLoadedPosition(level, pos)) continue;
            beforeStates.put(pos, level.getBlockState(pos));
            // Successful targets are always synchronized exactly once below, so serializing their
            // potentially huge machine/inventory update tags before and after would buy nothing.
            if (requiresBlockEntityComparison(targetSet.contains(pos))) {
                beforeBlockEntities.put(pos, blockEntitySyncState(level, pos));
            }
        }

        for (BlockPos pos : affected) {
            if (!beforeStates.containsKey(pos)) continue;
            try {
                BlockState current = level.getBlockState(pos);
                BlockState shaped = Block.updateFromNeighbourShapes(current, level, pos);
                // Deliver the deduplicated directed callbacks below. UPDATE_KNOWN_SHAPE avoids
                // setBlock recursively emitting the same neighbour relationship a second time.
                if (!shaped.equals(current)) level.setBlock(pos, shaped, Block.UPDATE_KNOWN_SHAPE);
            } catch (Throwable throwable) {
                MyDimension.LOGGER.warn("Builder neighbour-shape stabilization failed at {}", pos, throwable);
            }
        }

        for (NeighborNotification notification : buildNeighborNotifications(targets)) {
            if (!validLoadedPosition(level, notification.target)
                    || !validLoadedPosition(level, notification.source)) continue;
            try {
                Block sourceBlock = level.getBlockState(notification.source).getBlock();
                level.neighborChanged(notification.target, sourceBlock, notification.source);
            } catch (Throwable throwable) {
                MyDimension.LOGGER.warn("Builder neighbour callback stabilization failed for {} <- {}",
                        notification.target, notification.source, throwable);
            }
        }

        if (initializeFreshBlockEntities) {
            initializeDeferredStructuralBlockEntities(level, targets);
        }

        for (BlockPos pos : affected) {
            BlockState beforeState = beforeStates.get(pos);
            if (beforeState == null || !validLoadedPosition(level, pos)) continue;
            try {
                BlockState current = level.getBlockState(pos);
                boolean successfulTarget = targetSet.contains(pos);
                boolean stateChanged = !beforeState.equals(current);
                boolean blockEntityChanged = false;
                if (requiresBlockEntityComparison(successfulTarget)) {
                    BlockEntitySyncState beforeBlockEntity = beforeBlockEntities.get(pos);
                    BlockEntitySyncState afterBlockEntity = blockEntitySyncState(level, pos);
                    blockEntityChanged = beforeBlockEntity == null
                            || !beforeBlockEntity.equivalent(afterBlockEntity);
                }
                if (!successfulTarget && !stateChanged && !blockEntityChanged) continue;
                BlockEntity blockEntity = level.getBlockEntity(pos);
                if (blockEntity != null) blockEntity.setChanged();
                level.sendBlockUpdated(pos, beforeState, current, Block.UPDATE_CLIENTS);
            } catch (Throwable throwable) {
                MyDimension.LOGGER.warn("Builder stabilization sync failed at {}", pos, throwable);
            }
        }
    }

    /**
     * Runs the first server ticker invocation for explicitly vetted structural block entities
     * created by this batch before its transactional after-image is captured. Create item vaults
     * defer both connectivity and their serialized last-known position until this invocation.
     * Capturing the pre-initialization image would make an otherwise untouched material-waiting
     * task look externally modified on resume.
     *
     * <p>This is limited to successful targets, history-enabled construction, and a small explicit
     * allowlist of non-processing structural types. Ordinary and unknown machine block entities are
     * never advanced, and exact after-image validation remains in force once this bounded
     * initialization pass has completed.</p>
     */
    private static void initializeDeferredStructuralBlockEntities(ServerLevel level,
                                                                   Iterable<BlockPos> targets) {
        for (BlockPos pos : targets) {
            if (!validLoadedPosition(level, pos)) continue;
            try {
                BlockState state = level.getBlockState(pos);
                BlockEntity blockEntity = level.getBlockEntity(pos);
                if (blockEntity == null || blockEntity.isRemoved()
                        || !(state.getBlock() instanceof EntityBlock entityBlock)) continue;
                ResourceLocation typeId = BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(blockEntity.getType());
                if (!requiresDeferredStructuralFirstTick(typeId)) continue;
                runBlockEntityTicker(entityBlock, level, pos, state, blockEntity);
            } catch (Throwable throwable) {
                // A compatibility initializer must not invalidate already successful placements. If
                // it cannot initialize here, the exact continuation check still fails closed if the
                // ordinary world tick later mutates the recorded image.
                MyDimension.LOGGER.warn("Builder structural first-tick stabilization failed at {}",
                        pos, throwable);
            }
        }
    }

    static boolean requiresDeferredStructuralFirstTick(ResourceLocation blockEntityTypeId) {
        return CREATE_ITEM_VAULT.equals(blockEntityTypeId);
    }

    @SuppressWarnings("unchecked")
    private static <T extends BlockEntity> void runBlockEntityTicker(EntityBlock block, ServerLevel level,
                                                                      BlockPos pos, BlockState state,
                                                                      BlockEntity blockEntity) {
        BlockEntityType<T> type = (BlockEntityType<T>) blockEntity.getType();
        BlockEntityTicker<T> ticker = block.getTicker(level, state, type);
        if (ticker != null) ticker.tick(level, pos, state, (T) blockEntity);
    }

    static boolean requiresBlockEntityComparison(boolean successfulTarget) {
        return !successfulTarget;
    }

    private static boolean validLoadedPosition(ServerLevel level, BlockPos pos) {
        return pos.getY() >= level.getMinBuildHeight() && pos.getY() < level.getMaxBuildHeight()
                && level.hasChunkAt(pos);
    }

    private static BlockEntitySyncState blockEntitySyncState(ServerLevel level, BlockPos pos) {
        BlockEntity blockEntity = level.getBlockEntity(pos);
        if (blockEntity == null) return new BlockEntitySyncState(null, null, true);
        try {
            return new BlockEntitySyncState(blockEntity.getType(), blockEntity.getUpdateTag().copy(), true);
        } catch (Throwable throwable) {
            // An opaque modded BE cannot be compared safely. Sync it conservatively only when it is
            // part of the affected area, while still avoiding unconditional setChanged for normal BEs.
            return new BlockEntitySyncState(blockEntity.getType(), null, false);
        }
    }

    private static boolean captureStableBuildHistory(ServerLevel level,
                                                     Map<BlockPos, WorldDelta.Snapshot> beforeImages,
                                                     Execution result) {
        try {
            result.changed.clear();
            for (Map.Entry<BlockPos, WorldDelta.Snapshot> entry : beforeImages.entrySet()) {
                WorldDelta.Snapshot before = entry.getValue();
                WorldDelta.Snapshot after = WorldDelta.snapshot(level, entry.getKey());
                if (before.equals(after)) continue;
                result.changed.add(new WorldDelta(entry.getKey(), before.state(), before.blockEntity(),
                        after.state(), after.blockEntity()));
            }
            return true;
        } catch (Throwable throwable) {
            MyDimension.LOGGER.warn("Builder could not capture stabilized build history", throwable);
            return false;
        }
    }

    /**
     * Makes one placement attempt against the latest world. Returning false is
     * reserved exclusively for a currently-unsatisfied canSurvive dependency,
     * allowing the caller to retry it after later supports in the same batch.
     * Every other result is terminal for this batch and records its own ledger
     * or blocked/missing outcome exactly once.
     */
    private static boolean placeBuildAttempt(ServerPlayer player, List<SupplyPool> pools, boolean free,
                                             Execution result, BuildAttempt attempt,
                                             boolean allowReplacement) {
        ServerLevel level = player.serverLevel();
        BlockPos pos = attempt.candidate.target();
        BlockState desired = attempt.desired;
        SupplyPool pool = free ? null : findPool(pools, attempt.cost,
                BuilderBlockCompatibility.constructionFallbacks(desired));
        int costCount = attempt.cost.getCount();
        boolean destructiveReplacement;
        try {
            BlockState existing = level.getBlockState(pos);
            if (existing.equals(desired)) return true;
            if (!validBuildEnvelope(player, pos, desired, existing, allowReplacement)) {
                result.blocked++;
                return true;
            }
            destructiveReplacement = BuilderReplacementPolicy.requiresBreaking(existing);
            if (destructiveReplacement && !mayDestroyForReplacement(player, pos, existing)) {
                result.blocked++;
                return true;
            }
            if (!desired.canSurvive(level, pos)) return false;
        } catch (Throwable throwable) {
            result.blocked++;
            MyDimension.LOGGER.warn("Builder rejected placement target {} after a dynamic check failed", pos,
                    throwable);
            return true;
        }
        if (!free && pool == null) {
            result.blocked++;
            return true;
        }
        if (pool != null && pool.available() < costCount) {
            result.missing.add(new PendingBuildData.Entry(pos, desired, attempt.blockEntityTag));
            return true;
        }

        BlockState beforeState;
        BlockSnapshot forgeSnapshot;
        Map<BlockPos, WorldDelta.Snapshot> replacementBeforeImages = Map.of();
        try {
            beforeState = level.getBlockState(pos);
            destructiveReplacement = BuilderReplacementPolicy.requiresBreaking(beforeState);
            if (!validBuildEnvelope(player, pos, desired, beforeState, allowReplacement)
                    || destructiveReplacement && !mayDestroyForReplacement(player, pos, beforeState)) {
                result.blocked++;
                return true;
            }
            if (destructiveReplacement) {
                // Break and placement callbacks may synchronously reshape a paired block or direct
                // neighbour. Keep a current per-attempt image so a rejected placement can restore
                // the complete replacement, even when transaction history is disabled.
                replacementBeforeImages = snapshotReplacementArea(level, pos, beforeState);
            }
            forgeSnapshot = BlockSnapshot.create(level.dimension(), level, pos);
        } catch (Throwable throwable) {
            result.blocked++;
            MyDimension.LOGGER.warn("Builder could not snapshot placement target {} in {}", pos,
                    level.dimension().location(), throwable);
            return true;
        }
        boolean placed = false;
        List<ItemStack> replacementDrops = List.of();
        try {
            if (destructiveReplacement) {
                BuilderDropCapture.CaptureResult<Boolean> broken = BuilderDropCapture.capture(
                        () -> destroyBlockForReplacement(player, pos));
                if (!broken.value() || !level.getBlockState(pos).canBeReplaced()) {
                    restoreSnapshotsWithoutDrops(level, replacementBeforeImages);
                    result.blocked++;
                    return true;
                }
                if (!player.isCreative()) replacementDrops = broken.drops();
            }
            placed = level.setBlock(pos, desired, Block.UPDATE_ALL);
            if (placed) {
                BlockEvent.EntityPlaceEvent event = new BlockEvent.EntityPlaceEvent(forgeSnapshot,
                        beforeState, player);
                if (MinecraftForge.EVENT_BUS.post(event)) {
                    placed = false;
                }
            }
            if (placed && !attempt.placementStack.isEmpty()
                    && attempt.placementStack.is(desired.getBlock().asItem())) {
                BlockState placedState = level.getBlockState(pos);
                placedState.getBlock().setPlacedBy(level, pos, placedState, player,
                        attempt.placementStack.copy());
            }
            if (placed && attempt.blockEntityTag != null
                    && !applyBlockEntityTag(player, pos, attempt.blockEntityTag)) {
                placed = false;
            }
            // A placement callback may synchronously replace or consume the block (for example a
            // powered TNT). Such side effects are not represented by this transaction, so never debit
            // material or record an air-to-air delta as a successful placement.
            if (placed && !level.getBlockState(pos).is(desired.getBlock())) {
                placed = false;
            }
        } catch (Throwable throwable) {
            MyDimension.LOGGER.warn("Builder placement failed safely at {} in {}", pos,
                    level.dimension().location(), throwable);
            placed = false;
        }
        if (!placed) {
            try {
                if (destructiveReplacement) restoreSnapshotsWithoutDrops(level, replacementBeforeImages);
                else forgeSnapshot.restore(true, false);
            } catch (Throwable throwable) {
                MyDimension.LOGGER.error("Builder could not restore rejected placement at {} in {}", pos,
                        level.dimension().location(), throwable);
            }
            result.blocked++;
            return true;
        }
        if (pool != null) {
            List<ItemStack> consumed = pool.consume(costCount);
            if (result.captureHistory) {
                consumed.forEach(stack -> addLedgerStack(result.debits, stack));
            }
        }
        for (ItemStack drop : replacementDrops) {
            if (drop.isEmpty()) continue;
            result.replacementDrops.add(new PositionedDrop(pos.immutable(), drop.copy()));
            if (result.captureHistory) addLedgerStack(result.credits, drop);
        }
        BlockState successfulState = level.getBlockState(pos);
        result.successfulBuildPositions.add(pos.immutable());
        result.captureSound(pos, successfulState);
        result.changedCount++;
        return true;
    }

    private static boolean mayDestroyForReplacement(ServerPlayer player, BlockPos pos,
                                                    BlockState existing) {
        ServerLevel level = player.serverLevel();
        // Adventure-mode CanDestroy eligibility is evaluated by Forge/ServerPlayerGameMode below;
        // an unconditional mayBuild check here would incorrectly reject such authorized tools.
        return !player.isSpectator() && level.mayInteract(player, pos)
                && BuilderReplacementPolicy.canReplaceTarget(existing, level, pos,
                true, player.isCreative());
    }

    /**
     * Mirrors {@link net.minecraft.server.level.ServerPlayerGameMode#destroyBlock(BlockPos)} while
     * deliberately treating every survival-breakable block as harvestable. The scepter is not a
     * pickaxe, so vanilla's ordinary harvest gate would otherwise remove stone, ores, and modded
     * tool-gated blocks without running their loot table at all. The original held stack is still
     * supplied to the loot table, giving the normal unenchanted output and preserving mod hooks.
     *
     * <p>The Forge break event is posted exactly once here. Do not precede this method with an
     * event-based permission probe: a protection mod may have non-idempotent listeners.</p>
     */
    private static boolean destroyBlockForReplacement(ServerPlayer player, BlockPos pos) {
        ServerLevel level = player.serverLevel();
        BlockState state = level.getBlockState(pos);
        int experience = ForgeHooks.onBlockBreakEvent(level,
                player.gameMode.getGameModeForPlayer(), player, pos);
        if (experience == -1) return false;

        BlockEntity blockEntity = level.getBlockEntity(pos);
        Block block = state.getBlock();
        if (block instanceof GameMasterBlock && !player.canUseGameMasterBlocks()) {
            level.sendBlockUpdated(pos, state, state, Block.UPDATE_ALL);
            return false;
        }
        ItemStack held = player.getMainHandItem();
        if (held.onBlockStartBreak(pos, player)
                || player.blockActionRestricted(level, pos,
                player.gameMode.getGameModeForPlayer())) {
            return false;
        }

        if (player.isCreative()) {
            return removeReplacementBlock(level, player, pos, state, false);
        }

        ItemStack lootTool = held.copy();
        held.mineBlock(level, state, pos, player);
        if (held.isEmpty() && !lootTool.isEmpty()) {
            net.minecraftforge.event.ForgeEventFactory.onPlayerDestroyItem(
                    player, lootTool, InteractionHand.MAIN_HAND);
        }
        // Replacement is allowed only for states with survival destroy speed. Force the harvest
        // gate so a non-tool scepter cannot suppress the block's otherwise-normal loot table.
        boolean removed = removeReplacementBlock(level, player, pos, state, true);
        if (removed) {
            block.playerDestroy(level, player, pos, state, blockEntity, lootTool);
            if (experience > 0) block.popExperience(level, pos, experience);
        }
        return removed;
    }

    private static boolean removeReplacementBlock(ServerLevel level, ServerPlayer player,
                                                  BlockPos pos, BlockState state,
                                                  boolean canHarvest) {
        boolean removed = state.onDestroyedByPlayer(level, pos, player, canHarvest,
                level.getFluidState(pos));
        if (removed) state.getBlock().destroy(level, pos, state);
        return removed;
    }

    private static Map<BlockPos, WorldDelta.Snapshot> snapshotReplacementArea(
            ServerLevel level, BlockPos pos, BlockState state) {
        Map<BlockPos, WorldDelta.Snapshot> snapshots = new java.util.LinkedHashMap<>();
        for (BlockPos affected : buildStabilizationPositions(demolitionAffectedPositions(pos, state))) {
            if (validLoadedPosition(level, affected)) {
                snapshots.put(affected, WorldDelta.snapshot(level, affected));
            }
        }
        return snapshots;
    }

    private static boolean restoreSnapshotsWithoutDrops(ServerLevel level,
                                                        Map<BlockPos, WorldDelta.Snapshot> snapshots) {
        try {
            boolean restored = BuilderDropCapture.discardEntities(() -> restoreSnapshots(level, snapshots));
            if (!restored) {
                MyDimension.LOGGER.error("Builder could not restore a complete snapshot set in {}",
                        level.dimension().location());
            }
            return restored;
        } catch (RuntimeException exception) {
            MyDimension.LOGGER.error("Builder snapshot restoration failed in {}",
                    level.dimension().location(), exception);
            return false;
        }
    }

    /** Runs at most two passes; values returning false after pass two remain unresolved. */
    static <T> List<T> processWithSingleRetry(List<T> values, java.util.function.Predicate<T> process) {
        List<T> deferred = new ArrayList<>();
        for (T value : values) {
            if (!process.test(value)) deferred.add(value);
        }
        if (deferred.isEmpty()) return List.of();
        List<T> unresolved = new ArrayList<>();
        for (T value : deferred) {
            if (!process.test(value)) unresolved.add(value);
        }
        return List.copyOf(unresolved);
    }

    private static Execution demolish(ServerPlayer player, ItemStack scepter,
                                      List<SurfacePlanner.Candidate> candidates, UUID transactionId,
                                      boolean captureHistory) {
        ServerLevel level = player.serverLevel();
        Execution result = new Execution(player.getOffhandItem().copy(), captureHistory,
                OperationSoundKind.BREAK);
        List<PositionedDrop> deferredDrops = captureHistory ? List.of() : new ArrayList<>();
        try {
            for (SurfacePlanner.Candidate candidate : candidates) {
            BlockPos pos = candidate.target();
            BlockState state;
            ItemStack toolBeforeBlock;
            ToolCheck tool;
            List<ItemStack> normalDrops;
            Map<BlockPos, WorldDelta.Snapshot> beforeImages;
            try {
                state = level.getBlockState(pos);
                if (state.isAir() || state.is(BuilderTags.CONSTRUCTION_PROTECTED)
                        || state.is(BuilderTags.TRANSACTION_UNSAFE)) {
                    result.blocked++;
                    continue;
                }
                if (ForgeHooks.onBlockBreakEvent(level, player.gameMode.getGameModeForPlayer(), player, pos) == -1) {
                    result.blocked++;
                    continue;
                }
                toolBeforeBlock = player.getOffhandItem().copy();
                tool = checkTool(state, toolBeforeBlock);
                beforeImages = captureHistory ? snapshotDemolitionArea(level, pos, state) : Map.of();
                BlockEntity blockEntity = level.getBlockEntity(pos);
                normalDrops = tool.canDrop
                        ? Block.getDrops(state, level, pos, blockEntity, player, toolBeforeBlock) : List.of();
            } catch (Throwable throwable) {
                result.blocked++;
                MyDimension.LOGGER.warn("Builder rejected demolition candidate {} after a mod callback failed",
                        pos, throwable);
                continue;
            }

            boolean removed;
            List<ItemStack> capturedDrops;
            try {
                if (tool.canDrop) {
                    BuilderDropCapture.CaptureResult<Boolean> captured = BuilderDropCapture.capture(
                            () -> level.removeBlock(pos, false));
                    removed = captured.value();
                    capturedDrops = captured.drops();
                } else if (tool.recognized) {
                    removed = BuilderDropCapture.discardEntities(
                            () -> level.removeBlock(pos, false));
                    capturedDrops = List.of();
                } else {
                    removed = removeWithoutBreakEffect(level, pos);
                    capturedDrops = List.of();
                }
            } catch (Throwable throwable) {
                if (captureHistory) restoreSnapshotsWithoutDrops(level, beforeImages);
                result.blocked++;
                MyDimension.LOGGER.warn("Builder rolled back failed demolition at {}", pos, throwable);
                continue;
            }
            if (!removed) {
                if (captureHistory) restoreSnapshotsWithoutDrops(level, beforeImages);
                result.blocked++;
                continue;
            }

            Map<BlockPos, WorldDelta.Snapshot> afterImages = Map.of();
            if (captureHistory) {
                afterImages = new java.util.LinkedHashMap<>();
                try {
                    for (BlockPos affected : beforeImages.keySet()) {
                        afterImages.put(affected, WorldDelta.snapshot(level, affected));
                    }
                } catch (Throwable throwable) {
                    restoreSnapshotsWithoutDrops(level, beforeImages);
                    result.blocked++;
                    MyDimension.LOGGER.warn("Builder rolled back demolition at {} because its after-image failed",
                            pos, throwable);
                    continue;
                }
            }
            result.captureSound(pos, state);

            if (tool.canDrop) {
                List<ItemStack> drops = new ArrayList<>(normalDrops.size() + capturedDrops.size());
                normalDrops.forEach(stack -> drops.add(stack.copy()));
                capturedDrops.forEach(stack -> drops.add(stack.copy()));
                if (captureHistory) {
                    drops.forEach(drop -> addLedgerStack(result.credits, drop));
                    dropOverflowAt(level, pos, transactionId,
                            BuilderMaterials.insert(player, scepter, drops));
                } else {
                    // History-off is the low-overhead mode.  Keep each source position, but defer
                    // remote storage until the batch is complete so bound chunks/capabilities are
                    // resolved once instead of once per block and per drop stack.
                    drops.stream().filter(drop -> !drop.isEmpty())
                            .forEach(drop -> deferredDrops.add(new PositionedDrop(pos.immutable(), drop.copy())));
                }
            }
            // Settle the Nth block's drops with the pre-damage tool, then apply exactly one durability point.
            // If this breaks the tool, only subsequent blocks lose harvesting eligibility.
            boolean stopAfterCurrentBlock = false;
            if (tool.recognized && !isFree(player)) {
                try {
                    player.getOffhandItem().hurtAndBreak(1, player,
                            broken -> broken.broadcastBreakEvent(InteractionHand.OFF_HAND));
                } catch (RuntimeException exception) {
                    // Finish accounting this already removed block, but do not let a tool that
                    // refuses durability damage harvest the rest of the batch for free.
                    MyDimension.LOGGER.warn("Builder tool damage callback failed after removing {}", pos,
                            exception);
                    stopAfterCurrentBlock = true;
                }
            }
            if (captureHistory) {
                for (Map.Entry<BlockPos, WorldDelta.Snapshot> entry : beforeImages.entrySet()) {
                    WorldDelta.Snapshot after = afterImages.get(entry.getKey());
                    if (entry.getValue().equals(after)) continue;
                    result.changed.add(new WorldDelta(entry.getKey(), entry.getValue().state(),
                            entry.getValue().blockEntity(), after.state(), after.blockEntity()));
                }
                result.changedCount = result.changed.size();
            } else {
                result.changedCount++;
            }
            if (stopAfterCurrentBlock) break;
            }
        } finally {
            if (!deferredDrops.isEmpty()) {
                settleDemolitionDrops(player, scepter, transactionId, deferredDrops);
            }
        }
        result.offhandAfter = player.getOffhandItem().copy();
        return result;
    }

    /**
     * Stores every demolition output in one remote material session while
     * preserving the original per-stack call semantics and source position.
     */
    private static void settleDemolitionDrops(ServerPlayer player, ItemStack scepter,
                                               UUID transactionId, List<PositionedDrop> drops) {
        List<ItemStack> offered = drops.stream().map(drop -> drop.stack.copy()).toList();
        // Every harvested block was settled before damaging its tool in the original per-block
        // order.  Reserving the offhand here preserves that rule if the tool broke during the batch.
        List<ItemStack> remainders = BuilderMaterials.insertAlignedPreservingOffhand(
                player, scepter, offered);
        ServerLevel level = player.serverLevel();
        for (int index = 0; index < drops.size(); index++) {
            ItemStack remainder = remainders.get(index);
            if (!remainder.isEmpty()) {
                dropOverflowAt(level, drops.get(index).pos, transactionId, List.of(remainder));
            }
        }
    }

    /** Stores successful replacement outputs in one material session and keeps overflow at its source. */
    private static void settleBuildReplacementDrops(ServerPlayer player, ItemStack scepter,
                                                     UUID transactionId, List<PositionedDrop> drops) {
        List<ItemStack> offered = drops.stream().map(drop -> drop.stack.copy()).toList();
        List<ItemStack> remainders = BuilderMaterials.insertAligned(player, scepter, offered);
        ServerLevel level = player.serverLevel();
        for (int index = 0; index < drops.size(); index++) {
            ItemStack remainder = remainders.get(index);
            if (!remainder.isEmpty()) {
                dropOverflowAt(level, drops.get(index).pos, transactionId, List.of(remainder));
            }
        }
    }

    /**
     * Removes a block without ServerLevel#destroyBlock's level-event 2001.
     * Level#removeBlock still restores the contained fluid and runs ordinary
     * setBlock/onRemove/neighbor lifecycle.  Any lifecycle-generated entities
     * are canceled rather than captured because this path is deliberately
     * drop-free.
     */
    static boolean removeWithoutBreakEffect(ServerLevel level, BlockPos pos) {
        return BuilderDropCapture.discardEntities(() -> level.removeBlock(pos, false));
    }

    private static Map<BlockPos, WorldDelta.Snapshot> snapshotDemolitionArea(ServerLevel level, BlockPos pos,
                                                                              BlockState state) {
        Map<BlockPos, WorldDelta.Snapshot> snapshots = new java.util.LinkedHashMap<>();
        for (BlockPos affected : demolitionAffectedPositions(pos, state)) {
            snapshots.put(affected, WorldDelta.snapshot(level, affected));
        }
        return snapshots;
    }

    /** Positions vanilla may synchronously remove when one half of a structural block is broken. */
    private static List<BlockPos> demolitionAffectedPositions(BlockPos pos, BlockState state) {
        java.util.LinkedHashSet<BlockPos> positions = new java.util.LinkedHashSet<>();
        positions.add(pos.immutable());
        if (state.hasProperty(net.minecraft.world.level.block.state.properties.BlockStateProperties.DOUBLE_BLOCK_HALF)) {
            net.minecraft.world.level.block.state.properties.DoubleBlockHalf half = state.getValue(
                    net.minecraft.world.level.block.state.properties.BlockStateProperties.DOUBLE_BLOCK_HALF);
            positions.add(pos.relative(half == net.minecraft.world.level.block.state.properties.DoubleBlockHalf.LOWER
                    ? Direction.UP : Direction.DOWN).immutable());
        }
        if (state.hasProperty(net.minecraft.world.level.block.state.properties.BlockStateProperties.BED_PART)
                && state.hasProperty(net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING)) {
            net.minecraft.world.level.block.state.properties.BedPart part = state.getValue(
                    net.minecraft.world.level.block.state.properties.BlockStateProperties.BED_PART);
            Direction facing = state.getValue(
                    net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING);
            positions.add(pos.relative(part == net.minecraft.world.level.block.state.properties.BedPart.FOOT
                    ? facing : facing.getOpposite()).immutable());
        }
        return List.copyOf(positions);
    }

    private static boolean restoreSnapshots(ServerLevel level, Map<BlockPos, WorldDelta.Snapshot> snapshots) {
        List<Map.Entry<BlockPos, WorldDelta.Snapshot>> entries = new ArrayList<>(snapshots.entrySet());
        boolean restored = true;
        for (int index = entries.size() - 1; index >= 0; index--) {
            Map.Entry<BlockPos, WorldDelta.Snapshot> entry = entries.get(index);
            WorldDelta.Snapshot snapshot = entry.getValue();
            try {
                restored &= new WorldDelta(entry.getKey(), snapshot.state(), snapshot.blockEntity(),
                        snapshot.state(), snapshot.blockEntity()).restoreBefore(level);
            } catch (Throwable throwable) {
                restored = false;
                MyDimension.LOGGER.error("Builder could not restore demolition side effect at {} in {}",
                        entry.getKey(), level.dimension().location(), throwable);
            }
        }
        if (restored) {
            for (Map.Entry<BlockPos, WorldDelta.Snapshot> entry : entries) {
                WorldDelta.Snapshot snapshot = entry.getValue();
                WorldDelta expected = new WorldDelta(entry.getKey(), snapshot.state(),
                        snapshot.blockEntity(), snapshot.state(), snapshot.blockEntity());
                if (!expected.matchesBefore(level)) {
                    restored = false;
                    break;
                }
            }
        }
        return restored;
    }

    /** Best-effort immediate compensation when the durable APPLIED record cannot replace PREPARED. */
    private static boolean rollbackUnrecorded(ServerPlayer player, ItemStack scepter,
                                              BuilderTransaction.Type type, UUID transactionId,
                                              Execution execution, ServerLevel level) {
        if (execution.changed.isEmpty()) return true;
        boolean demolition = type == BuilderTransaction.Type.DEMOLISH;
        if (!execution.credits.isEmpty()) {
            List<net.minecraft.world.entity.item.ItemEntity> entities = transactionEntities(
                    level, transactionId, execution.changed);
            boolean reclaimed = demolition
                    ? BuilderMaterials.canAndRemove(player, scepter, execution.credits, entities)
                    : BuilderMaterials.canAndRemoveIncludingOffhand(
                    player, scepter, execution.credits, entities);
            if (!reclaimed) return false;
        }
        if (!restoreDeltas(level, execution.changed, true)) {
            restoreDeltas(level, execution.changed, false);
            BlockPos dropPos = execution.changed.get(0).pos();
            List<ItemStack> overflow = demolition
                    ? BuilderMaterials.insertPreservingOffhand(player, scepter, execution.credits)
                    : BuilderMaterials.insert(player, scepter, execution.credits);
            dropOverflowAt(level, dropPos, transactionId, overflow);
            return false;
        }
        if (demolition) {
            player.setItemInHand(InteractionHand.OFF_HAND, execution.offhandBefore.copy());
            return true;
        }
        BlockPos dropPos = execution.changed.get(0).pos();
        dropOverflowAt(level, dropPos, transactionId,
                BuilderMaterials.insert(player, scepter, execution.debits));
        return true;
    }

    private static boolean restoreDeltas(ServerLevel level, List<WorldDelta> deltas, boolean before) {
        try {
            return BuilderDropCapture.capture(() -> {
                boolean success = true;
                if (before) {
                    for (int index = deltas.size() - 1; index >= 0; index--) {
                        success &= deltas.get(index).restoreBefore(level);
                    }
                } else {
                    for (WorldDelta delta : deltas) success &= delta.restoreAfter(level);
                }
                if (!success) return false;
                for (WorldDelta delta : deltas) {
                    if (before ? !delta.matchesBefore(level) : !delta.matchesAfter(level)) return false;
                }
                return true;
            }).value();
        } catch (RuntimeException exception) {
            return false;
        }
    }

    private static List<net.minecraft.world.entity.item.ItemEntity> transactionEntities(
            ServerLevel level, UUID transactionId, List<WorldDelta> deltas) {
        java.util.LinkedHashMap<UUID, net.minecraft.world.entity.item.ItemEntity> values =
                new java.util.LinkedHashMap<>();
        for (WorldDelta delta : deltas) {
            for (net.minecraft.world.entity.item.ItemEntity entity : level.getEntitiesOfClass(
                    net.minecraft.world.entity.item.ItemEntity.class,
                    new net.minecraft.world.phys.AABB(delta.pos()).inflate(2.0D), candidate ->
                            candidate.getPersistentData().hasUUID("mydimension:builder_transaction")
                                    && candidate.getPersistentData().getUUID("mydimension:builder_transaction")
                                    .equals(transactionId))) {
                values.put(entity.getUUID(), entity);
            }
        }
        return List.copyOf(values.values());
    }

    private static BlockState desiredState(ServerPlayer player, SurfacePlanner.Candidate candidate, Direction face) {
        ItemStack offhand = player.getOffhandItem();
        if (!(offhand.getItem() instanceof BlockItem blockItem)) return candidate.desiredState();
        BlockHitResult virtualHit = new BlockHitResult(Vec3.atCenterOf(candidate.reference()), face,
                candidate.reference(), false);
        BlockPlaceContext context = new BlockPlaceContext(new UseOnContext(player, InteractionHand.OFF_HAND,
                virtualHit));
        BlockState calculated = blockItem.getBlock().getStateForPlacement(context);
        return calculated == null ? blockItem.getBlock().defaultBlockState() : calculated;
    }

    private static boolean validBuildEnvelope(ServerPlayer player, BlockPos pos, BlockState desired,
                                              BlockState existing, boolean allowReplacement) {
        if (!validStaticBuildEnvelope(player, pos, desired, existing, allowReplacement)) return false;
        // Match normal BlockItem placement semantics: no solid collision shape may intersect any
        // player, mob, vehicle or other collidable entity at the target, not merely the operator.
        return player.serverLevel().isUnobstructed(desired, pos, CollisionContext.empty());
    }

    private static boolean validStaticBuildEnvelope(ServerPlayer player, BlockPos pos, BlockState desired,
                                                     BlockState existing, boolean allowReplacement) {
        ServerLevel level = player.serverLevel();
        WorldBorder border = level.getWorldBorder();
        if (pos.getY() < level.getMinBuildHeight() || pos.getY() >= level.getMaxBuildHeight()
                || !border.isWithinBounds(pos)
                || !BuilderReplacementPolicy.canReplaceTarget(existing, level, pos,
                allowReplacement, player.isCreative())
                || desired.is(BuilderTags.CONSTRUCTION_PROTECTED)
                || desired.is(BuilderTags.TRANSACTION_UNSAFE)) return false;
        return true;
    }

    /**
     * Returns the base block-item debit for a state. State properties are part of the blueprint payload,
     * not separate materials: for example, every water-cauldron level maps through vanilla's block/item
     * alias to one cauldron item, and a waterlogged slab still maps to its slab item. Component-count
     * properties remain additive because those states physically represent more than one placed item.
     */
    static ItemStack constructionCost(BlockState state) {
        Block block = state.getBlock();
        ItemStack cost = new ItemStack(block.asItem());
        if (cost.isEmpty()) return ItemStack.EMPTY;
        int count = 1;
        if (block instanceof SlabBlock && state.getValue(SlabBlock.TYPE) == SlabType.DOUBLE) {
            count = 2;
        } else if (block instanceof SnowLayerBlock) {
            count = state.getValue(SnowLayerBlock.LAYERS);
        } else if (block instanceof CandleBlock) {
            count = state.getValue(CandleBlock.CANDLES);
        } else if (block instanceof SeaPickleBlock) {
            count = state.getValue(SeaPickleBlock.PICKLES);
        } else if (block instanceof TurtleEggBlock) {
            count = state.getValue(TurtleEggBlock.EGGS);
        }
        cost.setCount(count);
        return cost;
    }

    private static ToolCheck checkTool(BlockState state, ItemStack tool) {
        if (tool.isEmpty()) return new ToolCheck(false, false);
        ToolAction required = null;
        if (state.is(BlockTags.MINEABLE_WITH_PICKAXE)) required = ToolActions.PICKAXE_DIG;
        else if (state.is(BlockTags.MINEABLE_WITH_AXE)) required = ToolActions.AXE_DIG;
        else if (state.is(BlockTags.MINEABLE_WITH_SHOVEL)) required = ToolActions.SHOVEL_DIG;
        else if (state.is(BlockTags.MINEABLE_WITH_HOE)) required = ToolActions.HOE_DIG;
        boolean matchingType = (required != null && tool.canPerformAction(required))
                || tool.getDestroySpeed(state) > 1.0F;
        boolean tier = matchingType && (!state.requiresCorrectToolForDrops() || tool.isCorrectToolForDrops(state));
        return new ToolCheck(matchingType, tier);
    }

    private static boolean validReachAndSight(ServerPlayer player, BlockHitResult hit) {
        return BuilderReachValidator.canReachAndSee(player, hit.getBlockPos(), hit.getDirection());
    }

    private static boolean isFree(ServerPlayer player) {
        return player.isCreative() && BuilderRuntime.settings().creativeBypassesCosts();
    }

    /** Executes one part of an already validated blueprint. */
    public static BlueprintBatchResult executeBlueprintBatch(ServerPlayer player, ItemStack scepter,
            List<com.xfestudio.mydimension.builder.blueprint.BlueprintPlacementPlan.PlannedBlock> blocks,
            UUID transactionId, boolean captureHistory) {
        List<SurfacePlanner.Candidate> candidates = new ArrayList<>(blocks.size());
        Map<BlockPos, net.minecraft.nbt.CompoundTag> blockEntities = new java.util.HashMap<>();
        for (var block : blocks) {
            candidates.add(new SurfacePlanner.Candidate(block.worldPos(), block.worldPos(), block.state(), 0));
            if (block.blockEntityTag() != null) blockEntities.put(block.worldPos(), block.blockEntityTag());
        }
        if (captureHistory && !prepareHistory(player, scepter, transactionId,
                BuilderTransaction.Type.BLUEPRINT, candidates, Direction.UP, false, blockEntities)) {
            List<PendingBuildData.Entry> deferred = blocks.stream()
                    .map(block -> new PendingBuildData.Entry(block.worldPos(), block.state(), block.blockEntityTag()))
                    .toList();
            player.displayClientMessage(Component.translatable(
                    "message.mydimension.builder.history_budget_exceeded"), true);
            return new BlueprintBatchResult(0, deferred, 0, false, null);
        }
        Execution execution = build(player, scepter, candidates, Direction.UP, transactionId, false,
                blockEntities, captureHistory);
        boolean committed = true;
        if (captureHistory) {
            refreshFinalAfterImages(player.serverLevel(), execution);
            committed = recordTransaction(player, scepter, BuilderTransaction.Type.BLUEPRINT,
                    transactionId, execution);
        }
        return new BlueprintBatchResult(execution.changedCount, List.copyOf(execution.missing), execution.blocked,
                committed, execution.sound);
    }

    private static boolean recordTransaction(ServerPlayer player, ItemStack scepter, BuilderTransaction.Type type,
                                             UUID transactionId, Execution execution) {
        return recordTransaction(player, scepter, type, transactionId, execution, player.serverLevel());
    }

    private static boolean recordTransaction(ServerPlayer player, ItemStack scepter, BuilderTransaction.Type type,
                                             UUID transactionId, Execution execution,
                                             ServerLevel executionLevel) {
        return recordTransaction(player, scepter, type, transactionId, execution, executionLevel, true);
    }

    private static boolean recordTransaction(ServerPlayer player, ItemStack scepter, BuilderTransaction.Type type,
                                             UUID transactionId, Execution execution,
                                             ServerLevel executionLevel, boolean rollbackOnFailure) {
        BuilderHistoryData history = BuilderHistoryData.get(player.getServer());
        if (execution.changed.isEmpty()) {
            history.abortPrepared(player.getUUID(), RealmwrightData.id(scepter), transactionId);
            return true;
        }
        BuilderTransaction transaction = new BuilderTransaction(transactionId, RealmwrightData.id(scepter),
                executionLevel.dimension(), type, System.currentTimeMillis(), execution.changed,
                execution.debits, execution.credits, execution.offhandBefore, execution.offhandAfter,
                BuilderTransaction.State.APPLIED);
        boolean committed;
        try {
            committed = history.commitPrepared(player.getUUID(), RealmwrightData.id(scepter), transaction,
                    BuilderRuntime.settings().undoDepth());
        } catch (RuntimeException exception) {
            history.conflictPrepared(player.getUUID(), RealmwrightData.id(scepter), transactionId);
            committed = false;
            MyDimension.LOGGER.error("Builder transaction {} could not commit its history record",
                    transactionId, exception);
        }
        if (!committed) {
            // Never compensate a task after its recorded after-image stopped matching the world:
            // doing so could overwrite another player's/mod's intervening change. The durable
            // conflict marker is the only safe result in that case.
            boolean rolledBack = rollbackOnFailure && rollbackUnrecorded(player, scepter, type,
                    transactionId, execution, executionLevel);
            if (rolledBack) {
                history.discardConflictMarker(player.getUUID(), RealmwrightData.id(scepter), transactionId);
                execution.changed.clear();
                execution.debits.clear();
                execution.credits.clear();
                execution.changedCount = 0;
            }
            player.displayClientMessage(Component.translatable(
                    "message.mydimension.builder.history_commit_failed"), true);
            return false;
        }
        return true;
    }

    /** Captures neighbour-aware final states only when undo recording was explicitly enabled. */
    private static void refreshFinalAfterImages(ServerLevel level, Execution execution) {
        if (execution.changed.isEmpty()) return;
        List<WorldDelta> refreshed = new ArrayList<>(execution.changed.size());
        try {
            for (WorldDelta delta : execution.changed) {
                WorldDelta.Snapshot after = WorldDelta.snapshot(level, delta.pos());
                refreshed.add(new WorldDelta(delta.pos(), delta.beforeState(), delta.beforeBlockEntity(),
                        after.state(), after.blockEntity()));
            }
        } catch (Throwable throwable) {
            // Each edit already owns a valid immediate after-image. Keep that safe
            // fallback rather than stranding a durable PREPARED entry.
            MyDimension.LOGGER.warn("Builder could not refresh final neighbour-aware history images", throwable);
            return;
        }
        execution.changed.clear();
        execution.changed.addAll(refreshed);
    }

    private static boolean prepareHistory(ServerPlayer player, ItemStack scepter, UUID transactionId,
                                          BuilderTransaction.Type type,
                                          List<SurfacePlanner.Candidate> candidates, Direction face,
                                          boolean allowOffhandOverride,
                                          Map<BlockPos, net.minecraft.nbt.CompoundTag> blockEntityTags) {
        long estimate;
        try {
            estimate = estimateHistoryBytes(player, type, candidates, face, allowOffhandOverride,
                    blockEntityTags, RealmwrightData.allowsReplacement(scepter));
        } catch (RuntimeException exception) {
            MyDimension.LOGGER.warn("Unable to estimate builder transaction {} before execution", transactionId,
                    exception);
            return false;
        }
        return BuilderHistoryData.get(player.getServer()).prepare(player.getUUID(), RealmwrightData.id(scepter),
                transactionId, player.level().dimension(), type, player.getOffhandItem(), estimate)
                == BuilderHistoryData.PrepareResult.PREPARED;
    }

    /** Conservative retained-NBT estimate; evaluated before any material extraction or world edit. */
    private static long estimateHistoryBytes(ServerPlayer player, BuilderTransaction.Type type,
                                             List<SurfacePlanner.Candidate> candidates, Direction face,
                                             boolean allowOffhandOverride,
                                             Map<BlockPos, net.minecraft.nbt.CompoundTag> blockEntityTags,
                                             boolean allowReplacement) {
        ServerLevel level = player.serverLevel();
        long estimate = 4_096L + 2L * stackBytes(player.getOffhandItem());
        java.util.LinkedHashSet<BlockPos> buildTargets = new java.util.LinkedHashSet<>();
        java.util.HashSet<BlockPos> estimatedDemolitionPositions = new java.util.HashSet<>();
        for (SurfacePlanner.Candidate candidate : candidates) {
            if (type == BuilderTransaction.Type.DEMOLISH) {
                BlockPos target = candidate.target();
                BlockState targetState = level.getBlockState(target);
                for (BlockPos pos : demolitionAffectedPositions(target, targetState)) {
                    if (!estimatedDemolitionPositions.add(pos)) continue;
                    BlockEntity existingBlockEntity = level.getBlockEntity(pos);
                    if (existingBlockEntity == null) {
                        estimate = saturatedAdd(estimate, ordinaryHistoryEntryBytes(type));
                        continue;
                    }
                    WorldDelta.Snapshot before = WorldDelta.snapshot(level, pos);
                    WorldDelta predicted = new WorldDelta(pos, before.state(), before.blockEntity(),
                            net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(), null);
                    long entry = 512L + Integer.toUnsignedLong(predicted.save().sizeInBytes());
                    // Container contents can appear once in the before-image and again in the exact drop ledger.
                    entry = saturatedAdd(entry, 2L * tagBytes(before.blockEntity()));
                    estimate = saturatedAdd(estimate, entry);
                }
                continue;
            }

            BlockPos pos = candidate.target();
            buildTargets.add(pos.immutable());
            BlockState beforeState = level.getBlockState(pos);
            BlockState afterState = allowOffhandOverride ? desiredState(player, candidate, face)
                    : candidate.desiredState();
            net.minecraft.nbt.CompoundTag afterBlockEntity = blockEntityTags.get(pos);
            if (afterBlockEntity == null && afterState.hasBlockEntity()) {
                afterBlockEntity = predictBlockEntityTag(pos, afterState);
                if (afterBlockEntity == null) {
                    estimate = saturatedAdd(estimate, saturatedAdd(ordinaryHistoryEntryBytes(type),
                            UNKNOWN_BLOCK_ENTITY_BYTES));
                    continue;
                }
            }
            BlockEntity existingBlockEntity = level.getBlockEntity(pos);
            if (existingBlockEntity == null && afterBlockEntity == null) {
                estimate = saturatedAdd(estimate, ordinaryHistoryEntryBytes(type));
                continue;
            }
            WorldDelta.Snapshot before = existingBlockEntity == null
                    ? new WorldDelta.Snapshot(beforeState, null) : WorldDelta.snapshot(level, pos);
            WorldDelta predicted = new WorldDelta(pos, before.state(), before.blockEntity(), afterState,
                    afterBlockEntity);
            long entry = 512L + Integer.toUnsignedLong(predicted.save().sizeInBytes());
            entry = saturatedAdd(entry, stackBytes(constructionCost(afterState)) + 128L);
            entry = saturatedAdd(entry, tagBytes(afterBlockEntity));
            if (allowReplacement && BuilderReplacementPolicy.requiresBreaking(beforeState)) {
                // A container's retained before-image and its item outputs may both carry the
                // complete inventory NBT. Mirror demolition's conservative credit-ledger reserve.
                entry = saturatedAdd(entry, 2L * tagBytes(before.blockEntity()));
            }
            estimate = saturatedAdd(estimate, entry);
        }
        if (type != BuilderTransaction.Type.DEMOLISH && !buildTargets.isEmpty()) {
            for (BlockPos neighbour : buildStabilizationPositions(buildTargets)) {
                if (buildTargets.contains(neighbour) || !level.hasChunkAt(neighbour)) continue;
                BlockState state = level.getBlockState(neighbour);
                BlockEntity blockEntity = level.getBlockEntity(neighbour);
                if (blockEntity == null) {
                    estimate = saturatedAdd(estimate, ordinaryHistoryEntryBytes(type));
                    continue;
                }
                WorldDelta.Snapshot snapshot = WorldDelta.snapshot(level, neighbour);
                WorldDelta predicted = new WorldDelta(neighbour, state, snapshot.blockEntity(),
                        state, snapshot.blockEntity());
                estimate = saturatedAdd(estimate,
                        512L + Integer.toUnsignedLong(predicted.save().sizeInBytes()));
            }
        }
        return estimate;
    }

    static long ordinaryHistoryEntryBytes(BuilderTransaction.Type type) {
        return ORDINARY_HISTORY_ENTRY_BYTES;
    }

    private static net.minecraft.nbt.CompoundTag predictBlockEntityTag(BlockPos pos, BlockState state) {
        if (!(state.getBlock() instanceof net.minecraft.world.level.block.EntityBlock entityBlock)) return null;
        try {
            BlockEntity predicted = entityBlock.newBlockEntity(pos, state);
            return predicted == null ? null : predicted.saveWithFullMetadata();
        } catch (RuntimeException exception) {
            return null;
        }
    }

    private static long stackBytes(ItemStack stack) {
        return stack.isEmpty() ? 0L
                : Integer.toUnsignedLong(stack.save(new net.minecraft.nbt.CompoundTag()).sizeInBytes());
    }

    private static long tagBytes(net.minecraft.nbt.CompoundTag tag) {
        return tag == null ? 0L : Integer.toUnsignedLong(tag.sizeInBytes());
    }

    private static long saturatedAdd(long left, long right) {
        if (right > 0L && left > Long.MAX_VALUE - right) return Long.MAX_VALUE;
        return left + right;
    }

    /** Coalesces equivalent ledger entries without ever exceeding an item's normal stack size. */
    private static void addLedgerStack(List<ItemStack> ledger, ItemStack value) {
        if (value.isEmpty()) return;
        int remaining = value.getCount();
        int maximum = Math.max(1, value.getMaxStackSize());
        for (ItemStack existing : ledger) {
            if (remaining <= 0) break;
            if (!ItemStack.isSameItemSameTags(existing, value) || existing.getCount() >= maximum) continue;
            int moved = Math.min(remaining, maximum - existing.getCount());
            existing.grow(moved);
            remaining -= moved;
        }
        while (remaining > 0) {
            int moved = Math.min(remaining, maximum);
            ledger.add(value.copyWithCount(moved));
            remaining -= moved;
        }
    }

    private static boolean applyBlockEntityTag(ServerPlayer player, BlockPos pos,
                                                net.minecraft.nbt.CompoundTag supplied) {
        BlockEntity blockEntity = player.serverLevel().getBlockEntity(pos);
        if (blockEntity == null || !supplied.contains("id", net.minecraft.nbt.Tag.TAG_STRING)) return false;
        net.minecraft.resources.ResourceLocation suppliedId = net.minecraft.resources.ResourceLocation.tryParse(
                supplied.getString("id"));
        net.minecraft.resources.ResourceLocation actualId =
                net.minecraft.core.registries.BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(blockEntity.getType());
        if (suppliedId == null || !suppliedId.equals(actualId)
                || (!player.isCreative() && !player.hasPermissions(2))
                || (blockEntity.onlyOpCanSetNbt() && !player.canUseGameMasterBlocks())) return false;
        try {
            net.minecraft.nbt.CompoundTag copy = supplied.copy();
            copy.putInt("x", pos.getX());
            copy.putInt("y", pos.getY());
            copy.putInt("z", pos.getZ());
            blockEntity.load(copy);
            blockEntity.setChanged();
            player.serverLevel().sendBlockUpdated(pos, player.serverLevel().getBlockState(pos),
                    player.serverLevel().getBlockState(pos), Block.UPDATE_ALL);
            return true;
        } catch (RuntimeException ignored) {
            return false;
        }
    }

    private static void dropOverflow(ServerPlayer player, UUID transactionId, List<ItemStack> values) {
        dropOverflowAt(player.serverLevel(), player.blockPosition(), transactionId, values);
    }

    private static void dropOverflowAt(ServerLevel level, BlockPos pos, UUID transactionId,
                                       List<ItemStack> values) {
        for (ItemStack stack : values) {
            net.minecraft.world.entity.item.ItemEntity entity = new net.minecraft.world.entity.item.ItemEntity(level,
                    pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, stack.copy());
            entity.getPersistentData().putUUID("mydimension:builder_transaction", transactionId);
            level.addFreshEntity(entity);
        }
    }

    public static void playOperationSound(ServerPlayer player,
                                          @javax.annotation.Nullable OperationSound operationSound) {
        if (operationSound == null) return;
        try {
            var soundType = operationSound.state.getSoundType(
                    player.serverLevel(), operationSound.pos, player);
            player.serverLevel().playSound(null, operationSound.pos,
                    selectOperationSound(soundType.getPlaceSound(), soundType.getBreakSound(),
                            operationSound.kind),
                    SoundSource.BLOCKS, (soundType.getVolume() + 1.0F) * 0.5F,
                    soundType.getPitch() * 0.8F);
        } catch (Throwable throwable) {
            MyDimension.LOGGER.warn("Builder could not play its batch sound at {}",
                    operationSound.pos, throwable);
        }
    }

    static <T> T selectOperationSound(T placeSound, T breakSound, OperationSoundKind kind) {
        return switch (kind) {
            case PLACE -> placeSound;
            case BREAK -> breakSound;
        };
    }

    public record Result(int changed, int missing, int blocked, boolean truncated, String rejectionKey,
                         boolean shouldSynchronize) {
        public static Result disabled() { return rejected("message.mydimension.builder.disabled"); }
        public static Result rejected(String key) { return new Result(0, 0, 0, false, key, false); }
        public boolean accepted() { return rejectionKey == null; }
    }

    private record ToolCheck(boolean recognized, boolean canDrop) {
    }

    private static final class Execution {
        private final List<WorldDelta> changed = new ArrayList<>();
        private final List<PendingBuildData.Entry> missing = new ArrayList<>();
        private final List<ItemStack> debits = new ArrayList<>();
        private final List<ItemStack> credits = new ArrayList<>();
        private final List<PositionedDrop> replacementDrops = new ArrayList<>();
        private final java.util.LinkedHashSet<BlockPos> successfulBuildPositions =
                new java.util.LinkedHashSet<>();
        private final ItemStack offhandBefore;
        private final boolean captureHistory;
        private final OperationSoundKind soundKind;
        private ItemStack offhandAfter = ItemStack.EMPTY;
        private int changedCount;
        private int blocked;
        @javax.annotation.Nullable private OperationSound sound;

        private Execution(ItemStack offhandBefore, boolean captureHistory, OperationSoundKind soundKind) {
            this.offhandBefore = offhandBefore;
            this.captureHistory = captureHistory;
            this.soundKind = soundKind;
        }

        private void captureSound(BlockPos pos, BlockState state) {
            if (sound == null) sound = new OperationSound(pos, state, soundKind);
        }
    }

    public record BlueprintBatchResult(int changed, List<PendingBuildData.Entry> missing, int blocked,
                                       boolean committed, @javax.annotation.Nullable OperationSound sound) {
    }

    public record OperationSound(BlockPos pos, BlockState state, OperationSoundKind kind) {
        public OperationSound {
            pos = pos.immutable();
        }
    }

    public enum OperationSoundKind {
        PLACE,
        BREAK
    }

    record NeighborNotification(BlockPos target, BlockPos source) {
        NeighborNotification {
            target = target.immutable();
            source = source.immutable();
        }
    }

    private record BlockEntitySyncState(
            @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntityType<?> type,
            @javax.annotation.Nullable net.minecraft.nbt.CompoundTag updateTag,
            boolean reliable) {
        private boolean equivalent(@javax.annotation.Nullable BlockEntitySyncState other) {
            return other != null && reliable && other.reliable && type == other.type
                    && java.util.Objects.equals(updateTag, other.updateTag);
        }
    }

    private record BuildAttempt(SurfacePlanner.Candidate candidate, BlockState desired, ItemStack cost,
                                ItemStack placementStack,
                                net.minecraft.nbt.CompoundTag blockEntityTag) {
    }

    private record PositionedDrop(BlockPos pos, ItemStack stack) {
    }

    private static final class SupplyPool {
        private final ItemStack template;
        private final List<Item> fallbacks;
        private final List<SupplyReserve> reserves = new ArrayList<>();
        private int requested;

        private SupplyPool(ItemStack template, List<Item> fallbacks) {
            this.template = template;
            this.fallbacks = List.copyOf(fallbacks);
        }

        private void addReserve(ItemStack material, int count) {
            if (count <= 0 || material.isEmpty()) return;
            for (SupplyReserve reserve : reserves) {
                if (!ItemStack.isSameItemSameTags(reserve.template, material)) continue;
                reserve.available += count;
                reserve.extracted += count;
                return;
            }
            reserves.add(new SupplyReserve(material.copyWithCount(1), count));
        }

        private int available() {
            return reserves.stream().mapToInt(reserve -> reserve.available).sum();
        }

        /** Exact material is stored first, followed by fallbacks in policy order. */
        private List<ItemStack> consume(int count) {
            if (count <= 0 || available() < count) return List.of();
            int remaining = count;
            List<ItemStack> consumed = new ArrayList<>();
            for (SupplyReserve reserve : reserves) {
                if (remaining <= 0) break;
                int taken = Math.min(remaining, reserve.available);
                if (taken <= 0) continue;
                reserve.available -= taken;
                consumed.add(reserve.template.copyWithCount(taken));
                remaining -= taken;
            }
            return List.copyOf(consumed);
        }

        private void resetAvailable() {
            reserves.forEach(reserve -> reserve.available = reserve.extracted);
        }

        private List<ItemStack> unusedStacks() {
            return reserves.stream().filter(reserve -> reserve.available > 0)
                    .map(reserve -> reserve.template.copyWithCount(reserve.available)).toList();
        }
    }

    private static final class SupplyReserve {
        private final ItemStack template;
        private int available;
        private int extracted;

        private SupplyReserve(ItemStack template, int extracted) {
            this.template = template;
            this.available = extracted;
            this.extracted = extracted;
        }
    }

    private static SupplyPool findPool(List<SupplyPool> pools, ItemStack stack, List<Item> fallbacks) {
        for (SupplyPool pool : pools) {
            if (ItemStack.isSameItemSameTags(pool.template, stack)
                    && pool.fallbacks.equals(fallbacks)) return pool;
        }
        return null;
    }
}