Skip to content

Make ^ support nbt (properly) #2734

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

QuImUfu
Copy link

@QuImUfu QuImUfu commented Mar 14, 2025

My implementation of #2733,
It adds ^{=nbt} support, integrated in current ^ support to allow replacing/keeping arbitrary parts of a block.

Additionally, adds {nbt} support for merging NBT tags into existing ones.

Examples:

//replace chest ^barrel will keep orientation and NBT intact and just replace the block type, keeping e.g. contents as-is.
//replace chest ^[facing=north] will make all chest face north, keeping their NBT intact.
//replace chest,barrel ^{=LootTable:"minecraft:chests/simple_dungeon"} will make both, chests and barrels contain dungeon loot, while removing any potential other NBT.
//set ^{=} deletes nbt from selection. (does not work for LootTable tags due to a bug in vanilla MC I can't link here or find again because mojangs bug tracker is completely broken)
//replace decorated_pot ^{LootTable:"minecraft:chests/simple_dungeon"} will make pots contain dungeon loot while keeping their pattern.
...

@QuImUfu QuImUfu force-pushed the nbt-aware-partial-patterns branch from a572827 to 9c974cf Compare March 15, 2025 08:34
@QuImUfu QuImUfu marked this pull request as ready for review March 15, 2025 08:53
@QuImUfu QuImUfu requested a review from a team as a code owner March 15, 2025 08:53
Copy link
Member

@me4502 me4502 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. I've left a comment around API breakages. I haven't reviewed the actual parser itself as the diff is broken currently by the rename.

Also as this is adding behaviour, this should be targeting master, not 7.3.x.

import java.util.stream.Stream;


public class PartiallyApplyingPatternParser extends InputParser<Pattern> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renaming this class would be an API break, so it'd need to retain its original name, or duplicate it and deprecate the old one.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the rule for API breaks/changes? Am I allowed to change behaviour in a potentially breaking way (this is) and still maintain the same name/API? Or do I need to provide a fully backwards-compatible implementation?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created a deprecated legacy version, that should behave like before. Do I need to do the same for the two Patterns that I changed?
Is there some documentation on what needs to stay API compatible?

@@ -40,13 +40,13 @@ public TypeApplyingPattern(Extent extent, BlockState blockState) {

@Override
public BaseBlock applyBlock(BlockVector3 position) {
BlockState oldBlock = getExtent().getBlock(position);
BaseBlock oldBlock = getExtent().getFullBlock(position);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tested how well this performs? This fundamentally means the pattern is doing a lot more work per-block.

Also, have you tested how this behaves when set to another block with a block entity of a different type, with conflicting data? Eg, change a chest with items to a jukebox and make sure it doesn't explode?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does a lot more (in some cases unavoidable) work. I did not do large scale testing where performance issues would become apparent. I will think about how we can avoid incurring a performance penalty (if there is one, I'll test that) for blocks that can't have NBT or when NBT is overwritten anyway.

If it breaks something, it can already break with the vanilla /data command. But it and the data command, in fact, are able to break a lot of (as far as I have tested only non-vanilla) blocks, and AFAICT, there is not much we could do about it. We could maintain a gigantic database of sanitizers, one for every block with tile entity in every mod, plead to mod devs to sanitize their NBT properly, or we could prevent the game from flushing to disk until after the command finished, to prevent game-cashing NBT from corrupting worlds, at the expense of possibly prohibitive RAM use.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to detect any performance impact, which honestly surprised me. Not sure if my testing was flawed.
The performance impact seems, at least on my PC, to be completely drowned by IO for huge edits, and be undetectably small for smaller ones.
If you manage to find a scenario in which my changes have a significant performance impact, I'd be happy to take another look.

@QuImUfu QuImUfu changed the base branch from version/7.3.x to master March 16, 2025 20:06
private interface ExtendPatternFactory {
Pattern forExtend(Extent e);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why you're commenting on style when you're not part of the project. This is fine by our standards.

@octylFractal
Copy link
Member

octylFractal commented Mar 16, 2025

I have concerns about the exact syntax here, I don't think we should allow ^{} to be deletion / require a prefix comma -- this is inconsistent with the existing function.

As it stands, ^ is purely overwrite/additive. ^foo means "set block type to foo keeping all applicable state entries", ^[x=y] means "set the block state to the previous state with x set to y". I think it should remain that way for NBT as well, which would imply that ^{} is essentially a no-op and should be illegal syntax, as ^[] is today. If we want to add a variant that clears existing state, I think it should use a different prefix, or perhaps an extended one such as ^= ("equals" to imply removal of unwritten state).

@QuImUfu
Copy link
Author

QuImUfu commented Mar 16, 2025

While I understand you concern, I have some concerns with merge only for ^:

The current syntax allows for simply including {} to sidestep any NBT handling and (if implemented correctly, I probably will have to fix that) prevent any performance penalty.

If we do merge only, we need to add a different way to have ^[..=..] and ^.. keep (with related performance penalty) or drop NBT.

I'd suggest following to make it more consistent, without introducing a new prefix:
Changing {,..} to just {..} and {..} to {=..} or ={..} (the second being slightly confusing in combination with other overrides) and keeping merging as default this way. But that'd still include new syntax for ^ only applicable to NBT (we could also add ^[=..] but that would be a mostly useless feature just for consistencies’ sake).

If you have a different idea on how that could be implemented more consistently, I'm very open to suggestions.

@QuImUfu QuImUfu force-pushed the nbt-aware-partial-patterns branch from 9c974cf to 4f58081 Compare March 21, 2025 12:51
@QuImUfu
Copy link
Author

QuImUfu commented Mar 21, 2025

I have changed it to merge by default and set with {=...}.

@QuImUfu QuImUfu requested review from octylFractal and me4502 April 5, 2025 07:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants