Skip to content

Commit

Permalink
Merge branch 'master' of github.com:MCHPR/MCHPRS
Browse files Browse the repository at this point in the history
  • Loading branch information
StackDoubleFlow committed Dec 14, 2023
2 parents 955cf8d + 2ff1eee commit 9767ca0
Show file tree
Hide file tree
Showing 9 changed files with 157 additions and 53 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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). |
Expand Down Expand Up @@ -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 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) |
Expand All @@ -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 (`-p` to update the entire plot) |
| `//help` | None | Displays help for WorldEdit commands |

## Acknowledgments
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/plot/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!");
Expand Down
2 changes: 0 additions & 2 deletions crates/core/src/plot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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,
Expand Down
42 changes: 23 additions & 19 deletions crates/core/src/plot/worldedit/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -993,16 +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 (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;
}
}
};

update(ctx.plot, first_pos, second_pos);

ctx.player.send_worldedit_message(&format!(
"Your selection was updated sucessfully. ({:?})",
Expand Down
18 changes: 15 additions & 3 deletions crates/core/src/plot/worldedit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{for_each_block_mut_optimized, World};
use execute::*;
use mchprs_blocks::block_entities::{BlockEntity, ContainerType};
use mchprs_blocks::blocks::Block;
Expand Down Expand Up @@ -540,7 +541,8 @@ static COMMANDS: Lazy<HashMap<&'static str, WorldeditCommand>> = 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()
Expand Down Expand Up @@ -694,7 +696,10 @@ static COMMANDS: Lazy<HashMap<&'static str, WorldeditCommand>> = Lazy::new(|| {
execute_fn: execute_update,
description: "Updates all blocks in the selection",
permission_node: "mchprs.we.update",
requires_positions: true,
requires_positions: false,
flags: &[
flag!('p', None, "Update the entire plot"),
],
..Default::default()
},
"/help" => WorldeditCommand {
Expand Down Expand Up @@ -1136,3 +1141,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);
});
}
19 changes: 6 additions & 13 deletions crates/core/src/redpiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod passes;

use crate::redpiler::passes::make_default_pass_manager;
use crate::redstone;
use crate::world::World;
use crate::world::{for_each_block_mut_optimized, World};
use backend::JITBackend;
use mchprs_blocks::blocks::Block;
use mchprs_blocks::BlockPos;
Expand Down Expand Up @@ -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();
}
Expand Down
15 changes: 4 additions & 11 deletions crates/core/src/redpiler/passes/identify_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,16 +30,9 @@ impl<W: World> Pass<W> 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 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_each_block_optimized(plot, first_pos, second_pos, |pos| {
for_pos(ignore_wires, plot, graph, pos)
});
}

fn should_run(&self, _: &CompilerOptions) -> bool {
Expand Down
99 changes: 99 additions & 0 deletions crates/core/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<F, W: World>(
world: &W,
first_pos: BlockPos,
second_pos: BlockPos,
mut f: F,
) where
F: FnMut(BlockPos),
{
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(first_pos.y, second_pos.y);
let end_y = i32::max(first_pos.y, second_pos.y);

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) {
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<F, W: World>(
world: &mut W,
first_pos: BlockPos,
second_pos: BlockPos,
mut f: F,
) where
F: FnMut(&mut W, BlockPos),
{
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(first_pos.y, second_pos.y);
let end_y = i32::max(first_pos.y, second_pos.y);

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) {
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);
}
}
}
}
}
}
}
}
7 changes: 6 additions & 1 deletion crates/core/src/world/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,10 @@ impl ChunkSection {
}
&self.multi_block
}

pub fn block_count(&self) -> u32 {
self.block_count
}
}

impl Default for ChunkSection {
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 9767ca0

Please sign in to comment.