Banners: one loader for saved and generated banners

The generated banner reuses save.rs's BannerBlockEntity.loadAdditional
(now decode_banner) instead of a copy of it, and the generated block
entity clones its NBT only for the kinds that read it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Ludovic MarieandClaude Opus 5.5 committed 2026-10-25 23:43:03 +01:00
1 parent bb9c474c64
commit 401ac1322f
2 files changed
+26 -42

No files matched your search

+12 -11
View File
@@ -567,6 +567,17 @@ fn merge_block_entity(original: &Tag, loaded: &Tag, current: &Tag) -> Tag {
}
merged
}
/// `BannerBlockEntity.loadAdditional` (and the `components` a block entity keeps).
pub fn decode_banner(tag: &Tag) -> crate::containers::Banner {
crate::containers::Banner {
layers: crate::banner::layers_from_nbt(tag.get("patterns")),
name: text(tag.get("CustomName")),
components: match tag.get("components") {
Some(Tag::Compound(c)) => c.clone(),
_ => Compound::new(),
},
}
}
pub fn decode_block_entity(tag: &Tag) -> Option<((i32, i32, i32), crate::containers::BlockEntity)> {
use crate::containers::BlockEntity;
let int = |k: &str| number(tag.get(k)).map(|v| v as i32);
@@ -600,17 +611,7 @@ pub fn decode_block_entity(tag: &Tag) -> Option<((i32, i32, i32), crate::contain
return Some((pos, BlockEntity::Lectern(lectern)));
}
if id == "minecraft:banner" {
return Some((
pos,
BlockEntity::Banner(crate::containers::Banner {
layers: crate::banner::layers_from_nbt(tag.get("patterns")),
name: text(tag.get("CustomName")),
components: match tag.get("components") {
Some(Tag::Compound(c)) => c.clone(),
_ => Compound::new(),
},
}),
));
return Some((pos, BlockEntity::Banner(decode_banner(tag))));
}
if id == "minecraft:beacon" {
let beacon = crate::containers::Beacon {
+14 -31
View File
@@ -128,40 +128,23 @@ fn text(nbt: &Compound, key: &str) -> Option<String> {
}
}
/// `BannerBlockEntity.loadAdditional`: the `patterns` layers and the custom
/// name a structure template saves with its banner (the End cities' tower
/// tops place black triangles this way).
fn banner_from_nbt(nbt: &Compound) -> crate::containers::Banner {
crate::containers::Banner {
layers: crate::banner::layers_from_nbt(nbt.get(&JavaString::from("patterns"))),
name: text(nbt, "CustomName"),
components: match nbt.get(&JavaString::from("components")) {
Some(Tag::Compound(c)) => c.clone(),
_ => Compound::new(),
},
}
}
/// The client block entity for one of a chunk's generated block entities,
/// before a container's loot is unpacked.
/// before a container's loot is unpacked: `StructureTemplate.placeInWorld`
/// hands the template's block entity NBT to the level's block entity.
fn generated_block_entity(block: &str, nbt: &Compound) -> Option<BlockEntity> {
let mut entity = BlockEntity::for_block(block)?;
let tag = Tag::Compound(nbt.clone());
// MonsterRoomFeature and the structures' setEntityId.
if let BlockEntity::Spawner(s) = &mut entity {
**s = crate::mobs::spawner::Spawner::load(&tag);
}
if let BlockEntity::TrialSpawner(s) = &mut entity {
**s = crate::mobs::trial_spawner::TrialSpawner::load(&tag);
}
if let BlockEntity::Vault(v) = &mut entity {
**v = crate::vault::Vault::load(&tag);
}
// StructureTemplate.placeInWorld hands the template's block entity NBT to
// the level, so `BannerBlockEntity.loadAdditional` keeps the banner's
// patterns (the End cities' black triangles) and its name.
if let BlockEntity::Banner(b) = &mut entity {
*b = banner_from_nbt(nbt);
match &mut entity {
// MonsterRoomFeature and the structures' setEntityId.
BlockEntity::Spawner(s) => {
**s = crate::mobs::spawner::Spawner::load(&Tag::Compound(nbt.clone()));
}
BlockEntity::TrialSpawner(s) => {
**s = crate::mobs::trial_spawner::TrialSpawner::load(&Tag::Compound(nbt.clone()));
}
BlockEntity::Vault(v) => **v = crate::vault::Vault::load(&Tag::Compound(nbt.clone())),
// BannerBlockEntity.loadAdditional: the End cities' black triangles.
BlockEntity::Banner(b) => *b = crate::save::decode_banner(&Tag::Compound(nbt.clone())),
_ => {}
}
Some(entity)
}