122 lines
3.0 KiB
Rust
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."
|
|
}
|
|
}
|