Various minor

cfi smooth
image command
fix perm typo
fix mask typo
fix random offset transform
This commit is contained in:
Jesse Boyd 2017-05-09 21:02:44 +10:00
parent 85ff1967d7
commit f8199a3b43
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
8 changed files with 256 additions and 9 deletions

View File

@ -405,9 +405,17 @@ public class FaweBukkit implements IFawe, Listener {
// }
// }
private boolean runChunkLoad = false;
@EventHandler
public void onChunkLoad(ChunkLoadEvent event) {
SetQueue.IMP.runMiscTasks();
if (runChunkLoad) return;
try {
runChunkLoad = true;
SetQueue.IMP.runMiscTasks();
} finally {
runChunkLoad = false;
}
}
@EventHandler

View File

@ -4,6 +4,7 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.collection.LocalBlockVector2DSet;
import com.boydti.fawe.object.collection.SummedAreaTable;
import com.boydti.fawe.object.schematic.Schematic;
import com.boydti.fawe.util.CachedTextureUtil;
import com.boydti.fawe.util.MathMan;
@ -44,7 +45,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
private final Int2ObjectOpenHashMap<char[][][]> blocks = new Int2ObjectOpenHashMap<>();
private final byte[] heights;
public final byte[] heights;
private final byte[] biomes;
private final char[] floor;
private final char[] main;
@ -101,6 +102,72 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
this.textureUtil = textureUtil;
}
public void smooth(BufferedImage img, boolean white, int radius, int iterations) {
smooth(img, null, white, radius, iterations);
}
public void smooth(Mask mask, int radius, int iterations) {
smooth(null, mask, false, radius, iterations);
}
private void smooth(BufferedImage img, Mask mask, boolean white, int radius, int iterations) {
char snow = 78 << 4;
long[] copy = new long[heights.length];
char[] layers = new char[heights.length];
int width = getWidth();
int length = getLength();
SummedAreaTable table = new SummedAreaTable(copy, layers, width, radius);
for (int j = 0; j < iterations; j++) {
for (int i = 0; i < heights.length; i++) {
char combined = floor[i];
int id = combined >> 4;
if (id == 78 || id == 80) {
layers[i] = (char) (((heights[i] & 0xFF) << 3) + (floor[i] & 0x7) + 1);
} else {
layers[i] = (char) (((heights[i] & 0xFF) << 3) + 8);
}
}
int index = 0;
table.processSummedAreaTable();
if (img != null) {
for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++) {
int height = img.getRGB(x, z) & 0xFF;
if (height == 255 || height > 0 && !white && PseudoRandom.random.nextInt(256) <= height) {
int newHeight = table.average(x, z, index);
int blockHeight = (newHeight - 1) >> 3;
int layerHeight = (newHeight - 1) & 0x7;
heights[index] = (byte) blockHeight;
int id = floor[index] >> 4;
if (id == 78 || id == 80) {
floor[index] = (char) (snow + layerHeight);
}
}
}
}
} else if (mask != null) {
for (int z = 0; z < getLength(); z++) {
mutable.mutZ(z);
for (int x = 0; x < getWidth(); x++, index++) {
int y = heights[index] & 0xFF;
mutable.mutX(x);
mutable.mutY(y);
if (mask.test(mutable)) {
int height = table.average(x, z, index);
int blockHeight = (height - 1) >> 3;
int layerHeight = (height - 1) & 0x7;
heights[index] = (byte) blockHeight;
int id = floor[index] >> 4;
if (id == 78 || id == 80) {
floor[index] = (char) (snow + layerHeight);
}
}
}
}
}
}
}
public void setHeight(BufferedImage img) {
int index = 0;
for (int z = 0; z < getLength(); z++) {

View File

@ -0,0 +1,93 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.util.MathMan;
public class SummedAreaTable {
private final char[] source;
private final long[] summed;
private final int length;
private final int width;
private final int area;
private final int radius;
private final float areaInverse;
public SummedAreaTable(long[] buffer, char[] matrix, int width, int radius) {
this.source = matrix;
this.summed = buffer;
this.width = width;
this.length = buffer.length / width;
this.radius = radius;
this.area = MathMan.sqr(radius * 2 + 1);
this.areaInverse = 1f/area;
}
public void processSummedAreaTable() {
int rowSize = source.length / width;
int colSize = width;
int index = 0;
for (int i=0; i<rowSize; i++) {
for (int j=0; j<colSize; j++, index++) {
summed[index] = getVal(i, j, index, source[index]);
}
}
}
private long getSum(int index) {
if (index < 0) return 0;
return summed[index];
}
public int average(int x, int z, int index) {
long centerHeight = source[index];
int minX = Math.max(0, x - radius) - x;
int minZ = Math.max(0, z - radius) - z;
int maxX = Math.min(width - 1, x + radius) - x;
int maxZ = Math.min(length - 1, z + radius) - z;
int maxzw = maxZ * width;
int XZ = index + maxzw + maxX;
int area = (maxX - minX + 1) * (maxZ - minZ + 1);
long total = getSum(XZ);
int minzw = minZ * width;
int Z = index + minzw + maxX;
if (x > radius) {
int X = index + minX + maxzw;
int M = index + minzw + minX;
total -= summed[X - 1];
total += getSum(M - width - 1);
}
total -= getSum(Z - width);
if (area == this.area) {
return (int) (total * areaInverse);
} else {
return MathMan.lossyFastDivide((int) total, area);
}
}
private long getVal(int row, int col, int index, long curr) {
long leftSum; // sub matrix sum of left matrix
long topSum; // sub matrix sum of top matrix
long topLeftSum; // sub matrix sum of top left matrix
/* top left value is itself */
if (index == 0) {
return curr;
}
/* top row */
else if (row == 0 && col != 0) {
leftSum = summed[index - 1];
return curr + leftSum;
}
/* left-most column */
else if (row !=0 && col == 0) {
topSum = summed[index - width];
return curr + topSum;
}
else {
leftSum = summed[index - 1];
topSum = summed[index - width];
topLeftSum = summed[index - width - 1]; // overlap between leftSum and topSum
return curr + leftSum + topSum - topLeftSum;
}
}
}

View File

@ -26,7 +26,7 @@ public class RandomOffsetTransform extends ResettableExtent {
public boolean setBiome(Vector2D pos, BaseBiome biome) {
int x = pos.getBlockX() + random.nextInt(1 + (dx << 1)) - dx;
int z = pos.getBlockZ() + random.nextInt(1 + (dz << 1)) - dz;
return super.setBiome(mutable.setComponents(x, z), biome);
return getExtent().setBiome(mutable.setComponents(x, z), biome);
}
@Override
@ -34,7 +34,7 @@ public class RandomOffsetTransform extends ResettableExtent {
int x = pos.getBlockX() + random.nextInt(1 + (dx << 1)) - dx;
int y = pos.getBlockY() + random.nextInt(1 + (dy << 1)) - dy;
int z = pos.getBlockZ() + random.nextInt(1 + (dz << 1)) - dz;
return super.setBlock(x, y, z, block);
return getExtent().setBlock(x, y, z, block);
}
@Override
@ -42,7 +42,7 @@ public class RandomOffsetTransform extends ResettableExtent {
x = x + random.nextInt(1 + (dx << 1)) - dx;
y = y + random.nextInt(1 + (dy << 1)) - dy;
z = z + random.nextInt(1 + (dz << 1)) - dz;
return super.setBlock(x, y, z, block);
return getExtent().setBlock(x, y, z, block);
}
@Override

View File

@ -149,6 +149,7 @@ public class CreateFromImage extends Command {
fp.sendMessage(BBC.getPrefix() + "/2 cfi ore[s]");
fp.sendMessage(BBC.getPrefix() + "/2 cfi schem [url] <mask> <schem> <rarity> <distance> <rotate>");
fp.sendMessage(BBC.getPrefix() + "/2 cfi height <image-url|height>");
fp.sendMessage(BBC.getPrefix() + "/2 cfi smooth <url|mask> <radius> <iterations> [whiteonly]");
fp.sendMessage(BBC.getPrefix() + "/2 cfi waterHeight <height>");
fp.sendMessage(BBC.getPrefix() + "/2 cfi waterId <number-id>");
fp.sendMessage(BBC.getPrefix() + "/2 cfi color <image-url>");
@ -433,6 +434,25 @@ public class CreateFromImage extends Command {
player.sendMessage(BBC.getPrefix() + "Set biome, what's next?");
return;
}
case "smooth": {
int id;
if (argList.size() < 4) {
C.COMMAND_SYNTAX.send(player, "/2 cfi " + argList.get(0) + " <url|mask> <radius> <iterations> [whiteonly]");
return;
}
int radius = Integer.parseInt(argList.get(2));
int iterations = Integer.parseInt(argList.get(3));
BufferedImage img = getImgurImage(argList.get(1), fp);
if (img != null) {
boolean whiteOnly = argList.size() == 5 && Boolean.parseBoolean(argList.get(4));
generator.smooth(img, whiteOnly, radius, iterations);
} else {
Mask mask = we.getMaskFactory().parseFromInput(argList.get(1), context);
generator.smooth(mask, radius, iterations);
}
player.sendMessage(BBC.getPrefix() + "Smoothed terrain, what's next?");
return;
}
case "overlay":
case "setoverlay": {
Pattern id;
@ -552,7 +572,7 @@ public class CreateFromImage extends Command {
player.sendMessage(BBC.getPrefix() + "Cancelled!");
return;
default:
C.COMMAND_SYNTAX.send(player, "/2 cfi <setBiome|setOverlay|setMain|setFloor|setColumn|addCaves|addOre[s]|addSchems|setHeight|setColor|setGlassColor|setBiomeColor|setBlockAndBiomeColor|setColorPaletteComplexity|setColorPaletteRandomization|setColorPaletteBlocks|biomepriority|done|cancel|>");
C.COMMAND_SYNTAX.send(player, "/2 cfi <setBiome|setOverlay|setMain|setFloor|setColumn|addCaves|addOre[s]|addSchems|setHeight|setColor|setGlassColor|setBiomeColor|setBlockAndBiomeColor|setColorPaletteComplexity|setColorPaletteRandomization|setColorPaletteBlocks|biomepriority|smooth|done|cancel|>");
return;
}
} catch (IOException e) {

View File

@ -81,6 +81,10 @@ public class MathMan {
return floatNumber > (float) floor ? floor + 1 : floor;
}
public static int sqr(int val) {
return val * val;
}
public static int clamp(int check, int min, int max) {
return check > max ? max : (check < min ? min : check);
}

View File

@ -19,22 +19,32 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.command.FawePrimitiveBinding;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.jnbt.anvil.generator.CavesGen;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MutableBlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
@ -44,6 +54,10 @@ import com.sk89q.worldedit.util.command.binding.Text;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.util.command.parametric.ParameterException;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import static com.google.common.base.Preconditions.checkNotNull;
@ -92,13 +106,54 @@ public class GenerationCommands {
min = 1,
max = 1
)
@CommandPermissions("worldedit.generation.cylinder")
@CommandPermissions("worldedit.generation.ore")
@Logging(PLACEMENT)
public void ores(Player player, LocalSession session, EditSession editSession, @Selection Region region, Mask mask) throws WorldEditException, ParameterException {
editSession.addOres(region, mask);
BBC.VISITOR_BLOCK.send(player, editSession.getBlockChangeCount());
}
@Command(
aliases = { "/image" },
desc = "Generate an image",
usage = "<imgur> [randomize=true] [complexity=100]",
min = 1,
max = 3
)
@CommandPermissions("worldedit.generation.image")
@Logging(PLACEMENT)
public void image(Player player, LocalSession session, EditSession editSession, String arg, @Optional("true") boolean randomize, @Optional("100") int threshold) throws WorldEditException, ParameterException, IOException {
TextureUtil tu = Fawe.get().getCachedTextureUtil(randomize, 0, threshold);
URL url = new URL(arg);
if (!url.getHost().equalsIgnoreCase("i.imgur.com")) {
throw new IOException("Only i.imgur.com links are allowed!");
}
FawePlayer<Object> fp = FawePlayer.wrap(player);
BufferedImage image = MainUtil.toRGB(ImageIO.read(url));
MutableBlockVector pos1 = new MutableBlockVector(player.getPosition());
MutableBlockVector pos2 = new MutableBlockVector(pos1.add(image.getWidth() - 1, 0, image.getHeight() - 1));
CuboidRegion region = new CuboidRegion(pos1, pos2);
int[] count = new int[1];
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(Vector pos) throws WorldEditException {
try {
int x = pos.getBlockX() - pos1.getBlockX();
int z = pos.getBlockZ() - pos1.getBlockZ();
int color = image.getRGB(x, z);
BaseBlock block = tu.getNearestBlock(color);
count[0]++;
return editSession.setBlockFast(pos, block);
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
}, editSession);
Operations.completeBlindly(visitor);
BBC.VISITOR_BLOCK.send(player, editSession.getBlockChangeCount());
}
@Command(
aliases = { "/ore" },
usage = "<mask> <pattern> <size> <freq> <rarity> <minY> <maxY>",
@ -107,7 +162,7 @@ public class GenerationCommands {
min = 7,
max = 7
)
@CommandPermissions("worldedit.generation.cylinder")
@CommandPermissions("worldedit.generation.ore")
@Logging(PLACEMENT)
public void ore(Player player, LocalSession session, EditSession editSession, @Selection Region region, Mask mask, Pattern material, int size, int freq, int rarity, int minY, int maxY) throws WorldEditException, ParameterException {
editSession.addOre(region, mask, material, size, freq, rarity, minY, maxY);

View File

@ -158,7 +158,7 @@ public class MaskCommands extends MethodCommands {
}
@Command(
aliases = {"#existing"},
aliases = {"#solid"},
desc = "If there is a solid block"
)
public Mask solid(EditSession extent) {