From 48502d81c9f410cb0c338bef32fda78ceb2114fb Mon Sep 17 00:00:00 2001 From: random-geek <35757396+random-geek@users.noreply.github.com> Date: Fri, 22 Jan 2021 00:03:11 -0800 Subject: [PATCH] Partially working deleteobjects --- Manual.md | 12 ++++---- README.md | 2 +- src/cmd_line.rs | 5 ++- src/commands/delete_objects.rs | 56 +++++++++++++++++++++++----------- src/instance.rs | 2 +- 5 files changed, 51 insertions(+), 26 deletions(-) diff --git a/Manual.md b/Manual.md index 313951d..7466c10 100644 --- a/Manual.md +++ b/Manual.md @@ -76,18 +76,18 @@ terrain glitches. ### deleteobjects -Usage: `deleteobjects [--obj ] [--items] [--p1 x y z] [--p2 x y z] [--invert]` +Usage: `deleteobjects [--obj ] [--items [item]] [--p1 x y z] [--p2 x y z] [--invert]` -Delete objects (entities) of a certain name and/or within a certain area. +Delete objects/entities, including item entities (dropped items). Arguments: -- `--obj`: Name of object to search for, e.g. "boats:boat". If not specified, +- `--obj`: Name of object to delete, e.g. "boats:boat". If not specified, all objects will be deleted. -- `--items`: Search for only item entities (dropped items). If this flag is -set, `--obj` can optionally be used to specify an item name. +- `--items [item]`: Delete item entities (dropped items). If an optional item +name is specified, only items with that name will be deleted. - `--p1, --p2`: Area in which to delete objects. If not specified, objects will -be deleted across the entire map. +be deleted everywhere. - `--invert`: Delete objects *outside* the given area. ### fill diff --git a/README.md b/README.md index 16e0693..9ef6c45 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Some parts of the original MapEdit code were adapted from AndrejIT's [map_unexplore][5] project. All due credit goes to the author(s) of that project. -Thank you to ExeterDad and the moderators of the late Hometown server, for +Thank you also to ExeterDad and the moderators of the late Hometown server, for partially inspiring MapEdit/MapEditr. [4]: https://github.com/minetest/minetest diff --git a/src/cmd_line.rs b/src/cmd_line.rs index e78469f..eefe890 100644 --- a/src/cmd_line.rs +++ b/src/cmd_line.rs @@ -100,6 +100,8 @@ fn to_cmd_line_args<'a>(tup: &(ArgType, &'a str)) ArgType::Items => Arg::with_name("items") .long("items") + .min_values(0) + .max_values(1) .help(help) }] } @@ -158,7 +160,8 @@ fn parse_cmd_line_args() -> anyhow::Result { param2_val: sub_matches.value_of("param2_val") .map(|v| v.parse().unwrap()), object: sub_matches.value_of("object").map(str::to_string), - items: sub_matches.is_present("items"), + items: sub_matches.values_of("items") + .map(|v| v.map(str::to_string).collect()), }) } diff --git a/src/commands/delete_objects.rs b/src/commands/delete_objects.rs index 4b0cb10..a215648 100644 --- a/src/commands/delete_objects.rs +++ b/src/commands/delete_objects.rs @@ -8,6 +8,9 @@ use crate::utils::{query_keys, fmt_big_num}; use memmem::{Searcher, TwoWaySearcher}; +const ITEM_ENT_NAME: &[u8] = b"__builtin:item"; + + macro_rules! unwrap_or { ($res:expr, $alt:expr) => { match $res { @@ -22,40 +25,59 @@ macro_rules! unwrap_or { fn can_delete( obj: &StaticObject, area: &Option, - invert: bool + invert: bool, + obj_name: &Option>, + item_searcher: &Option ) -> bool { - // Check area requirements + // Check area requirement if let Some(a) = area { const DIV_FAC: i32 = 10_000; let rounded_pos = obj.f_pos.map( |v| (v - DIV_FAC / 2).div_euclid(DIV_FAC)); if a.contains(rounded_pos) == invert { - return false; + return false; // Object not included in area. } } - true + // Check name requirement + if let Some(n) = obj_name { + if let Ok(le_data) = LuaEntityData::deserialize(obj) { + if &le_data.name != n { + return false; // Object name does not match. + } + + if let Some(is) = item_searcher { + if is.search_in(&le_data.data).is_none() { + return false; // Item entity name does not match. + } + } + } else { + return false; // Unsupported object type, don't delete it. + } + } + + true // Delete if all tests pass. } fn delete_objects(inst: &mut InstBundle) { - const ITEM_ENT_NAME: &[u8] = b"__builtin:item"; - let search_obj = if inst.args.items { + 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()) }; + + // 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 item_searcher = search_item.as_ref() + .map(|s| TwoWaySearcher::new(s)); + let keys = query_keys(&mut inst.db, &mut inst.status, search_obj.as_deref(), inst.args.area, inst.args.invert, true); - let search_item = search_obj.as_ref().filter(|_| inst.args.items).map(|s| - format!( - "[\"itemstring\"] = \"{}\"", - String::from_utf8(s.to_owned()).unwrap() - ).into_bytes() - ); - let item_searcher = search_item.as_ref().map(|s| TwoWaySearcher::new(s)); - inst.status.begin_editing(); let mut count: u64 = 0; for key in keys { @@ -65,12 +87,12 @@ fn delete_objects(inst: &mut InstBundle) { let mut modified = false; for i in (0..block.static_objects.list.len()).rev() { - let obj = &block.static_objects.list[i]; - if can_delete( &block.static_objects.list[i], &inst.args.area, - inst.args.invert + inst.args.invert, + &search_obj, + &item_searcher ) { block.static_objects.list.remove(i); modified = true; diff --git a/src/instance.rs b/src/instance.rs index a2441f0..2961dfe 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -35,7 +35,7 @@ pub struct InstArgs { pub new_node: Option, pub param2_val: Option, pub object: Option, - pub items: bool, + pub items: Option>, }