mirror of
https://github.com/YouHaveTrouble/BlockEdit.git
synced 2026-06-29 13:36:19 +00:00
Custom operations are now possible!
This commit is contained in:
@@ -1,9 +1,18 @@
|
||||
package me.youhavetrouble.blockedit;
|
||||
|
||||
import me.youhavetrouble.blockedit.api.BlockEditOperation;
|
||||
import me.youhavetrouble.blockedit.util.ChunkWork;
|
||||
import me.youhavetrouble.blockedit.util.Selection;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class WorkSplitter {
|
||||
|
||||
@@ -21,10 +30,36 @@ public class WorkSplitter {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
public static ChunkWork locationToChunkWork(double x, double z) {
|
||||
int chunkX = (int) x >> 4;
|
||||
int chunkZ = (int) z >> 4;
|
||||
return new ChunkWork(chunkX, chunkZ);
|
||||
public static void runOperation(HashSet<ChunkWork> chunkWorks, Selection selection, int chunksPerTick, BlockEditOperation operation) {
|
||||
if (selection == null) return;
|
||||
List<ChunkWork> chunkWork = new ArrayList<>(chunkWorks);
|
||||
AtomicInteger element = new AtomicInteger(chunkWork.size()-1);
|
||||
Bukkit.getScheduler().runTaskTimer(BlockEdit.getPlugin(), (task) -> {
|
||||
if (element.get() < 0) {
|
||||
task.cancel();
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i< chunksPerTick; i++) {
|
||||
processChunkWork(chunkWork.get(element.getAndDecrement()), selection, operation);
|
||||
}
|
||||
}, 0, 1);
|
||||
}
|
||||
|
||||
private static void processChunkWork(ChunkWork chunkWork, Selection selection, BlockEditOperation operation) {
|
||||
World world = selection.getWorld();
|
||||
if (world == null) return;
|
||||
chunkWork.getChunkAsync(world).thenAccept(chunk -> {
|
||||
// skip y levels that are not in the selection
|
||||
for (int y = (int) selection.getMinY(); y <= selection.getMaxY(); y++) {
|
||||
for (int x = 0; x <= 15; x++) {
|
||||
for (int z = 0; z <= 15; z++) {
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
if (!selection.contains(block.getLocation().toVector())) continue;
|
||||
operation.transformBlock(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package me.youhavetrouble.blockedit.api;
|
||||
|
||||
import me.youhavetrouble.blockedit.WorkSplitter;
|
||||
import me.youhavetrouble.blockedit.util.ChunkWork;
|
||||
import me.youhavetrouble.blockedit.util.Selection;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
public class BlockEditAPI {
|
||||
|
||||
/**
|
||||
* @param selection The area that will be operated on
|
||||
* @param chunksPerTick Amount of chunks per tick to modify
|
||||
* @param operation Operation to execute
|
||||
*/
|
||||
public static void runOperation(Selection selection, int chunksPerTick, BlockEditOperation operation) {
|
||||
HashSet<ChunkWork> work = WorkSplitter.getOperatedOnChunks(selection);
|
||||
WorkSplitter.runOperation(work, selection, chunksPerTick, operation);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package me.youhavetrouble.blockedit.api;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public interface BlockEditOperation {
|
||||
|
||||
/**
|
||||
* This function will run for every block in the selection it is executed on.
|
||||
* @param block Current block.
|
||||
*/
|
||||
void transformBlock(Block block);
|
||||
|
||||
}
|
||||
@@ -2,7 +2,9 @@ package me.youhavetrouble.blockedit.commands;
|
||||
|
||||
import me.youhavetrouble.blockedit.BEPlayer;
|
||||
import me.youhavetrouble.blockedit.WorkSplitter;
|
||||
import me.youhavetrouble.blockedit.api.BlockEditAPI;
|
||||
import me.youhavetrouble.blockedit.operations.ReplaceOperation;
|
||||
import me.youhavetrouble.blockedit.util.Selection;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -31,12 +33,12 @@ public class ReplaceCommand implements TabExecutor {
|
||||
player.sendMessage(Component.text("You need to provide block type to replace"));
|
||||
return true;
|
||||
}
|
||||
Material materialToReplace = Material.getMaterial(args[0].toUpperCase());
|
||||
Material materialToReplace = Material.getMaterial(args[1].toUpperCase());
|
||||
if (materialToReplace == null) {
|
||||
player.sendMessage(Component.text("Provided material does not exist"));
|
||||
return true;
|
||||
}
|
||||
Material material = Material.getMaterial(args[1].toUpperCase());
|
||||
Material material = Material.getMaterial(args[0].toUpperCase());
|
||||
if (material == null) {
|
||||
player.sendMessage(Component.text("Provided material does not exist"));
|
||||
return true;
|
||||
@@ -50,7 +52,7 @@ public class ReplaceCommand implements TabExecutor {
|
||||
player.sendMessage(Component.text("You need to select 2 points to do this"));
|
||||
return true;
|
||||
}
|
||||
new ReplaceOperation(WorkSplitter.getOperatedOnChunks(selection), bePlayer,blockDataToReplaceWith, blockData, 1);
|
||||
BlockEditAPI.runOperation(new Selection(selection, bePlayer.getSelectionWorld()), 1, new ReplaceOperation(blockData, blockDataToReplaceWith));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ package me.youhavetrouble.blockedit.commands;
|
||||
|
||||
import me.youhavetrouble.blockedit.BEPlayer;
|
||||
import me.youhavetrouble.blockedit.WorkSplitter;
|
||||
import me.youhavetrouble.blockedit.api.BlockEditAPI;
|
||||
import me.youhavetrouble.blockedit.operations.SetOperation;
|
||||
import me.youhavetrouble.blockedit.util.Selection;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
@@ -38,7 +40,7 @@ public class SetCommand implements TabExecutor {
|
||||
player.sendMessage(Component.text("You need to select 2 points to do this"));
|
||||
return true;
|
||||
}
|
||||
new SetOperation(WorkSplitter.getOperatedOnChunks(selection), bePlayer, blockData, 1);
|
||||
BlockEditAPI.runOperation(new Selection(selection, bePlayer.getSelectionWorld()), 1, new SetOperation(blockData));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,60 +1,14 @@
|
||||
package me.youhavetrouble.blockedit.operations;
|
||||
|
||||
import me.youhavetrouble.blockedit.BEPlayer;
|
||||
import me.youhavetrouble.blockedit.BlockEdit;
|
||||
import me.youhavetrouble.blockedit.util.ChunkWork;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import me.youhavetrouble.blockedit.api.BlockEditOperation;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
public record ReplaceOperation(BlockData blockToReplace, BlockData blockToSet) implements BlockEditOperation {
|
||||
|
||||
public class ReplaceOperation {
|
||||
|
||||
private final BoundingBox selection;
|
||||
private final BlockData blockToSet, getBlockToReplace;
|
||||
private final List<ChunkWork> chunkwork = new ArrayList<>();
|
||||
|
||||
public ReplaceOperation(HashSet<ChunkWork> chunkWorks, BEPlayer bePlayer,BlockData blockToReplace , BlockData blockToSet, int chunksPerTick) {
|
||||
this.selection = bePlayer.getSelection();
|
||||
this.blockToSet = blockToSet;
|
||||
this.getBlockToReplace = blockToReplace;
|
||||
this.chunkwork.addAll(chunkWorks);
|
||||
AtomicInteger element = new AtomicInteger(chunkwork.size()-1);
|
||||
|
||||
Bukkit.getScheduler().runTaskTimer(BlockEdit.getPlugin(), (task) -> {
|
||||
if (element.get() < 0) {
|
||||
task.cancel();
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i< chunksPerTick; i++) {
|
||||
processChunkWork(chunkwork.get(element.getAndDecrement()), bePlayer.getSelectionWorld());
|
||||
}
|
||||
}, 0, 1);
|
||||
@Override
|
||||
public void transformBlock(Block block) {
|
||||
if (block.getBlockData().matches(blockToReplace))
|
||||
block.setBlockData(blockToSet);
|
||||
}
|
||||
|
||||
private void processChunkWork(ChunkWork chunkWork, UUID worldUuid) {
|
||||
World world = Bukkit.getWorld(worldUuid);
|
||||
if (world == null) return;
|
||||
chunkWork.getChunkAsync(world).thenAccept(chunk -> {
|
||||
// skip y levels that are not in the selection
|
||||
for (int y = (int) selection.getMinY(); y <= selection.getMaxY(); y++) {
|
||||
for (int x = 0; x <= 15; x++) {
|
||||
for (int z = 0; z <= 15; z++) {
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
if (!selection.contains(block.getLocation().toVector())) continue;
|
||||
if (block.getBlockData().matches(getBlockToReplace))
|
||||
block.setBlockData(blockToSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,58 +1,15 @@
|
||||
package me.youhavetrouble.blockedit.operations;
|
||||
|
||||
import me.youhavetrouble.blockedit.BEPlayer;
|
||||
import me.youhavetrouble.blockedit.BlockEdit;
|
||||
import me.youhavetrouble.blockedit.util.ChunkWork;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
import me.youhavetrouble.blockedit.api.BlockEditOperation;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class SetOperation {
|
||||
|
||||
private final BoundingBox selection;
|
||||
private final BlockData blockToSet;
|
||||
private final List<ChunkWork> chunkwork = new ArrayList<>();
|
||||
public record SetOperation(BlockData blockData) implements BlockEditOperation {
|
||||
|
||||
public SetOperation(HashSet<ChunkWork> chunkWorks, BEPlayer bePlayer, BlockData blockToSet, int chunksPerTick) {
|
||||
this.selection = bePlayer.getSelection();
|
||||
this.blockToSet = blockToSet;
|
||||
this.chunkwork.addAll(chunkWorks);
|
||||
|
||||
AtomicInteger element = new AtomicInteger(chunkwork.size()-1);
|
||||
|
||||
Bukkit.getScheduler().runTaskTimer(BlockEdit.getPlugin(), (task) -> {
|
||||
if (element.get() < 0) {
|
||||
task.cancel();
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i< chunksPerTick; i++) {
|
||||
processChunkWork(chunkwork.get(element.getAndDecrement()), bePlayer.getSelectionWorld());
|
||||
}
|
||||
}, 0, 1);
|
||||
@Override
|
||||
public void transformBlock(Block block) {
|
||||
block.setBlockData(blockData);
|
||||
}
|
||||
|
||||
private void processChunkWork(ChunkWork chunkWork, UUID worldUuid) {
|
||||
World world = Bukkit.getWorld(worldUuid);
|
||||
if (world == null) return;
|
||||
chunkWork.getChunkAsync(world).thenAccept(chunk -> {
|
||||
// skip y levels that are not in the selection
|
||||
for (int y = (int) selection.getMinY(); y <= selection.getMaxY(); y++) {
|
||||
for (int x = 0; x <= 15; x++) {
|
||||
for (int z = 0; z <= 15; z++) {
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
if (!selection.contains(block.getLocation().toVector())) continue;
|
||||
block.setBlockData(blockToSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package me.youhavetrouble.blockedit.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class Selection extends BoundingBox {
|
||||
|
||||
private UUID worldUuid;
|
||||
|
||||
public Selection(Location location1, Location location2, UUID worldUuid) {
|
||||
super(location1.getX(), location1.getY(), location1.getZ(), location2.getX(), location2.getY(), location2.getZ());
|
||||
this.worldUuid = worldUuid;
|
||||
}
|
||||
|
||||
public Selection(BoundingBox boundingBox, UUID worldUuid) {
|
||||
super(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ());
|
||||
this.worldUuid = worldUuid;
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return Bukkit.getWorld(worldUuid);
|
||||
}
|
||||
|
||||
public UUID getWorldUuid() {
|
||||
return worldUuid;
|
||||
}
|
||||
|
||||
public void setWorldUuid(UUID worldUuid) {
|
||||
this.worldUuid = worldUuid;
|
||||
}
|
||||
}
|
||||
@@ -7,22 +7,4 @@ import static org.junit.Assert.assertEquals;
|
||||
public class WorkSplitterTest {
|
||||
|
||||
|
||||
/**
|
||||
* Test if location -> chunk location works properly
|
||||
*/
|
||||
@Test
|
||||
public void testLocationToChunk() {
|
||||
ChunkWork testOne = new ChunkWork(0,0);
|
||||
ChunkWork workSplitterTestOne = WorkSplitter.locationToChunkWork(15, 15);
|
||||
|
||||
ChunkWork testTwo = WorkSplitter.locationToChunkWork(10.233D, -138.788D);
|
||||
ChunkWork workSplitterTestTwo = new ChunkWork(0,-9);
|
||||
|
||||
assertEquals(workSplitterTestOne.getX(), testOne.getX());
|
||||
assertEquals(workSplitterTestOne.getZ(), testOne.getZ());
|
||||
|
||||
assertEquals(workSplitterTestTwo.getX(), testTwo.getX());
|
||||
assertEquals(workSplitterTestTwo.getZ(), testTwo.getZ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user