From b236c6d7d8c25f8f28e6c0547099eca528261622 Mon Sep 17 00:00:00 2001 From: random-geek <35757396+random-geek@users.noreply.github.com> Date: Wed, 20 Jan 2021 00:17:35 -0800 Subject: [PATCH] deleteobjects work --- src/cmd_line.rs | 13 +++++++++++ src/commands/delete_objects.rs | 40 ++++++++++++++++++++++++++++++++-- src/instance.rs | 4 ++++ src/map_block/mod.rs | 2 +- src/map_block/static_object.rs | 22 +++++++++++++++++++ 5 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/cmd_line.rs b/src/cmd_line.rs index a3fbc53..e78469f 100644 --- a/src/cmd_line.rs +++ b/src/cmd_line.rs @@ -49,6 +49,7 @@ fn to_cmd_line_args<'a>(tup: &(ArgType, &'a str)) ]; } vec![match arg { + // TODO: Remove unused conditions here. ArgType::InputMapPath => Arg::with_name("input_map") .required(true) @@ -90,6 +91,16 @@ fn to_cmd_line_args<'a>(tup: &(ArgType, &'a str)) Arg::with_name("param2_val") .required(true) .help(help), + ArgType::Object(req) => + Arg::with_name("object") + .long("obj") + .takes_value(true) + .required(req) + .help(help), + ArgType::Items => + Arg::with_name("items") + .long("items") + .help(help) }] } @@ -146,6 +157,8 @@ fn parse_cmd_line_args() -> anyhow::Result { new_node: sub_matches.value_of("new_node").map(str::to_string), 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"), }) } diff --git a/src/commands/delete_objects.rs b/src/commands/delete_objects.rs index b81258e..3f59b88 100644 --- a/src/commands/delete_objects.rs +++ b/src/commands/delete_objects.rs @@ -1,9 +1,11 @@ use super::Command; use crate::instance::{ArgType, InstBundle}; -use crate::map_block::{MapBlock}; +use crate::map_block::{MapBlock, LuaEntityData}; use crate::utils::{query_keys, fmt_big_num}; +use memmem::{Searcher, TwoWaySearcher}; + macro_rules! unwrap_or { ($res:expr, $alt:expr) => { @@ -16,11 +18,20 @@ macro_rules! unwrap_or { fn delete_objects(inst: &mut InstBundle) { + const ITEM_ENT_NAME: &'static [u8] = b"__builtin:item"; + let search_obj = if inst.args.items { + Some(String::from_utf8(ITEM_ENT_NAME.to_vec()).unwrap()) + } else { + inst.args.object.clone() + }; let keys = query_keys(&mut inst.db, &mut inst.status, - None, inst.args.area, inst.args.invert, true); + search_obj.clone(), inst.args.area, inst.args.invert, true); inst.status.begin_editing(); + let item_searcher = search_obj.as_ref().filter(|_| inst.args.items) + .map(|s| TwoWaySearcher::new(format!("[itemstring]=\"{}\"", s))); + let mut count: u64 = 0; for key in keys { inst.status.inc_done(); @@ -31,6 +42,7 @@ fn delete_objects(inst: &mut InstBundle) { for i in (0..block.static_objects.list.len()).rev() { let obj = &block.static_objects.list[i]; + // Check area requirements if let Some(area) = inst.args.area { const DIV_FAC: i32 = 10_000; let rounded_pos = obj.f_pos.map( @@ -40,6 +52,26 @@ fn delete_objects(inst: &mut InstBundle) { } } + // Check name requirements + let le_data = unwrap_or!(LuaEntityData::deserialize(&obj), + continue); + if inst.args.items { + if le_data.name != ITEM_ENT_NAME { + continue; + } + if let Some(searcher) = &item_searcher { + if searcher.search_in(&le_data.data).is_none() { + continue; + } + } + } else { + if let Some(sobj) = &search_obj { + if le_data.name != sobj.as_bytes() { + continue; + } + } + } + block.static_objects.list.remove(i); modified = true; count += 1; @@ -62,6 +94,10 @@ pub fn get_command() -> Command { args: vec![ (ArgType::Area(false), "Area in which to delete objects"), (ArgType::Invert, "Delete all objects outside the area"), + (ArgType::Object(false), + "Name of object (or item with --item) to search for."), + (ArgType::Items, + "Delete dropped items using object name as item name."), ], help: "Delete certain objects (entities)." } diff --git a/src/instance.rs b/src/instance.rs index 3631995..a2441f0 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -18,6 +18,8 @@ pub enum ArgType { Node(bool), NewNode(bool), Param2Val(bool), + Object(bool), + Items, } @@ -32,6 +34,8 @@ pub struct InstArgs { pub node: Option, pub new_node: Option, pub param2_val: Option, + pub object: Option, + pub items: bool, } diff --git a/src/map_block/mod.rs b/src/map_block/mod.rs index 8fde766..db7a9b9 100644 --- a/src/map_block/mod.rs +++ b/src/map_block/mod.rs @@ -15,7 +15,7 @@ pub use map_block::{MapBlock, is_valid_generated}; pub use compression::ZlibContainer; pub use node_data::NodeData; pub use metadata::NodeMetadataList; -pub use static_object::{StaticObject, StaticObjectList}; +pub use static_object::{StaticObject, StaticObjectList, LuaEntityData}; pub use node_timer::{NodeTimer, NodeTimerList}; pub use name_id_map::NameIdMap; diff --git a/src/map_block/static_object.rs b/src/map_block/static_object.rs index baa9776..46949d6 100644 --- a/src/map_block/static_object.rs +++ b/src/map_block/static_object.rs @@ -62,3 +62,25 @@ impl StaticObjectList { } } } + + +pub struct LuaEntityData { + pub name: Vec, + pub data: Vec +} + +impl LuaEntityData { + pub fn deserialize(src: &StaticObject) -> Result { + if src.obj_type != 7 { + return Err(MapBlockError::Other); + } + let mut src_data = Cursor::new(src.data.as_slice()); + if src_data.read_u8()? != 1 { + return Err(MapBlockError::Other); + } + + let name = read_string16(&mut src_data)?; + let data = read_string32(&mut src_data)?; + Ok(Self {name, data}) + } +}