I can never decide how to handle imports, arrg
parent
9528a11e1e
commit
7d9d95b8ed
27
Manual.md
27
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 <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>`
|
||||
|
|
|
@ -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."
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>>);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue