Completion Part 3
This commit is contained in:
parent
b1f3f66006
commit
b18b0e96cc
61
Manual.md
61
Manual.md
@ -50,6 +50,8 @@ WorldEdit `//fixlight` command.
|
||||
|
||||
## Commands
|
||||
|
||||
TODO: Unify documentation style, provide examples.
|
||||
|
||||
### clone
|
||||
|
||||
Usage: `clone --p1 x y z --p2 x y z --offset x y z`
|
||||
@ -59,9 +61,9 @@ Clone (copy) the contents of an area to a new location.
|
||||
Arguments:
|
||||
|
||||
- `--p1, --p2`: Area to clone.
|
||||
- `--offset`: Vector to shift the area by. For example, to copy an area 50
|
||||
nodes downward (negative Y direction), use `--offset 0 -50 0`. Directions may
|
||||
be determined using Minetest's F5 debug menu.
|
||||
- `--offset x y z`: Vector to shift the area by. For example, to copy an area
|
||||
50 nodes downward (negative Y direction), use `--offset 0 -50 0`. Directions
|
||||
may be determined using Minetest's F5 debug menu.
|
||||
|
||||
This command copies nodes, param1, param2, and metadata. Nothing will be copied
|
||||
from or into mapblocks that are not yet generated.
|
||||
@ -92,55 +94,57 @@ contents) are also deleted.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `--node`: (Optional) Name of node to delete metadata from. If not specified,
|
||||
metadata will be deleted from any node.
|
||||
- `--node <node>`: (Optional) Name of node to delete metadata from. If not
|
||||
specified, metadata will be deleted from any node.
|
||||
- `--p1, --p2`: (Optional) Area in which to delete metadata. If not specified,
|
||||
metadata will be deleted everywhere.
|
||||
- `--invert`: If present, delete metadata *outside* the given area.
|
||||
|
||||
### deleteobjects
|
||||
|
||||
Usage: `deleteobjects [--obj <object>] [--items [item]] [--p1 x y z] [--p2 x y z] [--invert]`
|
||||
Usage: `deleteobjects [--obj <object>] [--items [items]] [--p1 x y z] [--p2 x y z] [--invert]`
|
||||
|
||||
Delete objects/entities, including item entities (dropped items).
|
||||
Delete certain objects (entities) and/or item entities (dropped items).
|
||||
|
||||
Arguments:
|
||||
|
||||
- `--obj`: Name of object to delete, e.g. "boats:boat". If not specified,
|
||||
all objects will be deleted.
|
||||
- `--items [item]`: Delete item entities (dropped items). If an optional item
|
||||
name is specified, only items with that name will be deleted.
|
||||
- `--p1, --p2`: Area in which to delete objects. If not specified, objects will
|
||||
be deleted everywhere.
|
||||
- `--invert`: Delete objects *outside* the given area.
|
||||
- `--obj <object>`: (Optional) Name of object to delete, e.g. "boats:boat".
|
||||
- `--items [items]`: If present, delete only item entities (dropped items). If
|
||||
one or more item names are listed after `--items`, only those items will be
|
||||
deleted.
|
||||
- `--p1, --p2`: (Optional) Area in which to delete objects. If not specified,
|
||||
objects will be deleted everywhere.
|
||||
- `--invert`: If present, delete objects *outside* the given area.
|
||||
|
||||
`--obj` and `--items` cannot be used simultaneously.
|
||||
|
||||
### deletetimers
|
||||
|
||||
Usage: `deletetimers [--node <node>] [--p1 x y z] [--p2 x y z] [--invert]`
|
||||
|
||||
Delete node timers of a certain node and/or within a certain area.
|
||||
Delete node timers of certain nodes.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `--node`: Name of node to modify. If not specified, the node timers of all
|
||||
nodes will be deleted.
|
||||
- `--p1, --p2`: Area in which to delete node timers.
|
||||
- `--invert`: Only delete node timers *outside* the given area.
|
||||
- `--node <node>`: If specified, only delete node timers from nodes with the
|
||||
given name.
|
||||
- `--p1, --p2`: (Optional) Area in which to delete node timers.
|
||||
- `--invert`: Delete node timers *outside* the given area.
|
||||
|
||||
### fill
|
||||
|
||||
Usage: `fill --p1 x y z --p2 x y z [--invert] <new_node>`
|
||||
|
||||
Fills the given area with one node. The affected mapblocks must be already
|
||||
generated for fill to work.
|
||||
Fills everything inside or outside an area with one node. Mapblocks that are
|
||||
not yet generated will not be affected.
|
||||
|
||||
This command does not affect param2, node metadata, etc.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `new_node`: Name of node to fill the area with.
|
||||
- `--p1, --p2`: Area to fill.
|
||||
- `--invert`: Fill everything *outside* the given area.
|
||||
- `--invert`: Fill all generated nodes *outside* the given area.
|
||||
- `<new_node>`: Name of node to fill the area with.
|
||||
|
||||
### overlay
|
||||
|
||||
@ -150,12 +154,12 @@ Copy part or all of a source map into the main map.
|
||||
|
||||
Arguments:
|
||||
|
||||
- `input_map`: Path to source map/world. This will not be modified.
|
||||
- `<input_map>`: Path to the source map/world. This world will not be modified.
|
||||
- `--p1, --p2`: Area to copy from. If not specified, MapEditr will try to
|
||||
copy everything from the input map file.
|
||||
copy everything from the source map.
|
||||
- `--invert`: If present, copy everything *outside* the given area.
|
||||
- `--offset`: Offset to move nodes by when copying; default is no offset.
|
||||
Currently, an offset cannot be used with an inverted selection.
|
||||
- `--offset x y z`: Vector to shift nodes by when copying; default is no
|
||||
offset. Currently, an offset cannot be used with an inverted selection.
|
||||
|
||||
This command will always copy nodes, param1, param2, and metadata. If no
|
||||
offset is used, objects/entities and node timers may also be copied.
|
||||
@ -168,8 +172,7 @@ mapblocks can be copied verbatim.
|
||||
|
||||
### replaceininv
|
||||
|
||||
Usage: `replaceininv [--delete] [--deletemeta] [--nodes <nodes>] [--p1 x y z]
|
||||
[--p2 x y z] [--invert] <item> [new_item]`
|
||||
Usage: `replaceininv [--delete] [--deletemeta] [--nodes <nodes>] [--p1 x y z] [--p2 x y z] [--invert] <item> [new_item]`
|
||||
|
||||
Replace or delete certain items in node inventories.
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
// TODO: Move this file somewhere else?
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::map_block::{MapBlock, NodeMetadataList};
|
||||
use crate::map_block::{MapBlock, NodeMetadataList, NameIdMap};
|
||||
use crate::spatial::{Vec3, Area};
|
||||
|
||||
|
||||
@ -81,7 +80,7 @@ pub fn merge_metadata(
|
||||
// Warning: diff can be negative!
|
||||
let diff = offset.x + offset.y * 16 + offset.z * 256;
|
||||
|
||||
// Delete any existing metadata in the destination block
|
||||
// Delete any existing metadata in the destination area.
|
||||
let mut to_delete = Vec::with_capacity(dst_meta.len());
|
||||
for (&idx, _) in dst_meta.iter() {
|
||||
let pos = Vec3::from_u16_key(idx);
|
||||
@ -115,27 +114,26 @@ pub fn clean_name_id_map(block: &mut MapBlock) {
|
||||
}
|
||||
|
||||
// Rebuild the name-ID map.
|
||||
let mut new_nimap = BTreeMap::new();
|
||||
let mut map = vec![0u16; id_count];
|
||||
for id in 0..id_count {
|
||||
let mut new_nimap = NameIdMap(BTreeMap::new());
|
||||
let mut map = vec![0u16; id_count]; // map[old_node_id] == new_node_id
|
||||
for (&id, name) in &block.nimap.0 {
|
||||
// Skip unused IDs.
|
||||
if !used[id] {
|
||||
if !used[id as usize] {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = &block.nimap.0[&(id as u16)];
|
||||
if let Some(first_id) = new_nimap.iter().position(|(_, v)| v == name) {
|
||||
if let Some(first_id) = new_nimap.get_id(&name) {
|
||||
// Name is already in the map; map old, duplicate ID to the
|
||||
// existing ID.
|
||||
map[id] = first_id as u16;
|
||||
map[id as usize] = first_id as u16;
|
||||
} else {
|
||||
// Name is not yet in the map; assign it to the next ID.
|
||||
new_nimap.insert(new_nimap.len() as u16, name.clone());
|
||||
new_nimap.0.insert(new_nimap.0.len() as u16, name.clone());
|
||||
// Map old ID to newly-inserted ID.
|
||||
map[id] = new_nimap.len() as u16 - 1;
|
||||
map[id as usize] = new_nimap.0.len() as u16 - 1;
|
||||
}
|
||||
}
|
||||
block.nimap.0 = new_nimap;
|
||||
block.nimap = new_nimap;
|
||||
|
||||
// Re-assign node IDs.
|
||||
for id in &mut nd.nodes {
|
||||
|
@ -92,8 +92,7 @@ fn to_cmd_line_args<'a>(tup: &(ArgType, &'a str))
|
||||
ArgType::Items =>
|
||||
Arg::with_name("items")
|
||||
.long("items")
|
||||
.min_values(0)
|
||||
.max_values(1),
|
||||
.min_values(0),
|
||||
ArgType::NewItem =>
|
||||
Arg::with_name("new_item")
|
||||
.takes_value(true),
|
||||
@ -252,6 +251,7 @@ fn print_log(log_type: LogType, msg: String) {
|
||||
|
||||
fn get_confirmation() -> bool {
|
||||
print!("Proceed? (Y/n): ");
|
||||
std::io::stdout().flush().unwrap();
|
||||
let mut result = String::new();
|
||||
std::io::stdin().read_line(&mut result).unwrap();
|
||||
result.trim().to_ascii_lowercase() == "y"
|
||||
|
@ -1,48 +1,77 @@
|
||||
use super::Command;
|
||||
use super::{Command, ArgResult};
|
||||
|
||||
use crate::unwrap_or;
|
||||
use crate::spatial::Area;
|
||||
use crate::instance::{ArgType, InstBundle};
|
||||
use crate::instance::{ArgType, InstArgs, InstBundle};
|
||||
use crate::map_block::{MapBlock, StaticObject, LuaEntityData};
|
||||
use crate::utils::{query_keys, to_bytes, to_slice, fmt_big_num};
|
||||
|
||||
use memmem::{Searcher, TwoWaySearcher};
|
||||
|
||||
const ITEM_ENT_NAME: &[u8] = b"__builtin:item";
|
||||
const ITEM_NAME_PAT: &[u8] = b"[\"itemstring\"] = \"";
|
||||
|
||||
|
||||
fn verify_args(args: &InstArgs) -> ArgResult {
|
||||
if args.object.is_some() && args.items.is_some() {
|
||||
return ArgResult::error("Cannot use both --obj and --items.");
|
||||
}
|
||||
ArgResult::Ok
|
||||
}
|
||||
|
||||
|
||||
#[inline]
|
||||
fn get_item_name<'a>(data: &'a [u8], searcher: &TwoWaySearcher) -> &'a[u8] {
|
||||
if data.starts_with(b"return") {
|
||||
if let Some(idx) = searcher.search_in(data) {
|
||||
let name = &data[idx + ITEM_NAME_PAT.len()..]
|
||||
.split(|&c| c == b' ' || c == b'"').next();
|
||||
if let Some(n) = name {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
b""
|
||||
} else {
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn can_delete(
|
||||
obj: &StaticObject,
|
||||
area: &Option<Area>,
|
||||
invert: bool,
|
||||
obj_name: &Option<Vec<u8>>,
|
||||
item_searcher: &Option<TwoWaySearcher>
|
||||
item_names: &[Vec<u8>],
|
||||
item_name_searcher: &TwoWaySearcher
|
||||
) -> bool {
|
||||
// Check area requirement
|
||||
if let Some(a) = area {
|
||||
const DIV_FAC: i32 = 10_000;
|
||||
let rounded_pos = obj.f_pos.map(
|
||||
|v| (v - DIV_FAC / 2).div_euclid(DIV_FAC));
|
||||
let rounded_pos = obj.f_pos
|
||||
.map(|v| (v + DIV_FAC / 2).div_euclid(DIV_FAC));
|
||||
if a.contains(rounded_pos) == invert {
|
||||
return false; // Object not included in area.
|
||||
}
|
||||
}
|
||||
|
||||
// Check name requirement
|
||||
if let Some(n) = obj_name {
|
||||
// Check name requirements
|
||||
if let Some(name) = obj_name {
|
||||
if let Ok(le_data) = LuaEntityData::deserialize(obj) {
|
||||
if &le_data.name != n {
|
||||
if &le_data.name != name {
|
||||
return false; // Object name does not match.
|
||||
}
|
||||
|
||||
if let Some(is) = item_searcher {
|
||||
if is.search_in(&le_data.data).is_none() {
|
||||
return false; // Item entity name does not match.
|
||||
if !item_names.is_empty() {
|
||||
let item_name =
|
||||
get_item_name(&le_data.data, &item_name_searcher);
|
||||
if !item_names.iter().any(|n| n == item_name) {
|
||||
// Item entity's item name does not match.
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false; // Unsupported object type, don't delete it.
|
||||
return false; // Keep invalid or unsupported objects.
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,20 +80,18 @@ fn can_delete(
|
||||
|
||||
|
||||
fn delete_objects(inst: &mut InstBundle) {
|
||||
let search_obj = if inst.args.items.is_some() {
|
||||
let obj_name = if inst.args.items.is_some() {
|
||||
Some(ITEM_ENT_NAME.to_owned())
|
||||
} else {
|
||||
inst.args.object.as_ref().map(to_bytes)
|
||||
};
|
||||
|
||||
// search_item will be Some if (1) item search is enabled and (2) an item
|
||||
// is specified.
|
||||
let search_item = inst.args.items.as_ref().and_then(|items| items.get(0))
|
||||
.map(to_bytes);
|
||||
let item_searcher = search_item.as_ref().map(|s| TwoWaySearcher::new(s));
|
||||
let item_names: Vec<_> = inst.args.items.as_ref().unwrap_or(&Vec::new())
|
||||
.iter().map(to_bytes).collect();
|
||||
let item_name_searcher = TwoWaySearcher::new(ITEM_NAME_PAT);
|
||||
|
||||
let keys = query_keys(&mut inst.db, &mut inst.status,
|
||||
to_slice(&search_obj), inst.args.area, inst.args.invert, true);
|
||||
to_slice(&obj_name), inst.args.area, inst.args.invert, true);
|
||||
|
||||
inst.status.begin_editing();
|
||||
let mut count: u64 = 0;
|
||||
@ -75,13 +102,14 @@ fn delete_objects(inst: &mut InstBundle) {
|
||||
{ inst.status.inc_failed(); continue; });
|
||||
|
||||
let mut modified = false;
|
||||
for i in (0..block.static_objects.len()).rev() {
|
||||
for i in (0 .. block.static_objects.len()).rev() {
|
||||
if can_delete(
|
||||
&block.static_objects[i],
|
||||
&inst.args.area,
|
||||
inst.args.invert,
|
||||
&search_obj,
|
||||
&item_searcher
|
||||
&obj_name,
|
||||
&item_names,
|
||||
&item_name_searcher
|
||||
) {
|
||||
block.static_objects.remove(i);
|
||||
modified = true;
|
||||
@ -102,17 +130,38 @@ fn delete_objects(inst: &mut InstBundle) {
|
||||
pub fn get_command() -> Command {
|
||||
Command {
|
||||
func: delete_objects,
|
||||
verify_args: None,
|
||||
verify_args: Some(verify_args),
|
||||
args: vec![
|
||||
(ArgType::Area(false), "Area in which to delete objects"),
|
||||
(ArgType::Invert, "Delete all objects outside the area"),
|
||||
(ArgType::Object,
|
||||
"Name of object to delete. If not specified, all objects will \
|
||||
be deleted"),
|
||||
(ArgType::Invert,
|
||||
"If present, delete objects *outside* the given area."),
|
||||
(ArgType::Object, "Name of object to delete"),
|
||||
(ArgType::Items,
|
||||
"Delete item entities. Optionally specify an item name to \
|
||||
delete."),
|
||||
"If present, delete item entities. Optionally list one or \
|
||||
more item names after `--items` to delete only those items."),
|
||||
],
|
||||
help: "Delete certain objects (entities)."
|
||||
help: "Delete certain objects and/or item entities."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_delete_objects() {
|
||||
let searcher = TwoWaySearcher::new(ITEM_NAME_PAT);
|
||||
let pairs: &[(&[u8], &[u8])] = &[
|
||||
(b"default:glass", b"default:glass"),
|
||||
(b"return {}", b""),
|
||||
(b"return {[\"itemstring\"] = \"\", [\"age\"] = 100}", b""),
|
||||
(b"return {[\"itemstring\"] = \"mod:item\"}", b"mod:item"),
|
||||
(b"return {[\"age\"] = 400, [\"itemstring\"] = \"one:two 99 32\"}",
|
||||
b"one:two"),
|
||||
];
|
||||
for &(data, name) in pairs {
|
||||
assert_eq!(get_item_name(data, &searcher), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ fn delete_timers(inst: &mut InstBundle) {
|
||||
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 mut block = unwrap_or!(MapBlock::deserialize(&data),
|
||||
{ inst.status.inc_failed(); continue; });
|
||||
|
||||
let node_id = node.as_deref().and_then(|n| block.nimap.get_id(n));
|
||||
if node.is_some() && node_id.is_none() {
|
||||
@ -68,11 +69,11 @@ pub fn get_command() -> Command {
|
||||
verify_args: None,
|
||||
args: vec![
|
||||
(ArgType::Area(false), "Area in which to delete timers"),
|
||||
(ArgType::Invert, "Delete all timers outside the given area."),
|
||||
(ArgType::Invert, "Delete node timers *outside* the given area."),
|
||||
(ArgType::Node(false),
|
||||
"Node to delete timers from. If not specified, all node \
|
||||
timers will be deleted.")
|
||||
"Node to delete timers from. If not specified, node timers \
|
||||
will be deleted from any node.")
|
||||
],
|
||||
help: "Delete node timers."
|
||||
help: "Delete node timers of certain nodes."
|
||||
}
|
||||
}
|
||||
|
@ -44,10 +44,8 @@ fn fill(inst: &mut InstBundle) {
|
||||
|
||||
let pos = Vec3::from_block_key(key);
|
||||
let data = inst.db.get_block(key).unwrap();
|
||||
let mut block = unwrap_or!(MapBlock::deserialize(&data), {
|
||||
inst.status.inc_failed();
|
||||
continue;
|
||||
});
|
||||
let mut block = unwrap_or!(MapBlock::deserialize(&data),
|
||||
{ inst.status.inc_failed(); continue; });
|
||||
|
||||
if area.contains_block(pos) != area.touches_block(pos) {
|
||||
// Fill part of block
|
||||
@ -82,8 +80,9 @@ pub fn get_command() -> Command {
|
||||
verify_args: None,
|
||||
args: vec![
|
||||
(ArgType::Area(true), "Area to fill"),
|
||||
(ArgType::NewNode, "Name of node to fill area with"),
|
||||
(ArgType::Invert, "Fill all generated areas outside the area.")
|
||||
(ArgType::Invert,
|
||||
"Fill all generated nodes *outside* the given area."),
|
||||
(ArgType::NewNode, "Name of node to fill the area with"),
|
||||
],
|
||||
help: "Fill the entire area with one node."
|
||||
}
|
||||
|
@ -167,8 +167,9 @@ fn overlay_with_offset(inst: &mut InstBundle) {
|
||||
);
|
||||
|
||||
let dst_part_abs = dst_area.map_or(
|
||||
// If no area is given, the destination part is the whole mapblock.
|
||||
Area::new(dst_pos * 16, dst_pos * 16 + 15),
|
||||
|ref a| a.abs_block_overlap(dst_pos).unwrap()
|
||||
|a| a.abs_block_overlap(dst_pos).unwrap()
|
||||
);
|
||||
let src_part_abs = dst_part_abs - offset;
|
||||
let src_blocks_needed = src_part_abs.to_touching_block_area();
|
||||
@ -224,11 +225,13 @@ pub fn get_command() -> Command {
|
||||
func: overlay,
|
||||
verify_args: Some(verify_args),
|
||||
args: vec![
|
||||
(ArgType::InputMapPath, "Path to input map file"),
|
||||
(ArgType::Area(false), "Area to overlay"),
|
||||
(ArgType::Invert, "Overlay all nodes outside the given area"),
|
||||
(ArgType::Offset(false), "Vector to offset nodes by"),
|
||||
(ArgType::InputMapPath, "Path to the source map/world"),
|
||||
(ArgType::Area(false), "Area to copy from. If not specified, \
|
||||
everything from the source map will be copied."),
|
||||
(ArgType::Invert,
|
||||
"If present, copy everything *outside* the given area."),
|
||||
(ArgType::Offset(false), "Vector to shift nodes by when copying"),
|
||||
],
|
||||
help: "Copy part or all of one world/map into another."
|
||||
help: "Copy part or all of a source map into the main map."
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,8 @@ fn replace_in_inv(inst: &mut InstBundle) {
|
||||
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 mut block = unwrap_or!(MapBlock::deserialize(&data),
|
||||
{ inst.status.inc_failed(); continue; });
|
||||
|
||||
let node_data = block.node_data.get_ref();
|
||||
let node_ids: Vec<_> = nodes.iter()
|
||||
@ -89,7 +90,8 @@ fn replace_in_inv(inst: &mut InstBundle) {
|
||||
}
|
||||
|
||||
let mut meta = unwrap_or!(
|
||||
NodeMetadataList::deserialize(block.metadata.get_ref()), continue);
|
||||
NodeMetadataList::deserialize(block.metadata.get_ref()),
|
||||
{ inst.status.inc_failed(); continue; });
|
||||
|
||||
let block_corner = Vec3::from_block_key(key) * 16;
|
||||
let mut modified = false;
|
||||
|
@ -8,7 +8,7 @@ use crate::utils::{query_keys, to_bytes, fmt_big_num};
|
||||
|
||||
|
||||
fn set_meta_var(inst: &mut InstBundle) {
|
||||
// TODO: Bytes input
|
||||
// TODO: Bytes input, create/delete variables
|
||||
let key = to_bytes(inst.args.key.as_ref().unwrap());
|
||||
let value = to_bytes(inst.args.value.as_ref().unwrap());
|
||||
let nodes: Vec<_> = inst.args.nodes.iter().map(to_bytes).collect();
|
||||
@ -22,7 +22,8 @@ fn set_meta_var(inst: &mut InstBundle) {
|
||||
for block_key in keys {
|
||||
inst.status.inc_done();
|
||||
let data = inst.db.get_block(block_key).unwrap();
|
||||
let mut block = unwrap_or!(MapBlock::deserialize(&data), continue);
|
||||
let mut block = unwrap_or!(MapBlock::deserialize(&data),
|
||||
{ inst.status.inc_failed(); continue; });
|
||||
|
||||
let node_data = block.node_data.get_ref();
|
||||
let node_ids: Vec<_> = nodes.iter()
|
||||
@ -32,7 +33,8 @@ fn set_meta_var(inst: &mut InstBundle) {
|
||||
}
|
||||
|
||||
let mut meta = unwrap_or!(
|
||||
NodeMetadataList::deserialize(block.metadata.get_ref()), continue);
|
||||
NodeMetadataList::deserialize(block.metadata.get_ref()),
|
||||
{ inst.status.inc_failed(); continue; });
|
||||
|
||||
let block_corner = Vec3::from_block_key(block_key) * 16;
|
||||
let mut modified = false;
|
||||
|
@ -140,7 +140,6 @@ impl StatusServer {
|
||||
}
|
||||
|
||||
pub fn inc_failed(&mut self) {
|
||||
// TODO: Proper error handling for all commands.
|
||||
self.status.lock().unwrap().blocks_failed += 1;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ mod cmd_line;
|
||||
|
||||
|
||||
// TODO: Check for unnecessary #derives!
|
||||
// TODO: Check mapedit TODOs and implement what's needed.
|
||||
fn main() {
|
||||
// TODO: Add GUI. hmm...
|
||||
cmd_line::run_cmd_line();
|
||||
|
Loading…
x
Reference in New Issue
Block a user