MapEditr/src/commands/set_param2.rs
2021-03-06 15:01:46 -08:00

122 lines
3.0 KiB
Rust

use super::Command;
use crate::spatial::{Vec3, Area, area_rel_block_overlap, area_contains_block};
use crate::instance::{ArgType, InstArgs, InstBundle};
use crate::map_block::MapBlock;
use crate::utils::{query_keys, to_bytes, to_slice, fmt_big_num};
fn set_in_area_node(block: &mut MapBlock, area: Area, id: u16, val: u8) -> u64
{
let nd = block.node_data.get_mut();
let mut count = 0;
for z in area.min.z ..= area.max.z {
let z_start = z * 256;
for y in area.min.y ..= area.max.y {
let zy_start = z_start + y * 16;
for x in area.min.x ..= area.max.x {
let i = (zy_start + x) as usize;
if nd.nodes[i] == id {
nd.param2[i] = val;
count += 1;
}
}
}
}
count
}
fn set_in_area(block: &mut MapBlock, area: Area, val: u8) {
let nd = block.node_data.get_mut();
for z in area.min.z ..= area.max.z {
let z_start = z * 256;
for y in area.min.y ..= area.max.y {
let zy_start = z_start + y * 16;
for x in area.min.x ..= area.max.x {
nd.param2[(zy_start + x) as usize] = val;
}
}
}
}
fn set_param2(inst: &mut InstBundle) {
let param2_val = inst.args.param2_val.unwrap();
let node = inst.args.node.as_ref().map(to_bytes);
let keys = query_keys(&mut inst.db, &mut inst.status,
to_slice(&node), inst.args.area, false, true);
inst.status.begin_editing();
let mut count: u64 = 0;
for key in keys {
inst.status.inc_done();
let pos = Vec3::from_block_key(key);
let data = inst.db.get_block(key).unwrap();
let mut block = MapBlock::deserialize(&data).unwrap();
let node_id = node.as_ref().and_then(|n| block.nimap.get_id(n));
if inst.args.node.is_some() && node_id.is_none() {
// Node not found in this map block.
continue;
}
let nd = block.node_data.get_mut();
if let Some(area) = inst.args.area
.filter(|a| !area_contains_block(&a, pos))
{ // Modify part of block
let overlap = area_rel_block_overlap(&area, pos).unwrap();
if let Some(nid) = node_id {
count +=
set_in_area_node(&mut block, overlap, nid, param2_val);
} else {
set_in_area(&mut block, overlap, param2_val);
count += overlap.volume();
}
} else { // Modify whole block
if let Some(nid) = node_id {
for i in 0 .. nd.param2.len() {
if nd.nodes[i] == nid {
nd.param2[i] = param2_val;
count += 1;
}
}
} else {
for x in &mut nd.param2 {
*x = param2_val;
}
count += nd.param2.len() as u64;
}
}
inst.db.set_block(key, &block.serialize()).unwrap();
}
inst.status.end_editing();
inst.status.log_info(format!("{} nodes set.", fmt_big_num(count)));
}
fn verify_args(args: &InstArgs) -> anyhow::Result<()> {
anyhow::ensure!(args.area.is_some() || args.node.is_some(),
"An area and/or node must be provided.");
Ok(())
}
pub fn get_command() -> Command {
Command {
func: set_param2,
verify_args: Some(verify_args),
args: vec![
(ArgType::Area(false), "Area in which to set param2 values"),
(ArgType::Node(false), "Node to set param2 values of"),
(ArgType::Param2Val, "New param2 value")
],
help: "Set param2 values of an area or node."
}
}