Custom operations are now possible!

This commit is contained in:
YouHaveTrouble
2021-07-27 02:10:20 +02:00
parent 97da78d1ef
commit 8fb1a36a07
9 changed files with 128 additions and 127 deletions
@@ -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;
}
}
-18
View File
@@ -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());
}
}