mostly working deletetimers

master
random-geek 2021-01-22 14:44:58 -08:00
parent 48502d81c9
commit 2a7b9705d0
6 changed files with 133 additions and 50 deletions

View File

@ -1,5 +1,6 @@
use super::Command; use super::Command;
use crate::unwrap_or;
use crate::spatial::Area; use crate::spatial::Area;
use crate::instance::{ArgType, InstBundle}; use crate::instance::{ArgType, InstBundle};
use crate::map_block::{MapBlock, StaticObject, LuaEntityData}; use crate::map_block::{MapBlock, StaticObject, LuaEntityData};
@ -7,20 +8,9 @@ use crate::utils::{query_keys, fmt_big_num};
use memmem::{Searcher, TwoWaySearcher}; use memmem::{Searcher, TwoWaySearcher};
const ITEM_ENT_NAME: &[u8] = b"__builtin:item"; const ITEM_ENT_NAME: &[u8] = b"__builtin:item";
macro_rules! unwrap_or {
($res:expr, $alt:expr) => {
match $res {
Ok(val) => val,
Err(_) => $alt
}
}
}
#[inline] #[inline]
fn can_delete( fn can_delete(
obj: &StaticObject, obj: &StaticObject,
@ -118,9 +108,11 @@ pub fn get_command() -> Command {
(ArgType::Area(false), "Area in which to delete objects"), (ArgType::Area(false), "Area in which to delete objects"),
(ArgType::Invert, "Delete all objects outside the area"), (ArgType::Invert, "Delete all objects outside the area"),
(ArgType::Object(false), (ArgType::Object(false),
"Name of object (or item with --item) to search for."), "Name of object to delete. If not specified, all objects will \
be deleted"),
(ArgType::Items, (ArgType::Items,
"Delete dropped items using object name as item name."), "Delete item entities. Optionally specify an item name to \
delete."),
], ],
help: "Delete certain objects (entities)." help: "Delete certain objects (entities)."
} }

View File

@ -0,0 +1,79 @@
use super::Command;
use crate::unwrap_or;
use crate::spatial::Vec3;
use crate::instance::{ArgType, InstBundle};
use crate::map_block::MapBlock;
use crate::utils::{query_keys, fmt_big_num};
fn delete_timers(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_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 node_data = block.node_data.get_ref();
let block_corner = Vec3::from_block_key(key) * 16;
let mut modified = false;
for i in (0..block.node_timers.len()).rev() {
let pos_idx = block.node_timers[i].pos;
let pos = Vec3::from_u16_key(pos_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[pos_idx as usize] != id {
continue;
}
}
block.node_timers.remove(i);
count += 1;
modified = true;
}
if modified {
inst.db.set_block(key, &block.serialize()).unwrap();
}
}
inst.status.end_editing();
inst.status.log_info(
format!("Deleted {} node timers.", fmt_big_num(count)));
}
pub fn get_command() -> Command {
Command {
func: delete_timers,
verify_args: None,
args: vec![
(ArgType::Area(false), "Area in which to delete timers"),
(ArgType::Invert, "Delete all timers outside the given area."),
(ArgType::Node(false),
"Node to delete timers from. If not specified, all node \
timers will be deleted.")
],
help: "Delete node timers."
}
}

View File

@ -5,6 +5,7 @@ use crate::instance::{ArgType, InstArgs, InstBundle};
mod clone; mod clone;
mod delete_blocks; mod delete_blocks;
mod delete_objects; mod delete_objects;
mod delete_timers;
mod fill; mod fill;
mod overlay; mod overlay;
mod replace_nodes; mod replace_nodes;
@ -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!("deleteobjects", delete_objects); new_cmd!("deleteobjects", delete_objects);
new_cmd!("deletetimers", delete_timers);
new_cmd!("fill", fill); new_cmd!("fill", fill);
new_cmd!("replacenodes", replace_nodes); new_cmd!("replacenodes", replace_nodes);
new_cmd!("overlay", overlay); new_cmd!("overlay", overlay);

View File

@ -1,5 +1,7 @@
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;
@ -25,7 +27,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: NodeTimerList pub node_timers: Vec<NodeTimer>
} }
impl MapBlock { impl MapBlock {
@ -64,7 +66,7 @@ impl MapBlock {
// Name-ID mappings // Name-ID mappings
let nimap = NameIdMap::deserialize(&mut data)?; let nimap = NameIdMap::deserialize(&mut data)?;
// Node timers // Node timers
let node_timers = NodeTimerList::deserialize(&mut data)?; let node_timers = deserialize_timers(&mut data)?;
Ok(Self { Ok(Self {
version, version,
@ -113,7 +115,7 @@ impl MapBlock {
// Name-ID mappings // Name-ID mappings
self.nimap.serialize(&mut data); self.nimap.serialize(&mut data);
// Node timers // Node timers
self.node_timers.serialize(&mut data); serialize_timers(&self.node_timers, &mut data);
buf = data.into_inner(); buf = data.into_inner();
buf.shrink_to_fit(); buf.shrink_to_fit();

View File

@ -3,47 +3,44 @@ use super::*;
#[derive(Debug)] #[derive(Debug)]
pub struct NodeTimer { pub struct NodeTimer {
pos: u16, pub pos: u16,
timeout: u32, pub timeout: u32,
elapsed: u32 pub elapsed: u32
} }
#[derive(Debug)] pub type NodeTimerList = Vec<NodeTimer>;
pub struct NodeTimerList {
timers: Vec<NodeTimer>
}
impl NodeTimerList {
pub fn deserialize(data: &mut Cursor<&[u8]>)
-> Result<Self, MapBlockError>
{
let data_len = data.read_u8()?;
if data_len != 10 {
return Err(MapBlockError::Other);
}
let count = data.read_u16::<BigEndian>()?; pub fn deserialize_timers(src: &mut Cursor<&[u8]>)
let mut timers = Vec::with_capacity(count as usize); -> Result<NodeTimerList, MapBlockError>
{
for _ in 0 .. count { let data_len = src.read_u8()?;
let pos = data.read_u16::<BigEndian>()?; if data_len != 10 {
let timeout = data.read_u32::<BigEndian>()?; return Err(MapBlockError::Other);
let elapsed = data.read_u32::<BigEndian>()?;
timers.push(NodeTimer {pos, timeout, elapsed});
}
Ok(NodeTimerList {timers})
} }
pub fn serialize(&self, data: &mut Cursor<Vec<u8>>) { let count = src.read_u16::<BigEndian>()?;
data.write_u8(10).unwrap(); let mut timers = Vec::with_capacity(count as usize);
data.write_u16::<BigEndian>(self.timers.len() as u16).unwrap();
for t in &self.timers { for _ in 0 .. count {
data.write_u16::<BigEndian>(t.pos).unwrap(); let pos = src.read_u16::<BigEndian>()?;
data.write_u32::<BigEndian>(t.timeout).unwrap(); let timeout = src.read_u32::<BigEndian>()?;
data.write_u32::<BigEndian>(t.elapsed).unwrap(); let elapsed = src.read_u32::<BigEndian>()?;
} timers.push(NodeTimer {pos, timeout, elapsed});
}
Ok(timers)
}
pub fn serialize_timers(timers: &NodeTimerList, dst: &mut Cursor<Vec<u8>>) {
dst.write_u8(10).unwrap();
dst.write_u16::<BigEndian>(timers.len() as u16).unwrap();
for t in timers {
dst.write_u16::<BigEndian>(t.pos).unwrap();
dst.write_u32::<BigEndian>(t.timeout).unwrap();
dst.write_u32::<BigEndian>(t.elapsed).unwrap();
} }
} }

View File

@ -67,6 +67,17 @@ pub fn query_keys(
} }
#[macro_export]
macro_rules! unwrap_or {
($res:expr, $alt:expr) => {
match $res {
Ok(val) => val,
Err(_) => $alt
}
}
}
pub fn fmt_duration(dur: Duration) -> String { pub fn fmt_duration(dur: Duration) -> String {
let s = dur.as_secs(); let s = dur.as_secs();
if s < 3600 { if s < 3600 {