Proper support for WorldEdit inventory

- Per player inventory mode (0, 1, 2)
- Use mode 2 for survival (setting air doesn't give you the blocks)
- Fixes several duplications glitches
- Adds speed and placement type option per player

-
This commit is contained in:
Jesse Boyd 2016-10-04 01:21:27 +11:00
parent 7886947061
commit 47cbc2bc8c
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
21 changed files with 353 additions and 84 deletions

View File

@ -204,42 +204,46 @@ public class FaweBukkit implements IFawe, Listener {
* - When a block change is requested, the SetQueue will first check if the chunk exists in the queue, or it will create and add it<br>
*/
@Override
public FaweQueue getNewQueue(World world, boolean dontCareIfFast) {
if (playerChunk != (playerChunk = true)) {
public FaweQueue getNewQueue(World world, boolean fast) {
if (fast) {
if (playerChunk != (playerChunk = true)) {
try {
Field fieldDirtyCount = ReflectionUtils.getRefClass("{nms}.PlayerChunk").getField("dirtyCount").getRealField();
fieldDirtyCount.setAccessible(true);
int mod = fieldDirtyCount.getModifiers();
if ((mod & Modifier.VOLATILE) == 0) {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(fieldDirtyCount, mod + Modifier.VOLATILE);
}
} catch (Throwable ignore) {
}
}
try {
Field fieldDirtyCount = ReflectionUtils.getRefClass("{nms}.PlayerChunk").getField("dirtyCount").getRealField();
fieldDirtyCount.setAccessible(true);
int mod = fieldDirtyCount.getModifiers();
if ((mod & Modifier.VOLATILE) == 0) {
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(fieldDirtyCount, mod + Modifier.VOLATILE);
}
} catch (Throwable ignore) {}
}
try {
return plugin.getQueue(world);
} catch (Throwable ignore) {}
// Disable incompatible settings
Settings.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
Settings.HISTORY.COMBINE_STAGES = false; // Performing a chunk copy (if possible) wouldn't be faster using the BukkitAPI
if (hasNMS) {
debug("====== NO NMS BLOCK PLACER FOUND ======");
debug("FAWE couldn't find a fast block placer");
debug("Bukkit version: " + Bukkit.getVersion());
debug("NMS label: " + plugin.getClass().getSimpleName().split("_")[1]);
debug("Fallback placer: " + BukkitQueue_All.class);
debug("=======================================");
debug("Download the version of FAWE for your platform");
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
debug("=======================================");
TaskManager.IMP.laterAsync(new Runnable() {
@Override
public void run() {
MainUtil.sendAdmin("&cNo NMS placer found, see console!");
}
}, 1);
hasNMS = false;
return plugin.getQueue(world);
} catch (Throwable ignore) {
}
// Disable incompatible settings
Settings.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
Settings.HISTORY.COMBINE_STAGES = false; // Performing a chunk copy (if possible) wouldn't be faster using the BukkitAPI
if (hasNMS) {
debug("====== NO NMS BLOCK PLACER FOUND ======");
debug("FAWE couldn't find a fast block placer");
debug("Bukkit version: " + Bukkit.getVersion());
debug("NMS label: " + plugin.getClass().getSimpleName().split("_")[1]);
debug("Fallback placer: " + BukkitQueue_All.class);
debug("=======================================");
debug("Download the version of FAWE for your platform");
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
debug("=======================================");
TaskManager.IMP.laterAsync(new Runnable() {
@Override
public void run() {
MainUtil.sendAdmin("&cNo NMS placer found, see console!");
}
}, 1);
hasNMS = false;
}
}
return new BukkitQueue_All(world);
}

View File

@ -82,6 +82,19 @@ public class Settings extends Config {
" - History on disk or memory will be deleted",
})
public int MAX_HISTORY_MB = -1;
@Comment("Needlessly make WorldEdit slower for this player (ms/block)")
public int SPEED_REDUCTION = 0;
@Comment({
"Should WorldEdit use inventory?",
"0 = No inventory usage (creative)",
"1 = Inventory for removing and placing (freebuild)",
"2 = Inventory for placing (survival)",
})
public static int INVENTORY_MODE = 0;
@Comment({
"Place chunks instead of individual blocks"
})
public static boolean FAST_PLACEMENT = true;
}
public static class HISTORY {
@ -297,6 +310,9 @@ public class Settings extends Config {
limit.MAX_FAILS = Math.max(limit.MAX_FAILS, newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE);
limit.MAX_ITERATIONS = Math.max(limit.MAX_ITERATIONS, newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE);
limit.MAX_HISTORY = Math.max(limit.MAX_HISTORY, newLimit.MAX_HISTORY_MB != -1 ? newLimit.MAX_HISTORY_MB : Integer.MAX_VALUE);
limit.INVENTORY_MODE = Math.min(limit.INVENTORY_MODE, newLimit.INVENTORY_MODE);
limit.SPEED_REDUCTION = Math.min(limit.SPEED_REDUCTION, newLimit.SPEED_REDUCTION);
limit.FAST_PLACEMENT |= newLimit.FAST_PLACEMENT;
}
}
return limit;

View File

@ -5,6 +5,7 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.history.change.Change;
import java.util.Iterator;
import org.bukkit.entity.Player;
@ -87,6 +88,11 @@ public class LoggingChangeSet extends FaweChangeSet {
parent.addEntityCreate(tag);
}
@Override
public Iterator<Change> getIterator(BlockBag blockBag, int mode, boolean redo) {
return parent.getIterator(blockBag, mode, redo);
}
@Override
public Iterator<Change> getIterator(boolean undo) {
return parent.getIterator(undo);

View File

@ -12,6 +12,9 @@ public class FaweLimit {
public int MAX_BLOCKSTATES = 0;
public int MAX_ENTITIES = 0;
public int MAX_HISTORY = 0;
public int INVENTORY_MODE = Integer.MAX_VALUE;
public int SPEED_REDUCTION = Integer.MAX_VALUE;
public boolean FAST_PLACEMENT = false;
public static FaweLimit MAX;
@ -42,6 +45,8 @@ public class FaweLimit {
return true;
}
};
MAX.SPEED_REDUCTION = 0;
MAX.INVENTORY_MODE = 0;
MAX.MAX_ACTIONS = 1;
MAX.MAX_CHANGES = Integer.MAX_VALUE;
MAX.MAX_FAILS = Integer.MAX_VALUE;
@ -50,6 +55,7 @@ public class FaweLimit {
MAX.MAX_BLOCKSTATES = Integer.MAX_VALUE;
MAX.MAX_ENTITIES = Integer.MAX_VALUE;
MAX.MAX_HISTORY = Integer.MAX_VALUE;
MAX.FAST_PLACEMENT = true;
}
public boolean MAX_CHANGES() {
@ -83,7 +89,10 @@ public class FaweLimit {
MAX_ITERATIONS == Integer.MAX_VALUE &&
MAX_BLOCKSTATES == Integer.MAX_VALUE &&
MAX_ENTITIES == Integer.MAX_VALUE &&
MAX_HISTORY == Integer.MAX_VALUE;
MAX_HISTORY == Integer.MAX_VALUE &&
INVENTORY_MODE == 0 &&
SPEED_REDUCTION == 0 &&
FAST_PLACEMENT == true;
}
public void set(FaweLimit limit) {
@ -95,10 +104,15 @@ public class FaweLimit {
MAX_FAILS = limit.MAX_FAILS;
MAX_ITERATIONS = limit.MAX_ITERATIONS;
MAX_HISTORY = limit.MAX_HISTORY;
INVENTORY_MODE = limit.INVENTORY_MODE;
SPEED_REDUCTION = limit.SPEED_REDUCTION;
FAST_PLACEMENT = limit.FAST_PLACEMENT;
}
public FaweLimit copy() {
FaweLimit limit = new FaweLimit();
limit.INVENTORY_MODE = INVENTORY_MODE;
limit.SPEED_REDUCTION = SPEED_REDUCTION;
limit.MAX_ACTIONS = MAX_ACTIONS;
limit.MAX_CHANGES = MAX_CHANGES;
limit.MAX_BLOCKSTATES = MAX_BLOCKSTATES;
@ -107,6 +121,7 @@ public class FaweLimit {
limit.MAX_FAILS = MAX_FAILS;
limit.MAX_ITERATIONS = MAX_ITERATIONS;
limit.MAX_HISTORY = MAX_HISTORY;
limit.FAST_PLACEMENT = FAST_PLACEMENT;
return limit;
}

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.object;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.world.World;
import java.util.ArrayList;
@ -42,6 +43,11 @@ public class NullChangeSet extends FaweChangeSet {
}
@Override
public Iterator<Change> getIterator(BlockBag blockBag, int mode, boolean redo) {
return getIterator(redo);
}
@Override
public final Iterator<Change> getIterator(boolean undo) {
return new ArrayList<Change>().iterator();

View File

@ -79,7 +79,7 @@ public class InspectBrush extends BrushTool implements DoubleActionTraceTool {
@Override
public void run(DiskStorageHistory value) {
try {
Iterator<MutableFullBlockChange> iter = value.getFullBlockIterator(false);
Iterator<MutableFullBlockChange> iter = value.getFullBlockIterator(null, 0, false);
while (iter.hasNext()) {
MutableFullBlockChange change = iter.next();
if (change.x != x || change.y != y || change.z != z) {

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.object.change;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.history.UndoContext;
@ -45,10 +46,11 @@ public class MutableBlockChange implements Change {
if (!checkedQueue) {
checkedQueue = true;
Extent extent = context.getExtent();
if (extent instanceof HasFaweQueue) {
(queue = ((HasFaweQueue) extent).getQueue()).setBlock(x, y, z, id, data);
ExtentTraverser found = new ExtentTraverser(extent).find(HasFaweQueue.class);
if (found != null) {
(queue = ((HasFaweQueue) found.get()).getQueue()).setBlock(x, y, z, id, data);
} else {
Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)");
Fawe.debug("FAWE does not support: " + extent + " for " + getClass() + " (bug Empire92)");
}
}
}

View File

@ -4,6 +4,7 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.history.UndoContext;
@ -39,10 +40,11 @@ public class MutableChunkChange implements Change {
if (!checkedQueue) {
checkedQueue = true;
Extent extent = context.getExtent();
if (extent instanceof HasFaweQueue) {
perform(queue = ((HasFaweQueue) extent).getQueue(), undo);
ExtentTraverser found = new ExtentTraverser(extent).find(HasFaweQueue.class);
if (found != null) {
perform(queue = ((HasFaweQueue) found.get()).getQueue(), undo);
} else {
Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)");
Fawe.debug("FAWE does not support: " + extent + " for " + getClass() + " (bug Empire92)");
}
}
}

View File

@ -84,10 +84,11 @@ public class MutableEntityChange implements Change {
if (!checkedQueue) {
checkedQueue = true;
Extent extent = context.getExtent();
if (extent instanceof HasFaweQueue) {
perform(queue = ((HasFaweQueue) extent).getQueue());
ExtentTraverser found = new ExtentTraverser(extent).find(HasFaweQueue.class);
if (found != null) {
perform(queue = ((HasFaweQueue) found.get()).getQueue());
} else {
Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)");
Fawe.debug("FAWE does not support: " + extent + " for " + getClass() + " (bug Empire92)");
}
}
}

View File

@ -4,8 +4,11 @@ import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.extent.inventory.BlockBagException;
import com.sk89q.worldedit.history.UndoContext;
import com.sk89q.worldedit.history.change.Change;
@ -16,14 +19,14 @@ public class MutableFullBlockChange implements Change {
public int x;
public int from;
public int to;
public BlockBag blockBag;
public boolean allowFetch;
public boolean allowStore;
public MutableFullBlockChange(int x, int y, int z, int combinedFrom, int combinedTo) {
this.x = x;
this.y = y;
this.z = z;
this.from = combinedFrom;
this.to = combinedTo;
public MutableFullBlockChange(BlockBag blockBag, int mode, boolean redo) {
this.blockBag = blockBag;
allowFetch = redo || mode == 1;
allowStore = !redo || mode == 1;
}
@Override
@ -46,15 +49,35 @@ public class MutableFullBlockChange implements Change {
if (!checkedQueue) {
checkedQueue = true;
Extent extent = context.getExtent();
if (extent instanceof HasFaweQueue) {
perform(queue = ((HasFaweQueue) extent).getQueue());
ExtentTraverser found = new ExtentTraverser(extent).find(HasFaweQueue.class);
if (found != null) {
perform(queue = ((HasFaweQueue) found.get()).getQueue());
} else {
Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)");
Fawe.debug("FAWE does not support: " + extent + " for " + getClass() + " (bug Empire92)");
}
}
}
public void perform(FaweQueue queue) {
queue.setBlock(x, y, z, FaweCache.getId(from), FaweCache.getData(from));
int idFrom = FaweCache.getId(from);
int dataFrom = FaweCache.getData(from);
if (blockBag != null) {
if (allowFetch && idFrom != 0) {
try {
blockBag.fetchPlacedBlock(idFrom, dataFrom);
} catch (BlockBagException e) {
return;
}
}
int idTo = FaweCache.getId(to);
int dataTo = FaweCache.getData(to);
if (allowStore && idTo != 0) {
try {
blockBag.storeDroppedBlock(idTo, dataTo);
} catch (BlockBagException ignored) {
}
}
}
queue.setBlock(x, y, z, idFrom, dataFrom);
}
}

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.object.change;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.Tag;
@ -46,10 +47,11 @@ public class MutableTileChange implements Change {
if (!checkedQueue) {
checkedQueue = true;
Extent extent = context.getExtent();
if (extent instanceof HasFaweQueue) {
perform(queue = ((HasFaweQueue) extent).getQueue());
ExtentTraverser found = new ExtentTraverser(extent).find(HasFaweQueue.class);
if (found != null) {
perform(queue = ((HasFaweQueue) found.get()).getQueue());
} else {
Fawe.debug("FAWE doesn't support: " + extent + " for " + getClass() + " (bug Empire92)");
Fawe.debug("FAWE does not support: " + extent + " for " + getClass() + " (bug Empire92)");
}
}
}

View File

@ -5,6 +5,7 @@ import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.change.MutableChunkChange;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.world.World;
import java.util.ArrayList;
@ -76,6 +77,11 @@ public class CPUOptimizedChangeSet extends FaweChangeSet {
throw new UnsupportedOperationException("Invalid mode");
}
@Override
public Iterator<Change> getIterator(BlockBag blockBag, int mode, boolean redo) {
return getIterator(redo);
}
@Override
public Iterator<Change> getIterator(boolean redo) {
return changes.iterator();

View File

@ -17,6 +17,7 @@ import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.history.change.BlockChange;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.history.change.EntityCreate;
@ -93,6 +94,7 @@ public abstract class FaweChangeSet implements ChangeSet {
public abstract void addTileRemove(CompoundTag tag);
public abstract void addEntityRemove(CompoundTag tag);
public abstract void addEntityCreate(CompoundTag tag);
public abstract Iterator<Change> getIterator(BlockBag blockBag, int mode, boolean redo);
public abstract Iterator<Change> getIterator(boolean redo);
public void delete() {};

View File

@ -12,6 +12,7 @@ import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.world.World;
import java.io.EOFException;
@ -382,12 +383,24 @@ public abstract class FaweStreamChangeSet extends FaweChangeSet {
};
}
public Iterator<MutableFullBlockChange> getFullBlockIterator(final boolean dir) throws IOException {
@Override
public Iterator<Change> getIterator(BlockBag blockBag, int mode, boolean redo) {
if (blockBag != null && mode > 0) {
try {
return (Iterator<Change>) (Iterator<?>) getFullBlockIterator(blockBag, mode, redo);
} catch (IOException e) {
e.printStackTrace();
}
}
return getIterator(redo);
}
public Iterator<MutableFullBlockChange> getFullBlockIterator(BlockBag blockBag, int inventory, final boolean dir) throws IOException {
final FaweInputStream is = new FaweInputStream(getBlockIS());
if (is == null) {
return new ArrayList<MutableFullBlockChange>().iterator();
}
final MutableFullBlockChange change = new MutableFullBlockChange(0, 0, 0, 0, 0);
final MutableFullBlockChange change = new MutableFullBlockChange(blockBag, inventory, dir);
return new Iterator<MutableFullBlockChange>() {
private MutableFullBlockChange last = read();
public MutableFullBlockChange read() {

View File

@ -0,0 +1,27 @@
package com.boydti.fawe.object.extent;
import com.boydti.fawe.Fawe;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
public class SlowExtent extends AbstractDelegateExtent {
private final long sleep;
public SlowExtent(Extent extent, long sleep) {
super(extent);
this.sleep = sleep;
}
@Override
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
if (!Fawe.get().isMainThread()) try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
return super.setBlock(location, block);
}
}

View File

@ -88,7 +88,6 @@ public class PlotTrim implements Listener {
}
public void run() {
System.out.println("Run!");
Bukkit.getPluginManager().registerEvents(this, (Plugin) PS.get().IMP);
final Set<ChunkLoc> mcas = new HashSet<>();
if (deleteUnowned && area != null) {

View File

@ -34,8 +34,8 @@ public class EditSessionBuilder {
private Boolean fastmode;
private Boolean checkMemory;
private Boolean combineStages;
private BlockBag blockBag;
private EventBus eventBus;
private BlockBag blockBag;
private EditSessionEvent event;
/**
@ -77,6 +77,15 @@ public class EditSessionBuilder {
return limit(FaweLimit.MAX.copy());
}
public EditSessionBuilder limitUnprocessed(@Nonnull FawePlayer fp) {
checkNotNull(fp);
limitUnlimited();
FaweLimit tmp = fp.getLimit();
limit.INVENTORY_MODE = tmp.INVENTORY_MODE;
limit.FAST_PLACEMENT = tmp.FAST_PLACEMENT;
return this;
}
public EditSessionBuilder changeSet(@Nullable FaweChangeSet changeSet) {
this.changeSet = changeSet;
return this;

View File

@ -45,6 +45,7 @@ import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.boydti.fawe.object.extent.FaweRegionExtent;
import com.boydti.fawe.object.extent.NullExtent;
import com.boydti.fawe.object.extent.ProcessedWEExtent;
import com.boydti.fawe.object.extent.SlowExtent;
import com.boydti.fawe.object.extent.TransformExtent;
import com.boydti.fawe.object.mask.ResettableMask;
import com.boydti.fawe.object.progress.DefaultProgressTracker;
@ -69,6 +70,7 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.MaskingExtent;
import com.sk89q.worldedit.extent.buffer.ForgetfulExtentBuffer;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.extent.inventory.BlockBagExtent;
import com.sk89q.worldedit.extent.world.SurvivalModeExtent;
import com.sk89q.worldedit.function.GroundFunction;
import com.sk89q.worldedit.function.RegionMaskingFilter;
@ -262,14 +264,14 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY);
}
}
this.blockBag = blockBag;
this.originalLimit = limit;
this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null;
this.limit = limit.copy();
if (queue == null) {
if (world instanceof MCAWorld) {
queue = ((MCAWorld) world).getQueue();
} else {
queue = SetQueue.IMP.getNewQueue(this, fastmode, autoQueue);
queue = SetQueue.IMP.getNewQueue(this, fastmode || limit.FAST_PLACEMENT, autoQueue);
}
}
if (Settings.EXPERIMENTAL.ANVIL_QUEUE_MODE && !(queue instanceof MCAQueue)) {
@ -282,15 +284,23 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
}
this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), bus, event, Stage.BEFORE_CHANGE);
this.bypassHistory = (this.extent = wrapExtent(bypassAll, bus, event, Stage.BEFORE_REORDER));
if (!fastmode && !(changeSet instanceof NullChangeSet)) {
if (player != null && Fawe.imp().getBlocksHubApi() != null) {
changeSet = LoggingChangeSet.wrap(player, changeSet);
if (!fastmode) {
if (this.blockBag != null && limit.INVENTORY_MODE > 0) {
this.bypassHistory = new BlockBagExtent(this.bypassHistory, this.blockBag, limit.INVENTORY_MODE == 1);
}
if (combineStages) {
changeTask = changeSet;
changeSet.addChangeTask(queue);
} else {
this.extent = (history = new HistoryExtent(this, bypassHistory, changeSet, queue));
if (limit.SPEED_REDUCTION > 0) {
this.bypassHistory = new SlowExtent(this.bypassHistory, limit.SPEED_REDUCTION);
}
if (!(changeSet instanceof NullChangeSet)) {
if (player != null && Fawe.imp().getBlocksHubApi() != null) {
changeSet = LoggingChangeSet.wrap(player, changeSet);
}
if (combineStages) {
changeTask = changeSet;
changeSet.addChangeTask(queue);
} else {
this.extent = (history = new HistoryExtent(this, bypassHistory, changeSet, queue));
}
}
}
if (allowedRegions != null) {
@ -1102,7 +1112,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
context.setExtent(editSession.bypassAll);
ChangeSet changeSet = getChangeSet();
editSession.getQueue().setChangeTask(null);
Operations.completeSmart(ChangeSetExecutor.createUndo(changeSet, context), new Runnable() {
Operations.completeSmart(ChangeSetExecutor.create(changeSet, context, ChangeSetExecutor.Type.UNDO, editSession.getBlockBag(), editSession.getLimit().INVENTORY_MODE), new Runnable() {
@Override
public void run() {
editSession.flushQueue();
@ -1121,7 +1131,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue {
context.setExtent(editSession.bypassAll);
ChangeSet changeSet = getChangeSet();
editSession.getQueue().setChangeTask(null);
Operations.completeSmart(ChangeSetExecutor.createRedo(changeSet, context), new Runnable() {
Operations.completeSmart(ChangeSetExecutor.create(changeSet, context, ChangeSetExecutor.Type.REDO, editSession.getBlockBag(), editSession.getLimit().INVENTORY_MODE), new Runnable() {
@Override
public void run() {
editSession.flushQueue();

View File

@ -514,13 +514,15 @@ public class LocalSession {
loadSessionHistoryFromDisk(player.getUniqueId(), player.getWorld());
if (getHistoryNegativeIndex() < history.size()) {
FaweChangeSet changeSet = (FaweChangeSet) history.get(getHistoryIndex());
final FawePlayer fp = FawePlayer.wrap(player);
EditSession newEditSession = new EditSessionBuilder(changeSet.getWorld())
.allowedRegionsEverywhere()
.checkMemory(false)
.changeSet(changeSet)
.fastmode(false)
.limitUnlimited()
.player(FawePlayer.wrap(player))
.limitUnprocessed(fp)
.player(fp)
.blockBag(getBlockBag(player))
.build();
newEditSession.undo(newEditSession);
setDirty();
@ -561,13 +563,15 @@ public class LocalSession {
setDirty();
historyNegativeIndex--;
FaweChangeSet changeSet = (FaweChangeSet) history.get(getHistoryIndex());
final FawePlayer fp = FawePlayer.wrap(player);
EditSession newEditSession = new EditSessionBuilder(changeSet.getWorld())
.allowedRegionsEverywhere()
.checkMemory(false)
.changeSet(changeSet)
.fastmode(false)
.limitUnlimited()
.player(FawePlayer.wrap(player))
.limitUnprocessed(fp)
.player(fp)
.blockBag(getBlockBag(player))
.build();
newEditSession.redo(newEditSession);
return newEditSession;

View File

@ -0,0 +1,111 @@
package com.sk89q.worldedit.extent.inventory;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Applies a {@link BlockBag} to operations.
*/
public class BlockBagExtent extends AbstractDelegateExtent {
private final boolean mine;
private int[] missingBlocks = new int[4096];
private BlockBag blockBag;
/**
* Create a new instance.
*
* @param extent the extent
* @param blockBag the block bag
*/
public BlockBagExtent(Extent extent, @Nonnull BlockBag blockBag) {
this(extent, blockBag, false);
}
public BlockBagExtent(Extent extent, @Nonnull BlockBag blockBag, boolean mine) {
super(extent);
checkNotNull(blockBag);
this.blockBag = blockBag;
this.mine = mine;
}
/**
* Get the block bag.
*
* @return a block bag, which may be null if none is used
*/
public @Nullable BlockBag getBlockBag() {
return blockBag;
}
/**
* Set the block bag.
*
* @param blockBag a block bag, which may be null if none is used
*/
public void setBlockBag(@Nullable BlockBag blockBag) {
this.blockBag = blockBag;
}
/**
* Gets the list of missing blocks and clears the list for the next
* operation.
*
* @return a map of missing blocks
*/
public Map<Integer, Integer> popMissing() {
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < missingBlocks.length; i++) {
int count = missingBlocks[i];
if (count > 0) {
map.put(i, count);
}
}
Arrays.fill(missingBlocks, 0);
return map;
}
@Override
public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException {
CompoundTag nbt = block.getNbtData();
final int type = block.getType();
if (type != 0) {
try {
blockBag.fetchPlacedBlock(block.getId(), block.getData());
if (nbt != null) {
// Remove items (to avoid duplication)
if (nbt.containsKey("items")) {
block.setNbtData(null);
}
}
} catch (UnplaceableBlockException e) {
return false;
} catch (BlockBagException e) {
missingBlocks[type]++;
return false;
}
}
if (mine) {
BaseBlock lazyBlock = getExtent().getLazyBlock(position);
int existing = lazyBlock.getType();
if (existing != 0) {
try {
blockBag.storeDroppedBlock(existing, lazyBlock.getData());
} catch (BlockBagException ignored) {}
}
}
return super.setBlock(position, block);
}
}

View File

@ -19,7 +19,9 @@
package com.sk89q.worldedit.function.operation;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.history.UndoContext;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.history.changeset.ChangeSet;
@ -47,13 +49,16 @@ public class ChangeSetExecutor implements Operation {
* @param type type of change
* @param context the undo context
*/
private ChangeSetExecutor(ChangeSet changeSet, Type type, UndoContext context) {
private ChangeSetExecutor(ChangeSet changeSet, Type type, UndoContext context, BlockBag blockBag, int inventory) {
checkNotNull(changeSet);
checkNotNull(type);
checkNotNull(context);
this.type = type;
this.context = context;
if (type == Type.UNDO) {
if (changeSet instanceof FaweChangeSet) {
iterator = ((FaweChangeSet) changeSet).getIterator(blockBag, inventory, type == Type.REDO);
}
else if (type == Type.UNDO) {
iterator = changeSet.backwardIterator();
} else {
iterator = changeSet.forwardIterator();
@ -82,6 +87,10 @@ public class ChangeSetExecutor implements Operation {
public void addStatusMessages(List<String> messages) {
}
public static ChangeSetExecutor create(ChangeSet changeSet, UndoContext context, Type type, BlockBag blockBag, int inventory) {
return new ChangeSetExecutor(changeSet, type, context, blockBag, inventory);
}
/**
* Create a new undo operation.
*
@ -89,8 +98,9 @@ public class ChangeSetExecutor implements Operation {
* @param context an undo context
* @return an operation
*/
@Deprecated
public static ChangeSetExecutor createUndo(ChangeSet changeSet, UndoContext context) {
return new ChangeSetExecutor(changeSet, Type.UNDO, context);
return new ChangeSetExecutor(changeSet, Type.UNDO, context, null, 0);
}
/**
@ -100,8 +110,9 @@ public class ChangeSetExecutor implements Operation {
* @param context an undo context
* @return an operation
*/
@Deprecated
public static ChangeSetExecutor createRedo(ChangeSet changeSet, UndoContext context) {
return new ChangeSetExecutor(changeSet, Type.REDO, context);
return new ChangeSetExecutor(changeSet, Type.REDO, context, null, 0);
}
public static Class<?> inject() {