mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-25 03:55:35 +01:00
Various
Fixes #456 Delay command registration WIP shatter/stencil brush Minor FaweQueue optimization
This commit is contained in:
parent
eb55f5fd7d
commit
b595ec2f2d
@ -121,6 +121,8 @@ public enum BBC {
|
|||||||
BRUSH_HEIGHT_INVALID("Invalid height map file (%s0)", "WorldEdit.Brush"),
|
BRUSH_HEIGHT_INVALID("Invalid height map file (%s0)", "WorldEdit.Brush"),
|
||||||
BRUSH_SMOOTH("Smooth brush equipped (%s0 x %s1 using %s2. Note: Use the blend brush if you want to smooth overhangs or caves.).", "WorldEdit.Brush"),
|
BRUSH_SMOOTH("Smooth brush equipped (%s0 x %s1 using %s2. Note: Use the blend brush if you want to smooth overhangs or caves.).", "WorldEdit.Brush"),
|
||||||
BRUSH_SPHERE("Sphere brush shape equipped (%s0).", "WorldEdit.Brush"),
|
BRUSH_SPHERE("Sphere brush shape equipped (%s0).", "WorldEdit.Brush"),
|
||||||
|
BRUSH_SHATTER("Shatter brush shape equipped (%s0, %s1).", "WorldEdit.Brush"),
|
||||||
|
BRUSH_STENCIL("Stencil brush equipped (%s0).", "WorldEdit.Brush"),
|
||||||
BRUSH_LINE("Line brush shape equipped (%s0).", "WorldEdit.Brush"),
|
BRUSH_LINE("Line brush shape equipped (%s0).", "WorldEdit.Brush"),
|
||||||
BRUSH_SPLINE("Spline brush shape equipped (%s0). Right click an end to add a shape", "WorldEdit.Brush"),
|
BRUSH_SPLINE("Spline brush shape equipped (%s0). Right click an end to add a shape", "WorldEdit.Brush"),
|
||||||
BRUSH_SPLINE_PRIMARY_2("Added position, Click the same spot to join!", "WorldEdit.Brush"),
|
BRUSH_SPLINE_PRIMARY_2("Added position, Click the same spot to join!", "WorldEdit.Brush"),
|
||||||
|
@ -572,14 +572,38 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, CHUNKSECTIONS, SECTION> exte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCachedCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
|
public int getCachedCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
|
||||||
FaweChunk fc = map.getCachedFaweChunk(x >> 4, z >> 4);
|
int cx = x >> 4;
|
||||||
|
int cz = z >> 4;
|
||||||
|
FaweChunk fc = map.getCachedFaweChunk(cx, cz);
|
||||||
if (fc != null) {
|
if (fc != null) {
|
||||||
int combined = fc.getBlockCombinedId(x & 15, y, z & 15);
|
int combined = fc.getBlockCombinedId(x & 15, y, z & 15);
|
||||||
if (combined != 0) {
|
if (combined != 0) {
|
||||||
return combined;
|
return combined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getCombinedId4Data(x, y, z);
|
int cy = y >> 4;
|
||||||
|
if (cx != lastSectionX || cz != lastSectionZ) {
|
||||||
|
lastSectionX = cx;
|
||||||
|
lastSectionZ = cz;
|
||||||
|
lastChunk = ensureChunkLoaded(cx, cz);
|
||||||
|
if (lastChunk != null) {
|
||||||
|
lastChunkSections = getSections(lastChunk);
|
||||||
|
lastSection = getCachedSection(lastChunkSections, cy);
|
||||||
|
} else {
|
||||||
|
lastChunkSections = null;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (cy != lastSectionY) {
|
||||||
|
if (lastChunkSections != null) {
|
||||||
|
lastSection = getCachedSection(lastChunkSections, cy);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastSection == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return getCombinedId4Data(lastSection, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -24,6 +24,6 @@ public class FlattenBrush extends HeightBrush {
|
|||||||
mask = null;
|
mask = null;
|
||||||
}
|
}
|
||||||
heightMap.setSize(size);
|
heightMap.setSize(size);
|
||||||
heightMap.apply(editSession, mask, position, size, rotation, yscale, true, true);
|
heightMap.perform(editSession, mask, position, size, rotation, yscale, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,6 @@ public class HeightBrush implements Brush {
|
|||||||
mask = null;
|
mask = null;
|
||||||
}
|
}
|
||||||
heightMap.setSize(size);
|
heightMap.setSize(size);
|
||||||
heightMap.apply(editSession, mask, position, size, rotation, yscale, true, false);
|
heightMap.perform(editSession, mask, position, size, rotation, yscale, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,135 @@
|
|||||||
|
package com.boydti.fawe.object.brush;
|
||||||
|
|
||||||
|
import com.boydti.fawe.object.PseudoRandom;
|
||||||
|
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
|
||||||
|
import com.sk89q.worldedit.BlockVector;
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
|
import com.sk89q.worldedit.MutableBlockVector;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.command.tool.brush.Brush;
|
||||||
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
|
import com.sk89q.worldedit.function.mask.Masks;
|
||||||
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
|
import com.sk89q.worldedit.function.visitor.BreadthFirstSearch;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
|
|
||||||
|
public class ShatterBrush implements Brush {
|
||||||
|
private final int count;
|
||||||
|
|
||||||
|
public ShatterBrush(int count) {
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void build(EditSession editSession, final Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
|
||||||
|
// We'll want this to be somewhat circular, so the cuboid needs to fit.
|
||||||
|
int r2Radius = (int) Math.ceil(size * Math.sqrt(2));
|
||||||
|
int radius2 = (int) (Math.ceil(r2Radius * r2Radius));
|
||||||
|
Vector bot = new MutableBlockVector(position.subtract(size, size, size));
|
||||||
|
Vector top = new MutableBlockVector(position.add(size, size, size));
|
||||||
|
CuboidRegion region = new CuboidRegion(bot, top);
|
||||||
|
// We'll want to use a fast random
|
||||||
|
PseudoRandom random = new PseudoRandom();
|
||||||
|
// We don't need double precision, so use a BlockVector
|
||||||
|
BlockVector min = region.getMinimumPoint().toBlockVector();
|
||||||
|
BlockVector max = region.getMaximumPoint().toBlockVector();
|
||||||
|
// Let's keep it inside the brush radius
|
||||||
|
int dx = max.getBlockX() - min.getBlockX() + 1;
|
||||||
|
int dy = max.getBlockY() - min.getBlockY() + 1;
|
||||||
|
int dz = max.getBlockZ() - min.getBlockZ() + 1;
|
||||||
|
// We'll store the points in a set
|
||||||
|
LocalBlockVectorSet queue = new LocalBlockVectorSet();
|
||||||
|
// User could select a single block and try to create 10 points = infinite loop
|
||||||
|
// To avoid being stuck in an infinite loop, let's stop after 5 collisions
|
||||||
|
int maxFails = 5;
|
||||||
|
for (int added = 0; added < count;) {
|
||||||
|
int x = (int) (random.nextDouble() * dx) + min.getBlockX();
|
||||||
|
int z = (int) (random.nextDouble() * dz) + min.getBlockZ();
|
||||||
|
int y = editSession.getHighestTerrainBlock(x, z, 0, 255);
|
||||||
|
// Check the adjacent blocks efficiently (loops over the adjacent blocks, or the set; whichever is faster)
|
||||||
|
if (!queue.containsRadius(x, y, z, 1)) {
|
||||||
|
added++;
|
||||||
|
queue.add(x, y, z);
|
||||||
|
} else if (maxFails-- <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ideally we'd calculate all the bisecting planes, but that's complex to program
|
||||||
|
// With this algorithm compute time depends on the number of blocks rather than the number of points
|
||||||
|
// - Expand from each point (block by block) until there is a collision
|
||||||
|
{
|
||||||
|
// Keep track of where we've visited
|
||||||
|
LocalBlockVectorSet visited = queue;
|
||||||
|
LocalBlockVectorSet tmp = new LocalBlockVectorSet();
|
||||||
|
// Individual frontier for each point
|
||||||
|
LocalBlockVectorSet[] frontiers = new LocalBlockVectorSet[queue.size()];
|
||||||
|
// Keep track of where each frontier has visited
|
||||||
|
LocalBlockVectorSet[] frontiersVisited = new LocalBlockVectorSet[queue.size()];
|
||||||
|
// Initiate the frontier with the starting points
|
||||||
|
int i = 0;
|
||||||
|
for (Vector pos : queue) {
|
||||||
|
LocalBlockVectorSet set = new LocalBlockVectorSet();
|
||||||
|
set.add(pos);
|
||||||
|
frontiers[i] = set;
|
||||||
|
frontiersVisited[i] = set.clone();
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
// Mask
|
||||||
|
Mask mask = editSession.getMask();
|
||||||
|
if (mask == null) {
|
||||||
|
mask = Masks.alwaysTrue();
|
||||||
|
}
|
||||||
|
final Mask finalMask = mask;
|
||||||
|
// Expand
|
||||||
|
boolean notEmpty = true;
|
||||||
|
while (notEmpty) {
|
||||||
|
notEmpty = false;
|
||||||
|
for (i = 0; i < frontiers.length; i++) {
|
||||||
|
LocalBlockVectorSet frontier = frontiers[i];
|
||||||
|
notEmpty |= !frontier.isEmpty();
|
||||||
|
final LocalBlockVectorSet frontierVisited = frontiersVisited[i];
|
||||||
|
// This is a temporary set with the next blocks the frontier will visit
|
||||||
|
final LocalBlockVectorSet finalTmp = tmp;
|
||||||
|
frontier.forEach(new LocalBlockVectorSet.BlockVectorSetVisitor() {
|
||||||
|
@Override
|
||||||
|
public void run(int x, int y, int z, int index) {
|
||||||
|
if (PseudoRandom.random.random(2) == 0) {
|
||||||
|
finalTmp.add(x, y, z);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (Vector direction : BreadthFirstSearch.DEFAULT_DIRECTIONS) {
|
||||||
|
int x2 = x + direction.getBlockX();
|
||||||
|
int y2 = y + direction.getBlockY();
|
||||||
|
int z2 = z + direction.getBlockZ();
|
||||||
|
// Check boundary
|
||||||
|
int dx = position.getBlockX() - x2;
|
||||||
|
int dy = position.getBlockY() - y2;
|
||||||
|
int dz = position.getBlockZ() - z2;
|
||||||
|
int dSqr = (dx * dx) + (dy * dy) + (dz * dz);
|
||||||
|
if (dSqr <= radius2) {
|
||||||
|
if (finalMask.test(MutableBlockVector.get(x2, y2, z2))) {
|
||||||
|
// (collision) If it's visited and part of another frontier, set the block
|
||||||
|
if (!visited.add(x2, y2, z2)) {
|
||||||
|
if (!frontierVisited.contains(x2, y2, z2)) {
|
||||||
|
editSession.setBlock(x2, y2, z2, pattern);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Hasn't visited and not a collision = add it
|
||||||
|
finalTmp.add(x2, y2, z2);
|
||||||
|
frontierVisited.add(x2, y2, z2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Swap the frontier with the temporary set
|
||||||
|
frontiers[i] = tmp;
|
||||||
|
tmp = frontier;
|
||||||
|
tmp.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.boydti.fawe.object.brush;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
|
import com.sk89q.worldedit.function.mask.Masks;
|
||||||
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class StencilBrush extends HeightBrush {
|
||||||
|
private final boolean onlyWhite;
|
||||||
|
|
||||||
|
public StencilBrush(InputStream stream, int rotation, double yscale, boolean onlyWhite, Clipboard clipboard) {
|
||||||
|
super(stream, rotation, yscale, clipboard);
|
||||||
|
this.onlyWhite = onlyWhite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
|
||||||
|
int size = (int) sizeDouble;
|
||||||
|
Mask mask = editSession.getMask();
|
||||||
|
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
|
||||||
|
mask = null;
|
||||||
|
}
|
||||||
|
heightMap.setSize(size);
|
||||||
|
for (int x = -size; x <= size; x++) {
|
||||||
|
int xx = position.getBlockX() + x;
|
||||||
|
for (int z = -size; z <= size; z++) {
|
||||||
|
int zz = position.getBlockZ() + z;
|
||||||
|
double raise;
|
||||||
|
switch (rotation) {
|
||||||
|
default:raise = heightMap.getHeight(x, z); break;
|
||||||
|
case 1: raise = heightMap.getHeight(z, x); break;
|
||||||
|
case 2: raise = heightMap.getHeight(-x, -z); break;
|
||||||
|
case 3: raise = heightMap.getHeight(-z, -x);break;
|
||||||
|
}
|
||||||
|
raise *= yscale;
|
||||||
|
if (raise == 0 || (onlyWhite && raise < 255)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int[] data = heightMap.generateHeightData(editSession, mask, position, size, rotation, yscale, true, false);
|
||||||
|
int diameter = size * 2;
|
||||||
|
int x = position.getBlockX();
|
||||||
|
int y = position.getBlockY();
|
||||||
|
int z = position.getBlockZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -118,7 +118,32 @@ public class ScalableHeightMap {
|
|||||||
return new ArrayHeightMap(array);
|
return new ArrayHeightMap(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
|
public void perform(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
|
||||||
|
int[] data = generateHeightData(session, mask, pos, size, rotationMode, yscale, smooth, towards);
|
||||||
|
applyHeightMapData(data, session, mask, pos, size, rotationMode, yscale, smooth, towards);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyHeightMapData(int[] data, EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) throws MaxChangedBlocksException {
|
||||||
|
Vector top = session.getMaximumPoint();
|
||||||
|
int maxY = top.getBlockY();
|
||||||
|
int diameter = 2 * size + 1;
|
||||||
|
int iterations = 1;
|
||||||
|
WorldVector min = new WorldVector(LocalWorldAdapter.adapt(session.getWorld()), pos.subtract(size, maxY, size));
|
||||||
|
Vector max = pos.add(size, maxY, size);
|
||||||
|
Region region = new CuboidRegion(session.getWorld(), min, max);
|
||||||
|
HeightMap heightMap = new HeightMap(session, region, true);
|
||||||
|
if (smooth) {
|
||||||
|
try {
|
||||||
|
HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1));
|
||||||
|
data = filter.filter(data, diameter, diameter);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
heightMap.apply(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] generateHeightData(EditSession session, Mask mask, Vector pos, int size, int rotationMode, double yscale, boolean smooth, boolean towards) {
|
||||||
Vector top = session.getMaximumPoint();
|
Vector top = session.getMaximumPoint();
|
||||||
int maxY = top.getBlockY();
|
int maxY = top.getBlockY();
|
||||||
int diameter = 2 * size + 1;
|
int diameter = 2 * size + 1;
|
||||||
@ -201,19 +226,6 @@ public class ScalableHeightMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int iterations = 1;
|
return newData;
|
||||||
WorldVector min = new WorldVector(LocalWorldAdapter.adapt(session.getWorld()), pos.subtract(size, maxY, size));
|
|
||||||
Vector max = pos.add(size, maxY, size);
|
|
||||||
Region region = new CuboidRegion(session.getWorld(), min, max);
|
|
||||||
HeightMap heightMap = new HeightMap(session, region, true);
|
|
||||||
if (smooth) {
|
|
||||||
try {
|
|
||||||
HeightMapFilter filter = (HeightMapFilter) HeightMapFilter.class.getConstructors()[0].newInstance(GaussianKernel.class.getConstructors()[0].newInstance(5, 1));
|
|
||||||
newData = filter.filter(newData, diameter, diameter);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
MainUtil.handleError(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
heightMap.apply(newData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,9 @@ import com.boydti.fawe.object.brush.LineBrush;
|
|||||||
import com.boydti.fawe.object.brush.RaiseBrush;
|
import com.boydti.fawe.object.brush.RaiseBrush;
|
||||||
import com.boydti.fawe.object.brush.RecurseBrush;
|
import com.boydti.fawe.object.brush.RecurseBrush;
|
||||||
import com.boydti.fawe.object.brush.SplineBrush;
|
import com.boydti.fawe.object.brush.SplineBrush;
|
||||||
|
import com.boydti.fawe.object.brush.StencilBrush;
|
||||||
import com.boydti.fawe.object.brush.TargetMode;
|
import com.boydti.fawe.object.brush.TargetMode;
|
||||||
|
import com.boydti.fawe.object.brush.ShatterBrush;
|
||||||
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
|
import com.boydti.fawe.object.brush.heightmap.ScalableHeightMap;
|
||||||
import com.boydti.fawe.object.brush.scroll.ScrollClipboard;
|
import com.boydti.fawe.object.brush.scroll.ScrollClipboard;
|
||||||
import com.boydti.fawe.object.brush.scroll.ScrollMask;
|
import com.boydti.fawe.object.brush.scroll.ScrollMask;
|
||||||
@ -79,6 +81,7 @@ import com.sk89q.worldedit.extension.platform.CommandManager;
|
|||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
import com.sk89q.worldedit.function.mask.BlockMask;
|
import com.sk89q.worldedit.function.mask.BlockMask;
|
||||||
|
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
|
||||||
import com.sk89q.worldedit.function.mask.Mask;
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
import com.sk89q.worldedit.function.pattern.BlockPattern;
|
import com.sk89q.worldedit.function.pattern.BlockPattern;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
@ -268,7 +271,7 @@ public class BrushCommands {
|
|||||||
File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
|
File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||||
File dir = new File(working, (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? (player.getUniqueId().toString() + File.separator) : "") + filename);
|
File dir = new File(working, (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? (player.getUniqueId().toString() + File.separator) : "") + filename);
|
||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
if (!filename.contains("/") && !filename.contains("\\")) {
|
if ((!filename.contains("/") && !filename.contains("\\")) || player.hasPermission("worldedit.schematic.load.other")) {
|
||||||
dir = new File(this.worldEdit.getWorkingDirectoryFile(config.saveDir), filename);
|
dir = new File(this.worldEdit.getWorkingDirectoryFile(config.saveDir), filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -507,27 +510,52 @@ public class BrushCommands {
|
|||||||
if (!FawePlayer.wrap(player).hasPermission("fawe.tips")) BBC.TIP_BRUSH_COMMAND.or(BBC.TIP_BRUSH_RELATIVE, BBC.TIP_BRUSH_TRANSFORM, BBC.TIP_BRUSH_MASK_SOURCE, BBC.TIP_BRUSH_MASK, BBC.TIP_BRUSH_COPY, BBC.TIP_BRUSH_HEIGHT, BBC.TIP_BRUSH_SPLINE).send(player);
|
if (!FawePlayer.wrap(player).hasPermission("fawe.tips")) BBC.TIP_BRUSH_COMMAND.or(BBC.TIP_BRUSH_RELATIVE, BBC.TIP_BRUSH_TRANSFORM, BBC.TIP_BRUSH_MASK_SOURCE, BBC.TIP_BRUSH_MASK, BBC.TIP_BRUSH_COPY, BBC.TIP_BRUSH_HEIGHT, BBC.TIP_BRUSH_SPLINE).send(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Command(
|
@Command(
|
||||||
// aliases = { "test" },
|
aliases = { "shatter", "partition", "split" },
|
||||||
// usage = "<pattern> [radius] [count] [distance]",
|
usage = "<pattern> [radius] [count] [distance]",
|
||||||
// flags = "h",
|
desc = "Creates random lines to break the terrain into pieces",
|
||||||
// desc = "Choose the sphere brush",
|
help =
|
||||||
// help =
|
"Chooses the shatter brush",
|
||||||
// "Chooses the sphere brush.\n" +
|
min = 1,
|
||||||
// "The -h flag creates hollow spheres instead.",
|
max = -1
|
||||||
// min = 1,
|
)
|
||||||
// max = -1
|
@CommandPermissions("worldedit.brush.shatter")
|
||||||
// )
|
public void shatterBrush(Player player, EditSession editSession, LocalSession session, Pattern fill, @Optional("10") double radius, @Optional("10") int count) throws WorldEditException {
|
||||||
// @CommandPermissions("worldedit.brush.test")
|
worldEdit.checkMaxBrushRadius(radius);
|
||||||
// public void testBrush(Player player, LocalSession session, Pattern fill, @Optional("10") double radius, @Optional("10") int count, @Optional("10") int distance) throws WorldEditException {
|
|
||||||
// worldEdit.checkMaxBrushRadius(radius);
|
BrushTool tool = session.getBrushTool(player);
|
||||||
//
|
tool.setFill(fill);
|
||||||
// BrushTool tool = session.getBrushTool(player);
|
tool.setSize(radius);
|
||||||
// tool.setFill(fill);
|
tool.setMask(new ExistingBlockMask(editSession));
|
||||||
// tool.setSize(radius);
|
tool.setBrush(new ShatterBrush(count), "worldedit.brush.shatter");
|
||||||
// tool.setBrush(new Test(count), "worldedit.brush.test");
|
player.print(BBC.getPrefix() + BBC.BRUSH_SHATTER.f(radius, count));
|
||||||
// player.print("equiped");
|
}
|
||||||
// }
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "stencil", "color"},
|
||||||
|
usage = "<pattern> [radius] [file|#clipboard|null] [rotation] [yscale]",
|
||||||
|
desc = "Use a height map to paint a surface",
|
||||||
|
help =
|
||||||
|
"Chooses the stencil brush.\n" +
|
||||||
|
"The -w flag will only apply at maximum saturation",
|
||||||
|
min = 1,
|
||||||
|
max = -1
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.brush.stencil")
|
||||||
|
public void stencilBrush(Player player, LocalSession session, Pattern fill, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale, @Switch('w') boolean onlyWhite) throws WorldEditException {
|
||||||
|
worldEdit.checkMaxBrushRadius(radius);
|
||||||
|
BrushTool tool = session.getBrushTool(player);
|
||||||
|
InputStream stream = getHeightmapStream(filename);
|
||||||
|
tool.setFill(fill);
|
||||||
|
tool.setSize(radius);
|
||||||
|
try {
|
||||||
|
tool.setBrush(new StencilBrush(stream, rotation, yscale, onlyWhite, filename.equalsIgnoreCase("#clipboard") ? session.getClipboard().getClipboard() : null), "worldedit.brush.height", player);
|
||||||
|
} catch (EmptyClipboardException ignore) {
|
||||||
|
tool.setBrush(new StencilBrush(stream, rotation, yscale, onlyWhite, null), "worldedit.brush.height", player);
|
||||||
|
}
|
||||||
|
|
||||||
|
player.print(BBC.getPrefix() + BBC.BRUSH_STENCIL.f(radius));
|
||||||
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
aliases = { "cylinder", "cyl", "c" },
|
aliases = { "cylinder", "cyl", "c" },
|
||||||
@ -701,11 +729,9 @@ public class BrushCommands {
|
|||||||
terrainBrush(player, session, radius, filename, rotation, yscale, true, ScalableHeightMap.Shape.CONE);
|
terrainBrush(player, session, radius, filename, rotation, yscale, true, ScalableHeightMap.Shape.CONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void terrainBrush(Player player, LocalSession session, double radius, String filename, int rotation, double yscale, boolean flat, ScalableHeightMap.Shape shape) throws WorldEditException {
|
private InputStream getHeightmapStream(String filename) {
|
||||||
worldEdit.checkMaxBrushRadius(radius);
|
|
||||||
String filenamePng = (filename.endsWith(".png") ? filename : filename + ".png");
|
String filenamePng = (filename.endsWith(".png") ? filename : filename + ".png");
|
||||||
File file = new File(Fawe.imp().getDirectory(), "heightmap" + File.separator + filenamePng);
|
File file = new File(Fawe.imp().getDirectory(), "heightmap" + File.separator + filenamePng);
|
||||||
InputStream stream = null;
|
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
if (!filename.equals("#clipboard") && filename.length() >= 7) {
|
if (!filename.equals("#clipboard") && filename.length() >= 7) {
|
||||||
try {
|
try {
|
||||||
@ -719,19 +745,24 @@ public class BrushCommands {
|
|||||||
url = new URL("https://i.imgur.com/" + filenamePng);
|
url = new URL("https://i.imgur.com/" + filenamePng);
|
||||||
}
|
}
|
||||||
ReadableByteChannel rbc = Channels.newChannel(url.openStream());
|
ReadableByteChannel rbc = Channels.newChannel(url.openStream());
|
||||||
stream = Channels.newInputStream(rbc);
|
return Channels.newInputStream(rbc);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (!filename.equalsIgnoreCase("#clipboard")){
|
} else if (!filename.equalsIgnoreCase("#clipboard")){
|
||||||
try {
|
try {
|
||||||
stream = new FileInputStream(file);
|
return new FileInputStream(file);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void terrainBrush(Player player, LocalSession session, double radius, String filename, int rotation, double yscale, boolean flat, ScalableHeightMap.Shape shape) throws WorldEditException {
|
||||||
|
worldEdit.checkMaxBrushRadius(radius);
|
||||||
|
InputStream stream = getHeightmapStream(filename);
|
||||||
BrushTool tool = session.getBrushTool(player);
|
BrushTool tool = session.getBrushTool(player);
|
||||||
tool.setSize(radius);
|
tool.setSize(radius);
|
||||||
if (flat) {
|
if (flat) {
|
||||||
|
@ -55,6 +55,7 @@ import java.io.InputStream;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.ReadableByteChannel;
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@ -132,7 +133,7 @@ public class SchematicCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
if (!filename.contains("/") && !filename.contains("\\")) {
|
if ((!filename.contains("/") && !filename.contains("\\")) || player.hasPermission("worldedit.schematic.load.other")) {
|
||||||
dir = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
|
dir = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||||
f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension());
|
f = this.worldEdit.getSafeSaveFile(player, dir, filename, format.getExtension(), format.getExtension());
|
||||||
}
|
}
|
||||||
@ -203,8 +204,13 @@ public class SchematicCommands {
|
|||||||
final File parent = f.getParentFile();
|
final File parent = f.getParentFile();
|
||||||
if ((parent != null) && !parent.exists()) {
|
if ((parent != null) && !parent.exists()) {
|
||||||
if (!parent.mkdirs()) {
|
if (!parent.mkdirs()) {
|
||||||
log.info("Could not create folder for schematics!");
|
try {
|
||||||
return;
|
Files.createDirectories(parent.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
log.info("Could not create folder for schematics!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -18,6 +18,7 @@ import com.sk89q.worldedit.EditSession;
|
|||||||
import com.sk89q.worldedit.LocalConfiguration;
|
import com.sk89q.worldedit.LocalConfiguration;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
|
import com.sk89q.worldedit.MutableBlockVector;
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
@ -232,7 +233,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
|||||||
public Vector getPosition(EditSession editSession, Player player) {
|
public Vector getPosition(EditSession editSession, Player player) {
|
||||||
switch (targetMode) {
|
switch (targetMode) {
|
||||||
case TARGET_BLOCK_RANGE:
|
case TARGET_BLOCK_RANGE:
|
||||||
return player.getBlockTrace(getRange(), true);
|
return new MutableBlockVector(player.getBlockTrace(getRange(), true));
|
||||||
case FOWARD_POINT_PITCH: {
|
case FOWARD_POINT_PITCH: {
|
||||||
int d = 0;
|
int d = 0;
|
||||||
Location loc = player.getLocation();
|
Location loc = player.getLocation();
|
||||||
@ -241,7 +242,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
|||||||
d += (int) (Math.sin(Math.toRadians(pitch)) * 50);
|
d += (int) (Math.sin(Math.toRadians(pitch)) * 50);
|
||||||
final Vector vector = loc.getDirection().setY(0).normalize().multiply(d);
|
final Vector vector = loc.getDirection().setY(0).normalize().multiply(d);
|
||||||
vector.add(loc.getX(), loc.getY(), loc.getZ()).toBlockVector();
|
vector.add(loc.getX(), loc.getY(), loc.getZ()).toBlockVector();
|
||||||
return vector;
|
return new MutableBlockVector(vector);
|
||||||
}
|
}
|
||||||
case TARGET_POINT_HEIGHT: {
|
case TARGET_POINT_HEIGHT: {
|
||||||
Location loc = player.getLocation();
|
Location loc = player.getLocation();
|
||||||
@ -256,10 +257,10 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final int distance = (height - y) + 8;
|
final int distance = (height - y) + 8;
|
||||||
return player.getBlockTrace(distance, true);
|
return new MutableBlockVector(player.getBlockTrace(distance, true));
|
||||||
}
|
}
|
||||||
case TARGET_FACE_RANGE:
|
case TARGET_FACE_RANGE:
|
||||||
return player.getBlockTraceFace(getRange(), true);
|
return new MutableBlockVector(player.getBlockTraceFace(getRange(), true));
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,7 @@ public final class CommandManager {
|
|||||||
private final WorldEdit worldEdit;
|
private final WorldEdit worldEdit;
|
||||||
private final PlatformManager platformManager;
|
private final PlatformManager platformManager;
|
||||||
private volatile Dispatcher dispatcher;
|
private volatile Dispatcher dispatcher;
|
||||||
|
private volatile Platform platform;
|
||||||
private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler();
|
private final DynamicStreamHandler dynamicHandler = new DynamicStreamHandler();
|
||||||
private final ExceptionConverter exceptionConverter;
|
private final ExceptionConverter exceptionConverter;
|
||||||
|
|
||||||
@ -246,7 +247,9 @@ public final class CommandManager {
|
|||||||
.registerMethods(new BrushCommands(worldEdit))
|
.registerMethods(new BrushCommands(worldEdit))
|
||||||
.parent().graph().getDispatcher();
|
.parent().graph().getDispatcher();
|
||||||
|
|
||||||
|
if (platform != null) {
|
||||||
|
platform.registerCommands(dispatcher);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommandManager getInstance() {
|
public static CommandManager getInstance() {
|
||||||
@ -281,7 +284,7 @@ public final class CommandManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
platform.registerCommands(dispatcher);
|
this.platform = platform;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregister() {
|
public void unregister() {
|
||||||
|
Loading…
Reference in New Issue
Block a user