1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! V3814 (24w05b + 3) — schematic-relevant subset of `V3814.java`.
//!
//! The "old attributes" rename `minecraft:horse.jump_strength` ->
//! `minecraft:generic.jump_strength`, applied via
//! `ConverterAbstractOldAttributesRename` (V3814.java:14-18).
//!
//! That helper renames the `Name` field of each entry in an entity's
//! `Attributes` list and the `AttributeName` field of each entry in an item's
//! `AttributeModifiers` list. (The PLAYER registration it also performs is
//! non-schematic and skipped.) The lookup is exact — no namespace correction.
//!
//! VERSION = MCVersions.V24W05B (3811) + 3 = 3814.
use crate::nbt::NbtMap;
use super::super::registry::RegistryBuilder;
use super::super::types::{MapExt, ValueExt};
const VERSION: i32 = 3814;
/// `(old, new)` attribute renames (V3814.java:14-16).
const ATTRIBUTE_RENAMES: &[(&str, &str)] = &[(
"minecraft:horse.jump_strength",
"minecraft:generic.jump_strength",
)];
fn rename(name: &str) -> Option<&'static str> {
ATTRIBUTE_RENAMES
.iter()
.find(|(old, _)| *old == name)
.map(|(_, new)| *new)
}
/// Inverse lookup: map the new name back to the old name. The forward rename is
/// one-to-one, so this is exact (lossless).
fn rename_inverse(name: &str) -> Option<&'static str> {
ATTRIBUTE_RENAMES
.iter()
.find(|(_, new)| *new == name)
.map(|(old, _)| *old)
}
/// Inverse of `rename_list_field`: rename `data[list][].key` new -> old.
fn rename_list_field_inverse(data: &mut NbtMap, list: &str, key: &str) {
if let Some(list) = data.get_list_mut(list) {
for el in list.iter_mut() {
if let Some(map) = el.as_compound_mut() {
if let Some(value) = map.get_string(key) {
if let Some(old) = rename_inverse(value) {
map.set_string(key, old);
}
}
}
}
}
}
/// `RenameHelper.renameString(map, key, renamer)` over every map in `data[list]`.
fn rename_list_field(data: &mut NbtMap, list: &str, key: &str) {
if let Some(list) = data.get_list_mut(list) {
for el in list.iter_mut() {
if let Some(map) = el.as_compound_mut() {
if let Some(value) = map.get_string(key) {
if let Some(new) = rename(value) {
map.set_string(key, new);
}
}
}
}
}
}
pub fn register(reg: &mut RegistryBuilder) {
// ENTITY: Attributes[].Name. (PLAYER registration is non-schematic, skipped.)
reg.entity.add_structure_converter(
VERSION,
0,
Box::new(|data: &mut NbtMap, _from, _to| rename_list_field(data, "Attributes", "Name")),
);
// REVERSE: rename Attributes[].Name new -> old (one-to-one, lossless).
reg.entity.add_reverse_converter(
VERSION,
0,
Box::new(|data: &mut NbtMap, _from, _to| {
rename_list_field_inverse(data, "Attributes", "Name")
}),
);
// ITEM_STACK: AttributeModifiers[].AttributeName.
reg.item_stack.add_structure_converter(
VERSION,
0,
Box::new(|data: &mut NbtMap, _from, _to| {
rename_list_field(data, "AttributeModifiers", "AttributeName")
}),
);
// REVERSE: rename AttributeModifiers[].AttributeName new -> old (lossless).
reg.item_stack.add_reverse_converter(
VERSION,
0,
Box::new(|data: &mut NbtMap, _from, _to| {
rename_list_field_inverse(data, "AttributeModifiers", "AttributeName")
}),
);
}