Various
Fixed slow bukkit api placer (if no NMS placer exists) (it will try to stay above 18.5 TPS) Added more messages to translations Added copy brush Added resizable clipboard builder (API) Added image download
This commit is contained in:
parent
3d8a7f84cd
commit
8555276a78
@ -0,0 +1,201 @@
|
||||
package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.example.CharFaweChunk;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.worldedit.LocalWorld;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.bukkit.BukkitUtil;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.util.ArrayList;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public class BukkitChunk_All extends CharFaweChunk<Chunk> {
|
||||
|
||||
/**
|
||||
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
|
||||
*
|
||||
* @param parent
|
||||
* @param x
|
||||
* @param z
|
||||
*/
|
||||
public BukkitChunk_All(FaweQueue parent, int x, int z) {
|
||||
super(parent, x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getNewChunk() {
|
||||
return Bukkit.getWorld(getParent().getWorldName()).getChunkAt(getX(), getZ());
|
||||
}
|
||||
|
||||
private int layer = -1;
|
||||
private int index;
|
||||
private boolean place = true;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public void execute(long start) {
|
||||
int recommended = 25 + BukkitQueue_All.ALLOCATE;
|
||||
boolean more = true;
|
||||
FaweQueue parent = getParent();
|
||||
final Chunk chunk = getChunk();
|
||||
chunk.load(true);
|
||||
final World world = chunk.getWorld();
|
||||
char[][] sections = getCombinedIdArrays();
|
||||
if (layer == -1) {
|
||||
// Biomes
|
||||
if (layer == 0) {
|
||||
final int[][] biomes = getBiomeArray();
|
||||
if (biomes != null) {
|
||||
final LocalWorld lw = BukkitUtil.getLocalWorld(world);
|
||||
final int X = getX() << 4;
|
||||
final int Z = getZ() << 4;
|
||||
final BaseBiome bb = new BaseBiome(0);
|
||||
int last = 0;
|
||||
for (int x = 0; x < 16; x++) {
|
||||
final int[] array = biomes[x];
|
||||
if (array == null) {
|
||||
continue;
|
||||
}
|
||||
for (int z = 0; z < 16; z++) {
|
||||
final int biome = array[z];
|
||||
if (biome == 0) {
|
||||
continue;
|
||||
}
|
||||
if (last != biome) {
|
||||
last = biome;
|
||||
bb.setId(biome);
|
||||
}
|
||||
lw.setBiome(new Vector2D(X + x, Z + z), bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (index != 0) {
|
||||
if (place) {
|
||||
layer--;
|
||||
} else {
|
||||
layer++;
|
||||
}
|
||||
}
|
||||
mainloop:
|
||||
do {
|
||||
if (place) {
|
||||
if (++layer >= sections.length) {
|
||||
place = false;
|
||||
layer = sections.length - 1;
|
||||
}
|
||||
} else if (--layer < 0) {
|
||||
more = false;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
// Efficiently merge sections
|
||||
int changes = getCount(layer);
|
||||
int lighting = getRelight(layer);
|
||||
if (changes == 0) {
|
||||
continue;
|
||||
}
|
||||
final char[] newArray = sections[layer];
|
||||
if (newArray == null) {
|
||||
continue;
|
||||
}
|
||||
boolean checkTime = !((getAir(layer) == 4096 || (getCount(layer) == 4096 && getAir(layer) == 0) || (getCount(layer) == getAir(layer))) && getRelight(layer) == 0);
|
||||
if (!checkTime || Settings.PARALLEL_THREADS > 1) {
|
||||
ArrayList<Thread> threads = new ArrayList<Thread>();
|
||||
for (int k = 0; k < 16; k++) {
|
||||
final int l = k << 8;
|
||||
final int y = FaweCache.CACHE_Y[layer][l];
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int m = l; m < l + 256; m++) {
|
||||
char combined = newArray[m];
|
||||
switch (combined) {
|
||||
case 0:
|
||||
continue;
|
||||
case 1:
|
||||
if (!place) {
|
||||
int x = FaweCache.CACHE_X[layer][m];
|
||||
int z = FaweCache.CACHE_Z[layer][m];
|
||||
chunk.getBlock(x, y, z).setTypeId(0, false);
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
if (place) {
|
||||
int x = FaweCache.CACHE_X[layer][m];
|
||||
int z = FaweCache.CACHE_Z[layer][m];
|
||||
int id = combined >> 4;
|
||||
int data = combined & 0xF;
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
if (data == 0) {
|
||||
block.setTypeId(id, false);
|
||||
} else {
|
||||
block.setTypeIdAndData(id, (byte) data, false);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
threads.add(thread);
|
||||
thread.start();
|
||||
}
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
} else {
|
||||
for (;index < 4096; index++) {
|
||||
int j = place ? index : 4095 - index;
|
||||
char combined = newArray[j];
|
||||
switch (combined) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
if (!place) {
|
||||
int x = FaweCache.CACHE_X[layer][j];
|
||||
int z = FaweCache.CACHE_Z[layer][j];
|
||||
int y = FaweCache.CACHE_Y[layer][j];
|
||||
chunk.getBlock(x, y, z).setTypeId(0, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (place) {
|
||||
int id = combined >> 4;
|
||||
int data = combined & 0xF;
|
||||
int x = FaweCache.CACHE_X[layer][j];
|
||||
int z = FaweCache.CACHE_Z[layer][j];
|
||||
int y = FaweCache.CACHE_Y[layer][j];
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
if (data == 0) {
|
||||
block.setTypeId(id, false);
|
||||
} else {
|
||||
block.setTypeIdAndData(id, (byte) data, false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (checkTime && System.currentTimeMillis() - start > recommended) {
|
||||
index++;
|
||||
break mainloop;
|
||||
}
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
} catch (final Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
} while (System.currentTimeMillis() - start < recommended);
|
||||
if (more || place) {
|
||||
this.addToQueue();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +1,13 @@
|
||||
package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.example.CharFaweChunk;
|
||||
import com.boydti.fawe.example.NMSMappedFaweQueue;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.worldedit.LocalWorld;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.bukkit.BukkitUtil;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -23,7 +15,6 @@ import java.util.UUID;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMappedFaweQueue<World, CHUNK, CHUNKSECTIONS, SECTION> {
|
||||
|
||||
@ -143,115 +134,6 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
|
||||
try {
|
||||
// TODO track stage
|
||||
// TODO set task
|
||||
|
||||
final CharFaweChunk<Chunk> fs = ((CharFaweChunk<Chunk>) fc);
|
||||
final Chunk chunk = fs.getChunk();
|
||||
chunk.load(true);
|
||||
final World world = chunk.getWorld();
|
||||
char[][] sections = fs.getCombinedIdArrays();
|
||||
boolean done = false;
|
||||
boolean more = false;
|
||||
// Efficiently merge sections
|
||||
for (int j = 0; j < sections.length; j++) {
|
||||
final int jf = j;
|
||||
int changes = fs.getCount(j);
|
||||
int lighting = fs.getRelight(j);
|
||||
if (changes == 0) {
|
||||
continue;
|
||||
}
|
||||
final char[] newArray = sections[j];
|
||||
if (newArray == null) {
|
||||
continue;
|
||||
}
|
||||
if (done) {
|
||||
more = true;
|
||||
break;
|
||||
}
|
||||
done = true;
|
||||
sections[j] = null;
|
||||
ArrayList<Thread> threads = new ArrayList<Thread>();
|
||||
for (int k = 0; k < 16; k++) {
|
||||
final int l = k << 8;
|
||||
final int y = FaweCache.CACHE_Y[j][l];
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int m = l; m < l + 256; m++) {
|
||||
int combined = newArray[m];
|
||||
switch (combined) {
|
||||
case 0:
|
||||
continue;
|
||||
case 1:
|
||||
int x = FaweCache.CACHE_X[jf][m];
|
||||
int z = FaweCache.CACHE_Z[jf][m];
|
||||
chunk.getBlock(x, y, z).setTypeId(0, false);
|
||||
continue;
|
||||
default:
|
||||
x = FaweCache.CACHE_X[jf][m];
|
||||
z = FaweCache.CACHE_Z[jf][m];
|
||||
int id = combined >> 4;
|
||||
int data = combined & 0xF;
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
if (data == 0) {
|
||||
block.setTypeId(id, false);
|
||||
} else {
|
||||
block.setTypeIdAndData(id, (byte) data, false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
threads.add(thread);
|
||||
thread.start();
|
||||
}
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
if (more) {
|
||||
fc.addToQueue();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Biomes
|
||||
final int[][] biomes = fs.getBiomeArray();
|
||||
if (biomes != null) {
|
||||
final LocalWorld lw = BukkitUtil.getLocalWorld(world);
|
||||
final int X = fs.getX() << 4;
|
||||
final int Z = fs.getZ() << 4;
|
||||
final BaseBiome bb = new BaseBiome(0);
|
||||
int last = 0;
|
||||
for (int x = 0; x < 16; x++) {
|
||||
final int[] array = biomes[x];
|
||||
if (array == null) {
|
||||
continue;
|
||||
}
|
||||
for (int z = 0; z < 16; z++) {
|
||||
final int biome = array[z];
|
||||
if (biome == 0) {
|
||||
continue;
|
||||
}
|
||||
if (last != biome) {
|
||||
last = biome;
|
||||
bb.setId(biome);
|
||||
}
|
||||
lw.setBiome(new Vector2D(X + x, Z + z), bb);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (final Throwable e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweChunk getFaweChunk(int x, int z) {
|
||||
return new CharFaweChunk<Chunk>(this, x, z) {
|
||||
|
@ -1,14 +1,26 @@
|
||||
package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
public class BukkitQueue_All extends BukkitQueue_0<Chunk, Chunk, Chunk> {
|
||||
|
||||
public static int ALLOCATE;
|
||||
public static double TPS_TARGET = 18.5;
|
||||
|
||||
public BukkitQueue_All(String world) {
|
||||
super(world);
|
||||
if (Settings.ALLOCATE != Integer.MIN_VALUE) {
|
||||
ALLOCATE = Settings.ALLOCATE;
|
||||
Settings.ALLOCATE = Integer.MIN_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCombinedId4Data(Chunk section, int x, int y, int z) {
|
||||
@ -34,4 +46,36 @@ public class BukkitQueue_All extends BukkitQueue_0<Chunk, Chunk, Chunk> {
|
||||
public Chunk getChunk(World world, int x, int z) {
|
||||
return world.getChunkAt(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweChunk getFaweChunk(int x, int z) {
|
||||
return new BukkitChunk_All(this, x, z);
|
||||
}
|
||||
|
||||
private int skip;
|
||||
|
||||
@Override
|
||||
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
|
||||
if (skip > 0) {
|
||||
skip--;
|
||||
fc.addToQueue();
|
||||
return true;
|
||||
}
|
||||
long start = System.currentTimeMillis();
|
||||
((BukkitChunk_All) fc).execute(start);
|
||||
if (System.currentTimeMillis() - start > 50 || Fawe.get().getTPS() < TPS_TARGET) {
|
||||
skip = 10;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSet(boolean parallel) {
|
||||
super.startSet(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSet(boolean parallel) {
|
||||
super.endSet(true);
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ public class BukkitMain_110 extends ABukkitMain {
|
||||
@Override
|
||||
public BukkitQueue_0 getQueue(String world) {
|
||||
return new com.boydti.fawe.bukkit.v1_10.BukkitQueue_1_10(world);
|
||||
// return new BukkitQueue_All(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -626,4 +626,14 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
int j = FaweCache.CACHE_J[y][x][z];
|
||||
return array[j] >> 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweChunk getFaweChunk(int x, int z) {
|
||||
return new CharFaweChunk<Chunk>(this, x, z) {
|
||||
@Override
|
||||
public Chunk getNewChunk() {
|
||||
return BukkitQueue18R3.this.getWorld().getChunkAt(getX(), getZ());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.regions.general.plot.PlotSquaredFeature;
|
||||
import com.boydti.fawe.util.FaweTimer;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
@ -111,6 +112,11 @@ public class Fawe {
|
||||
*/
|
||||
private static Fawe INSTANCE;
|
||||
|
||||
/**
|
||||
* TPS timer
|
||||
*/
|
||||
private final FaweTimer timer;
|
||||
|
||||
/**
|
||||
* Get the implementation specific class
|
||||
* @return
|
||||
@ -173,6 +179,7 @@ public class Fawe {
|
||||
MainUtil.deleteOlder(new File(IMP.getDirectory(), "clipboard"), TimeUnit.DAYS.toMillis(Settings.DELETE_CLIPBOARD_AFTER_DAYS));
|
||||
|
||||
TaskManager.IMP = this.IMP.getTaskManager();
|
||||
TaskManager.IMP.repeat(timer = new FaweTimer(), 50);
|
||||
if (Settings.METRICS) {
|
||||
this.IMP.startMetrics();
|
||||
}
|
||||
@ -201,6 +208,10 @@ public class Fawe {
|
||||
this.setupMemoryListener();
|
||||
}
|
||||
|
||||
public double getTPS() {
|
||||
return timer.getTPS();
|
||||
}
|
||||
|
||||
private void setupEvents() {
|
||||
WorldEdit.getInstance().getEventBus().register(new WESubscriber());
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.schematic.Schematic;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
@ -139,6 +140,17 @@ public class FaweAPI {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Just forwards to ClipboardFormat.SCHEMATIC.load(file)
|
||||
* @see com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat
|
||||
* @see com.boydti.fawe.object.schematic.Schematic
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
public static Schematic load(File file) throws IOException {
|
||||
return ClipboardFormat.SCHEMATIC.load(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of supported protection plugin masks.
|
||||
* @return Set of FaweMaskManager
|
||||
|
@ -44,6 +44,7 @@ public enum BBC {
|
||||
DOWNLOAD_LINK("%s", "Web"),
|
||||
|
||||
|
||||
|
||||
COMMAND_COPY("%s0 blocks were copied", "WorldEdit.Copy"),
|
||||
COMMAND_CUT("%s0 blocks were cut", "WorldEdit.Cut"),
|
||||
COMMAND_PASTE("The clipboard has been pasted at %s0", "WorldEdit.Paste"),
|
||||
@ -81,6 +82,7 @@ public enum BBC {
|
||||
BRUSH_EXTINGUISHER("Extinguisher equipped (%s0).", "WorldEdit.Brush"),
|
||||
BRUSH_GRAVITY("Gravity brush equipped (%s0)", "WorldEdit.Brush"),
|
||||
BRUSH_HEIGHT("Height brush equipped (%s0)", "WorldEdit.Brush"),
|
||||
BRUSH_COPY("Copy brush equipped (%s0)", "WorldEdit.Brush"),
|
||||
BRUSH_HEIGHT_INVALID("Invalid height map file (%s0)", "WorldEdit.Brush"),
|
||||
BRUSH_SMOOTH("Smooth brush equipped (%s0 x %s1 using %s2).", "WorldEdit.Brush"),
|
||||
BRUSH_SPHERE("Sphere brush shape equipped (%s0).", "WorldEdit.Brush"),
|
||||
@ -100,10 +102,11 @@ public enum BBC {
|
||||
SELECTOR_CUBOID_POS1("First position set to %s0 %s1.", "WorldEdit.Selector"),
|
||||
SELECTOR_CUBOID_POS2("Second position set to %s0 %s1.", "WorldEdit.Selector"),
|
||||
|
||||
COMMAND_INVALID_SYNTAX("The command was not used properly (no more help available).", "WorldEdit.Command"),
|
||||
|
||||
PROGRESS_MESSAGE("[ Queue: %s0 | Dispatched: %s1 ]", "Progress"),
|
||||
PROGRESS_DONE ("[ Took: %s0s ]", "Progress"),
|
||||
|
||||
|
||||
COMMAND_SYNTAX("&cUsage: &7%s0", "Error"),
|
||||
NO_PERM("&cYou are lacking the permission node: %s0", "Error"),
|
||||
SCHEMATIC_NOT_FOUND("&cSchematic not found: &7%s0", "Error"),
|
||||
@ -308,6 +311,10 @@ public enum BBC {
|
||||
}
|
||||
}
|
||||
|
||||
public static String getPrefix() {
|
||||
return (PREFIX.isEmpty() ? "" : PREFIX.s() + " ");
|
||||
}
|
||||
|
||||
public void send(final FawePlayer<?> player, final Object... args) {
|
||||
if (isEmpty()) {
|
||||
return;
|
||||
|
@ -1,4 +0,0 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
public class AbstractDelegateBrush {
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package com.boydti.fawe.object.brush;
|
||||
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.clipboard.ResizableClipboardBuilder;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.object.function.NullRegionFunction;
|
||||
import com.boydti.fawe.object.function.mask.AbstractDelegateMask;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.command.tool.BrushTool;
|
||||
import com.sk89q.worldedit.command.tool.brush.Brush;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
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.operation.Operations;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
|
||||
public class CopyBrush implements Brush {
|
||||
|
||||
private final BrushTool tool;
|
||||
private final LocalSession session;
|
||||
private final Player player;
|
||||
|
||||
public CopyBrush(Player player, LocalSession session, BrushTool tool) {
|
||||
this.tool = tool;
|
||||
this.session = session;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(final EditSession editSession, Vector position, Pattern pattern, double size) throws MaxChangedBlocksException {
|
||||
Mask mask = tool.getMask();
|
||||
if (mask == null) {
|
||||
mask = Masks.alwaysTrue();
|
||||
}
|
||||
final ResizableClipboardBuilder builder = new ResizableClipboardBuilder(editSession.getWorld());
|
||||
final int size2 = (int) (size * size);
|
||||
final int minY = position.getBlockY();
|
||||
mask = new AbstractDelegateMask(mask) {
|
||||
private int visited = 0;
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
if (super.test(vector) && vector.getBlockY() >= minY) {
|
||||
BaseBlock block = editSession.getLazyBlock(vector);
|
||||
if (block != EditSession.nullBlock) {
|
||||
if (visited++ > size2) {
|
||||
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
|
||||
}
|
||||
builder.add(vector, EditSession.nullBlock, block);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, new NullRegionFunction());
|
||||
visitor.visit(position);
|
||||
Operations.completeBlindly(visitor);
|
||||
// To clipboard
|
||||
Clipboard clipboard = builder.build();
|
||||
session.setClipboard(new ClipboardHolder(clipboard, editSession.getWorld().getWorldData()));
|
||||
int blocks = builder.size();
|
||||
BBC.COMMAND_COPY.send(player, blocks);
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ public class HeightBrush implements Brush {
|
||||
double yscale = 1;
|
||||
private final BrushTool tool;
|
||||
|
||||
public HeightBrush(File file, int rotation, double yscale, BrushTool tool, EditSession session, Clipboard clipboard) {
|
||||
public HeightBrush(File file, int rotation, double yscale, BrushTool tool, Clipboard clipboard) {
|
||||
this.tool = tool;
|
||||
this.rotation = (rotation / 90) % 4;
|
||||
this.yscale = yscale;
|
||||
|
@ -271,48 +271,44 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||
if (summary != null) {
|
||||
return summary;
|
||||
}
|
||||
try {
|
||||
if (bdFile.exists()) {
|
||||
int ox = getOriginX();
|
||||
int oz = getOriginZ();
|
||||
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
|
||||
return summary = new DiskStorageSummary(ox, oz);
|
||||
if (bdFile.exists()) {
|
||||
int ox = getOriginX();
|
||||
int oz = getOriginZ();
|
||||
if ((ox != 0 || oz != 0) && !requiredRegion.isIn(ox, oz)) {
|
||||
return summary = new DiskStorageSummary(ox, oz);
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(bdFile)) {
|
||||
FaweInputStream gis = MainUtil.getCompressedIS(fis);
|
||||
// skip mode
|
||||
gis.skip(1);
|
||||
// origin
|
||||
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
setOrigin(ox, oz);
|
||||
summary = new DiskStorageSummary(ox, oz);
|
||||
if (!requiredRegion.isIn(ox, oz)) {
|
||||
fis.close();
|
||||
gis.close();
|
||||
return summary;
|
||||
}
|
||||
try (FileInputStream fis = new FileInputStream(bdFile)) {
|
||||
FaweInputStream gis = MainUtil.getCompressedIS(fis);
|
||||
// skip mode
|
||||
gis.skip(1);
|
||||
// origin
|
||||
ox = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
oz = ((gis.read() << 24) + (gis.read() << 16) + (gis.read() << 8) + (gis.read() << 0));
|
||||
setOrigin(ox, oz);
|
||||
summary = new DiskStorageSummary(ox, oz);
|
||||
if (!requiredRegion.isIn(ox, oz)) {
|
||||
byte[] buffer = new byte[9];
|
||||
int i = 0;
|
||||
int amount = (Settings.BUFFER_SIZE - HEADER_SIZE) / 9;
|
||||
while (!shallow && ++i < amount) {
|
||||
if (gis.read(buffer) == -1) {
|
||||
fis.close();
|
||||
gis.close();
|
||||
return summary;
|
||||
}
|
||||
byte[] buffer = new byte[9];
|
||||
int i = 0;
|
||||
int amount = (Settings.BUFFER_SIZE - HEADER_SIZE) / 9;
|
||||
while (!shallow && ++i < amount) {
|
||||
if (gis.read(buffer) == -1) {
|
||||
fis.close();
|
||||
gis.close();
|
||||
return summary;
|
||||
}
|
||||
int x = ((byte) buffer[0] & 0xFF) + ((byte) buffer[1] << 8) + ox;
|
||||
int z = ((byte) buffer[2] & 0xFF) + ((byte) buffer[3] << 8) + oz;
|
||||
int combined1 = buffer[7] & 0xFF;
|
||||
int combined2 = buffer[8] & 0xFF;
|
||||
summary.add(x, z, ((combined2 << 4) + (combined1 >> 4)));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
int x = ((byte) buffer[0] & 0xFF) + ((byte) buffer[1] << 8) + ox;
|
||||
int z = ((byte) buffer[2] & 0xFF) + ((byte) buffer[3] << 8) + oz;
|
||||
int combined1 = buffer[7] & 0xFF;
|
||||
int combined2 = buffer[8] & 0xFF;
|
||||
summary.add(x, z, ((combined2 << 4) + (combined1 >> 4)));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
MainUtil.handleError(e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
@ -0,0 +1,89 @@
|
||||
package com.boydti.fawe.object.clipboard;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.change.MutableBlockChange;
|
||||
import com.boydti.fawe.object.change.MutableTileChange;
|
||||
import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.history.change.Change;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class ResizableClipboardBuilder extends MemoryOptimizedHistory {
|
||||
|
||||
private int minX = Integer.MAX_VALUE;
|
||||
private int minY = Integer.MAX_VALUE;
|
||||
private int minZ = Integer.MAX_VALUE;
|
||||
|
||||
private int maxX = Integer.MIN_VALUE;
|
||||
private int maxY = Integer.MIN_VALUE;
|
||||
private int maxZ = Integer.MIN_VALUE;
|
||||
|
||||
|
||||
public ResizableClipboardBuilder(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(int x, int y, int z, int combinedFrom, int combinedTo) {
|
||||
super.add(x, y, z, combinedFrom, combinedTo);
|
||||
if (x < minX) {
|
||||
if (maxX == Integer.MIN_VALUE) {
|
||||
maxX = x;
|
||||
}
|
||||
minX = x;
|
||||
}
|
||||
else if (x > maxX) {
|
||||
maxX = x;
|
||||
}
|
||||
if (y < minY) {
|
||||
if (maxY == Integer.MIN_VALUE) {
|
||||
maxY = y;
|
||||
}
|
||||
minY = y;
|
||||
}
|
||||
else if (y > maxY) {
|
||||
maxY = y;
|
||||
}
|
||||
if (z < minZ) {
|
||||
if (maxZ == Integer.MIN_VALUE) {
|
||||
maxZ = z;
|
||||
}
|
||||
minZ = z;
|
||||
}
|
||||
else if (z > maxZ) {
|
||||
maxZ = z;
|
||||
}
|
||||
}
|
||||
|
||||
public Clipboard build() {
|
||||
Vector pos1 = new Vector(minX, minY, minZ);
|
||||
Vector pos2 = new Vector(maxX, maxY, maxZ);
|
||||
CuboidRegion region = new CuboidRegion(pos1, pos2);
|
||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
|
||||
Iterator<Change> iter = getIterator(true);
|
||||
try {
|
||||
while (iter.hasNext()) {
|
||||
Change change = iter.next();
|
||||
if (change instanceof MutableBlockChange) {
|
||||
MutableBlockChange blockChange = (MutableBlockChange) change;
|
||||
clipboard.setBlock(blockChange.x, blockChange.y, blockChange.z, FaweCache.getBlock(blockChange.id, blockChange.data));
|
||||
} else if (change instanceof MutableTileChange) {
|
||||
MutableTileChange tileChange = (MutableTileChange) change;
|
||||
int x = tileChange.tag.getInt("x");
|
||||
int y = tileChange.tag.getInt("y");
|
||||
int z = tileChange.tag.getInt("z");
|
||||
clipboard.setTile(x, y, z, tileChange.tag);
|
||||
}
|
||||
}
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return clipboard;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.boydti.fawe.object.function;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
|
||||
public class NullRegionFunction implements RegionFunction {
|
||||
@Override
|
||||
public boolean apply(Vector position) throws WorldEditException {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.boydti.fawe.object.function.mask;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class AbstractDelegateMask implements Mask {
|
||||
|
||||
private final Mask parent;
|
||||
|
||||
public AbstractDelegateMask(Mask parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Vector vector) {
|
||||
return parent.test(vector);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
return parent.toMask2D();
|
||||
}
|
||||
}
|
@ -68,7 +68,7 @@ public class PNGWriter implements ClipboardWriter {
|
||||
}
|
||||
for (int j = 0; j < dpxj.length; j++) {
|
||||
dpxj[j] = cx + j * d;
|
||||
dpyj[j] = imageSize + d + j * d_2;
|
||||
dpyj[j] = imageSize / 2 + d + j * d_2;
|
||||
}
|
||||
for (int i = 0; i < Math.max(256, dpxi.length); i++) {
|
||||
dpxi[i] = i * d;
|
||||
|
@ -0,0 +1,118 @@
|
||||
package com.boydti.fawe.object.schematic;
|
||||
|
||||
import com.boydti.fawe.object.clipboard.LazyClipboard;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.transform.BlockTransformExtent;
|
||||
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.math.transform.Transform;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class Schematic {
|
||||
private final Clipboard clipboard;
|
||||
|
||||
public Schematic(Clipboard clipboard) {
|
||||
checkNotNull(clipboard);
|
||||
this.clipboard = clipboard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the schematic for a region
|
||||
* @param region
|
||||
*/
|
||||
public Schematic(Region region) {
|
||||
checkNotNull(region);
|
||||
checkNotNull(region.getWorld());
|
||||
EditSession session = new EditSessionBuilder(region.getWorld()).allowedRegionsEverywhere().autoQueue(false).build();
|
||||
this.clipboard = new BlockArrayClipboard(region, LazyClipboard.of(session, region));
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards to paste(world, to, true, true, null)
|
||||
* @param world
|
||||
* @param to
|
||||
* @return
|
||||
*/
|
||||
public EditSession paste(World world, Vector to) {
|
||||
return paste(world, to, true, true, null);
|
||||
}
|
||||
|
||||
public void save(File file, ClipboardFormat format) throws IOException {
|
||||
checkNotNull(file);
|
||||
checkNotNull(format);
|
||||
if (!file.exists()) {
|
||||
File parent = file.getParentFile();
|
||||
if (parent != null) {
|
||||
parent.mkdirs();
|
||||
}
|
||||
file.createNewFile();
|
||||
}
|
||||
save(new FileOutputStream(file), format);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save this schematic to a stream
|
||||
* @param stream
|
||||
* @param format
|
||||
* @throws IOException
|
||||
*/
|
||||
public void save(OutputStream stream, ClipboardFormat format) throws IOException {
|
||||
checkNotNull(stream);
|
||||
checkNotNull(format);
|
||||
format.getWriter(stream).write(clipboard, clipboard.getRegion().getWorld().getWorldData());
|
||||
}
|
||||
|
||||
/**
|
||||
* Paste this schematic in a world
|
||||
* @param world
|
||||
* @param to
|
||||
* @param allowUndo
|
||||
* @param pasteAir
|
||||
* @param transform
|
||||
* @return
|
||||
*/
|
||||
public EditSession paste(World world, Vector to, boolean allowUndo, boolean pasteAir, @Nullable Transform transform) {
|
||||
checkNotNull(world);
|
||||
checkNotNull(to);
|
||||
Region region = clipboard.getRegion();
|
||||
EditSessionBuilder builder = new EditSessionBuilder(world).autoQueue(true).checkMemory(false).allowedRegionsEverywhere().limitUnlimited();
|
||||
EditSession editSession;
|
||||
if (allowUndo) {
|
||||
editSession = builder.build();
|
||||
} else {
|
||||
editSession = builder.changeSetNull().build();
|
||||
}
|
||||
Extent extent = clipboard;
|
||||
if (transform != null) {
|
||||
extent = new BlockTransformExtent(clipboard, transform, world.getWorldData().getBlockRegistry());
|
||||
}
|
||||
ForwardExtentCopy copy = new ForwardExtentCopy(extent, clipboard.getRegion(), clipboard.getOrigin(), editSession, to);
|
||||
copy.setTransform(transform);
|
||||
if (!pasteAir) {
|
||||
copy.setSourceMask(new ExistingBlockMask(clipboard));
|
||||
}
|
||||
try {
|
||||
Operations.completeLegacy(copy);
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
editSession.flushQueue();
|
||||
return editSession;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package com.boydti.fawe.object.visitor;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Visits adjacent points on the same X-Z plane as long as the points
|
||||
* pass the given mask, and then executes the provided region
|
||||
* function on the entire column.
|
||||
*
|
||||
* <p>This is used by {@code //fill}.</p>
|
||||
*/
|
||||
public class AboveVisitor extends RecursiveVisitor {
|
||||
|
||||
private int baseY;
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param baseY the base Y
|
||||
*/
|
||||
public AboveVisitor(Mask mask, RegionFunction function, int baseY) {
|
||||
super(mask, function);
|
||||
checkNotNull(mask);
|
||||
|
||||
this.baseY = baseY;
|
||||
|
||||
Collection<Vector> directions = getDirections();
|
||||
directions.clear();
|
||||
directions.add(new Vector(1, 0, 0));
|
||||
directions.add(new Vector(-1, 0, 0));
|
||||
directions.add(new Vector(0, 0, 1));
|
||||
directions.add(new Vector(0, 0, -1));
|
||||
directions.add(new Vector(0, 1, 0));
|
||||
directions.add(new Vector(0, -1, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isVisitable(Vector from, Vector to) {
|
||||
return (from.getBlockY() >= baseY) && super.isVisitable(from, to);
|
||||
}
|
||||
}
|
45
core/src/main/java/com/boydti/fawe/util/FaweTimer.java
Normal file
45
core/src/main/java/com/boydti/fawe/util/FaweTimer.java
Normal file
@ -0,0 +1,45 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
public class FaweTimer implements Runnable {
|
||||
|
||||
private long tick = 0;
|
||||
|
||||
private final double[] history = new double[] {20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d,20d};
|
||||
private int historyIndex = 0;
|
||||
private long lastPoll = System.nanoTime();
|
||||
private final long tickInterval = 50;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final long startTime = System.nanoTime();
|
||||
final long currentTime = System.currentTimeMillis();
|
||||
long timeSpent = (startTime - lastPoll) / 1000;
|
||||
if (timeSpent == 0)
|
||||
{
|
||||
timeSpent = 1;
|
||||
}
|
||||
tick++;
|
||||
double tps = tickInterval * 1000000.0 / timeSpent;
|
||||
history[historyIndex++] = tps;
|
||||
if (historyIndex >= history.length) {
|
||||
historyIndex = 0;
|
||||
}
|
||||
lastPoll = startTime;
|
||||
}
|
||||
|
||||
private long lastGetTPSTick = 0;
|
||||
private double lastGetTPSValue = 20d;
|
||||
|
||||
public double getTPS() {
|
||||
if (tick == lastGetTPSTick) {
|
||||
return lastGetTPSValue;
|
||||
}
|
||||
double total = 0;
|
||||
for (double tps : history) {
|
||||
total += tps;
|
||||
}
|
||||
lastGetTPSValue = total / history.length;
|
||||
lastGetTPSTick = tick;
|
||||
return lastGetTPSValue;
|
||||
}
|
||||
}
|
62
core/src/main/java/com/boydti/fawe/util/HastebinUtility.java
Normal file
62
core/src/main/java/com/boydti/fawe/util/HastebinUtility.java
Normal file
@ -0,0 +1,62 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class HastebinUtility {
|
||||
|
||||
public static final String BIN_URL = "http://hastebin.com/documents", USER_AGENT = "Mozilla/5.0";
|
||||
public static final Pattern PATTERN = Pattern.compile("\\{\"key\":\"([\\S\\s]*)\"\\}");
|
||||
|
||||
public static String upload(final String string) throws IOException {
|
||||
final URL url = new URL(BIN_URL);
|
||||
final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("User-Agent", USER_AGENT);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
|
||||
outputStream.write(string.getBytes());
|
||||
outputStream.flush();
|
||||
}
|
||||
|
||||
StringBuilder response;
|
||||
try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
response = new StringBuilder();
|
||||
|
||||
String inputLine;
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
response.append(inputLine);
|
||||
}
|
||||
}
|
||||
|
||||
Matcher matcher = PATTERN.matcher(response.toString());
|
||||
if (matcher.matches()) {
|
||||
return "http://hastebin.com/" + matcher.group(1);
|
||||
} else {
|
||||
throw new RuntimeException("Couldn't read response!");
|
||||
}
|
||||
}
|
||||
|
||||
public static String upload(final File file) throws IOException {
|
||||
final StringBuilder content = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
int i = 0;
|
||||
while ((line = reader.readLine()) != null && i++ < 1000) {
|
||||
content.append(line).append("\n");
|
||||
}
|
||||
}
|
||||
return upload(content.toString());
|
||||
}
|
||||
|
||||
}
|
71
core/src/main/java/com/boydti/fawe/util/ImgurUtility.java
Normal file
71
core/src/main/java/com/boydti/fawe/util/ImgurUtility.java
Normal file
@ -0,0 +1,71 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
|
||||
public class ImgurUtility {
|
||||
public static final String CLIENT_ID = "50e34b65351eb07";
|
||||
|
||||
public static URL uploadImage(File file) throws IOException {
|
||||
return uploadImage(new FileInputStream(file));
|
||||
}
|
||||
|
||||
public static URL uploadImage(InputStream is) throws IOException {
|
||||
is = new BufferedInputStream(is);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(Short.MAX_VALUE);
|
||||
int d;
|
||||
while ((d = is.read()) != -1) {
|
||||
baos.write(d);
|
||||
}
|
||||
baos.flush();
|
||||
return uploadImage(baos.toByteArray());
|
||||
}
|
||||
|
||||
public static URL uploadImage(byte[] image) throws IOException {
|
||||
String json = getImgurContent(CLIENT_ID, image);
|
||||
Gson gson = new Gson();
|
||||
JsonObject obj = gson.fromJson(json, JsonObject.class);
|
||||
JsonObject data = obj.get("data").getAsJsonObject();
|
||||
String link = data.get("link").getAsString();
|
||||
return new URL(link);
|
||||
}
|
||||
|
||||
public static String getImgurContent(String clientID, byte[] image) throws IOException {
|
||||
String imageString = DatatypeConverter.printBase64Binary(image);
|
||||
URL url = new URL("https://api.imgur.com/3/image");
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
String data = URLEncoder.encode("image", "UTF-8") + "=" + URLEncoder.encode(imageString, "UTF-8");
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Authorization", "Client-ID " + clientID);
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
conn.connect();
|
||||
StringBuilder stb = new StringBuilder();
|
||||
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
|
||||
wr.write(data);
|
||||
wr.flush();
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
String line;
|
||||
while ((line = rd.readLine()) != null) {
|
||||
stb.append(line).append("\n");
|
||||
}
|
||||
wr.close();
|
||||
rd.close();
|
||||
return stb.toString();
|
||||
}
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
package com.boydti.fawe.util;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class TaskManager {
|
||||
|
||||
@ -38,6 +40,64 @@ public abstract class TaskManager {
|
||||
*/
|
||||
public abstract void task(final Runnable r);
|
||||
|
||||
/**
|
||||
* Run a bunch of tasks in parallel
|
||||
* @param runnables The tasks to run
|
||||
* @param numThreads Number of threads (null = config.yml parallel threads)
|
||||
*/
|
||||
public void parallel(Collection<Runnable> runnables, @Nullable Integer numThreads) {
|
||||
if (runnables == null) {
|
||||
return;
|
||||
}
|
||||
if (numThreads == null) {
|
||||
numThreads = Settings.PARALLEL_THREADS;
|
||||
}
|
||||
if (numThreads <= 1) {
|
||||
for (Runnable run : runnables) {
|
||||
if (run != null) {
|
||||
run.run();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
int numRuns = runnables.size();
|
||||
int amountPerThread = 1 + numRuns / numThreads;
|
||||
final Runnable[][] split = new Runnable[numThreads][amountPerThread];
|
||||
Thread[] threads = new Thread[numThreads];
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
for (Runnable run : runnables) {
|
||||
split[i][j] = run;
|
||||
if (++i >= numThreads) {
|
||||
i = 0;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < threads.length; i++) {
|
||||
final Runnable[] toRun = split[i];
|
||||
Thread thread = threads[i] = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int j = 0; j < toRun.length; j++) {
|
||||
Runnable run = toRun[j];
|
||||
if (run != null) {
|
||||
run.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
}
|
||||
for (Thread thread : threads) {
|
||||
try {
|
||||
thread.join();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a task on the current thread or asynchronously
|
||||
* - If it's already the main thread, it will jst call run()
|
||||
|
@ -24,6 +24,7 @@ import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.brush.CopyBrush;
|
||||
import com.boydti.fawe.object.brush.HeightBrush;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
@ -135,7 +136,7 @@ public class BrushCommands {
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "clipboard", "copy" },
|
||||
aliases = { "clipboard", "paste" },
|
||||
usage = "",
|
||||
desc = "Choose the clipboard brush",
|
||||
help =
|
||||
@ -248,13 +249,31 @@ public class BrushCommands {
|
||||
BrushTool tool = session.getBrushTool(player.getItemInHand());
|
||||
tool.setSize(radius);
|
||||
try {
|
||||
tool.setBrush(new HeightBrush(file, rotation, yscale, tool, editSession, session.getClipboard().getClipboard()), "worldedit.brush.height");
|
||||
tool.setBrush(new HeightBrush(file, rotation, yscale, tool, session.getClipboard().getClipboard()), "worldedit.brush.height");
|
||||
} catch (EmptyClipboardException ignore) {
|
||||
tool.setBrush(new HeightBrush(file, rotation, yscale, tool, editSession, null), "worldedit.brush.height");
|
||||
tool.setBrush(new HeightBrush(file, rotation, yscale, tool, null), "worldedit.brush.height");
|
||||
}
|
||||
BBC.BRUSH_HEIGHT.send(player, radius);
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "copy" },
|
||||
usage = "[depth]",
|
||||
desc = "Copy brush",
|
||||
help =
|
||||
"Right click the base of an object to copy.\n",
|
||||
min = 0,
|
||||
max = 1
|
||||
)
|
||||
@CommandPermissions("worldedit.brush.copy")
|
||||
public void copy(Player player, LocalSession session, EditSession editSession, @Optional("5") double radius, @Optional("") final String filename, @Optional("0") final int rotation, @Optional("1") final double yscale) throws WorldEditException {
|
||||
worldEdit.checkMaxBrushRadius(radius);
|
||||
BrushTool tool = session.getBrushTool(player.getItemInHand());
|
||||
tool.setSize(radius);
|
||||
tool.setBrush(new CopyBrush(player, session, tool), "worldedit.brush.copy");
|
||||
BBC.BRUSH_COPY.send(player, radius);
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = { "butcher", "kill" },
|
||||
usage = "[radius]",
|
||||
|
@ -23,6 +23,7 @@ import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.clipboard.LazyClipboard;
|
||||
import com.boydti.fawe.util.ImgurUtility;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
@ -41,6 +42,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||
import com.sk89q.worldedit.function.block.BlockReplace;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||
@ -58,6 +60,9 @@ import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.util.command.binding.Switch;
|
||||
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@ -220,7 +225,31 @@ public class ClipboardCommands {
|
||||
ClipboardHolder holder = session.getClipboard();
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
BBC.GENERATING_LINK.send(player, formatName);
|
||||
URL url = FaweAPI.upload(clipboard, format);
|
||||
URL url;
|
||||
switch (format) {
|
||||
case PNG:
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(Short.MAX_VALUE);
|
||||
ClipboardWriter writer = format.getWriter(baos);
|
||||
writer.write(clipboard, null);
|
||||
baos.flush();
|
||||
FileOutputStream fos = new FileOutputStream("blah.png");
|
||||
fos.write(baos.toByteArray());
|
||||
fos.close();
|
||||
url = null;
|
||||
url = ImgurUtility.uploadImage(baos.toByteArray());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
url = null;
|
||||
}
|
||||
break;
|
||||
case SCHEMATIC:
|
||||
url = FaweAPI.upload(clipboard, format);
|
||||
break;
|
||||
default:
|
||||
url = null;
|
||||
break;
|
||||
}
|
||||
if (url == null) {
|
||||
BBC.GENERATING_LINK_FAILED.send(player);
|
||||
} else {
|
||||
|
@ -254,7 +254,7 @@ public final class CommandManager {
|
||||
try {
|
||||
dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
|
||||
} catch (CommandPermissionsException e) {
|
||||
actor.printError("You are not permitted to do that. Are you in the right mode?");
|
||||
BBC.NO_PERM.send(actor, "worldedit.*");
|
||||
} catch (InvalidUsageException e) {
|
||||
if (e.isFullHelpSuggested()) {
|
||||
actor.printRaw(ColorCodeBuilder.asColorCodes(new CommandUsageBox(e.getCommand(), e.getCommandUsed("/", ""), locals)));
|
||||
@ -264,8 +264,8 @@ public final class CommandManager {
|
||||
}
|
||||
} else {
|
||||
String message = e.getMessage();
|
||||
actor.printError(message != null ? message : "The command was not used properly (no more help available).");
|
||||
actor.printError("Usage: " + e.getSimpleUsageString("/"));
|
||||
actor.print(BBC.getPrefix() + (message != null ? message : "The command was not used properly (no more help available)."));
|
||||
BBC.COMMAND_SYNTAX.send(actor, e.getSimpleUsageString("/"));
|
||||
}
|
||||
} catch (WrappedCommandException e) {
|
||||
FaweException faweException = FaweException.get(e);
|
||||
|
@ -23,6 +23,7 @@ import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||
import com.boydti.fawe.object.schematic.FaweFormat;
|
||||
import com.boydti.fawe.object.schematic.PNGWriter;
|
||||
import com.boydti.fawe.object.schematic.Schematic;
|
||||
import com.boydti.fawe.object.schematic.StructureFormat;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
@ -138,7 +139,7 @@ public enum ClipboardFormat {
|
||||
}
|
||||
},
|
||||
|
||||
PNG("png") {
|
||||
PNG("png", "image") {
|
||||
@Override
|
||||
public ClipboardReader getReader(InputStream inputStream) throws IOException {
|
||||
return null;
|
||||
@ -286,6 +287,14 @@ public enum ClipboardFormat {
|
||||
*/
|
||||
public abstract ClipboardWriter getWriter(OutputStream outputStream) throws IOException;
|
||||
|
||||
public Schematic load(File file) throws IOException {
|
||||
return load(new FileInputStream(file));
|
||||
}
|
||||
|
||||
public Schematic load(InputStream stream) throws IOException {
|
||||
return new Schematic(this.getReader(stream).read(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file extension used
|
||||
* @return file extension string
|
||||
|
Loading…
Reference in New Issue
Block a user