From c0a9f408a9ec16f4418d4e133d13cc38350fb4a8 Mon Sep 17 00:00:00 2001 From: Paul1365972 Date: Sun, 26 Nov 2023 22:53:42 +0100 Subject: [PATCH 1/5] Improve compile speed for large words --- crates/core/src/plot/mod.rs | 2 -- .../src/redpiler/passes/identify_nodes.rs | 24 +++++++++++++++---- crates/core/src/world/storage.rs | 7 +++++- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/crates/core/src/plot/mod.rs b/crates/core/src/plot/mod.rs index b76c6bca..b9b5e4ea 100644 --- a/crates/core/src/plot/mod.rs +++ b/crates/core/src/plot/mod.rs @@ -162,7 +162,6 @@ impl World for PlotWorld { ) } - /// Returns the block state id of the block at `pos` fn get_block_raw(&self, pos: BlockPos) -> u32 { let chunk_index = match self.get_chunk_index_for_block(pos.x, pos.z) { @@ -173,7 +172,6 @@ impl World for PlotWorld { chunk.get_block((pos.x & 0xF) as u32, pos.y as u32, (pos.z & 0xF) as u32) } - fn delete_block_entity(&mut self, pos: BlockPos) { let chunk_index = match self.get_chunk_index_for_block(pos.x, pos.z) { Some(idx) => idx, diff --git a/crates/core/src/redpiler/passes/identify_nodes.rs b/crates/core/src/redpiler/passes/identify_nodes.rs index 8de57b51..568ce0d7 100644 --- a/crates/core/src/redpiler/passes/identify_nodes.rs +++ b/crates/core/src/redpiler/passes/identify_nodes.rs @@ -32,11 +32,25 @@ impl Pass for IdentifyNodes { let start_pos = first_pos.min(second_pos); let end_pos = first_pos.max(second_pos); - for y in start_pos.y..=end_pos.y { - for z in start_pos.z..=end_pos.z { - for x in start_pos.x..=end_pos.x { - let pos = BlockPos::new(x, y, z); - for_pos(ignore_wires, plot, graph, pos); + + for chunk_z in (start_pos.z / 16)..=(end_pos.z / 16) { + for chunk_x in (start_pos.x / 16)..=(end_pos.x / 16) { + let chunk = plot.get_chunk(chunk_x, chunk_z).unwrap(); + for chunk_y in (start_pos.y / 16)..=(end_pos.y / 16) { + if chunk.sections[chunk_y as usize].block_count() > 0 { + for y in 0..=15 { + for z in 0..=15 { + for x in 0..=15 { + let pos = BlockPos::new( + chunk_x * 16 + x, + chunk_y * 16 + y, + chunk_z * 16 + z, + ); + for_pos(ignore_wires, plot, graph, pos); + } + } + } + } } } } diff --git a/crates/core/src/world/storage.rs b/crates/core/src/world/storage.rs index d4d6b06a..72179bbd 100644 --- a/crates/core/src/world/storage.rs +++ b/crates/core/src/world/storage.rs @@ -386,6 +386,10 @@ impl ChunkSection { } &self.multi_block } + + pub fn block_count(&self) -> u32 { + self.block_count + } } impl Default for ChunkSection { @@ -416,7 +420,8 @@ impl Chunk { pub fn encode_packet(&self) -> PacketEncoder { // Integer arithmetic trick: ceil(log2(x)) can be calculated with 32 - (x - 1).leading_zeros(). // See also: https://wiki.vg/Protocol#Chunk_Data_and_Update_Light - const HEIGHTMAP_BITS: u8 = (32 - ((PLOT_BLOCK_HEIGHT as u32 + 1) - 1).leading_zeros()) as u8; + const HEIGHTMAP_BITS: u8 = + (32 - ((PLOT_BLOCK_HEIGHT as u32 + 1) - 1).leading_zeros()) as u8; let mut heightmap_buffer = BitBuffer::create(HEIGHTMAP_BITS, 16 * 16); for x in 0..16 { for z in 0..16 { From f2e3aa305f55094f3aae1ba3bbfeeefa323ceece Mon Sep 17 00:00:00 2001 From: Paul1365972 Date: Mon, 27 Nov 2023 00:50:20 +0100 Subject: [PATCH 2/5] Improve WE commands - Improve //update performance - Allow for plot wide //update - Update after paste with //paste -u - Improve /rtps u[nlimited] ergonomics --- crates/core/src/plot/commands.rs | 2 +- crates/core/src/plot/worldedit/execute.rs | 47 +++++---- crates/core/src/plot/worldedit/mod.rs | 15 ++- .../src/redpiler/passes/identify_nodes.rs | 26 +---- crates/core/src/world/mod.rs | 99 +++++++++++++++++++ 5 files changed, 139 insertions(+), 50 deletions(-) diff --git a/crates/core/src/plot/commands.rs b/crates/core/src/plot/commands.rs index 4c169cdf..44bfedb8 100644 --- a/crates/core/src/plot/commands.rs +++ b/crates/core/src/plot/commands.rs @@ -301,7 +301,7 @@ impl Plot { return false; } Tps::Limited(tps) - } else if args[0] == "unlimited" { + } else if !args[0].is_empty() && "unlimited".starts_with(args[0]) { Tps::Unlimited } else { self.players[player].send_error_message("Unable to parse rtps!"); diff --git a/crates/core/src/plot/worldedit/execute.rs b/crates/core/src/plot/worldedit/execute.rs index b9206a4c..44cc9b48 100644 --- a/crates/core/src/plot/worldedit/execute.rs +++ b/crates/core/src/plot/worldedit/execute.rs @@ -3,7 +3,6 @@ use crate::chat::{ChatComponentBuilder, ColorCode}; use crate::config::CONFIG; use crate::player::PacketSender; use crate::plot::PLOT_BLOCK_HEIGHT; -use crate::redstone; use crate::utils::HyphenatedUUID; use mchprs_blocks::block_entities::InventoryEntry; use mchprs_blocks::blocks::{Block, FlipDirection, RotateAmt}; @@ -235,17 +234,17 @@ pub(super) fn execute_paste(ctx: CommandExecuteContext<'_>) { let offset_x = pos.x - cb.offset_x; let offset_y = pos.y - cb.offset_y; let offset_z = pos.z - cb.offset_z; - capture_undo( - ctx.plot, - ctx.player, - BlockPos::new(offset_x, offset_y, offset_z), - BlockPos::new( - offset_x + cb.size_x as i32, - offset_y + cb.size_y as i32, - offset_z + cb.size_z as i32, - ), + let first_pos = BlockPos::new(offset_x, offset_y, offset_z); + let second_pos = BlockPos::new( + offset_x + cb.size_x as i32, + offset_y + cb.size_y as i32, + offset_z + cb.size_z as i32, ); + capture_undo(ctx.plot, ctx.player, first_pos, second_pos); paste_clipboard(ctx.plot, cb, pos, ctx.has_flag('a')); + if ctx.has_flag('u') { + update(ctx.plot, first_pos, second_pos); + } ctx.player.send_worldedit_message(&format!( "Your clipboard was pasted. ({:?})", start_time.elapsed() @@ -993,21 +992,21 @@ pub(super) fn execute_rstack(ctx: CommandExecuteContext<'_>) { pub(super) fn execute_update(ctx: CommandExecuteContext<'_>) { let start_time = Instant::now(); - let operation = worldedit_start_operation(ctx.player); - for x in operation.x_range() { - for y in operation.y_range() { - for z in operation.z_range() { - let block_pos = BlockPos::new(x, y, z); - let block = ctx.plot.get_block(block_pos); - redstone::update(block, ctx.plot, block_pos); - } - } - } + let pos = match (ctx.player.first_position, ctx.player.second_position) { + (None, None) => Some(ctx.plot.get_corners()), + (Some(first_pos), Some(second_pos)) => Some((first_pos, second_pos)), + _ => None, + }; + if let Some((first_pos, second_pos)) = pos { + update(ctx.plot, first_pos, second_pos); - ctx.player.send_worldedit_message(&format!( - "Your selection was updated sucessfully. ({:?})", - start_time.elapsed() - )); + ctx.player.send_worldedit_message(&format!( + "Your selection was updated sucessfully. ({:?})", + start_time.elapsed() + )); + } else { + ctx.player.send_error_message("Your selection is incomplete."); + } } pub(super) fn execute_replace_container(ctx: CommandExecuteContext<'_>) { diff --git a/crates/core/src/plot/worldedit/mod.rs b/crates/core/src/plot/worldedit/mod.rs index 055f7250..8da36d2d 100644 --- a/crates/core/src/plot/worldedit/mod.rs +++ b/crates/core/src/plot/worldedit/mod.rs @@ -5,8 +5,9 @@ mod schematic; use super::{Plot, PlotWorld}; use crate::player::{PacketSender, Player, PlayerPos}; +use crate::redstone; use crate::world::storage::PalettedBitBuffer; -use crate::world::World; +use crate::world::{World, for_each_block_mut_optimized}; use execute::*; use mchprs_blocks::block_entities::{BlockEntity, ContainerType}; use mchprs_blocks::blocks::Block; @@ -540,7 +541,8 @@ static COMMANDS: Lazy> = Lazy::new(|| { execute_fn: execute_paste, description: "Paste the clipboard's contents", flags: &[ - flag!('a', None, "Skip air blocks") + flag!('a', None, "Skip air blocks"), + flag!('u', None, "Also update all affected blocks"), ], permission_node: "worldedit.clipboard.paste", ..Default::default() @@ -694,7 +696,7 @@ static COMMANDS: Lazy> = Lazy::new(|| { execute_fn: execute_update, description: "Updates all blocks in the selection", permission_node: "mchprs.we.update", - requires_positions: true, + requires_positions: false, ..Default::default() }, "/help" => WorldeditCommand { @@ -1136,3 +1138,10 @@ fn expand_selection(player: &mut Player, amount: BlockPos, contract: bool) { player.worldedit_set_second_position(p2); } } + +fn update(plot: &mut PlotWorld, first_pos: BlockPos, second_pos: BlockPos) { + for_each_block_mut_optimized(plot, first_pos, second_pos, |plot, pos| { + let block = plot.get_block(pos); + redstone::update(block, plot, pos); + }); +} diff --git a/crates/core/src/redpiler/passes/identify_nodes.rs b/crates/core/src/redpiler/passes/identify_nodes.rs index 568ce0d7..75bc8458 100644 --- a/crates/core/src/redpiler/passes/identify_nodes.rs +++ b/crates/core/src/redpiler/passes/identify_nodes.rs @@ -11,7 +11,7 @@ use super::Pass; use crate::redpiler::compile_graph::{CompileGraph, CompileNode, NodeState, NodeType}; use crate::redpiler::{CompilerInput, CompilerOptions}; use crate::redstone; -use crate::world::World; +use crate::world::{for_each_block_optimized, World}; use mchprs_blocks::block_entities::BlockEntity; use mchprs_blocks::blocks::{Block, RedstoneComparator, RedstoneRepeater}; use mchprs_blocks::BlockPos; @@ -33,27 +33,9 @@ impl Pass for IdentifyNodes { let start_pos = first_pos.min(second_pos); let end_pos = first_pos.max(second_pos); - for chunk_z in (start_pos.z / 16)..=(end_pos.z / 16) { - for chunk_x in (start_pos.x / 16)..=(end_pos.x / 16) { - let chunk = plot.get_chunk(chunk_x, chunk_z).unwrap(); - for chunk_y in (start_pos.y / 16)..=(end_pos.y / 16) { - if chunk.sections[chunk_y as usize].block_count() > 0 { - for y in 0..=15 { - for z in 0..=15 { - for x in 0..=15 { - let pos = BlockPos::new( - chunk_x * 16 + x, - chunk_y * 16 + y, - chunk_z * 16 + z, - ); - for_pos(ignore_wires, plot, graph, pos); - } - } - } - } - } - } - } + for_each_block_optimized(plot, start_pos, end_pos, |pos| { + for_pos(ignore_wires, plot, graph, pos) + }); } fn should_run(&self, _: &CompilerOptions) -> bool { diff --git a/crates/core/src/world/mod.rs b/crates/core/src/world/mod.rs index 6b69381d..3294b011 100644 --- a/crates/core/src/world/mod.rs +++ b/crates/core/src/world/mod.rs @@ -54,3 +54,102 @@ pub trait World { false } } + +// TODO: I have no idea how to deduplicate this in a sane way + +/// Executes the given function for each block excluding most air blocks +pub fn for_each_block_optimized( + world: &W, + start_pos: BlockPos, + end_pos: BlockPos, + mut f: F, +) where + F: FnMut(BlockPos), +{ + let start_x = i32::min(start_pos.x, end_pos.x); + let end_x = i32::max(start_pos.x, end_pos.x); + + let start_y = i32::min(start_pos.y, end_pos.y); + let end_y = i32::max(start_pos.y, end_pos.y); + + let start_z = i32::min(start_pos.z, end_pos.z); + let end_z = i32::max(start_pos.z, end_pos.z); + + // Iterate over chunks + for chunk_start_x in (start_x..=end_x).step_by(16) { + for chunk_start_z in (start_z..=end_z).step_by(16) { + let chunk = world + .get_chunk(chunk_start_x.div_euclid(16), chunk_start_z.div_euclid(16)) + .unwrap(); + for chunk_start_y in (start_y..=end_y).step_by(16) { + // Check if the chunk even has non air blocks + if chunk.sections[chunk_start_y as usize / 16].block_count() > 0 { + // Calculate the end position of the current chunk + let chunk_end_x = i32::min(chunk_start_x + 16 - 1, end_x); + let chunk_end_y = i32::min(chunk_start_y + 16 - 1, end_y); + let chunk_end_z = i32::min(chunk_start_z + 16 - 1, end_z); + + // Iterate over each position within the current chunk + for y in chunk_start_y..=chunk_end_y { + for z in chunk_start_z..=chunk_end_z { + for x in chunk_start_x..=chunk_end_x { + let pos = BlockPos::new(x, y, z); + f(pos); + } + } + } + } + } + } + } +} + +/// Executes the given function for each block excluding most air blocks +pub fn for_each_block_mut_optimized( + world: &mut W, + start_pos: BlockPos, + end_pos: BlockPos, + mut f: F, +) where + F: FnMut(&mut W, BlockPos), +{ + let start_x = i32::min(start_pos.x, end_pos.x); + let end_x = i32::max(start_pos.x, end_pos.x); + + let start_y = i32::min(start_pos.y, end_pos.y); + let end_y = i32::max(start_pos.y, end_pos.y); + + let start_z = i32::min(start_pos.z, end_pos.z); + let end_z = i32::max(start_pos.z, end_pos.z); + + // Iterate over chunks + for chunk_start_x in (start_x..=end_x).step_by(16) { + for chunk_start_z in (start_z..=end_z).step_by(16) { + for chunk_start_y in (start_y..=end_y).step_by(16) { + // Check if the chunk even has non air blocks + if world + .get_chunk(chunk_start_x.div_euclid(16), chunk_start_z.div_euclid(16)) + .unwrap() + .sections[chunk_start_y as usize / 16] + .block_count() + > 0 + { + // Calculate the end position of the current chunk + let chunk_end_x = i32::min(chunk_start_x + 16 - 1, end_x); + let chunk_end_y = i32::min(chunk_start_y + 16 - 1, end_y); + let chunk_end_z = i32::min(chunk_start_z + 16 - 1, end_z); + + // Iterate over each position within the current chunk + for y in chunk_start_y..=chunk_end_y { + for z in chunk_start_z..=chunk_end_z { + for x in chunk_start_x..=chunk_end_x { + let pos = BlockPos::new(x, y, z); + f(world, pos); + } + } + } + } + } + } + } +} From 39ebdb2dbc214effaf150f30ce316337cbb54dce Mon Sep 17 00:00:00 2001 From: Paul1365972 Date: Mon, 27 Nov 2023 02:15:30 +0100 Subject: [PATCH 3/5] Reflect changes in README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 865963d0..c73ae90a 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ server_context = "global" ### General Commands | Command | Alias | Description | | --- | --- |--- | -| `/rtps [rtps]` | None | Set the **redstone** ticks per second in the plot to `[rtps]`. (There are two game ticks in a redstone tick) | +| `/rtps [rtps\|unlimited]` | None | Set the **redstone** ticks per second in the plot to `[rtps]`. (There are two game ticks in a redstone tick) | | `/radvance [ticks]` | `/radv` | Advances the plot by `[ticks]` redstone ticks. | | `/teleport [player]` | `/tp` | Teleports you to `[player]`. | | `/teleport [x] [y] [z]` | `/tp` | Teleports you to `[x] [y] [z]`. Supports relative coordinates. Floats can be expressed as described [here](https://doc.rust-lang.org/std/primitive.f64.html#grammar). | @@ -122,7 +122,7 @@ These are the commands that are currently implemented: | `//replace` | None | Replace all blocks in a selection with another | | `//copy` | `//c` | Copy the selection to the clipboard | | `//cut` | `//x` | Cut the selection to the clipboard | -| `//paste` | `//v` | Paste the clipboard's contents | +| `//paste` | `//v` | Paste the clipboard's contents (`-a` to copy air, `-u` to also update) | | `//undo` | None | Undoes the last action (from history) | | `//redo` | None | Redoes the last action (from history) | | `//rstack` | `//rs` | Stack with more options, Refer to [RedstoneTools](https://github.com/paulikauro/RedstoneTools) | @@ -136,7 +136,7 @@ These are the commands that are currently implemented: | `//shift` | None | Shift the selection area | | `//flip` | `//f` | Flip the contents of the clipboard across the origin | | `//rotate` | `//r` | Rotate the contents of the clipboard | -| `//update` | None | Updates all blocks in the selection | +| `//update` | None | Updates all blocks in the selection or entire plot | | `//help` | None | Displays help for WorldEdit commands | ## Acknowledgments From a8cec6e923c40848bcb632c68de4b9c0693de9e1 Mon Sep 17 00:00:00 2001 From: Paul1365972 Date: Mon, 27 Nov 2023 15:55:37 +0100 Subject: [PATCH 4/5] Also improve redpiler reset performance --- crates/core/src/redpiler/mod.rs | 19 ++++++------------- crates/core/src/world/mod.rs | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/crates/core/src/redpiler/mod.rs b/crates/core/src/redpiler/mod.rs index 8dfccb45..9605c221 100644 --- a/crates/core/src/redpiler/mod.rs +++ b/crates/core/src/redpiler/mod.rs @@ -5,7 +5,7 @@ mod passes; use crate::redpiler::passes::make_default_pass_manager; use crate::redstone; -use crate::world::World; +use crate::world::{World, for_each_block_mut_optimized}; use backend::JITBackend; use mchprs_blocks::blocks::Block; use mchprs_blocks::BlockPos; @@ -130,19 +130,12 @@ impl Compiler { if self.options.optimize { let (first_pos, second_pos) = bounds; - let start_pos = first_pos.min(second_pos); - let end_pos = first_pos.max(second_pos); - for y in start_pos.y..=end_pos.y { - for z in start_pos.z..=end_pos.z { - for x in start_pos.x..=end_pos.x { - let pos = BlockPos::new(x, y, z); - let block = world.get_block(pos); - if matches!(block, Block::RedstoneWire { .. }) { - redstone::update(block, world, pos); - } - } + for_each_block_mut_optimized(world, first_pos, second_pos, |world, pos| { + let block = world.get_block(pos); + if matches!(block, Block::RedstoneWire { .. }) { + redstone::update(block, world, pos); } - } + }); } self.options = Default::default(); } diff --git a/crates/core/src/world/mod.rs b/crates/core/src/world/mod.rs index 3294b011..afcd93a0 100644 --- a/crates/core/src/world/mod.rs +++ b/crates/core/src/world/mod.rs @@ -60,20 +60,20 @@ pub trait World { /// Executes the given function for each block excluding most air blocks pub fn for_each_block_optimized( world: &W, - start_pos: BlockPos, - end_pos: BlockPos, + first_pos: BlockPos, + second_pos: BlockPos, mut f: F, ) where F: FnMut(BlockPos), { - let start_x = i32::min(start_pos.x, end_pos.x); - let end_x = i32::max(start_pos.x, end_pos.x); + let start_x = i32::min(first_pos.x, second_pos.x); + let end_x = i32::max(first_pos.x, second_pos.x); - let start_y = i32::min(start_pos.y, end_pos.y); - let end_y = i32::max(start_pos.y, end_pos.y); + let start_y = i32::min(first_pos.y, second_pos.y); + let end_y = i32::max(first_pos.y, second_pos.y); - let start_z = i32::min(start_pos.z, end_pos.z); - let end_z = i32::max(start_pos.z, end_pos.z); + let start_z = i32::min(first_pos.z, second_pos.z); + let end_z = i32::max(first_pos.z, second_pos.z); // Iterate over chunks for chunk_start_x in (start_x..=end_x).step_by(16) { @@ -107,20 +107,20 @@ pub fn for_each_block_optimized( /// Executes the given function for each block excluding most air blocks pub fn for_each_block_mut_optimized( world: &mut W, - start_pos: BlockPos, - end_pos: BlockPos, + first_pos: BlockPos, + second_pos: BlockPos, mut f: F, ) where F: FnMut(&mut W, BlockPos), { - let start_x = i32::min(start_pos.x, end_pos.x); - let end_x = i32::max(start_pos.x, end_pos.x); + let start_x = i32::min(first_pos.x, second_pos.x); + let end_x = i32::max(first_pos.x, second_pos.x); - let start_y = i32::min(start_pos.y, end_pos.y); - let end_y = i32::max(start_pos.y, end_pos.y); + let start_y = i32::min(first_pos.y, second_pos.y); + let end_y = i32::max(first_pos.y, second_pos.y); - let start_z = i32::min(start_pos.z, end_pos.z); - let end_z = i32::max(start_pos.z, end_pos.z); + let start_z = i32::min(first_pos.z, second_pos.z); + let end_z = i32::max(first_pos.z, second_pos.z); // Iterate over chunks for chunk_start_x in (start_x..=end_x).step_by(16) { From b7b227769825d2985e7e5a944eae6644cadb4afe Mon Sep 17 00:00:00 2001 From: Paul1365972 Date: Tue, 5 Dec 2023 16:17:07 +0100 Subject: [PATCH 5/5] Add extra flag to update the entire plot --- README.md | 4 +-- crates/core/src/plot/worldedit/execute.rs | 31 +++++++++++-------- crates/core/src/plot/worldedit/mod.rs | 5 ++- crates/core/src/redpiler/mod.rs | 2 +- .../src/redpiler/passes/identify_nodes.rs | 5 +-- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c73ae90a..fcbece2d 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ These are the commands that are currently implemented: | `//replace` | None | Replace all blocks in a selection with another | | `//copy` | `//c` | Copy the selection to the clipboard | | `//cut` | `//x` | Cut the selection to the clipboard | -| `//paste` | `//v` | Paste the clipboard's contents (`-a` to copy air, `-u` to also update) | +| `//paste` | `//v` | Paste the clipboard's contents (`-a` to ignore air, `-u` to also update) | | `//undo` | None | Undoes the last action (from history) | | `//redo` | None | Redoes the last action (from history) | | `//rstack` | `//rs` | Stack with more options, Refer to [RedstoneTools](https://github.com/paulikauro/RedstoneTools) | @@ -136,7 +136,7 @@ These are the commands that are currently implemented: | `//shift` | None | Shift the selection area | | `//flip` | `//f` | Flip the contents of the clipboard across the origin | | `//rotate` | `//r` | Rotate the contents of the clipboard | -| `//update` | None | Updates all blocks in the selection or entire plot | +| `//update` | None | Updates all blocks in the selection (`-p` to update the entire plot) | | `//help` | None | Displays help for WorldEdit commands | ## Acknowledgments diff --git a/crates/core/src/plot/worldedit/execute.rs b/crates/core/src/plot/worldedit/execute.rs index 44cc9b48..4eaa28d1 100644 --- a/crates/core/src/plot/worldedit/execute.rs +++ b/crates/core/src/plot/worldedit/execute.rs @@ -992,21 +992,26 @@ pub(super) fn execute_rstack(ctx: CommandExecuteContext<'_>) { pub(super) fn execute_update(ctx: CommandExecuteContext<'_>) { let start_time = Instant::now(); - let pos = match (ctx.player.first_position, ctx.player.second_position) { - (None, None) => Some(ctx.plot.get_corners()), - (Some(first_pos), Some(second_pos)) => Some((first_pos, second_pos)), - _ => None, + let (first_pos, second_pos) = if ctx.has_flag('p') { + ctx.plot.get_corners() + } else { + if let (Some(first_pos), Some(second_pos)) = + (ctx.player.first_position, ctx.player.second_position) + { + (first_pos, second_pos) + } else { + ctx.player + .send_error_message("Your selection is incomplete."); + return; + } }; - if let Some((first_pos, second_pos)) = pos { - update(ctx.plot, first_pos, second_pos); - ctx.player.send_worldedit_message(&format!( - "Your selection was updated sucessfully. ({:?})", - start_time.elapsed() - )); - } else { - ctx.player.send_error_message("Your selection is incomplete."); - } + update(ctx.plot, first_pos, second_pos); + + ctx.player.send_worldedit_message(&format!( + "Your selection was updated sucessfully. ({:?})", + start_time.elapsed() + )); } pub(super) fn execute_replace_container(ctx: CommandExecuteContext<'_>) { diff --git a/crates/core/src/plot/worldedit/mod.rs b/crates/core/src/plot/worldedit/mod.rs index 8da36d2d..68a9c127 100644 --- a/crates/core/src/plot/worldedit/mod.rs +++ b/crates/core/src/plot/worldedit/mod.rs @@ -7,7 +7,7 @@ use super::{Plot, PlotWorld}; use crate::player::{PacketSender, Player, PlayerPos}; use crate::redstone; use crate::world::storage::PalettedBitBuffer; -use crate::world::{World, for_each_block_mut_optimized}; +use crate::world::{for_each_block_mut_optimized, World}; use execute::*; use mchprs_blocks::block_entities::{BlockEntity, ContainerType}; use mchprs_blocks::blocks::Block; @@ -697,6 +697,9 @@ static COMMANDS: Lazy> = Lazy::new(|| { description: "Updates all blocks in the selection", permission_node: "mchprs.we.update", requires_positions: false, + flags: &[ + flag!('p', None, "Update the entire plot"), + ], ..Default::default() }, "/help" => WorldeditCommand { diff --git a/crates/core/src/redpiler/mod.rs b/crates/core/src/redpiler/mod.rs index 9605c221..999d8cd5 100644 --- a/crates/core/src/redpiler/mod.rs +++ b/crates/core/src/redpiler/mod.rs @@ -5,7 +5,7 @@ mod passes; use crate::redpiler::passes::make_default_pass_manager; use crate::redstone; -use crate::world::{World, for_each_block_mut_optimized}; +use crate::world::{for_each_block_mut_optimized, World}; use backend::JITBackend; use mchprs_blocks::blocks::Block; use mchprs_blocks::BlockPos; diff --git a/crates/core/src/redpiler/passes/identify_nodes.rs b/crates/core/src/redpiler/passes/identify_nodes.rs index 75bc8458..2d0251d7 100644 --- a/crates/core/src/redpiler/passes/identify_nodes.rs +++ b/crates/core/src/redpiler/passes/identify_nodes.rs @@ -30,10 +30,7 @@ impl Pass for IdentifyNodes { let (first_pos, second_pos) = input.bounds; - let start_pos = first_pos.min(second_pos); - let end_pos = first_pos.max(second_pos); - - for_each_block_optimized(plot, start_pos, end_pos, |pos| { + for_each_block_optimized(plot, first_pos, second_pos, |pos| { for_pos(ignore_wires, plot, graph, pos) }); }