Fixes #89
brush fixes
optimizations
restructure
etc
This commit is contained in:
Jesse Boyd 2016-05-02 12:04:28 +10:00
parent ea6840535a
commit 9f0602f2ec
25 changed files with 400 additions and 406 deletions

View File

@ -1,8 +1,11 @@
package com.boydti.fawe.bukkit.logging;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import org.PrimeSoft.blocksHub.BlocksHub;
import org.PrimeSoft.blocksHub.IBlocksHubApi;
import org.bukkit.Bukkit;
@ -17,7 +20,7 @@ public class BlocksHubHook {
this.api = this.hub.getApi();
}
public Extent getLoggingExtent(final Extent parent, final ChangeSet set, final FawePlayer<?> player) {
return new LoggingExtent(parent, set, (FawePlayer<Player>) player, this.api);
public FaweChangeSet getLoggingChangeSet(EditSession session, FaweLimit limit, Extent parent, FaweChangeSet set, FaweQueue queue, FawePlayer<?> player) {
return new LoggingChangeSet((FawePlayer<Player>) player, set, api);
}
}

View File

@ -0,0 +1,86 @@
package com.boydti.fawe.bukkit.logging;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.history.change.Change;
import java.util.Iterator;
import org.PrimeSoft.blocksHub.IBlocksHubApi;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
public class LoggingChangeSet implements FaweChangeSet {
private final FaweChangeSet parent;
private final IBlocksHubApi api;
private final World world;
private final Location loc;
private final String name;
public LoggingChangeSet(FawePlayer<Player> player, FaweChangeSet parent, IBlocksHubApi api) {
this.parent = parent;
this.name = player.getName();
this.api = api;
this.world = player.parent.getWorld();
this.loc = new Location(world, 0, 0, 0);
}
@Override
public boolean flush() {
return parent.flush();
}
@Override
public int getCompressedSize() {
return parent.getCompressedSize();
}
@Override
public void add(Vector location, BaseBlock from, BaseBlock to) {
loc.setX(location.getX());
loc.setY(location.getY());
loc.setZ(location.getZ());
api.logBlock(name, world, loc, from.getId(), (byte) from.getData(), to.getId(), (byte) to.getData());
parent.add(location, from, to);
}
@Override
public void add(int x, int y, int z, int combinedId4DataFrom, BaseBlock to) {
loc.setX(x);
loc.setY(y);
loc.setZ(z);
api.logBlock(name, world, loc, combinedId4DataFrom >> 4, (byte) (combinedId4DataFrom & 0xF), to.getId(), (byte) to.getData());
parent.add(x, y, z, combinedId4DataFrom, to);
}
@Override
public void add(int x, int y, int z, int combinedId4DataFrom, int combinedId4DataTo) {
loc.setX(x);
loc.setY(y);
loc.setZ(z);
api.logBlock(name, world, loc, combinedId4DataFrom >> 4, (byte) (combinedId4DataFrom & 0xF), combinedId4DataTo >> 4, (byte) (combinedId4DataTo & 0xF));
parent.add(x, y, z, combinedId4DataFrom, combinedId4DataTo);
}
@Override
public void add(Change change) {
parent.add(change);
}
@Override
public Iterator<Change> backwardIterator() {
return parent.backwardIterator();
}
@Override
public Iterator<Change> forwardIterator() {
return parent.forwardIterator();
}
@Override
public int size() {
return parent.size();
}
}

View File

@ -24,10 +24,10 @@ public class BukkitEditSessionWrapper_0 extends EditSessionWrapper {
@Override
public Extent getHistoryExtent(EditSession session, FaweLimit limit, Extent parent, FaweChangeSet set, FaweQueue queue, FawePlayer<?> player) {
if (this.hook != null) {
// If we are doing logging, return a custom logging extent
return this.hook.getLoggingExtent(parent, set, player);
// If we are doing logging, use a custom logging ChangeSet
set = hook.getLoggingChangeSet(session, limit, parent, set, queue, player);
}
// Otherwise return the normal history extent
// Now return the normal history extent
return super.getHistoryExtent(session, limit, parent, set, queue, player);
}
}

View File

@ -79,7 +79,7 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
ChunkListener.physicsFreeze = false;
if (parallel) {
try {Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");fieldEnabled.setAccessible(true);fieldEnabled.set(null, timingsEnabled);
} catch (Throwable ignore) {ignore.printStackTrace();}
} catch (Throwable ignore) {}
try { Class.forName("org.spigotmc.AsyncCatcher").getField("enabled").set(null, true); } catch (Throwable ignore) {}
}
}

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit.v1_9;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.util.FaweQueue;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import net.minecraft.server.v1_9_R1.Block;
import net.minecraft.server.v1_9_R1.DataBits;
@ -96,7 +97,17 @@ public class BukkitChunk_1_9 extends CharFaweChunk<Chunk> {
if (sectionPalettes == null) {
sectionPalettes = new DataPaletteBlock[16];
}
DataPaletteBlock palette = sectionPalettes[layer] = new DataPaletteBlock();
DataPaletteBlock palette;
try {
palette = sectionPalettes[layer] = new DataPaletteBlock();
} catch (Throwable e) {
try {
Constructor<DataPaletteBlock> constructor = DataPaletteBlock.class.getDeclaredConstructor(IBlockData[].class);
palette = sectionPalettes[layer] = constructor.newInstance(null);
} catch (Throwable e2) {
throw new RuntimeException(e2);
}
}
char[] blocks = getIdArray(layer);
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {

View File

@ -10,6 +10,7 @@ import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.util.MemUtil;
import com.sk89q.worldedit.LocalSession;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
@ -224,6 +225,28 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
fieldSection.set(section, palette);
}
public ChunkSection newChunkSection(int y2, boolean flag, char[] array) {
try {
if (array == null) {
return new ChunkSection(y2, flag);
} else {
return new ChunkSection(y2, flag, array);
}
} catch (Throwable e) {
try {
if (array == null) {
Constructor<ChunkSection> constructor = ChunkSection.class.getDeclaredConstructor(int.class, boolean.class, IBlockData[].class);
return constructor.newInstance(y2, flag, null);
} else {
Constructor<ChunkSection> constructor = ChunkSection.class.getDeclaredConstructor(int.class, boolean.class, char[].class, IBlockData[].class);
return constructor.newInstance(y2, flag, array, null);
}
} catch (Throwable e2) {
throw new RuntimeException(e2);
}
}
}
@Override
public boolean setComponents(final FaweChunk pc) {
final BukkitChunk_1_9 fs = (BukkitChunk_1_9) pc;
@ -268,9 +291,6 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
}
}
}
if (removed) {
w.tileEntityListTick.clear();
}
// Trim entities
for (int i = 0; i < 16; i++) {

View File

@ -336,6 +336,9 @@ public class Fawe {
}
private void setupMemoryListener() {
if (Settings.MEM_FREE < 1) {
return;
}
final MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
final NotificationEmitter ne = (NotificationEmitter) memBean;

View File

@ -3,14 +3,10 @@ package com.boydti.fawe.command;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.extent.FaweExtent;
import com.boydti.fawe.object.extent.NullExtent;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.WEManager;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.world.World;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@ -37,21 +33,8 @@ public class Cancel extends FaweCommand {
continue;
}
if (uuid.equals(actor.getUniqueId())) {
// Cancel this
FaweExtent fe = session.getFaweExtent();
if (fe != null) {
if (session.cancel()) {
cancelled++;
try {
WEManager.IMP.cancelEdit(fe, BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
} catch (Throwable ignore) {}
World world = session.getWorld();
NullExtent nullExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
session.bypassHistory = nullExtent;
session.bypassNone = nullExtent;
session.bypassReorderHistory = nullExtent;
session.faweExtent = nullExtent;
queue.clear();
SetQueue.IMP.dequeue(queue);
}
}
}

View File

@ -92,14 +92,14 @@ public class Settings {
options.put("history.use-disk", STORE_HISTORY_ON_DISK);
options.put("history.compress", false);
options.put("history.chunk-wait-ms", CHUNK_WAIT);
options.put("history.buffer-size", BUFFER_SIZE);
// options.put("history.buffer-size", BUFFER_SIZE);
options.put("history.delete-after-days", DELETE_HISTORY_AFTER_DAYS);
options.put("region-restrictions", REGION_RESTRICTIONS);
options.put("queue.parallel-threads", UNSAFE_PARALLEL_THREADS);
options.put("queue.extra-time-ms", ALLOCATE);
options.put("queue.target-size", QUEUE_SIZE);
options.put("queue.max-wait-ms", QUEUE_MAX_WAIT);
options.put("queue.discard-after-ms", QUEUE_DISCARD_AFTER);
// options.put("queue.discard-after-ms", QUEUE_DISCARD_AFTER);
options.put("extent.allowed-plugins", new ArrayList<String>());
options.put("extent.debug", EXTENT_DEBUG);
options.put("metrics", METRICS);
@ -140,7 +140,7 @@ public class Settings {
QUEUE_SIZE = config.getInt("queue.target-size");
QUEUE_MAX_WAIT = config.getInt("queue.max-wait-ms");
UNSAFE_PARALLEL_THREADS = config.getInt("queue.parallel-threads");
QUEUE_DISCARD_AFTER = config.getInt("queue.discard-after-ms");
QUEUE_DISCARD_AFTER = config.getInt("queue.discard-after-ms", QUEUE_DISCARD_AFTER);
ALLOWED_3RDPARTY_EXTENTS = config.getStringList("extent.allowed-plugins");
EXTENT_DEBUG = config.getBoolean("extent.debug");
STORE_CLIPBOARD_ON_DISK = config.getBoolean("clipboard.use-disk");

View File

@ -50,37 +50,34 @@ public class HistoryExtent extends AbstractDelegateExtent {
@Override
public boolean setBlock(final Vector location, final BaseBlock block) throws WorldEditException {
if (super.setBlock(location, block)) {
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
int combined = queue.getCombinedId4DataDebug(x, y, z, 0, session);
int id = (combined >> 4);
if (id == block.getId()) {
if (!FaweCache.hasData(id)) {
return false;
}
int data = id & 0xF;
if (data == block.getData()) {
return false;
}
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
int combined = queue.getCombinedId4DataDebug(x, y, z, 0, session);
int id = (combined >> 4);
if (id == block.getId()) {
if (!FaweCache.hasData(id)) {
return false;
}
if (!FaweCache.hasNBT(id)) {
if (FaweCache.hasNBT(block.getId())) {
this.changeSet.add(x, y, z, combined, block);
} else {
this.changeSet.add(x, y, z, combined, (block.getId() << 4) + block.getData());
}
} else {
try {
this.changeSet.add(location, getBlock(location), block);
} catch (Throwable e) {
this.changeSet.add(x, y, z, combined, block);
}
int data = id & 0xF;
if (data == block.getData()) {
return false;
}
return true;
}
return false;
if (!FaweCache.hasNBT(id)) {
if (FaweCache.hasNBT(block.getId())) {
this.changeSet.add(x, y, z, combined, block);
} else {
this.changeSet.add(x, y, z, combined, (block.getId() << 4) + block.getData());
}
} else {
try {
this.changeSet.add(location, getBlock(location), block);
} catch (Throwable e) {
this.changeSet.add(x, y, z, combined, block);
}
}
return super.setBlock(location, block);
}
@Nullable

View File

@ -8,8 +8,12 @@ import com.sk89q.worldedit.EditSession;
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.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.regions.CuboidRegion;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
@ -21,12 +25,33 @@ public class HeightBrush implements Brush {
public final HeightMap heightMap;
private final int rotation;
double yscale = 1;
private final BrushTool tool;
public HeightBrush(File file, int rotation, double yscale) {
public HeightBrush(File file, int rotation, double yscale, BrushTool tool, EditSession session, CuboidRegion selection) {
this.tool = tool;
this.rotation = (rotation / 90) % 4;
this.yscale = yscale;
if (file == null || !file.exists()) {
heightMap = new HeightMap();
if (file.getName().equalsIgnoreCase("#selection.png") && selection != null) {
byte[][] heightArray = new byte[selection.getWidth()][selection.getLength()];
int minX = selection.getMinimumPoint().getBlockX();
int minZ = selection.getMinimumPoint().getBlockZ();
int minY = selection.getMinimumY() - 1;
int maxY = selection.getMaximumY() + 1;
int selHeight = selection.getHeight();
for (Vector pos : selection) {
int xx = pos.getBlockX();
int zz = pos.getBlockZ();
int worldPointHeight = session.getHighestTerrainBlock(xx, zz, minY, maxY);
int pointHeight = (256 * (worldPointHeight - minY)) / selHeight;
int x = xx - minX;
int z = zz - minZ;
heightArray[x][z] = (byte) pointHeight;
}
heightMap = new ArrayHeightMap(heightArray);
} else {
heightMap = new HeightMap();
}
} else {
try {
BufferedImage heightFile = ImageIO.read(file);
@ -53,10 +78,12 @@ public class HeightBrush implements Brush {
@Override
public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
Mask mask = tool.getMask();
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
mask = null;
}
int size = (int) sizeDouble;
heightMap.setSize(size);
int size2 = size * size;
int startY = position.getBlockY() + size;
int endY = position.getBlockY() - size;
@ -65,6 +92,7 @@ public class HeightBrush implements Brush {
Vector mutablePos = new Vector(0, 0, 0);
for (int x = -size; x <= size; x++) {
int xx = cx + x;
mutablePos.x = xx;
for (int z = -size; z <= size; z++) {
int zz = cz + z;
int raise;
@ -86,11 +114,18 @@ public class HeightBrush implements Brush {
if (raise == 0) {
continue;
}
mutablePos.z = zz;
int foundHeight = Integer.MAX_VALUE;
BaseBlock block = null;
for (int y = startY; y >= endY; y--) {
block = editSession.getLazyBlock(xx, y, zz);
if (block != EditSession.nullBlock) {
if (mask != null) {
mutablePos.y = y;
if (!mask.test(mutablePos)) {
continue;
}
}
foundHeight = y;
break;
}
@ -98,10 +133,17 @@ public class HeightBrush implements Brush {
if (foundHeight == Integer.MAX_VALUE) {
continue;
}
for (int y = foundHeight + 1; y <= foundHeight + raise; y++) {
mutablePos.x = xx;
mutablePos.y = y;
mutablePos.z = zz;
if (raise > 0) {
for (int y = foundHeight + 1; y <= foundHeight + raise; y++) {
mutablePos.y = y;
editSession.setBlock(mutablePos, block);
}
} else {
for (int y = foundHeight; y > foundHeight + raise; y--) {
mutablePos.y = y;
editSession.setBlock(mutablePos, EditSession.nullBlock);
}
mutablePos.y = foundHeight + raise;
editSession.setBlock(mutablePos, block);
}
}

View File

@ -152,6 +152,7 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
EditSessionFactory factory = WorldEdit.getInstance().getEditSessionFactory();
EditSession edit = factory.getEditSession(world, -1, null, player);
edit.setChangeSet(this);
edit.dequeue();
return edit;
}

View File

@ -12,13 +12,14 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.List;
public class FastWorldEditExtent extends FaweExtent {
public class FastWorldEditExtent extends AbstractDelegateExtent {
private final FaweQueue queue;
@ -228,9 +229,4 @@ public class FastWorldEditExtent extends FaweExtent {
}
}
}
@Override
public boolean contains(int x, int y, int z) {
return true;
}
}

View File

@ -3,14 +3,13 @@ package com.boydti.fawe.object.extent;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
public abstract class FaweExtent extends AbstractDelegateExtent {
public abstract class FaweRegionExtent extends AbstractDelegateExtent {
/**
* Create a new instance.
*
* @param extent the extent
*/
protected FaweExtent(Extent extent) {
public FaweRegionExtent(Extent extent) {
super(extent);
}

View File

@ -11,10 +11,10 @@ import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
public class SafeExtentWrapper extends AbstractDelegateExtent {
public class MemoryCheckingExtent extends AbstractDelegateExtent {
private final FawePlayer<?> player;
public SafeExtentWrapper(final FawePlayer<?> player, final Extent extent) {
public MemoryCheckingExtent(final FawePlayer<?> player, final Extent extent) {
super(extent);
this.player = player;
}

View File

@ -15,18 +15,16 @@ import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
public class NullExtent extends FaweExtent {
public class NullExtent implements Extent {
private final BBC reason;
/**
* Create a new instance.
*
* @param extent the extent
*/
public NullExtent(Extent extent, BBC failReason) {
super(extent);
public NullExtent(BBC failReason) {
this.reason = failReason;
}
@ -50,6 +48,12 @@ public class NullExtent extends FaweExtent {
throw new FaweException(reason);
}
@Nullable
@Override
public Operation commit() {
return null;
}
@Override
public boolean setBlock(final Vector arg0, final BaseBlock arg1) throws WorldEditException {
throw new FaweException(reason);
@ -79,17 +83,4 @@ public class NullExtent extends FaweExtent {
public Vector getMinimumPoint() {
return new Vector(0, 0, 0);
}
@Override
public boolean contains(int x, int y, int z) { return false; }
@Override
protected Operation commitBefore() {
return null;
}
@Override
public Extent getExtent() {
return this;
}
}

View File

@ -3,14 +3,9 @@ package com.boydti.fawe.object.extent;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.WEManager;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
@ -20,52 +15,30 @@ import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.HashSet;
import java.util.List;
public class ProcessedWEExtent extends FaweExtent {
private final FaweQueue queue;
public class ProcessedWEExtent extends FaweRegionExtent {
private final FaweLimit limit;
private Extent parent;
private final RegionWrapper[] mask;
private final FawePlayer<?> user;
private final HashSet<RegionWrapper> mask;
public ProcessedWEExtent(final World world, final FawePlayer<?> player, final HashSet<RegionWrapper> mask, FaweLimit limit, FaweQueue queue) {
super(world);
this.user = player;
this.queue = queue;
this.mask = mask;
public ProcessedWEExtent(final Extent parent, final HashSet<RegionWrapper> mask, FaweLimit limit) {
super(parent);
this.mask = mask.toArray(new RegionWrapper[mask.size()]);
this.limit = limit;
}
public void setParent(final Extent parent) {
this.parent = parent;
}
@Override
public Entity createEntity(final Location location, final BaseEntity entity) {
if (limit.MAX_ENTITIES-- < 0 || entity == null) {
return null;
}
if (WEManager.IMP.maskContains(this.mask, location.getBlockX(), location.getBlockZ())) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
ProcessedWEExtent.super.createEntity(location, entity);
}
});
}
return null;
return super.createEntity(location, entity);
}
@Override
public BaseBiome getBiome(final Vector2D position) {
if (!queue.isChunkLoaded(position.getBlockX() >> 4, position.getBlockZ() >> 4)) {
return EditSession.nullBiome;
}
return super.getBiome(position);
}
@ -74,21 +47,6 @@ public class ProcessedWEExtent extends FaweExtent {
@Override
public BaseBlock getLazyBlock(final Vector position) {
// TODO get fast!
// TODO caches base blocks
if ((this.lastBlock != null) && this.lastVector.equals(position.toBlockVector())) {
return this.lastBlock;
}
if (!queue.isChunkLoaded(position.getBlockX() >> 4, position.getBlockZ() >> 4)) {
try {
this.lastVector = position.toBlockVector();
return this.lastBlock = super.getBlock(position);
} catch (final Throwable e) {
return EditSession.nullBlock;
}
}
this.lastVector = position.toBlockVector();
return super.getLazyBlock(position);
}
@ -109,200 +67,27 @@ public class ProcessedWEExtent extends FaweExtent {
@Override
public boolean setBlock(final Vector location, final BaseBlock block) throws WorldEditException {
final short id = (short) block.getType();
boolean nbt = true;
switch (id) {
case 63:
case 68:
if (block.hasNbtData() && !MainUtil.isValidSign(block.getNbtData())) {
nbt = false;
}
case 54:
case 130:
case 142:
case 27:
case 137:
case 52:
case 154:
case 84:
case 25:
case 144:
case 138:
case 176:
case 177:
case 119:
case 323:
case 117:
case 116:
case 28:
case 66:
case 157:
case 61:
case 62:
case 140:
case 146:
case 149:
case 150:
case 158:
case 23:
case 123:
case 124:
case 29:
case 33:
case 151:
case 178: {
if (limit.MAX_BLOCKSTATES-- < 0) {
if (this.parent != null) {
WEManager.IMP.cancelEdit(this.parent, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES);
this.parent = null;
}
return false;
}
final int x = location.getBlockX();
final int z = location.getBlockZ();
if (WEManager.IMP.maskContains(this.mask, x, z)) {
if (limit.MAX_CHANGES-- < 0) {
if (this.parent != null) {
WEManager.IMP.cancelEdit(this.parent, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
this.parent = null;
}
return false;
}
if (block.hasNbtData() && nbt) {
final Vector loc = new Vector(location.x, location.y, location.z);
queue.addTask(x >> 4, z >> 4, new Runnable() {
@Override
public void run() {
try {
ProcessedWEExtent.super.setBlock(loc, block);
} catch (WorldEditException e) {
e.printStackTrace();
}
}
});
return true;
}
queue.setBlock(x, location.getBlockY(), z, id, FaweCache.hasData(id) ? (byte) block.getData() : 0);
return true;
} else if (limit.MAX_FAILS-- < 0) {
if (this.parent != null) {
WEManager.IMP.cancelEdit(this.parent, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
this.parent = null;
}
}
return false;
}
default: {
final int x = location.getBlockX();
final int y = location.getBlockY();
final int z = location.getBlockZ();
if (WEManager.IMP.maskContains(this.mask, location.getBlockX(), location.getBlockZ())) {
if (limit.MAX_CHANGES -- <0) {
WEManager.IMP.cancelEdit(this.parent, BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
this.parent = null;
return false;
}
switch (id) {
case 0:
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 25:
case 30:
case 32:
case 37:
case 39:
case 40:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 51:
case 52:
case 56:
case 57:
case 58:
case 60:
case 7:
case 8:
case 9:
case 10:
case 11:
case 73:
case 74:
case 78:
case 79:
case 80:
case 81:
case 82:
case 83:
case 84:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 117:
case 121:
case 122:
case 123:
case 124:
case 129:
case 133:
case 138:
case 137:
case 140:
case 165:
case 166:
case 169:
case 170:
case 172:
case 173:
case 174:
case 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192: {
queue.setBlock(x, y, z, id, (byte) 0);
return true;
}
default: {
queue.setBlock(x, y, z, id, (byte) block.getData());
return true;
}
}
} else if (limit.MAX_FAILS-- < 0) {
if (this.parent != null) {
WEManager.IMP.cancelEdit(this.parent, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
this.parent = null;
}
}
if (block.hasNbtData() && FaweCache.hasNBT(block.getType())) {
if (limit.MAX_BLOCKSTATES-- < 0) {
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES);
return false;
}
}
if (WEManager.IMP.maskContains(this.mask, (int) location.x, (int) location.z)) {
if (limit.MAX_CHANGES-- < 0) {
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES);
return false;
}
return super.setBlock(location, block);
} else if (limit.MAX_FAILS-- < 0) {
WEManager.IMP.cancelEdit(this, BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES);
}
return false;
}
@Override
public boolean setBiome(final Vector2D position, final BaseBiome biome) {
if (WEManager.IMP.maskContains(this.mask, position.getBlockX(), position.getBlockZ())) {
queue.setBiome(position.getBlockX(), position.getBlockZ(), biome);
}
return false;
return super.setBiome(position, biome);
}
@Override

View File

@ -54,6 +54,16 @@ public abstract class FaweQueue {
public void endSet(boolean parallel) {}
public int cancel() {
int count = 0;
for (EditSession session : sessions) {
if (session.cancel()) {
count++;
}
}
return count;
}
/**
* Gets the FaweChunk and sets the requested blocks
* @return

View File

@ -79,26 +79,34 @@ public class SetQueue {
if (SET_TASK.value2 == null) {
return;
}
if (Settings.UNSAFE_PARALLEL_THREADS <= 1) {
SET_TASK.value2.startSet(false);
SET_TASK.run();
SET_TASK.value2.endSet(false);
} else {
SET_TASK.value2.startSet(true);
ArrayList<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < Settings.UNSAFE_PARALLEL_THREADS; i++) {
threads.add(new Thread(SET_TASK));
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
if (Thread.currentThread() != Fawe.get().getMainThread()) {
throw new IllegalStateException("This shouldn't be possible for placement to occur off the main thread");
}
// Disable the async catcher as it can't discern async vs parallel
SET_TASK.value2.startSet(true);
try {
if (Settings.UNSAFE_PARALLEL_THREADS <= 1) {
SET_TASK.run();
} else {
ArrayList<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < Settings.UNSAFE_PARALLEL_THREADS; i++) {
threads.add(new Thread(SET_TASK));
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (Throwable e) {
e.printStackTrace();
} finally {
// Enable it again (note that we are still on the main thread)
SET_TASK.value2.endSet(true);
}
}

View File

@ -26,7 +26,7 @@ public class WEManager {
try {
final Field field = AbstractDelegateExtent.class.getDeclaredField("extent");
field.setAccessible(true);
field.set(parent, new NullExtent((Extent) field.get(parent), reason));
field.set(parent, new NullExtent(reason));
} catch (final Exception e) {
e.printStackTrace();
}
@ -42,6 +42,22 @@ public class WEManager {
return false;
}
public boolean maskContains(RegionWrapper[] mask, final int x, final int z) {
switch (mask.length) {
case 0:
return false;
case 1:
return mask[0].isIn(x, z);
default:
for (final RegionWrapper region : mask) {
if (region.isIn(x, z)) {
return true;
}
}
return false;
}
}
public HashSet<RegionWrapper> getMask(final FawePlayer<?> player) {
final HashSet<RegionWrapper> regions = new HashSet<>();
if (player.hasPermission("fawe.bypass") || !Settings.REGION_RESTRICTIONS) {

View File

@ -3,7 +3,7 @@ package com.boydti.fawe.wrappers;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.extent.FaweExtent;
import com.boydti.fawe.object.extent.FaweRegionExtent;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.BlockVector2D;
@ -230,7 +230,7 @@ public class WorldWrapper extends AbstractWorld {
public boolean regenerate(final Region region, final EditSession session) {
final FaweQueue queue = session.getQueue();
final FaweChangeSet fcs = (FaweChangeSet) session.getChangeSet();
final FaweExtent fe = session.getFaweExtent();
final FaweRegionExtent fe = session.getRegionExtent();
session.setChangeSet(fcs);
final boolean cuboid = region instanceof CuboidRegion;
Set<Vector2D> chunks = region.getChunks();

View File

@ -34,11 +34,10 @@ import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.boydti.fawe.object.extent.FaweExtent;
import com.boydti.fawe.object.extent.FaweRegionExtent;
import com.boydti.fawe.object.extent.MemoryCheckingExtent;
import com.boydti.fawe.object.extent.NullExtent;
import com.boydti.fawe.object.extent.ProcessedWEExtent;
import com.boydti.fawe.object.extent.SafeExtentWrapper;
import com.boydti.fawe.util.ExtentWrapper;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MemUtil;
import com.boydti.fawe.util.Perm;
@ -118,7 +117,6 @@ import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.lang.reflect.Field;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
@ -164,8 +162,9 @@ public class EditSession implements Extent {
public Actor actor;
public FaweChangeSet changeSet;
public EditSessionWrapper wrapper;
public FaweExtent faweExtent;
public MaskingExtent maskingExtent;
public FaweRegionExtent regionExtent;
public Extent primaryExtent;
public Extent bypassReorderHistory;
public Extent bypassHistory;
public Extent bypassNone;
@ -204,7 +203,6 @@ public class EditSession implements Extent {
}
private int changes = 0;
private int maxBlocks;
private BlockBag blockBag;
/**
@ -220,13 +218,14 @@ public class EditSession implements Extent {
checkNotNull(eventBus);
checkArgument(maxBlocks >= -1, "maxBlocks >= -1 required");
checkNotNull(event);
this.actor = event.getActor();
// Wrap world
// TODO block bag
this.blockBag = blockBag;
this.maxBlocks = maxBlocks;
// Invalid; return null extent
// Invalid world: return null extent
if (world == null) {
FaweExtent extent = faweExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
NullExtent extent = new NullExtent(BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
this.bypassReorderHistory = extent;
this.bypassHistory = extent;
this.bypassNone = extent;
@ -234,26 +233,18 @@ public class EditSession implements Extent {
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
return;
}
// Set the world of the event to the actual world (workaround for CoreProtect)
try {
Class<? extends EditSessionEvent> eventClass = event.getClass();
Field fieldWorld = eventClass.getDeclaredField("world");
fieldWorld.setAccessible(true);
if (world instanceof WorldWrapper) {
fieldWorld.set(event, ((WorldWrapper) world).getParent());
} else {
fieldWorld.set(event, world);
}
} catch (Throwable e) {
e.printStackTrace();
}
// Wrap the world
this.world = (world = new WorldWrapper((AbstractWorld) world));
// Delegate some methods to an implementation specific class
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
// Not a player; bypass history
if ((actor == null) || !actor.isPlayer()) {
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), true, true);
queue.addEditSession(this);
Extent extent = (this.faweExtent = new FastWorldEditExtent(world, queue));
Extent extent = primaryExtent = new FastWorldEditExtent(world, queue);
// Everything bypasses
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
@ -264,8 +255,9 @@ public class EditSession implements Extent {
this.changeSet = new NullChangeSet();
return;
}
this.changeSet = Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(world, actor.getUniqueId()) : new MemoryOptimizedHistory(actor);
Extent extent;
HashSet<RegionWrapper> mask;
final FawePlayer fp = FawePlayer.wrap(actor);
final LocalSession session = fp.getSession();
this.fastmode = session.hasFastMode();
@ -273,7 +265,7 @@ public class EditSession implements Extent {
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), true, true);
queue.addEditSession(this);
// Bypass skips processing and area restrictions
extent = (this.faweExtent = new FastWorldEditExtent(world, queue));
extent = primaryExtent = new FastWorldEditExtent(world, queue);
if (this.hasFastMode()) {
// Fastmode skips history and memory checks
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
@ -284,30 +276,28 @@ public class EditSession implements Extent {
this.bypassNone = extent;
return;
}
mask = null;
} else {
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), false, true);
queue.addEditSession(this);
this.limit = fp.getLimit();
final HashSet<RegionWrapper> mask = WEManager.IMP.getMask(fp);
mask = WEManager.IMP.getMask(fp);
if (mask.size() == 0) {
// No allowed area; return null extent
extent = faweExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
extent = new NullExtent(BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
this.bypassReorderHistory = extent;
this.bypassHistory = extent;
this.bypassNone = extent;
return;
}
// Process the WorldEdit action
ProcessedWEExtent processed = (ProcessedWEExtent) (this.faweExtent = new ProcessedWEExtent(world, fp, mask, limit, queue));
extent = processed;
extent = primaryExtent = new FastWorldEditExtent(world, queue);
if (this.hasFastMode()) {
// Fastmode skips history, masking, and memory checks
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
// Restrictions
extent = new ProcessedWEExtent(extent, mask, limit);
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY);
extent = new ExtentWrapper(extent);
// Set the parent. This allows efficient cancelling
processed.setParent(extent);
this.bypassReorderHistory = extent;
this.bypassHistory = extent;
this.bypassNone = extent;
@ -318,9 +308,8 @@ public class EditSession implements Extent {
if (Perm.hasPermission(fp, "worldedit.fast")) {
BBC.WORLDEDIT_OOM_ADMIN.send(fp);
}
// Memory limit reached; return null extent
extent = faweExtent = new NullExtent(world, BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
extent = new NullExtent(BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
this.bypassReorderHistory = extent;
this.bypassHistory = extent;
this.bypassNone = extent;
@ -328,14 +317,24 @@ public class EditSession implements Extent {
}
}
// Perform memory checks after reorder
extent = new SafeExtentWrapper(fp, extent);
processed.setParent(extent);
extent = new MemoryCheckingExtent(fp, extent);
}
// Include history, masking and memory checking.
Extent wrapped;
// First two events
extent = wrapped = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
// History
this.changeSet = Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(world, actor.getUniqueId()) : new MemoryOptimizedHistory(actor);
extent = this.wrapper.getHistoryExtent(this, limit, extent, this.changeSet, queue, fp);
// Region restrictions if mask is not null
if (mask != null) {
extent = this.regionExtent = new ProcessedWEExtent(extent, mask, limit);
}
// Masking
final Player skp = (Player) actor;
final int item = skp.getItemInHand();
boolean hasMask = session.getMask() != null;
@ -351,14 +350,44 @@ public class EditSession implements Extent {
extent = this.maskingExtent = new MaskingExtent(extent, Masks.alwaysTrue());
}
// Before history event
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY);
extent = new SafeExtentWrapper(fp, extent);
this.bypassReorderHistory = wrapped;
this.bypassHistory = wrapped;
this.bypassNone = extent;
return;
}
public FaweRegionExtent getRegionExtent() {
return regionExtent;
}
public boolean cancel() {
// Cancel this
if (primaryExtent != null && queue != null) {
try {
WEManager.IMP.cancelEdit(primaryExtent, BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
} catch (Throwable ignore) {}
NullExtent nullExtent = new NullExtent(BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
primaryExtent = nullExtent;
dequeue();
queue.clear();
return true;
}
return false;
}
public void dequeue() {
if (queue != null) {
SetQueue.IMP.dequeue(queue);
}
}
public FastWorldEditExtent getPrimaryExtent() {
return (FastWorldEditExtent) primaryExtent;
}
public void debug(BBC message, Object... args) {
message.send(actor, args);
}
@ -427,7 +456,7 @@ public class EditSession implements Extent {
* @return the limit (&gt;= 0) or -1 for no limit
*/
public int getBlockChangeLimit() {
return this.maxBlocks;
return -1;
}
/**
@ -489,10 +518,6 @@ public class EditSession implements Extent {
}
}
public FaweExtent getFaweExtent() {
return this.faweExtent;
}
/**
* Set the mask.
*

View File

@ -29,6 +29,7 @@ import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
@ -51,6 +52,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
@ -226,13 +228,13 @@ public class BrushCommands {
BrushTool tool = session.getBrushTool(player.getItemInHand());
tool.setSize(radius);
tool.setBrush(new GravityBrush(fromMaxY), "worldedit.brush.gravity");
tool.setBrush(new GravityBrush(fromMaxY, tool), "worldedit.brush.gravity");
BBC.BRUSH_GRAVITY.send(player, radius);
}
@Command(
aliases = { "height", "high" },
usage = "[radius] [file] [rotation] [yscale]",
aliases = { "height", "heightmap" },
usage = "[radius] [file|#selection|null] [rotation] [yscale]",
flags = "h",
desc = "Height brush",
help =
@ -246,7 +248,12 @@ public class BrushCommands {
File file = new File(Fawe.imp().getDirectory(), "heightmap" + File.separator + (filename.endsWith(".png") ? filename : filename + ".png"));
BrushTool tool = session.getBrushTool(player.getItemInHand());
tool.setSize(radius);
tool.setBrush(new HeightBrush(file, rotation, yscale), "worldedit.brush.height");
try {
tool.setBrush(new HeightBrush(file, rotation, yscale, tool, editSession, (CuboidRegion) session.getSelection(player.getWorld())), "worldedit.brush.height");
} catch (IncompleteRegionException ignore) {
ignore.printStackTrace();
tool.setBrush(new HeightBrush(file, rotation, yscale, tool, editSession, null), "worldedit.brush.height");
}
BBC.BRUSH_HEIGHT.send(player, radius);
}

View File

@ -47,6 +47,7 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
@ -278,7 +279,7 @@ public class ClipboardCommands {
final Vector origin = clipboard.getOrigin();
final Vector to = atOrigin ? origin : session.getPlacementPosition(player);
// Optimize for BlockArrayClipboard
if (clipboard instanceof BlockArrayClipboard) {
if (clipboard instanceof BlockArrayClipboard && region instanceof CuboidRegion) {
// To is relative to the world origin (player loc + small clipboard offset) (As the positions supplied are relative to the clipboard min)
final int relx = to.getBlockX() + bot.getBlockX() - origin.getBlockX();
final int rely = to.getBlockY() + bot.getBlockY() - origin.getBlockY();

View File

@ -23,18 +23,27 @@ import com.sk89q.worldedit.EditSession;
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.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.pattern.Pattern;
public class GravityBrush implements Brush {
private final boolean fullHeight;
private final BrushTool tool;
public GravityBrush(boolean fullHeight) {
public GravityBrush(boolean fullHeight, BrushTool tool) {
this.fullHeight = fullHeight;
this.tool = tool;
}
@Override
public void build(EditSession editSession, Vector position, Pattern pattern, double sizeDouble) throws MaxChangedBlocksException {
Mask mask = tool.getMask();
if (mask == Masks.alwaysTrue() || mask == Masks.alwaysTrue2D()) {
mask = null;
}
int size = (int) sizeDouble;
int endY = position.getBlockY() + size;
int startPerformY = Math.max(0, position.getBlockY() - size);
@ -51,11 +60,12 @@ public class GravityBrush implements Brush {
continue;
}
BaseBlock block = editSession.getLazyBlock(x, y, z);
if (block != EditSession.nullBlock) {
mutablePos.x = x;
mutablePos.y = y;
mutablePos.z = z;
if (block != EditSession.nullBlock && (mask == null || mask.test(mutablePos))) {
if (freeSpot != y) {
mutablePos.x = x;
mutablePos.y = freeSpot;
mutablePos.z = z;
editSession.setBlock(mutablePos, block);
mutablePos.y = y;
editSession.setBlock(mutablePos, EditSession.nullBlock);