Work on multi-node support
parent
0a4c759188
commit
98a0be45ec
|
@ -48,6 +48,7 @@ fn to_cmd_line_args<'a>(tup: &(ArgType, &'a str))
|
|||
.help(help)
|
||||
];
|
||||
}
|
||||
// TODO: Help is redundant.
|
||||
vec![match arg {
|
||||
ArgType::InputMapPath =>
|
||||
Arg::with_name("input_map")
|
||||
|
@ -76,6 +77,11 @@ fn to_cmd_line_args<'a>(tup: &(ArgType, &'a str))
|
|||
a
|
||||
}
|
||||
},
|
||||
ArgType::Nodes =>
|
||||
Arg::with_name("nodes")
|
||||
.long("nodes")
|
||||
.min_values(1)
|
||||
.help(help),
|
||||
ArgType::NewNode =>
|
||||
Arg::with_name("new_node")
|
||||
.takes_value(true)
|
||||
|
@ -169,6 +175,8 @@ fn parse_cmd_line_args() -> anyhow::Result<InstArgs> {
|
|||
offset: sub_matches.values_of("offset").map(arg_to_pos).transpose()
|
||||
.context("Invalid offset value")?,
|
||||
node: sub_matches.value_of("node").map(str::to_string),
|
||||
nodes: sub_matches.values_of("nodes").iter_mut().flatten()
|
||||
.map(str::to_string).collect(),
|
||||
new_node: sub_matches.value_of("new_node").map(str::to_string),
|
||||
item: sub_matches.value_of("item").map(str::to_string),
|
||||
new_item: sub_matches.value_of("new_item").map(str::to_string),
|
||||
|
|
|
@ -17,7 +17,7 @@ fn clone(inst: &mut InstBundle) {
|
|||
let offset = inst.args.offset.unwrap();
|
||||
let dst_area = src_area + offset;
|
||||
let mut keys = query_keys(&mut inst.db, &inst.status,
|
||||
Vec::new(), Some(dst_area), false, true);
|
||||
&[], Some(dst_area), false, true);
|
||||
|
||||
// Sort blocks according to offset such that we don't read blocks that
|
||||
// have already been written.
|
||||
|
|
|
@ -5,8 +5,8 @@ use crate::utils::query_keys;
|
|||
|
||||
|
||||
fn delete_blocks(inst: &mut InstBundle) {
|
||||
let keys = query_keys(&mut inst.db, &inst.status, Vec::new(),
|
||||
inst.args.area, inst.args.invert, false);
|
||||
let keys = query_keys(&mut inst.db, &inst.status,
|
||||
&[], inst.args.area, inst.args.invert, false);
|
||||
inst.status.begin_editing();
|
||||
|
||||
for key in keys {
|
||||
|
|
|
@ -4,14 +4,14 @@ 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};
|
||||
use crate::utils::{query_keys, to_bytes, to_slice, fmt_big_num};
|
||||
|
||||
|
||||
fn delete_metadata(inst: &mut InstBundle) {
|
||||
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
|
||||
let node = inst.args.node.as_ref().map(to_bytes);
|
||||
|
||||
let keys = query_keys(&mut inst.db, &mut inst.status,
|
||||
node.iter().collect(), inst.args.area, inst.args.invert, true);
|
||||
&to_slice(&node), inst.args.area, inst.args.invert, true);
|
||||
|
||||
inst.status.begin_editing();
|
||||
let mut count: u64 = 0;
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::unwrap_or;
|
|||
use crate::spatial::Area;
|
||||
use crate::instance::{ArgType, InstBundle};
|
||||
use crate::map_block::{MapBlock, StaticObject, LuaEntityData};
|
||||
use crate::utils::{query_keys, fmt_big_num};
|
||||
use crate::utils::{query_keys, to_bytes, to_slice, fmt_big_num};
|
||||
|
||||
use memmem::{Searcher, TwoWaySearcher};
|
||||
|
||||
|
@ -54,19 +54,18 @@ fn delete_objects(inst: &mut InstBundle) {
|
|||
let search_obj = if inst.args.items.is_some() {
|
||||
Some(ITEM_ENT_NAME.to_owned())
|
||||
} else {
|
||||
inst.args.object.as_ref().map(|s| s.as_bytes().to_owned())
|
||||
inst.args.object.as_ref().map(to_bytes)
|
||||
};
|
||||
|
||||
// search_item will be Some if (1) item search is enabled and (2) an item
|
||||
// is specified.
|
||||
let search_item = inst.args.items.as_ref()
|
||||
.and_then(|items| items.get(0))
|
||||
.map(|s| s.as_bytes().to_owned());
|
||||
let search_item = inst.args.items.as_ref().and_then(|items| items.get(0))
|
||||
.map(to_bytes);
|
||||
let item_searcher = search_item.as_ref()
|
||||
.map(|s| TwoWaySearcher::new(s));
|
||||
|
||||
let keys = query_keys(&mut inst.db, &mut inst.status,
|
||||
search_obj.iter().collect(), inst.args.area, inst.args.invert, true);
|
||||
&to_slice(&search_obj), inst.args.area, inst.args.invert, true);
|
||||
|
||||
inst.status.begin_editing();
|
||||
let mut count: u64 = 0;
|
||||
|
|
|
@ -4,14 +4,14 @@ use crate::unwrap_or;
|
|||
use crate::spatial::Vec3;
|
||||
use crate::instance::{ArgType, InstBundle};
|
||||
use crate::map_block::MapBlock;
|
||||
use crate::utils::{query_keys, fmt_big_num};
|
||||
use crate::utils::{query_keys, to_bytes, to_slice, fmt_big_num};
|
||||
|
||||
|
||||
fn delete_timers(inst: &mut InstBundle) {
|
||||
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
|
||||
let node = inst.args.node.as_ref().map(to_bytes);
|
||||
|
||||
let keys = query_keys(&mut inst.db, &mut inst.status,
|
||||
node.iter().collect(), inst.args.area, inst.args.invert, true);
|
||||
&to_slice(&node), inst.args.area, inst.args.invert, true);
|
||||
|
||||
inst.status.begin_editing();
|
||||
let mut count: u64 = 0;
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::spatial::{Vec3, Area, area_rel_block_overlap, area_contains_block};
|
|||
use crate::instance::{ArgType, InstBundle};
|
||||
use crate::map_block::{MapBlock};
|
||||
use crate::block_utils::clean_name_id_map;
|
||||
use crate::utils::{query_keys, fmt_big_num};
|
||||
use crate::utils::{query_keys, to_bytes, fmt_big_num};
|
||||
|
||||
|
||||
fn fill_area(block: &mut MapBlock, area: Area, id: u16) {
|
||||
|
@ -23,10 +23,10 @@ fn fill_area(block: &mut MapBlock, area: Area, id: u16) {
|
|||
|
||||
fn fill(inst: &mut InstBundle) {
|
||||
let area = inst.args.area.unwrap();
|
||||
let node = inst.args.new_node.as_ref().unwrap().as_bytes().to_owned();
|
||||
let node = to_bytes(inst.args.new_node.as_ref().unwrap());
|
||||
|
||||
let keys = query_keys(&mut inst.db, &mut inst.status,
|
||||
Vec::new(), Some(area), false, true);
|
||||
&[], Some(area), false, true);
|
||||
|
||||
inst.status.begin_editing();
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ fn overlay_no_offset(inst: &mut InstBundle) {
|
|||
|
||||
// Get keys from input database.
|
||||
let keys = query_keys(&mut idb, &inst.status,
|
||||
Vec::new(), inst.args.area, invert, true);
|
||||
&[], inst.args.area, invert, true);
|
||||
inst.status.begin_editing();
|
||||
|
||||
for key in keys {
|
||||
|
@ -107,7 +107,7 @@ fn overlay_with_offset(inst: &mut InstBundle) {
|
|||
|
||||
// Get keys from output database.
|
||||
let keys = query_keys(&mut inst.db, &inst.status,
|
||||
Vec::new(), dst_area, inst.args.invert, true);
|
||||
&[], dst_area, inst.args.invert, true);
|
||||
inst.status.begin_editing();
|
||||
|
||||
for key in keys {
|
||||
|
|
|
@ -4,7 +4,7 @@ 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};
|
||||
use crate::utils::{query_keys, to_bytes, fmt_big_num};
|
||||
|
||||
const NEWLINE: u8 = b'\n';
|
||||
const SPACE: u8 = b' ';
|
||||
|
@ -18,8 +18,12 @@ fn do_replace(inv: &mut Vec<u8>, item: &[u8], new_item: &[u8], del_meta: bool)
|
|||
let mut mods = 0;
|
||||
|
||||
for line in inv.split(|&x| x == NEWLINE) {
|
||||
let mut parts = line.splitn(4, |&x| x == SPACE);
|
||||
if line.is_empty() {
|
||||
// Necessary because of newline after final EndInventory
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut parts = line.splitn(4, |&x| x == SPACE);
|
||||
if parts.next() == Some(b"Item") && parts.next() == Some(item) {
|
||||
if delete {
|
||||
new_inv.extend_from_slice(b"Empty");
|
||||
|
@ -53,13 +57,13 @@ fn do_replace(inv: &mut Vec<u8>, item: &[u8], new_item: &[u8], del_meta: bool)
|
|||
|
||||
|
||||
fn replace_in_inv(inst: &mut InstBundle) {
|
||||
let item = inst.args.item.as_ref().unwrap().as_bytes().to_owned();
|
||||
let new_item = inst.args.new_item.as_ref().unwrap().as_bytes().to_owned();
|
||||
let item = to_bytes(inst.args.item.as_ref().unwrap());
|
||||
let new_item = to_bytes(inst.args.new_item.as_ref().unwrap());
|
||||
let del_meta = false;
|
||||
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
|
||||
let nodes: Vec<_> = inst.args.nodes.iter().map(to_bytes).collect();
|
||||
|
||||
let keys = query_keys(&mut inst.db, &mut inst.status,
|
||||
node.iter().collect(), inst.args.area, inst.args.invert, true);
|
||||
&nodes, inst.args.area, inst.args.invert, true);
|
||||
|
||||
inst.status.begin_editing();
|
||||
let mut item_mods: u64 = 0;
|
||||
|
@ -71,9 +75,10 @@ fn replace_in_inv(inst: &mut InstBundle) {
|
|||
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 node_ids: Vec<_> = nodes.iter()
|
||||
.filter_map(|n| block.nimap.get_id(n)).collect();
|
||||
if !nodes.is_empty() && node_ids.is_empty() {
|
||||
continue; // Block doesn't contain any of the required nodes.
|
||||
}
|
||||
|
||||
let mut meta = unwrap_or!(
|
||||
|
@ -90,10 +95,10 @@ fn replace_in_inv(inst: &mut InstBundle) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(id) = node_id {
|
||||
if node_data.nodes[idx as usize] != id {
|
||||
continue;
|
||||
}
|
||||
if !node_ids.is_empty()
|
||||
&& !node_ids.contains(&node_data.nodes[idx as usize])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let i_mods = do_replace(&mut data.inv, &item, &new_item, del_meta);
|
||||
|
@ -125,7 +130,7 @@ pub fn get_command() -> Command {
|
|||
(ArgType::NewItem, "Name of new item to replace with"),
|
||||
(ArgType::Area(false), "Area in which to modify inventories"),
|
||||
(ArgType::Invert, "Modify inventories outside the given area."),
|
||||
(ArgType::Node(false), "Node to modify inventories of")
|
||||
(ArgType::Nodes, "Names of nodes to modify inventories of")
|
||||
],
|
||||
help: "Replace items in node inventories."
|
||||
}
|
||||
|
|
|
@ -4,9 +4,8 @@ use crate::spatial::{Vec3, Area, area_contains_block, area_touches_block,
|
|||
area_rel_block_overlap};
|
||||
use crate::instance::{ArgType, InstArgs, InstBundle};
|
||||
use crate::map_block::MapBlock;
|
||||
use crate::utils::query_keys;
|
||||
use crate::time_keeper::TimeKeeper;
|
||||
use crate::utils::fmt_big_num;
|
||||
use crate::utils::{query_keys, to_bytes, fmt_big_num};
|
||||
|
||||
|
||||
fn do_replace(
|
||||
|
@ -113,10 +112,10 @@ fn do_replace(
|
|||
|
||||
|
||||
fn replace_nodes(inst: &mut InstBundle) {
|
||||
let node = inst.args.node.as_ref().unwrap().as_bytes().to_owned();
|
||||
let new_node = inst.args.new_node.as_ref().unwrap().as_bytes().to_owned();
|
||||
let node = to_bytes(inst.args.node.as_ref().unwrap());
|
||||
let new_node = to_bytes(inst.args.new_node.as_ref().unwrap());
|
||||
let keys = query_keys(&mut inst.db, &inst.status,
|
||||
vec![&node], inst.args.area, inst.args.invert, true);
|
||||
std::slice::from_ref(&node), inst.args.area, inst.args.invert, true);
|
||||
|
||||
inst.status.begin_editing();
|
||||
let mut count = 0;
|
||||
|
|
|
@ -4,16 +4,16 @@ 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};
|
||||
use crate::utils::{query_keys, to_bytes, 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 key = to_bytes(inst.args.key.as_ref().unwrap());
|
||||
let value = to_bytes(inst.args.value.as_ref().unwrap());
|
||||
let nodes: Vec<_> = inst.args.nodes.iter().map(to_bytes).collect();
|
||||
|
||||
let keys = query_keys(&mut inst.db, &mut inst.status,
|
||||
node.iter().collect(), inst.args.area, inst.args.invert, true);
|
||||
&nodes, inst.args.area, inst.args.invert, true);
|
||||
|
||||
inst.status.begin_editing();
|
||||
let mut count: u64 = 0;
|
||||
|
@ -24,9 +24,10 @@ fn set_meta_var(inst: &mut InstBundle) {
|
|||
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 node_ids: Vec<_> = nodes.iter()
|
||||
.filter_map(|n| block.nimap.get_id(n)).collect();
|
||||
if !nodes.is_empty() && node_ids.is_empty() {
|
||||
continue; // Block doesn't contain any of the required nodes.
|
||||
}
|
||||
|
||||
let mut meta = unwrap_or!(
|
||||
|
@ -44,10 +45,10 @@ fn set_meta_var(inst: &mut InstBundle) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if let Some(id) = node_id {
|
||||
if node_data.nodes[idx as usize] != id {
|
||||
continue;
|
||||
}
|
||||
if !node_ids.is_empty()
|
||||
&& !node_ids.contains(&node_data.nodes[idx as usize])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(val) = data.vars.get_mut(&key) {
|
||||
|
@ -76,11 +77,12 @@ pub fn get_command() -> Command {
|
|||
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::Area(false),
|
||||
"Optional 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.")
|
||||
(ArgType::Nodes,
|
||||
"Names of one or more nodes to modify. If not specified, all \
|
||||
nodes with the specified variable will be modified.")
|
||||
],
|
||||
help: "Set a variable in node metadata."
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ 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, fmt_big_num};
|
||||
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
|
||||
|
@ -43,10 +43,10 @@ fn set_in_area(block: &mut MapBlock, area: Area, val: u8) {
|
|||
|
||||
fn set_param2(inst: &mut InstBundle) {
|
||||
let param2_val = inst.args.param2_val.unwrap();
|
||||
let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned());
|
||||
let node = inst.args.node.as_ref().map(to_bytes);
|
||||
|
||||
let keys = query_keys(&mut inst.db, &mut inst.status,
|
||||
node.iter().collect(), inst.args.area, false, true);
|
||||
to_slice(&node), inst.args.area, false, true);
|
||||
|
||||
inst.status.begin_editing();
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ pub enum ArgType {
|
|||
Invert,
|
||||
Offset(bool),
|
||||
Node(bool),
|
||||
Nodes,
|
||||
NewNode,
|
||||
Item,
|
||||
NewItem,
|
||||
|
@ -36,6 +37,7 @@ pub struct InstArgs {
|
|||
pub invert: bool,
|
||||
pub offset: Option<Vec3>,
|
||||
pub node: Option<String>,
|
||||
pub nodes: Vec<String>,
|
||||
pub new_node: Option<String>,
|
||||
pub item: Option<String>,
|
||||
pub new_item: Option<String>,
|
||||
|
|
27
src/utils.rs
27
src/utils.rs
|
@ -11,8 +11,7 @@ use crate::spatial::{Area, Vec3};
|
|||
pub fn query_keys(
|
||||
db: &mut MapDatabase,
|
||||
status: &StatusServer,
|
||||
// TODO: Allow multiple names for setmetavar and replaceininv.
|
||||
search_strs: Vec<&Vec<u8>>,
|
||||
search_strs: &[Vec<u8>],
|
||||
area: Option<Area>,
|
||||
invert: bool,
|
||||
include_partial: bool
|
||||
|
@ -21,7 +20,7 @@ pub fn query_keys(
|
|||
|
||||
// Prepend 16-bit search string length to reduce false positives.
|
||||
// This will break if the name-ID map format changes.
|
||||
let string16s: Vec<Vec<u8>> = search_strs.iter().map(|&s| {
|
||||
let string16s: Vec<Vec<u8>> = search_strs.iter().map(|s| {
|
||||
let mut res = Vec::new();
|
||||
res.write_u16::<BigEndian>(s.len() as u16).unwrap();
|
||||
res.extend(s);
|
||||
|
@ -49,11 +48,10 @@ pub fn query_keys(
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if !data_searchers.is_empty() {
|
||||
// Data must match at least one search string.
|
||||
if data_searchers.iter().any(|s| s.search_in(&data).is_some()) {
|
||||
continue;
|
||||
}
|
||||
if !data_searchers.is_empty()
|
||||
&& !data_searchers.iter().any(|s| s.search_in(&data).is_some())
|
||||
{ // Data must match at least one search string.
|
||||
continue;
|
||||
}
|
||||
keys.push(key);
|
||||
|
||||
|
@ -69,6 +67,19 @@ pub fn query_keys(
|
|||
}
|
||||
|
||||
|
||||
pub fn to_bytes(s: &String) -> Vec<u8> {
|
||||
s.as_bytes().to_vec()
|
||||
}
|
||||
|
||||
|
||||
pub fn to_slice(opt: &Option<Vec<u8>>) -> &[Vec<u8>] {
|
||||
match opt {
|
||||
Some(x) => std::slice::from_ref(x),
|
||||
None => &[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! unwrap_or {
|
||||
($res:expr, $alt:expr) => {
|
||||
|
|
Loading…
Reference in New Issue