use crate::nbt::NbtMap;
use super::super::loss::{report_loss, LossKind, Severity};
use super::super::registry::RegistryBuilder;
use super::super::types::MapExt;
use super::super::version::EncodedVersion;
const VERSION: i32 = 1918;
fn profession_string(profession_id: i32, career_id: i32) -> &'static str {
match profession_id {
0 => match career_id {
2 => "minecraft:fisherman",
3 => "minecraft:shepherd",
4 => "minecraft:fletcher",
_ => "minecraft:farmer",
},
1 => {
if career_id == 2 {
"minecraft:cartographer"
} else {
"minecraft:librarian"
}
}
2 => "minecraft:cleric",
3 => match career_id {
2 => "minecraft:weaponsmith",
3 => "minecraft:toolsmith",
_ => "minecraft:armorer",
},
4 => {
if career_id == 2 {
"minecraft:leatherworker"
} else {
"minecraft:butcher"
}
}
5 => "minecraft:nitwit",
_ => "minecraft:none",
}
}
fn convert(data: &mut NbtMap, _from: EncodedVersion, _to: EncodedVersion) {
let profession = data.get_i32("Profession").unwrap_or(0);
let career = data.get_i32("Career").unwrap_or(0);
let career_level = data.get_i32("CareerLevel").unwrap_or(1);
data.take("Profession");
data.take("Career");
data.take("CareerLevel");
let mut villager_data = NbtMap::new();
villager_data.set_string("type", "minecraft:plains");
villager_data.set_string("profession", profession_string(profession, career));
villager_data.set_i32("level", career_level);
data.set_map("VillagerData", villager_data);
}
fn profession_pair(profession: &str) -> Option<(i32, i32)> {
match profession {
"minecraft:fisherman" => Some((0, 2)),
"minecraft:shepherd" => Some((0, 3)),
"minecraft:fletcher" => Some((0, 4)),
"minecraft:farmer" => Some((0, 0)), "minecraft:cartographer" => Some((1, 2)),
"minecraft:librarian" => Some((1, 0)), "minecraft:cleric" => Some((2, 0)), "minecraft:weaponsmith" => Some((3, 2)),
"minecraft:toolsmith" => Some((3, 3)),
"minecraft:armorer" => Some((3, 0)), "minecraft:leatherworker" => Some((4, 2)),
"minecraft:butcher" => Some((4, 0)), "minecraft:nitwit" => Some((5, 0)),
"minecraft:none" => Some((6, 0)),
_ => None,
}
}
fn revert(data: &mut NbtMap, _from: EncodedVersion, _to: EncodedVersion) {
let villager_data = match data.take("VillagerData") {
Some(crate::nbt::NbtValue::Compound(m)) => m,
_ => return,
};
let profession = villager_data
.get_string("profession")
.unwrap_or("minecraft:none");
let level = villager_data.get_i32("level").unwrap_or(1);
if let Some(villager_type) = villager_data.get_string("type") {
if villager_type != "minecraft:plains" {
report_loss(
VERSION,
LossKind::UnsupportedInTarget,
Severity::Loss,
format!(
"VillagerData.type '{villager_type}' has no legacy Profession/Career field; dropping biome type"
),
);
}
}
let (profession_id, career_id) = match profession_pair(profession) {
Some(pair) => pair,
None => {
report_loss(
VERSION,
LossKind::RenameAmbiguous,
Severity::Approximated,
"VillagerData.profession has no legacy Profession/Career mapping; defaulting to farmer",
);
(0, 0)
}
};
if matches!(
profession,
"minecraft:farmer"
| "minecraft:librarian"
| "minecraft:armorer"
| "minecraft:butcher"
| "minecraft:cleric"
| "minecraft:nitwit"
| "minecraft:none"
) {
report_loss(
VERSION,
LossKind::RenameAmbiguous,
Severity::Approximated,
"VillagerData.profession collapses multiple Career values; restoring canonical Career",
);
}
data.set_i32("Profession", profession_id);
data.set_i32("Career", career_id);
data.set_i32("CareerLevel", level);
}
pub fn register(reg: &mut RegistryBuilder) {
reg.entity
.add_converter_for_id("minecraft:villager", VERSION, 0, Box::new(convert));
reg.entity
.add_reverse_converter_for_id("minecraft:villager", VERSION, 0, Box::new(revert));
reg.entity
.add_converter_for_id("minecraft:zombie_villager", VERSION, 0, Box::new(convert));
reg.entity.add_reverse_converter_for_id(
"minecraft:zombie_villager",
VERSION,
0,
Box::new(revert),
);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dataconverter::registry::convert_entity_reverse;
#[test]
fn reverse_villager_none_uses_non_mapped_profession_preimage() {
let mut villager_data = NbtMap::new();
villager_data.set_string("type", "minecraft:plains");
villager_data.set_string("profession", "minecraft:none");
villager_data.set_i32("level", 2);
let mut villager = NbtMap::new();
villager.set_string("id", "minecraft:villager");
villager.set_map("VillagerData", villager_data);
let _ = convert_entity_reverse(&mut villager, 1918, 1917);
assert_eq!(villager.get_i32("Profession"), Some(6));
assert_eq!(villager.get_i32("Career"), Some(0));
assert_eq!(profession_string(6, 0), "minecraft:none");
}
#[test]
fn reverse_non_plains_villager_type_reports_loss() {
let mut villager_data = NbtMap::new();
villager_data.set_string("type", "minecraft:desert");
villager_data.set_string("profession", "minecraft:fletcher");
let mut villager = NbtMap::new();
villager.set_string("id", "minecraft:villager");
villager.set_map("VillagerData", villager_data);
let report = convert_entity_reverse(&mut villager, 1918, 1917);
assert_eq!(report.loss_count(), 1);
assert_eq!(villager.get_i32("Profession"), Some(0));
assert_eq!(villager.get_i32("Career"), Some(4));
}
}