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
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
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!
### `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`
**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 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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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<Vec<u8>>);

View File

@ -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<NodeTimer>
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::<BigEndian>()?;
// 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::<BigEndian>(self.timestamp).unwrap();
// Name-ID mappings

View File

@ -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<u16, NodeMetadata>
}

View File

@ -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;

View File

@ -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;

View File

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