MapEditr/src/commands/set_meta_var.rs
2021-01-26 14:32:58 -08:00

88 lines
2.4 KiB
Rust

use super::Command;
use crate::unwrap_or;
use crate::spatial::Vec3;
use crate::instance::{ArgType, InstBundle};
use crate::map_block::{MapBlock, NodeMetadataList};
use crate::utils::{query_keys, fmt_big_num};
fn set_meta_var(inst: &mut InstBundle) {
let key = inst.args.key.as_ref().unwrap().as_bytes().to_owned();
let value = inst.args.value.as_ref().unwrap().as_bytes().to_owned();
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
let keys = query_keys(&mut inst.db, &mut inst.status,
node.iter().collect(), inst.args.area, inst.args.invert, true);
inst.status.begin_editing();
let mut count: u64 = 0;
for block_key in keys {
inst.status.inc_done();
let data = inst.db.get_block(block_key).unwrap();
let mut block = unwrap_or!(MapBlock::deserialize(&data), continue);
let node_data = block.node_data.get_ref();
let node_id = node.as_deref().and_then(|n| block.nimap.get_id(n));
if node.is_some() && node_id.is_none() {
continue; // Block doesn't contain the required node.
}
let mut meta = unwrap_or!(
NodeMetadataList::deserialize(block.metadata.get_ref()), continue);
let block_corner = Vec3::from_block_key(block_key) * 16;
let mut modified = false;
for (&idx, data) in &mut meta.list {
let pos = Vec3::from_u16_key(idx);
let abs_pos = pos + block_corner;
if let Some(a) = inst.args.area {
if a.contains(abs_pos) == inst.args.invert {
continue;
}
}
if let Some(id) = node_id {
if node_data.nodes[idx as usize] != id {
continue;
}
}
if let Some(val) = data.vars.get_mut(&key) {
val.0 = value.clone();
modified = true;
count += 1;
}
}
if modified {
*block.metadata.get_mut() = meta.serialize(block.version);
inst.db.set_block(block_key, &block.serialize()).unwrap();
}
}
inst.status.end_editing();
inst.status.log_info(
format!("Set metadata variable of {} nodes.", fmt_big_num(count)));
}
pub fn get_command() -> Command {
Command {
func: set_meta_var,
verify_args: None,
args: vec![
(ArgType::Key, "Name of key to set in metadata"),
(ArgType::Value, "Value to set in metadata"),
(ArgType::Area(false), "Area in which to modify node metadata"),
(ArgType::Invert, "Modify node metadata outside the given area."),
(ArgType::Node(false),
"Node to modify metadata in. If not specified, all relevant \
metadata will be modified.")
],
help: "Set a variable in node metadata."
}
}