From 7d9d95b8edd62ab176b21d9176ce0ff2b19530f1 Mon Sep 17 00:00:00 2001 From: random-geek <35757396+random-geek@users.noreply.github.com> Date: Fri, 22 Jan 2021 21:06:22 -0800 Subject: [PATCH] I can never decide how to handle imports, arrg --- Manual.md | 27 ++++++----- src/commands/delete_metadata.rs | 83 +++++++++++++++++++++++++++++++++ src/commands/delete_objects.rs | 6 +-- src/commands/delete_timers.rs | 1 - src/commands/mod.rs | 2 + src/map_block/compression.rs | 5 +- src/map_block/map_block.rs | 8 ++-- src/map_block/metadata.rs | 8 ++-- src/map_block/mod.rs | 6 ++- src/map_block/node_data.rs | 8 +--- src/map_block/static_object.rs | 48 +++++++++---------- 11 files changed, 138 insertions(+), 64 deletions(-) create mode 100644 src/commands/delete_metadata.rs diff --git a/Manual.md b/Manual.md index 7b923fa..65d5413 100644 --- a/Manual.md +++ b/Manual.md @@ -81,6 +81,21 @@ area. will be invoked where the blocks were deleted, and this sometimes causes terrain glitches. +### deletemeta + +Usage: `deletemeta [--node ] [--p1 x y z] [--p2 x y z] [--invert]` + +Delete metadata of a certain node and/or within a certain area. This includes +node inventories as well. + +Arguments: + +- `--node`: Name of node to modify. If not specified, the metadata of all +nodes will be deleted. +- `--p1, --p2`: Area in which to delete metadata. If not specified, metadata +will be deleted everywhere. +- `--invert`: Only delete metadata *outside* the given area. + ### deleteobjects Usage: `deleteobjects [--obj ] [--items [item]] [--p1 x y z] [--p2 x y z] [--invert]` @@ -203,18 +218,6 @@ map.sqlite is 10 GB, make sure you have **at least 10 GB** of free space! # Danger Zone! -### `deletemeta` - -**Usage:** `deletemeta [--searchnode ] [--p1 x y z] [--p2 x y z] [--invert]` - -Delete metadata of a certain node and/or within a certain area. This includes node inventories as well. - -Arguments: - -- **`--searchnode`**: Name of node to search for. If not specified, the metadata of all nodes will be deleted. -- **`--p1, --p2`**: Area in which to delete metadata. Required if `searchnode` is not specified. -- **`--invert`**: Only delete metadata *outside* the given area. - ### `setmetavar` **Usage:** `setmetavar [--searchnode ] [--p1 x y z] [--p2 x y z] [--invert] ` diff --git a/src/commands/delete_metadata.rs b/src/commands/delete_metadata.rs new file mode 100644 index 0000000..48e0b50 --- /dev/null +++ b/src/commands/delete_metadata.rs @@ -0,0 +1,83 @@ +use super::Command; + +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}; + + +fn delete_metadata(inst: &mut InstBundle) { + let node = inst.args.node.as_ref().map(|s| s.as_bytes().to_owned()); + + let keys = query_keys(&mut inst.db, &mut inst.status, + node.as_deref(), inst.args.area, inst.args.invert, true); + + inst.status.begin_editing(); + let mut count: u64 = 0; + + for key in keys { + inst.status.inc_done(); + let data = inst.db.get_block(key).unwrap(); + 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 mut meta = unwrap_or!( + NodeMetadataList::deserialize(block.metadata.get_ref()), continue); + + let block_corner = Vec3::from_block_key(key) * 16; + let mut to_delete = Vec::with_capacity(meta.list.len()); + + for (&idx, _) in &meta.list { + let pos = Vec3::from_u16_key(idx); + let abs_pos = pos + block_corner; + + if let Some(a) = inst.args.area { + if a.contains(abs_pos) == inst.args.invert { + continue; + } + } + if let Some(id) = node_id { + if node_data.nodes[idx as usize] != id { + continue; + } + } + + to_delete.push(idx); + } + + if !to_delete.is_empty() { + count += to_delete.len() as u64; + for idx in &to_delete { + meta.list.remove(idx); + } + *block.metadata.get_mut() = meta.serialize(block.version); + inst.db.set_block(key, &block.serialize()).unwrap(); + } + } + + inst.status.end_editing(); + inst.status.log_info( + format!("Deleted metadata from {} nodes.", fmt_big_num(count))); +} + + +pub fn get_command() -> Command { + Command { + func: delete_metadata, + verify_args: None, + args: vec![ + (ArgType::Area(false), "Area in which to delete metadata"), + (ArgType::Invert, "Delete all metadata outside the given area."), + (ArgType::Node(false), + "Node to delete metadata from. If not specified, all metadata \ + will be deleted.") + ], + help: "Delete node metadata." + } +} diff --git a/src/commands/delete_objects.rs b/src/commands/delete_objects.rs index b1d8ffe..71bfeec 100644 --- a/src/commands/delete_objects.rs +++ b/src/commands/delete_objects.rs @@ -76,15 +76,15 @@ fn delete_objects(inst: &mut InstBundle) { let mut block = unwrap_or!(MapBlock::deserialize(&data), continue); let mut modified = false; - for i in (0..block.static_objects.list.len()).rev() { + for i in (0..block.static_objects.len()).rev() { if can_delete( - &block.static_objects.list[i], + &block.static_objects[i], &inst.args.area, inst.args.invert, &search_obj, &item_searcher ) { - block.static_objects.list.remove(i); + block.static_objects.remove(i); modified = true; count += 1; } diff --git a/src/commands/delete_timers.rs b/src/commands/delete_timers.rs index df6232b..6660f32 100644 --- a/src/commands/delete_timers.rs +++ b/src/commands/delete_timers.rs @@ -40,7 +40,6 @@ fn delete_timers(inst: &mut InstBundle) { continue; } } - if let Some(id) = node_id { if node_data.nodes[pos_idx as usize] != id { continue; diff --git a/src/commands/mod.rs b/src/commands/mod.rs index c637860..15f34c1 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -4,6 +4,7 @@ use crate::instance::{ArgType, InstArgs, InstBundle}; mod clone; mod delete_blocks; +mod delete_metadata; mod delete_objects; mod delete_timers; mod fill; @@ -31,6 +32,7 @@ pub fn get_commands() -> BTreeMap<&'static str, Command> { new_cmd!("clone", clone); new_cmd!("deleteblocks", delete_blocks); + new_cmd!("deletemeta", delete_metadata); new_cmd!("deleteobjects", delete_objects); new_cmd!("deletetimers", delete_timers); new_cmd!("fill", fill); diff --git a/src/map_block/compression.rs b/src/map_block/compression.rs index 2fa2de5..7be1b9e 100644 --- a/src/map_block/compression.rs +++ b/src/map_block/compression.rs @@ -1,12 +1,9 @@ -use std::io::Cursor; -use std::io::prelude::*; +use super::*; use flate2::write::ZlibEncoder; use flate2::read::ZlibDecoder; use flate2::Compression; -use super::MapBlockError; - pub trait Compress { fn compress(&self, dst: &mut Cursor>); diff --git a/src/map_block/map_block.rs b/src/map_block/map_block.rs index 93694aa..f8600c0 100644 --- a/src/map_block/map_block.rs +++ b/src/map_block/map_block.rs @@ -1,7 +1,5 @@ use super::*; -use super::node_timer::{serialize_timers, deserialize_timers}; - const MIN_BLOCK_VER: u8 = 25; const MAX_BLOCK_VER: u8 = 28; @@ -27,7 +25,7 @@ pub struct MapBlock { pub static_objects: StaticObjectList, pub timestamp: u32, pub nimap: NameIdMap, - pub node_timers: Vec + pub node_timers: NodeTimerList } impl MapBlock { @@ -60,7 +58,7 @@ impl MapBlock { // Node metadata let metadata = ZlibContainer::read(&mut data)?; // Static objects - let static_objects = StaticObjectList::deserialize(&mut data)?; + let static_objects = deserialize_objects(&mut data)?; // Timestamp let timestamp = data.read_u32::()?; // Name-ID mappings @@ -109,7 +107,7 @@ impl MapBlock { // Node metadata self.metadata.write(&mut data); // Static objects - self.static_objects.serialize(&mut data); + serialize_objects(&self.static_objects, &mut data); // Timestamp data.write_u32::(self.timestamp).unwrap(); // Name-ID mappings diff --git a/src/map_block/metadata.rs b/src/map_block/metadata.rs index eb31900..3944abe 100644 --- a/src/map_block/metadata.rs +++ b/src/map_block/metadata.rs @@ -1,12 +1,8 @@ -use std::io::prelude::*; -use std::io::Cursor; use std::collections::HashMap; -use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use memmem::{Searcher, TwoWaySearcher}; -use super::{MapBlockError, read_string16, write_string16, read_string32, - write_string32, vec_with_len}; +use super::*; #[derive(Debug, Clone)] @@ -63,6 +59,8 @@ impl NodeMetadata { #[derive(Debug)] pub struct NodeMetadataList { + // TODO: Switch to BTreeMap or something more stable + // TODO: This is just a wrapper struct, switch to a type alias? pub list: HashMap } diff --git a/src/map_block/mod.rs b/src/map_block/mod.rs index db7a9b9..d33fe0c 100644 --- a/src/map_block/mod.rs +++ b/src/map_block/mod.rs @@ -1,7 +1,6 @@ use std::io::prelude::*; use std::io::Cursor; - -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; +use byteorder::{ByteOrder, BigEndian, ReadBytesExt, WriteBytesExt}; mod map_block; mod compression; @@ -13,10 +12,13 @@ mod name_id_map; pub use map_block::{MapBlock, is_valid_generated}; pub use compression::ZlibContainer; +use compression::Compress; pub use node_data::NodeData; pub use metadata::NodeMetadataList; pub use static_object::{StaticObject, StaticObjectList, LuaEntityData}; +use static_object::{serialize_objects, deserialize_objects}; pub use node_timer::{NodeTimer, NodeTimerList}; +use node_timer::{serialize_timers, deserialize_timers}; pub use name_id_map::NameIdMap; diff --git a/src/map_block/node_data.rs b/src/map_block/node_data.rs index 66b4d2c..e2dd047 100644 --- a/src/map_block/node_data.rs +++ b/src/map_block/node_data.rs @@ -1,14 +1,8 @@ -use std::io::Cursor; -use std::io::prelude::*; - use flate2::write::ZlibEncoder; use flate2::read::ZlibDecoder; use flate2::Compression; -use byteorder::{ByteOrder, BigEndian}; - -use super::{MapBlockError, vec_with_len}; -use super::compression::Compress; +use super::*; const BLOCK_SIZE: usize = 16; diff --git a/src/map_block/static_object.rs b/src/map_block/static_object.rs index 46949d6..aaa71c4 100644 --- a/src/map_block/static_object.rs +++ b/src/map_block/static_object.rs @@ -31,35 +31,33 @@ impl StaticObject { } -#[derive(Debug)] -pub struct StaticObjectList { - pub list: Vec -} +pub type StaticObjectList = Vec; -impl StaticObjectList { - pub fn deserialize(src: &mut Cursor<&[u8]>) - -> Result - { - let version = src.read_u8()?; - if version != 0 { - return Err(MapBlockError::Other); - } - let count = src.read_u16::()?; - let mut list = Vec::with_capacity(count as usize); - for _ in 0 .. count { - list.push(StaticObject::deserialize(src)?); - } - - Ok(Self {list}) +pub fn deserialize_objects(src: &mut Cursor<&[u8]>) + -> Result +{ + let version = src.read_u8()?; + if version != 0 { + return Err(MapBlockError::Other); } - pub fn serialize(&self, dst: &mut Cursor>) { - dst.write_u8(0).unwrap(); - dst.write_u16::(self.list.len() as u16).unwrap(); - for obj in &self.list { - obj.serialize(dst); - } + let count = src.read_u16::()?; + let mut list = Vec::with_capacity(count as usize); + for _ in 0 .. count { + list.push(StaticObject::deserialize(src)?); + } + + Ok(list) +} + + +pub fn serialize_objects(objects: &StaticObjectList, dst: &mut Cursor>) +{ + dst.write_u8(0).unwrap(); + dst.write_u16::(objects.len() as u16).unwrap(); + for obj in objects { + obj.serialize(dst); } }