Paper icon indicating copy to clipboard operation
Paper copied to clipboard

BlockState#copy() does not infer block entity

Open YouHaveTrouble opened this issue 1 year ago • 1 comments

Expected behavior

BlockState copy = blockState.copy(location);
copy.update(true, true)

This should set the block type and copy over all block entity data like inventories, bee data, etc.

Observed/Actual behavior

Snippet above only properly sets the block type and does not copy over the block entity data. Throws following warning Skipping BlockEntity with id.

Steps/models to reproduce

Run this snippet with any valid input as blockState and location

BlockState copy = blockState.copy(location);
copy.update(true, true)

Plugin and Datapack List

Issue occurs with only the plugin I'm testing with

Server Plugins (1): Paper Plugins: BlockEdit

Datapacks: There are 3 data pack(s) enabled: [vanilla (built-in)], [file/bukkit (world)], [paper (built-in)] There are no more data packs available

Paper version

This server is running Paper version 1.21.3-77-master@1e035f3 (2024-12-01T15:52:35Z) (Implementing API version 1.21.3-R0.1-SNAPSHOT)

Other

No response

YouHaveTrouble avatar Dec 01 '24 17:12 YouHaveTrouble

TLDR rundown for anyone tackling this, the argument provider uses CraftBlockStates#getBlockState, which internally uses BlockEntity.loadStatic. That method is wrong, as the passed compound tag needs to have the BE id, which the arguments do not have to specify.

Instead, we should create the block entity if a tag is present from the blockdata/blockstate and then load from the tag.

lynxplay avatar Dec 01 '24 17:12 lynxplay

Any other steps to replicate? tried with a beehive and a chest with data in it and works fine

The-Epic avatar Feb 27 '25 13:02 The-Epic

getLifecycleManager().registerEventHandler(LifecycleEvents.COMMANDS, e -> {
            e.registrar().register(Commands.literal("place").then(
                    Commands.argument("block_state", ArgumentTypes.blockState())
                        .executes(commandContext -> {
                            final BlockState state = commandContext.getArgument("block_state", BlockState.class);
                            final CommandSender sender = commandContext.getSource().getSender();
                            if (!(sender instanceof final Player player)) return 0;

                            final BlockState copy = state.copy(player.getLocation());
                            copy.update(true);
                            return 1;
                        })
                ).build()
            );
        });

with /place chest{Items:[{Slot:0b,id:"minecraft:cake",count:1}]}

lynxplay avatar Feb 27 '25 13:02 lynxplay