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 crate::unwrap_or;
use crate::spatial::Area;
use crate::instance::{ArgType, InstBundle};
use crate::map_block::{MapBlock, StaticObject, LuaEntityData};
@ -7,20 +8,9 @@ use crate::utils::{query_keys, fmt_big_num};
use memmem::{Searcher, TwoWaySearcher};
const ITEM_ENT_NAME: &[u8] = b"__builtin:item";
macro_rules! unwrap_or {
($res:expr, $alt:expr) => {
match $res {
Ok(val) => val,
Err(_) => $alt
}
}
}
#[inline]
fn can_delete(
obj: &StaticObject,
@ -118,9 +108,11 @@ pub fn get_command() -> Command {
(ArgType::Area(false), "Area in which to delete objects"),
(ArgType::Invert, "Delete all objects outside the area"),
(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,
"Delete dropped items using object name as item name."),
"Delete item entities. Optionally specify an item name to \
delete."),
],
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 delete_blocks;
mod delete_objects;
mod delete_timers;
mod fill;
mod overlay;
mod replace_nodes;
@ -31,6 +32,7 @@ pub fn get_commands() -> BTreeMap<&'static str, Command> {
new_cmd!("clone", clone);
new_cmd!("deleteblocks", delete_blocks);
new_cmd!("deleteobjects", delete_objects);
new_cmd!("deletetimers", delete_timers);
new_cmd!("fill", fill);
new_cmd!("replacenodes", replace_nodes);
new_cmd!("overlay", overlay);

View File

@ -1,5 +1,7 @@
use super::*;
use super::node_timer::{serialize_timers, deserialize_timers};
const MIN_BLOCK_VER: u8 = 25;
const MAX_BLOCK_VER: u8 = 28;
@ -25,7 +27,7 @@ pub struct MapBlock {
pub static_objects: StaticObjectList,
pub timestamp: u32,
pub nimap: NameIdMap,
pub node_timers: NodeTimerList
pub node_timers: Vec<NodeTimer>
}
impl MapBlock {
@ -64,7 +66,7 @@ impl MapBlock {
// Name-ID mappings
let nimap = NameIdMap::deserialize(&mut data)?;
// Node timers
let node_timers = NodeTimerList::deserialize(&mut data)?;
let node_timers = deserialize_timers(&mut data)?;
Ok(Self {
version,
@ -113,7 +115,7 @@ impl MapBlock {
// Name-ID mappings
self.nimap.serialize(&mut data);
// Node timers
self.node_timers.serialize(&mut data);
serialize_timers(&self.node_timers, &mut data);
buf = data.into_inner();
buf.shrink_to_fit();

View File

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