I can never decide how to handle imports, arrg

master
random-geek 2021-01-22 21:06:22 -08:00
parent 9528a11e1e
commit 7d9d95b8ed
11 changed files with 138 additions and 64 deletions

View File

@ -81,6 +81,21 @@ area.
will be invoked where the blocks were deleted, and this sometimes causes will be invoked where the blocks were deleted, and this sometimes causes
terrain glitches. terrain glitches.
### deletemeta
Usage: `deletemeta [--node <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 ### deleteobjects
Usage: `deleteobjects [--obj <object>] [--items [item]] [--p1 x y z] [--p2 x y z] [--invert]` Usage: `deleteobjects [--obj <object>] [--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! # Danger Zone!
### `deletemeta`
**Usage:** `deletemeta [--searchnode <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` ### `setmetavar`
**Usage:** `setmetavar [--searchnode <searchnode>] [--p1 x y z] [--p2 x y z] [--invert] <metakey> <metavalue>` **Usage:** `setmetavar [--searchnode <searchnode>] [--p1 x y z] [--p2 x y z] [--invert] <metakey> <metavalue>`

View File

@ -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."
}
}

View File

@ -76,15 +76,15 @@ fn delete_objects(inst: &mut InstBundle) {
let mut block = unwrap_or!(MapBlock::deserialize(&data), continue); let mut block = unwrap_or!(MapBlock::deserialize(&data), continue);
let mut modified = false; 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( if can_delete(
&block.static_objects.list[i], &block.static_objects[i],
&inst.args.area, &inst.args.area,
inst.args.invert, inst.args.invert,
&search_obj, &search_obj,
&item_searcher &item_searcher
) { ) {
block.static_objects.list.remove(i); block.static_objects.remove(i);
modified = true; modified = true;
count += 1; count += 1;
} }

View File

@ -40,7 +40,6 @@ fn delete_timers(inst: &mut InstBundle) {
continue; continue;
} }
} }
if let Some(id) = node_id { if let Some(id) = node_id {
if node_data.nodes[pos_idx as usize] != id { if node_data.nodes[pos_idx as usize] != id {
continue; continue;

View File

@ -4,6 +4,7 @@ use crate::instance::{ArgType, InstArgs, InstBundle};
mod clone; mod clone;
mod delete_blocks; mod delete_blocks;
mod delete_metadata;
mod delete_objects; mod delete_objects;
mod delete_timers; mod delete_timers;
mod fill; mod fill;
@ -31,6 +32,7 @@ pub fn get_commands() -> BTreeMap<&'static str, Command> {
new_cmd!("clone", clone); new_cmd!("clone", clone);
new_cmd!("deleteblocks", delete_blocks); new_cmd!("deleteblocks", delete_blocks);
new_cmd!("deletemeta", delete_metadata);
new_cmd!("deleteobjects", delete_objects); new_cmd!("deleteobjects", delete_objects);
new_cmd!("deletetimers", delete_timers); new_cmd!("deletetimers", delete_timers);
new_cmd!("fill", fill); new_cmd!("fill", fill);

View File

@ -1,12 +1,9 @@
use std::io::Cursor; use super::*;
use std::io::prelude::*;
use flate2::write::ZlibEncoder; use flate2::write::ZlibEncoder;
use flate2::read::ZlibDecoder; use flate2::read::ZlibDecoder;
use flate2::Compression; use flate2::Compression;
use super::MapBlockError;
pub trait Compress { pub trait Compress {
fn compress(&self, dst: &mut Cursor<Vec<u8>>); fn compress(&self, dst: &mut Cursor<Vec<u8>>);

View File

@ -1,7 +1,5 @@
use super::*; use super::*;
use super::node_timer::{serialize_timers, deserialize_timers};
const MIN_BLOCK_VER: u8 = 25; const MIN_BLOCK_VER: u8 = 25;
const MAX_BLOCK_VER: u8 = 28; const MAX_BLOCK_VER: u8 = 28;
@ -27,7 +25,7 @@ pub struct MapBlock {
pub static_objects: StaticObjectList, pub static_objects: StaticObjectList,
pub timestamp: u32, pub timestamp: u32,
pub nimap: NameIdMap, pub nimap: NameIdMap,
pub node_timers: Vec<NodeTimer> pub node_timers: NodeTimerList
} }
impl MapBlock { impl MapBlock {
@ -60,7 +58,7 @@ impl MapBlock {
// Node metadata // Node metadata
let metadata = ZlibContainer::read(&mut data)?; let metadata = ZlibContainer::read(&mut data)?;
// Static objects // Static objects
let static_objects = StaticObjectList::deserialize(&mut data)?; let static_objects = deserialize_objects(&mut data)?;
// Timestamp // Timestamp
let timestamp = data.read_u32::<BigEndian>()?; let timestamp = data.read_u32::<BigEndian>()?;
// Name-ID mappings // Name-ID mappings
@ -109,7 +107,7 @@ impl MapBlock {
// Node metadata // Node metadata
self.metadata.write(&mut data); self.metadata.write(&mut data);
// Static objects // Static objects
self.static_objects.serialize(&mut data); serialize_objects(&self.static_objects, &mut data);
// Timestamp // Timestamp
data.write_u32::<BigEndian>(self.timestamp).unwrap(); data.write_u32::<BigEndian>(self.timestamp).unwrap();
// Name-ID mappings // Name-ID mappings

View File

@ -1,12 +1,8 @@
use std::io::prelude::*;
use std::io::Cursor;
use std::collections::HashMap; use std::collections::HashMap;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use memmem::{Searcher, TwoWaySearcher}; use memmem::{Searcher, TwoWaySearcher};
use super::{MapBlockError, read_string16, write_string16, read_string32, use super::*;
write_string32, vec_with_len};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -63,6 +59,8 @@ impl NodeMetadata {
#[derive(Debug)] #[derive(Debug)]
pub struct NodeMetadataList { 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<u16, NodeMetadata> pub list: HashMap<u16, NodeMetadata>
} }

View File

@ -1,7 +1,6 @@
use std::io::prelude::*; use std::io::prelude::*;
use std::io::Cursor; use std::io::Cursor;
use byteorder::{ByteOrder, BigEndian, ReadBytesExt, WriteBytesExt};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
mod map_block; mod map_block;
mod compression; mod compression;
@ -13,10 +12,13 @@ mod name_id_map;
pub use map_block::{MapBlock, is_valid_generated}; pub use map_block::{MapBlock, is_valid_generated};
pub use compression::ZlibContainer; pub use compression::ZlibContainer;
use compression::Compress;
pub use node_data::NodeData; pub use node_data::NodeData;
pub use metadata::NodeMetadataList; pub use metadata::NodeMetadataList;
pub use static_object::{StaticObject, StaticObjectList, LuaEntityData}; pub use static_object::{StaticObject, StaticObjectList, LuaEntityData};
use static_object::{serialize_objects, deserialize_objects};
pub use node_timer::{NodeTimer, NodeTimerList}; pub use node_timer::{NodeTimer, NodeTimerList};
use node_timer::{serialize_timers, deserialize_timers};
pub use name_id_map::NameIdMap; pub use name_id_map::NameIdMap;

View File

@ -1,14 +1,8 @@
use std::io::Cursor;
use std::io::prelude::*;
use flate2::write::ZlibEncoder; use flate2::write::ZlibEncoder;
use flate2::read::ZlibDecoder; use flate2::read::ZlibDecoder;
use flate2::Compression; use flate2::Compression;
use byteorder::{ByteOrder, BigEndian}; use super::*;
use super::{MapBlockError, vec_with_len};
use super::compression::Compress;
const BLOCK_SIZE: usize = 16; const BLOCK_SIZE: usize = 16;

View File

@ -31,35 +31,33 @@ impl StaticObject {
} }
#[derive(Debug)] pub type StaticObjectList = Vec<StaticObject>;
pub struct StaticObjectList {
pub list: Vec<StaticObject>
}
impl StaticObjectList {
pub fn deserialize(src: &mut Cursor<&[u8]>)
-> Result<Self, MapBlockError>
{
let version = src.read_u8()?;
if version != 0 {
return Err(MapBlockError::Other);
}
let count = src.read_u16::<BigEndian>()?; pub fn deserialize_objects(src: &mut Cursor<&[u8]>)
let mut list = Vec::with_capacity(count as usize); -> Result<StaticObjectList, MapBlockError>
for _ in 0 .. count { {
list.push(StaticObject::deserialize(src)?); let version = src.read_u8()?;
} if version != 0 {
return Err(MapBlockError::Other);
Ok(Self {list})
} }
pub fn serialize(&self, dst: &mut Cursor<Vec<u8>>) { let count = src.read_u16::<BigEndian>()?;
dst.write_u8(0).unwrap(); let mut list = Vec::with_capacity(count as usize);
dst.write_u16::<BigEndian>(self.list.len() as u16).unwrap(); for _ in 0 .. count {
for obj in &self.list { list.push(StaticObject::deserialize(src)?);
obj.serialize(dst); }
}
Ok(list)
}
pub fn serialize_objects(objects: &StaticObjectList, dst: &mut Cursor<Vec<u8>>)
{
dst.write_u8(0).unwrap();
dst.write_u16::<BigEndian>(objects.len() as u16).unwrap();
for obj in objects {
obj.serialize(dst);
} }
} }