Add tracing feature to EditSessions (Upstream 1301) (#1112)

Co-authored-by: Octavia Togami <octavia.togami@gmail.com>
Co-authored-by: dordsor21 <dordsor21@gmail.com>
Co-authored-by: NotMyFault <mc.cache@web.de>
This commit is contained in:
Matt
2021-09-19 16:02:41 -04:00
committed by GitHub
parent f405994346
commit 4f68fb0e26
52 changed files with 1248 additions and 279 deletions

View File

@ -53,7 +53,6 @@ import com.fastasyncworldedit.core.math.random.SimplexNoise;
import com.fastasyncworldedit.core.object.FaweLimit;
import com.fastasyncworldedit.core.queue.implementation.preloader.Preloader;
import com.fastasyncworldedit.core.regions.RegionWrapper;
import com.fastasyncworldedit.core.util.EditSessionBuilder;
import com.fastasyncworldedit.core.util.ExtentTraverser;
import com.fastasyncworldedit.core.util.MaskTraverser;
import com.fastasyncworldedit.core.util.MathMan;
@ -63,10 +62,12 @@ import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.ChangeSetExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.MaskingExtent;
import com.sk89q.worldedit.extent.TracingExtent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.extent.inventory.BlockBagExtent;
@ -135,7 +136,9 @@ import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.collection.BlockMap;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -155,12 +158,14 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@ -224,10 +229,11 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
@SuppressWarnings("ProtectedField")
protected final World world;
private final @Nullable
Actor actor;
//FAWE start
private final FaweLimit originalLimit;
private final FaweLimit limit;
private final Player player;
private AbstractChangeSet changeSet;
private boolean history;
@ -243,33 +249,31 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
private final int maxY;
//FAWE end
private final List<WatchdogTickingExtent> watchdogExtents = new ArrayList<>(2);
@Nullable
private final List<TracingExtent> tracingExtents;
//FAWE start
private final Relighter relighter;
private final boolean wnaMode;
@Nullable
private final Region[] allowedRegions;
@Deprecated
@Deprecated(forRemoval = true)
public EditSession(
@Nonnull EventBus bus, World world, @Nullable Player player,
@Nonnull EventBus bus, World world, @Nullable Player actor,
@Nullable FaweLimit limit, @Nullable AbstractChangeSet changeSet,
@Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue,
@Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages,
@Nullable BlockBag blockBag, @Nullable EditSessionEvent event
) {
this(new EditSessionBuilder(world)
.player(player)
this(new EditSessionBuilder(bus).world(world).actor(actor)
.limit(limit)
.changeSet(changeSet)
.allowedRegions(allowedRegions)
.autoQueue(autoQueue)
.fastmode(fastmode)
.fastMode(fastmode)
.checkMemory(checkMemory)
.combineStages(combineStages)
.blockBag(blockBag)
.eventBus(bus)
.event(event));
}
//FAWE end
@ -284,6 +288,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @param event the event to call with the extent
*/
//FAWE start - EditSessionEvent
@Deprecated(forRemoval = true)
public EditSession(
@Nonnull EventBus eventBus,
World world,
@ -294,14 +299,14 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
this(eventBus, world, null, null, null, null, true, null, null, null, blockBag, event);
}
public EditSession(EditSessionBuilder builder) {
EditSession(EditSessionBuilder builder) {
super(builder.compile().getExtent());
this.world = builder.getWorld();
this.bypassHistory = builder.getBypassHistory();
this.bypassAll = builder.getBypassAll();
this.originalLimit = builder.getLimit();
this.limit = builder.getLimit().copy();
this.player = builder.getPlayer();
this.actor = builder.getActor();
this.changeSet = builder.getChangeTask();
this.minY = world.getMinY();
this.maxY = world.getMaxY();
@ -309,6 +314,34 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
this.history = changeSet != null;
this.relighter = builder.getRelighter();
this.wnaMode = builder.isWNAMode();
if (builder.isTracing()) {
this.tracingExtents = new ArrayList<>();
checkNotNull(actor, "A player is required while tracing");
} else {
this.tracingExtents = null;
}
this.allowedRegions = builder.getAllowedRegions() != null ? builder.getAllowedRegions().clone() : null;
}
@Deprecated(forRemoval = true)
public EditSession(com.fastasyncworldedit.core.util.EditSessionBuilder builder) {
super(builder.compile().getExtent());
this.world = builder.getWorld();
this.bypassHistory = builder.getBypassHistory();
this.bypassAll = builder.getBypassAll();
this.originalLimit = builder.getLimit();
this.limit = builder.getLimit().copy();
this.actor = builder.getPlayer();
this.changeSet = builder.getChangeTask();
this.minY = world.getMinY();
this.maxY = world.getMaxY();
this.blockBag = builder.getBlockBag();
this.history = changeSet != null;
this.relighter = builder.getRelighter();
this.wnaMode = builder.isWNAMode();
this.tracingExtents = null;
this.allowedRegions = builder.getAllowedRegions() != null ? builder.getAllowedRegions().clone() : null;
}
@ -378,22 +411,48 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
new ExtentTraverser(this).setNext(extent);
}
//FAWE Start
/**
* Get the Player or null.
* Get the Actor or null.
*
* @return the player
* @return the actor
*/
@Nullable
public Player getPlayer() {
return player;
public Actor getActor() {
return actor;
}
//FAWE End
private Extent traceIfNeeded(Extent input) {
Extent output = input;
if (tracingExtents != null) {
TracingExtent newExtent = new TracingExtent(input);
output = newExtent;
tracingExtents.add(newExtent);
}
return output;
}
// pkg private for TracedEditSession only, may later become public API
boolean commitRequired() {
//FAWE start
return false;
}
//FAWE end
/**
* Get the current list of active tracing extents.
*/
private List<TracingExtent> getActiveTracingExtents() {
if (tracingExtents == null) {
return List.of();
}
return tracingExtents.stream()
.filter(TracingExtent::isActive)
.collect(Collectors.toList());
}
/**
* Turns on specific features for a normal WorldEdit session, such as
* {@link #setBatchingChunks(boolean)
@ -801,7 +860,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
}
}
player.print(Caption.of("fawe.error.worldedit.some.fails.blockbag", str.toString()));
actor.print(Caption.of("fawe.error.worldedit.some.fails.blockbag", str.toString()));
}
}
return Collections.emptyMap();
@ -964,6 +1023,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @param stage the level
* @return whether the block changed
* @throws WorldEditException thrown on a set error
* @deprecated Deprecated as may perform differently in FAWE.
*/
@Deprecated
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, Stage stage) throws
@ -995,6 +1055,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @param position the position to set the block at
* @param block the block
* @return whether the block changed
* @deprecated Deprecated as may perform differently in FAWE.
*/
@Deprecated
public <B extends BlockStateHolder<B>> boolean rawSetBlock(BlockVector3 position, B block) {
@ -1209,7 +1270,47 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
*/
@Override
public void close() {
flushSession();
flushQueue();
dumpTracingInformation();
}
private void dumpTracingInformation() {
if (this.tracingExtents == null) {
return;
}
List<TracingExtent> tracingExtents = getActiveTracingExtents();
assert actor != null;
if (tracingExtents.isEmpty()) {
actor.printError(TextComponent.of("worldedit.trace.no-tracing-extents"));
return;
}
// find the common stacks
Set<List<TracingExtent>> stacks = new LinkedHashSet<>();
Map<List<TracingExtent>, BlockVector3> stackToPosition = new HashMap<>();
Set<BlockVector3> touchedLocations = Collections.newSetFromMap(BlockMap.create());
for (TracingExtent tracingExtent : tracingExtents) {
touchedLocations.addAll(tracingExtent.getTouchedLocations());
}
for (BlockVector3 loc : touchedLocations) {
List<TracingExtent> stack = tracingExtents.stream()
.filter(it -> it.getTouchedLocations().contains(loc))
.collect(Collectors.toList());
boolean anyFailed = stack.stream()
.anyMatch(it -> it.getFailedActions().containsKey(loc));
if (anyFailed && stacks.add(stack)) {
stackToPosition.put(stack, loc);
}
}
stackToPosition.forEach((stack, position) -> {
// stack can never be empty, something has to have touched the position
TracingExtent failure = stack.get(0);
actor.printDebug(Caption.of(
"worldedit.trace.action-failed",
failure.getFailedActions().get(position).toString(),
position.toString(),
failure.getExtent().getClass().getName()
));
});
}
/**
@ -1234,11 +1335,11 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
FaweLimit used = getLimitUsed();
if (used.MAX_FAILS > 0) {
if (used.MAX_CHANGES > 0 || used.MAX_ENTITIES > 0) {
player.print(Caption.of("fawe.error.worldedit.some.fails", used.MAX_FAILS));
actor.print(Caption.of("fawe.error.worldedit.some.fails", used.MAX_FAILS));
} else if (new ExtentTraverser<>(getExtent()).findAndGet(FaweRegionExtent.class) != null) {
player.print(Caption.of("fawe.cancel.worldedit.cancel.reason.outside.region"));
actor.print(Caption.of("fawe.cancel.worldedit.cancel.reason.outside.region"));
} else {
player.print(Caption.of("fawe.cancel.worldedit.cancel.reason.outside.level"));
actor.print(Caption.of("fawe.cancel.worldedit.cancel.reason.outside.level"));
}
}
if (wnaMode) {
@ -1262,14 +1363,14 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
}
}
} catch (Throwable e) {
player.print(Caption.of("fawe.error.lighting"));
actor.print(Caption.of("fawe.error.lighting"));
e.printStackTrace();
}
// Cancel any preloader associated with the actor if present
if (getPlayer() != null) {
if (getActor() instanceof Player) {
Preloader preloader = Fawe.imp().getPreloader(false);
if (preloader != null) {
preloader.cancel(getPlayer());
preloader.cancel(getActor());
}
}
// Enqueue it
@ -1738,7 +1839,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* Stack a cuboid region.
*
* @param region the region to stack
* @param dir the direction to stack
* @param offset how far to move the contents each stack. Is directional.
* @param count the number of times to stack
* @param copyEntities true to copy entities
* @param copyBiomes true to copy biomes
@ -1747,18 +1848,18 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int stackCuboidRegion(
Region region, BlockVector3 dir, int count,
Region region, BlockVector3 offset, int count,
boolean copyEntities, boolean copyBiomes, Mask mask
) throws MaxChangedBlocksException {
checkNotNull(region);
checkNotNull(dir);
checkNotNull(offset);
checkArgument(count >= 1, "count >= 1 required");
BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1);
BlockVector3 to = region.getMinimumPoint();
ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to);
copy.setRepetitions(count);
copy.setTransform(new AffineTransform().translate(dir.multiply(size)));
copy.setTransform(new AffineTransform().translate(offset.multiply(size)));
copy.setCopyingEntities(copyEntities);
copy.setCopyingBiomes(copyBiomes);
final Region allowedRegion;
@ -1781,8 +1882,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* Move the blocks in a region a certain direction.
*
* @param region the region to move
* @param dir the direction
* @param distance the distance to move
* @param offset the offset. Is directional.
* @param multiplier the number to multiply the offset by
* @param copyAir true to copy air blocks
* @param moveEntities true to move entities
* @param copyBiomes true to copy biomes
@ -1792,8 +1893,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
*/
public int moveRegion(
Region region,
BlockVector3 dir,
int distance,
BlockVector3 offset,
int multiplier,
boolean copyAir,
boolean moveEntities,
boolean copyBiomes,
@ -1804,7 +1905,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
if (!copyAir) {
mask = new ExistingBlockMask(this);
}
return moveRegion(region, dir, distance, moveEntities, copyBiomes, mask, replacement);
return moveRegion(region, offset, multiplier, moveEntities, copyBiomes, mask, replacement);
//FAWE end
}
@ -1812,8 +1913,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* Move the blocks in a region a certain direction.
*
* @param region the region to move
* @param dir the direction
* @param distance the distance to move
* @param offset the offset. Is directional.
* @param multiplier the number to multiply the offset by
* @param moveEntities true to move entities
* @param copyBiomes true to copy biomes (source biome is unchanged)
* @param mask source mask for the operation (only matching blocks are moved)
@ -1823,18 +1924,18 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @throws IllegalArgumentException thrown if the region is not a flat region, but copyBiomes is true
*/
public int moveRegion(
Region region, BlockVector3 dir, int distance,
Region region, BlockVector3 offset, int multiplier,
boolean moveEntities, boolean copyBiomes, Mask mask, Pattern replacement
) throws MaxChangedBlocksException {
checkNotNull(region);
checkNotNull(dir);
checkArgument(distance >= 1, "distance >= 1 required");
checkNotNull(offset);
checkArgument(multiplier >= 1, "distance >= 1 required");
checkArgument(!copyBiomes || region instanceof FlatRegion, "can't copy biomes from non-flat region");
//FAWE start - add up distance
BlockVector3 to = region.getMinimumPoint().add(dir.multiply(distance));
BlockVector3 to = region.getMinimumPoint().add(offset.multiply(multiplier));
final BlockVector3 displace = dir.multiply(distance);
final BlockVector3 displace = offset.multiply(multiplier);
final BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1);
BlockVector3 disAbs = displace.abs();
@ -2941,7 +3042,20 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
) throws ExpressionException, MaxChangedBlocksException {
final Expression expression = Expression.compile(expressionString, "x", "y", "z");
expression.optimize();
return deformRegion(region, zero, unit, expression, timeout);
}
/**
* Internal version of {@link EditSession#deformRegion(Region, Vector3, Vector3, String, int)}.
*
* <p>
* The Expression class is subject to change. Expressions should be provided via the string overload.
* </p>
*/
public int deformRegion(
final Region region, final Vector3 zero, final Vector3 unit, final Expression expression,
final int timeout
) throws ExpressionException, MaxChangedBlocksException {
final Variable x = expression.getSlots().getVariable("x")
.orElseThrow(IllegalStateException::new);
final Variable y = expression.getSlots().getVariable("y")

View File

@ -0,0 +1,682 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.FaweRegionExtent;
import com.fastasyncworldedit.core.extent.HistoryExtent;
import com.fastasyncworldedit.core.extent.LimitExtent;
import com.fastasyncworldedit.core.extent.MultiRegionExtent;
import com.fastasyncworldedit.core.extent.NullExtent;
import com.fastasyncworldedit.core.extent.SingleRegionExtent;
import com.fastasyncworldedit.core.extent.SlowExtent;
import com.fastasyncworldedit.core.extent.StripNBTExtent;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightmapProcessor;
import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
import com.fastasyncworldedit.core.extent.processor.lighting.RelightProcessor;
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
import com.fastasyncworldedit.core.history.DiskStorageHistory;
import com.fastasyncworldedit.core.history.MemoryOptimizedHistory;
import com.fastasyncworldedit.core.history.RollbackOptimizedHistory;
import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet;
import com.fastasyncworldedit.core.history.changeset.BlockBagChangeSet;
import com.fastasyncworldedit.core.history.changeset.NullChangeSet;
import com.fastasyncworldedit.core.object.FaweLimit;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
import com.fastasyncworldedit.core.regions.RegionWrapper;
import com.fastasyncworldedit.core.util.MemUtil;
import com.fastasyncworldedit.core.util.Permission;
import com.fastasyncworldedit.core.wrappers.WorldWrapper;
import com.google.common.base.Preconditions;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Locatable;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Identifiable;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.World;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Locale;
import java.util.UUID;
/**
* A builder-style factory for {@link EditSession EditSessions}.
*/
public final class EditSessionBuilder {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final EventBus eventBus;
private FaweLimit limit;
private AbstractChangeSet changeSet;
private Region[] allowedRegions;
private Boolean fastMode;
private Boolean checkMemory;
private Boolean combineStages;
private EditSessionEvent event;
private String command;
private RelightMode relightMode;
private Relighter relighter;
private Boolean wnaMode;
private AbstractChangeSet changeTask;
private Extent bypassHistory;
private Extent bypassAll;
private Extent extent;
private boolean compiled;
private boolean wrapped;
private @Nullable
World world;
private int maxBlocks = -1;
@Nullable
private Actor actor;
@Nullable
private BlockBag blockBag;
private boolean tracing;
EditSessionBuilder(EventBus eventBus) {
this.eventBus = eventBus;
}
/**
* Set the world for the {@link EditSession}.
*
* @param world the world
* @return this builder
*/
public EditSessionBuilder world(@Nullable World world) {
this.world = world;
return setDirty();
}
/**
* Get the world to be edited if present or null
*/
@Nullable
public World getWorld() {
return world;
}
/**
* Get the maximum number of block changes allowed
*/
public int getMaxBlocks() {
return maxBlocks;
}
/**
* Set the maximum blocks to change for the {@link EditSession}.
*
* @param maxBlocks the maximum blocks to change
* @return this builder
*/
public EditSessionBuilder maxBlocks(int maxBlocks) {
this.maxBlocks = maxBlocks;
return setDirty();
}
/**
* Get the actor associated with the edit if present or null
*/
@Nullable
public Actor getActor() {
return actor;
}
/**
* Set the actor who owns the {@link EditSession}.
*
* @param actor the actor
* @return this builder
*/
public EditSessionBuilder actor(@Nullable Actor actor) {
this.actor = actor;
return setDirty();
}
/**
*
* Get the {@link BlockBag} associated with the edit if present or null
*/
@Nullable
public BlockBag getBlockBag() {
return blockBag;
}
/**
* Set the block bag for the {@link EditSession}.
*
* @param blockBag the block bag
* @return this builder
*/
public EditSessionBuilder blockBag(@Nullable BlockBag blockBag) {
this.blockBag = blockBag;
return setDirty();
}
/**
* Check if tracing is enabled.
*
* <em>Internal use only.</em>
*/
public boolean isTracing() {
return tracing;
}
/**
* Set tracing enabled/disabled.
*
* <em>Internal use only.</em>
*/
public EditSessionBuilder tracing(boolean tracing) {
this.tracing = tracing;
return setDirty();
}
/**
* Set the actor to one with a location/extent associated. Sets both the actor and the world.
*/
public <A extends Actor & Locatable> EditSessionBuilder locatableActor(A locatable) {
Extent extent = locatable.getExtent();
Preconditions.checkArgument(extent instanceof World, "%s is not located in a World", locatable);
return world(((World) extent)).actor(locatable);
}
/**
* Build the {@link EditSession} using properties described in this builder.
*
* @return the new EditSession
*/
public EditSession build() {
// TracedEditSession does nothing at the moment.
//if (WorldEdit.getInstance().getConfiguration().traceUnflushedSessions) {
// return new TracedEditSession(this);
//}
return new EditSession(this);
}
/**
* Set builder as changed and requiring (re-)compilation
*/
private EditSessionBuilder setDirty() {
compiled = false;
return this;
}
/**
* Set the {@link EditSessionEvent} instance to be used for firing at different stages of preparation
*/
public EditSessionBuilder event(@Nullable EditSessionEvent event) {
this.event = event;
return setDirty();
}
/**
* Set the limit(s) for the edit to use
*/
public EditSessionBuilder limit(@Nullable FaweLimit limit) {
this.limit = limit;
return setDirty();
}
/**
* Set the edit to be able to edit everywhere, and for any number of blocks
*/
public EditSessionBuilder limitUnlimited() {
return limit(FaweLimit.MAX.copy());
}
/**
* Unlimited in regions/block changes, but uses the given {@link Actor}'s inventory mode.
*/
public EditSessionBuilder limitUnprocessed(@Nonnull Actor player) {
limitUnlimited();
FaweLimit tmp = player.getLimit();
limit.INVENTORY_MODE = tmp.INVENTORY_MODE;
return setDirty();
}
/**
* Set the changeset to be used for history
*/
public EditSessionBuilder changeSet(@Nullable AbstractChangeSet changeSet) {
this.changeSet = changeSet;
return setDirty();
}
/**
* Do not process any history
*/
public EditSessionBuilder changeSetNull() {
return changeSet(new NullChangeSet(world));
}
/**
* Set the command used that created this edit. Used in {@link RollbackOptimizedHistory}
*/
public EditSessionBuilder command(String command) {
this.command = command;
return this;
}
/**
* Create a new changeset to be used for the edit's history.
*
* @param disk If disk should be used for history storage
* @param uuid UUID to be used for the history or null if unneeded.
*/
public EditSessionBuilder changeSet(boolean disk, @Nullable UUID uuid) {
if (disk) {
if (Settings.IMP.HISTORY.USE_DATABASE) {
this.changeSet = new RollbackOptimizedHistory(world, uuid);
} else {
this.changeSet = new DiskStorageHistory(world, uuid);
}
} else {
this.changeSet = new MemoryOptimizedHistory(world);
}
return setDirty();
}
/**
* Set the regions the edit is allowed to operate in. Set to null for the regions to be calculated based on the actor if
* present
*/
public EditSessionBuilder allowedRegions(@Nullable Region[] allowedRegions) {
this.allowedRegions = allowedRegions;
return setDirty();
}
/**
* Set the regions the edit is allowed to operate in. Set to null for the regions to be calculated based on the actor if
* present
*/
@Deprecated
public EditSessionBuilder allowedRegions(@Nullable RegionWrapper[] allowedRegions) {
this.allowedRegions = allowedRegions;
return setDirty();
}
/**
* Set the region the edit is allowed to operate in. Set to null for the regions to be calculated based on the actor if
* present
*/
public EditSessionBuilder allowedRegions(@Nullable RegionWrapper allowedRegion) {
this.allowedRegions = allowedRegion == null ? null : allowedRegion.toArray();
return setDirty();
}
/**
* Set the edit to be allowed to edit everywhere
*/
public EditSessionBuilder allowedRegionsEverywhere() {
return allowedRegions(new Region[]{RegionWrapper.GLOBAL()});
}
/**
* Does nothing as of 1.13 new queueing system
*/
@Deprecated(forRemoval = true)
public EditSessionBuilder autoQueue(@Nullable Boolean autoQueue) {
return setDirty();
}
/**
* Set fast mode. Use null to set to actor's fast mode setting. Also set to true by default if history for console disabled
*/
public EditSessionBuilder fastMode(@Nullable Boolean fastMode) {
this.fastMode = fastMode;
return setDirty();
}
/**
* Set the {@link RelightMode}
*/
public EditSessionBuilder relightMode(@Nullable RelightMode relightMode) {
this.relightMode = relightMode;
return setDirty();
}
/**
* Override if memory usage should be checked during editsession compilation. By default, checks memory if fastmode is not
* enabled and actor is not null.
*/
public EditSessionBuilder checkMemory(@Nullable Boolean checkMemory) {
this.checkMemory = checkMemory;
return setDirty();
}
/**
* Record history with dispatching:,
* - Much faster as it avoids duplicate block checks,
* - Slightly worse compression since dispatch order is different.
*/
public EditSessionBuilder combineStages(@Nullable Boolean combineStages) {
this.combineStages = combineStages;
return setDirty();
}
/**
* Compile the builder to the settings given. Prepares history, limits, lighting, etc.
*/
public EditSessionBuilder compile() {
if (compiled) {
return this;
}
compiled = true;
wrapped = false;
if (event == null) {
event = new EditSessionEvent(world, actor, -1, null);
}
if (actor == null && event.getActor() != null) {
actor = event.getActor();
}
if (limit == null) {
if (actor == null) {
limit = FaweLimit.MAX;
} else {
limit = actor.getLimit();
}
}
if (fastMode == null) {
if (actor == null) {
fastMode = !Settings.IMP.HISTORY.ENABLE_FOR_CONSOLE;
} else {
fastMode = actor.getSession().hasFastMode();
}
}
if (checkMemory == null) {
checkMemory = actor != null && !this.fastMode;
}
if (checkMemory) {
if (MemUtil.isMemoryLimitedSlow()) {
if (Permission.hasPermission(actor, "worldedit.fast")) {
actor.print(Caption.of("fawe.info.worldedit.oom.admin"));
}
throw FaweCache.LOW_MEMORY;
}
}
// this.originalLimit = limit;
this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null;
this.limit = limit.copy();
if (extent == null) {
IQueueExtent<IQueueChunk> queue = null;
World unwrapped = WorldWrapper.unwrap(world);
boolean placeChunks = (this.fastMode || this.limit.FAST_PLACEMENT) && (wnaMode == null || !wnaMode);
if (placeChunks) {
wnaMode = false;
if (unwrapped instanceof IQueueExtent) {
extent = queue = (IQueueExtent) unwrapped;
} else if (Settings.IMP.QUEUE.PARALLEL_THREADS > 1 && !Fawe.isMainThread()) {
ParallelQueueExtent parallel = new ParallelQueueExtent(Fawe.get().getQueueHandler(), world, fastMode);
queue = parallel.getExtent();
extent = parallel;
} else {
extent = queue = Fawe.get().getQueueHandler().getQueue(world);
}
} else {
wnaMode = true;
extent = world;
}
if (combineStages == null) {
combineStages =
// If it's enabled in the settings
Settings.IMP.HISTORY.COMBINE_STAGES
// If fast placement is disabled, it's slower to perform a copy on each chunk
&& this.limit.FAST_PLACEMENT
// If the edit uses items from the inventory we can't use a delayed task
&& this.blockBag == null;
}
extent = this.bypassAll = wrapExtent(extent, eventBus, event, EditSession.Stage.BEFORE_CHANGE);
this.bypassHistory = this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER);
if (!this.fastMode || changeSet != null) {
if (changeSet == null) {
if (Settings.IMP.HISTORY.USE_DISK) {
UUID uuid = actor == null ? Identifiable.CONSOLE : actor.getUniqueId();
if (Settings.IMP.HISTORY.USE_DATABASE) {
changeSet = new RollbackOptimizedHistory(world, uuid);
} else {
changeSet = new DiskStorageHistory(world, uuid);
}
} else {
if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0) {
//TODO add CPUOptimizedChangeSet
}
changeSet = new MemoryOptimizedHistory(world);
}
}
if (this.limit.SPEED_REDUCTION > 0) {
this.extent = this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION);
}
if (command != null && changeSet instanceof RollbackOptimizedHistory) {
((RollbackOptimizedHistory) changeSet).setCommand(this.command);
}
if (!(changeSet instanceof NullChangeSet)) {
if (this.blockBag != null) {
//TODO implement block bag as IBatchProcessor
changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1);
}
if (combineStages) {
changeTask = changeSet;
this.extent = extent.enableHistory(changeSet);
} else {
this.extent = new HistoryExtent(extent, changeSet);
}
}
}
if (allowedRegions == null) {
if (actor != null && !actor.hasPermission("fawe.bypass") && !actor.hasPermission("fawe.bypass.regions")) {
if (actor instanceof Player) {
Player player = (Player) actor;
allowedRegions = player.getCurrentRegions();
}
}
}
FaweRegionExtent regionExtent = null;
if (allowedRegions != null) {
if (allowedRegions.length == 0) {
regionExtent = new NullExtent(this.extent, FaweCache.NO_REGION);
} else {
if (allowedRegions.length == 1) {
regionExtent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]);
} else {
regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions);
}
}
} else {
allowedRegions = new Region[]{RegionWrapper.GLOBAL()};
}
// There's no need to do lighting (and it'll also just be a pain to implement) if we're not placing chunks
if (placeChunks) {
if (((relightMode != null && relightMode != RelightMode.NONE) || (relightMode == null && Settings.IMP.LIGHTING.MODE > 0))) {
relighter = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.WORLD_EDITING)
.getRelighterFactory().createRelighter(relightMode, world, queue);
extent.addProcessor(new RelightProcessor(relighter));
}
extent.addProcessor(new HeightmapProcessor(world.getMinY(), world.getMaxY()));
} else {
relighter = NullRelighter.INSTANCE;
}
if (limit != null && !limit.isUnlimited() && regionExtent != null) {
this.extent = new LimitExtent(regionExtent, limit);
} else if (limit != null && !limit.isUnlimited()) {
this.extent = new LimitExtent(this.extent, limit);
} else if (regionExtent != null) {
this.extent = regionExtent;
}
if (this.limit != null && this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) {
//TODO add batch processor for strip nbt
this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT);
}
this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY);
}
return this;
}
/**
* Get the relight engine to be used
*/
public Relighter getRelighter() {
return relighter;
}
/**
* If the edit will force using WNA
*/
public boolean isWNAMode() {
return wnaMode;
}
/**
* get the allowed regions associated with the edit's restricttions
*/
@Nullable
public Region[] getAllowedRegions() {
return allowedRegions;
}
/**
* Force WNA to be used instead of FAWE's queue system. Will use more memory, be slower, and more likely to cause issues.
*/
public EditSessionBuilder forceWNA() {
this.wnaMode = true;
return setDirty();
}
/**
* If an {@link EditSessionEvent} has been fired yet
*/
public boolean isWrapped() {
return wrapped;
}
/**
* Get the base extent that blocks are set to, bypassing any restrictions, limits and history. All extents up to and including
* {@link com.sk89q.worldedit.EditSession.Stage#BEFORE_REORDER}
*/
public Extent getBypassHistory() {
return bypassHistory;
}
/**
* Get the base extent that blocks are set to, bypassing any restrictions, limits and history. All extents up to and including
* {@link com.sk89q.worldedit.EditSession.Stage#BEFORE_CHANGE}
*/
public Extent getBypassAll() {
return bypassAll;
}
/**
* Get the edit's limits
*/
@Nonnull
public FaweLimit getLimit() {
return limit;
}
/**
* Get the change set that will be used for history
*/
public AbstractChangeSet getChangeTask() {
return changeTask;
}
/**
* Get the ultimate resultant extent
*/
public Extent getExtent() {
return extent != null ? extent : world;
}
/**
* Fire an {@link EditSessionEvent}. Fired after each stage of preparation, allows other plugins to add/alter extents.
*/
private Extent wrapExtent(
final Extent extent,
final EventBus eventBus,
EditSessionEvent event,
final EditSession.Stage stage
) {
event = event.clone(stage);
event.setExtent(extent);
eventBus.post(event);
if (event.isCancelled()) {
return new NullExtent(extent, FaweCache.MANUAL);
}
final Extent toReturn = event.getExtent();
if (toReturn instanceof com.sk89q.worldedit.extent.NullExtent) {
return new NullExtent(toReturn, FaweCache.MANUAL);
}
if (toReturn != extent) {
String className = toReturn.getClass().getName().toLowerCase(Locale.ROOT);
for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) {
if (className.contains(allowed.toLowerCase(Locale.ROOT))) {
this.wrapped = true;
return toReturn;
}
}
if (Settings.IMP.EXTENT.DEBUG) {
if (event.getActor() != null) {
event.getActor().printDebug(TextComponent.of("Potentially unsafe extent blocked: " + toReturn
.getClass()
.getName()));
event.getActor().printDebug(TextComponent.of(
" - For area restrictions and block logging, it is recommended to use the FaweAPI"));
event.getActor().printDebug(TextComponent.of(" - To allow " + toReturn
.getClass()
.getName() + ", add it to the FAWE `allowed-plugins` list in config.yml"));
event.getActor().printDebug(TextComponent.of(
" - If you are unsure which plugin tries to use the extent, you can find some additional information below:"));
event.getActor().printDebug(TextComponent.of(" - " + toReturn.getClass().getClassLoader()));
} else {
LOGGER.debug("Potentially unsafe extent blocked: " + toReturn.getClass().getName());
LOGGER.debug(" - For area restrictions and block logging, it is recommended to use the FaweAPI");
LOGGER.debug(" - To allow " + toReturn
.getClass()
.getName() + ", add it to the FAWE `allowed-plugins` list in config.yml");
LOGGER.debug(
" - If you are unsure which plugin tries to use the extent, you can find some additional information below:");
LOGGER.debug(" - " + toReturn.getClass().getClassLoader());
}
}
}
return extent;
}
}

View File

@ -22,11 +22,8 @@ package com.sk89q.worldedit;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.World;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Creates new {@link EditSession}s. To get an instance of this factory,
* use {@link WorldEdit#getEditSessionFactory()}.
@ -34,7 +31,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
* <p>It is no longer possible to replace the instance of this in WorldEdit
* with a custom one. Use {@link EditSessionEvent} to override
* the creation of {@link EditSession}s.</p>
*
* @deprecated Using the ever-extending factory methods is deprecated. Replace with {@link EditSessionBuilder},
* which in most cases will be as simple as calling {@code builder.world(world).build()}.
*/
@Deprecated
public class EditSessionFactory {
/**
@ -138,16 +139,10 @@ public class EditSessionFactory {
*/
static final class EditSessionFactoryImpl extends EditSessionFactory {
private final EventBus eventBus;
/**
* Create a new factory.
*
* @param eventBus the event bus
*/
EditSessionFactoryImpl(EventBus eventBus) {
checkNotNull(eventBus);
this.eventBus = eventBus;
EditSessionFactoryImpl() {
}
@Override
@ -167,16 +162,12 @@ public class EditSessionFactory {
@Override
public EditSession getEditSession(World world, int maxBlocks, BlockBag blockBag, Actor actor) {
if (WorldEdit.getInstance().getConfiguration().traceUnflushedSessions) {
return new TracedEditSession(
eventBus,
world,
maxBlocks,
blockBag,
new EditSessionEvent(world, actor, maxBlocks, null)
);
}
return new EditSession(eventBus, world, maxBlocks, blockBag, new EditSessionEvent(world, actor, maxBlocks, null));
return WorldEdit.getInstance().newEditSessionBuilder()
.world(world)
.maxBlocks(maxBlocks)
.blockBag(blockBag)
.actor(actor)
.build();
}
}

View File

@ -29,7 +29,6 @@ import com.fastasyncworldedit.core.internal.io.FaweInputStream;
import com.fastasyncworldedit.core.internal.io.FaweOutputStream;
import com.fastasyncworldedit.core.object.FaweLimit;
import com.fastasyncworldedit.core.util.BrushCache;
import com.fastasyncworldedit.core.util.EditSessionBuilder;
import com.fastasyncworldedit.core.util.MainUtil;
import com.fastasyncworldedit.core.util.StringMan;
import com.fastasyncworldedit.core.util.TextureHolder;
@ -168,6 +167,7 @@ public class LocalSession implements TextureHolder {
private transient World worldOverride;
private transient boolean tickingWatchdog = false;
private transient boolean hasBeenToldVersion;
private transient boolean tracingActions;
// Saved properties
private String lastScript;
@ -421,8 +421,8 @@ public class LocalSession implements TextureHolder {
}
//FAWE start
Player player = editSession.getPlayer();
int limit = player == null ? Integer.MAX_VALUE : player.getLimit().MAX_HISTORY;
Actor actor = editSession.getActor();
int limit = actor == null ? Integer.MAX_VALUE : actor.getLimit().MAX_HISTORY;
remember(editSession, true, limit);
}
@ -519,9 +519,9 @@ public class LocalSession implements TextureHolder {
return;
}
Player player = editSession.getPlayer();
if (player != null) {
loadSessionHistoryFromDisk(player.getUniqueId(), editSession.getWorld());
Actor actor = editSession.getActor();
if (actor != null) {
loadSessionHistoryFromDisk(actor.getUniqueId(), editSession.getWorld());
}
// Destroy any sessions after this undo point
if (append) {
@ -583,15 +583,17 @@ public class LocalSession implements TextureHolder {
loadSessionHistoryFromDisk(actor.getUniqueId(), world);
if (getHistoryNegativeIndex() < history.size()) {
ChangeSet changeSet = getChangeSet(history.get(getHistoryIndex()));
EditSessionBuilder builder = new EditSessionBuilder(world)
EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(world)
.checkMemory(false)
.changeSetNull()
.fastmode(false)
.limitUnprocessed((Player) actor)
.player((Player) actor)
.blockBag(getBlockBag((Player) actor));
.fastMode(false)
.limitUnprocessed(actor)
.actor(actor);
if (actor instanceof Player) {
builder = builder.blockBag(getBlockBag((Player) actor));
}
if (!actor.getLimit().RESTRICT_HISTORY_TO_REGIONS) {
builder.allowedRegionsEverywhere();
builder = builder.allowedRegionsEverywhere();
}
try (EditSession newEditSession = builder.build()) {
newEditSession.setBlocks(changeSet, ChangeSetExecutor.Type.UNDO);
@ -629,15 +631,17 @@ public class LocalSession implements TextureHolder {
setDirty();
historyNegativeIndex--;
ChangeSet changeSet = getChangeSet(history.get(getHistoryIndex()));
EditSessionBuilder builder = new EditSessionBuilder(world)
EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(world)
.checkMemory(false)
.changeSetNull()
.fastmode(false)
.limitUnprocessed((Player) actor)
.player((Player) actor)
.blockBag(getBlockBag((Player) actor));
.fastMode(false)
.limitUnprocessed(actor)
.actor(actor);
if (actor instanceof Player) {
builder = builder.blockBag(getBlockBag((Player) actor));
}
if (!actor.getLimit().RESTRICT_HISTORY_TO_REGIONS) {
builder.allowedRegionsEverywhere();
builder = builder.allowedRegionsEverywhere();
}
try (EditSession newEditSession = builder.build()) {
newEditSession.setBlocks(changeSet, ChangeSetExecutor.Type.REDO);
@ -670,6 +674,14 @@ public class LocalSession implements TextureHolder {
this.tickingWatchdog = tickingWatchdog;
}
public boolean isTracingActions() {
return tracingActions;
}
public void setTracingActions(boolean tracingActions) {
this.tracingActions = tracingActions;
}
/**
* Get the default region selector.
*
@ -1594,14 +1606,14 @@ public class LocalSession implements TextureHolder {
// Create an edit session
//FAWE start - we don't use the edit session builder yet
EditSession editSession;
EditSessionBuilder builder = new EditSessionBuilder(world);
EditSessionBuilder builder = WorldEdit.getInstance().newEditSessionBuilder().world(world);
if (actor.isPlayer() && actor instanceof Player) {
BlockBag blockBag = getBlockBag((Player) actor);
builder.player((Player) actor);
builder.actor(actor);
builder.blockBag(blockBag);
}
builder.command(command);
builder.fastmode(!this.sideEffectSet.doesApplyAny());
builder.fastMode(!this.sideEffectSet.doesApplyAny());
editSession = builder.build();

View File

@ -19,18 +19,36 @@
package com.sk89q.worldedit;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
/**
* Internal use only.
* Internal use only. Unused for now, but present in case upstream make it API.
*/
class TracedEditSession extends EditSession {
TracedEditSession(EventBus eventBus, World world, int maxBlocks, BlockBag blockBag, EditSessionEvent event) {
super(eventBus, world, maxBlocks, blockBag, event);
//FAWE start - does not work with FAWE's ways of doing things...
@Deprecated
//FAWE end
TracedEditSession(
EventBus eventBus, @Nullable World world, int maxBlocks, @Nullable BlockBag blockBag,
@Nullable Actor actor,
boolean tracing
) {
super(new EditSessionBuilder(eventBus)
.world(world)
.maxBlocks(maxBlocks)
.blockBag(blockBag)
.actor(actor)
.tracing(tracing));
}
TracedEditSession(EditSessionBuilder builder) {
super(builder);
}
private final Throwable stacktrace = new Throwable("Creation trace.");

View File

@ -41,6 +41,7 @@ import com.sk89q.worldedit.extension.factory.MaskFactory;
import com.sk89q.worldedit.extension.factory.PatternFactory;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Locatable;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.extent.inventory.BlockBag;
@ -68,6 +69,7 @@ import com.sk89q.worldedit.util.io.file.InvalidFilenameException;
import com.sk89q.worldedit.util.task.SimpleSupervisor;
import com.sk89q.worldedit.util.task.Supervisor;
import com.sk89q.worldedit.util.translation.TranslationManager;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BundledBlockData;
@ -120,7 +122,8 @@ public final class WorldEdit {
private final EventBus eventBus = new EventBus();
private final PlatformManager platformManager = new PlatformManager(this);
private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl(eventBus);
@Deprecated
private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl();
private final SessionManager sessions = new SessionManager(this);
private final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(
0,
@ -838,12 +841,41 @@ public final class WorldEdit {
/**
* Get a factory for {@link EditSession}s.
*
* @deprecated Use {@link #newEditSessionBuilder()} instead. See {@link EditSessionFactory} for details.
*/
@Deprecated
public EditSessionFactory getEditSessionFactory() {
return editSessionFactory;
}
/**
* Create a builder for {@link EditSession}s.
*/
public EditSessionBuilder newEditSessionBuilder() {
return new EditSessionBuilder(eventBus);
}
/**
* Shorthand for {@code newEditSessionBuilder().world(world).build()}.
*
* @param world the world
* @return the new {@link EditSession}
*/
public EditSession newEditSession(@Nullable World world) {
return newEditSessionBuilder().world(world).build();
}
/**
* Shorthand for {@code newEditSessionBuilder().locatableActor(locatableActor).build()}.
*
* @param locatableActor the actor
* @return the new {@link EditSession}
*/
public <A extends Actor & Locatable> EditSession newEditSession(A locatableActor) {
return newEditSessionBuilder().locatableActor(locatableActor).build();
}
/**
* Get the version.
*

View File

@ -110,7 +110,7 @@ public class ChunkCommands {
WorldEditAsyncCommandBuilder.createAndSendMessage(
actor,
() -> new ChunkListPaginationBox(region).create(page),
TranslatableComponent.of(
Caption.of(
"worldedit.listchunks.listfor",
TextComponent.of(actor.getName())
)

View File

@ -24,7 +24,6 @@ import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.event.extent.PasteEvent;
import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard;
import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder;
import com.fastasyncworldedit.core.extent.clipboard.ReadOnlyClipboard;
import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder;

View File

@ -29,6 +29,7 @@ import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.HookMode;
import com.sk89q.worldedit.command.util.PrintCommandHelp;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent;
@ -182,6 +183,32 @@ public class WorldEditCommands {
}
//FAWE end
@Command(
name = "trace",
desc = "Toggles trace hook"
)
void trace(
Actor actor, LocalSession session,
@Arg(desc = "The mode to set the trace hook to", def = "")
HookMode hookMode
) {
boolean previousMode = session.isTracingActions();
boolean newMode;
if (hookMode != null) {
newMode = hookMode == HookMode.ACTIVE;
if (newMode == previousMode) {
actor.printError(Caption.of(previousMode
? "worldedit.trace.active.already"
: "worldedit.trace.inactive.already"));
return;
}
} else {
newMode = !previousMode;
}
session.setTracingActions(newMode);
actor.printInfo(Caption.of(newMode ? "worldedit.trace.active" : "worldedit.trace.inactive"));
}
@Command(
name = "cui",
desc = "Complete CUI handshake (internal usage)"

View File

@ -69,8 +69,8 @@ public class EditSessionEvent extends Event implements Cancellable {
private final Actor actor;
private final int maxBlocks;
private final Stage stage;
private Extent extent;
private final List<TracingExtent> tracingExtents = new ArrayList<>();
private Extent extent;
private boolean tracing;
//FAWE start
private boolean cancelled;

View File

@ -404,7 +404,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
BlockVector3 spot = BlockVector3.at(x, y - 1, z);
final World world = getWorld();
if (!world.getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) {
try (EditSession session = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 1, this)) {
try (EditSession session = WorldEdit.getInstance().newEditSession(this)) {
session.setBlock(spot, BlockTypes.GLASS.getDefaultState());
} catch (MaxChangedBlocksException ignored) {
}

View File

@ -25,7 +25,6 @@ import com.fastasyncworldedit.core.entity.MapMetadatable;
import com.fastasyncworldedit.core.object.FaweLimit;
import com.fastasyncworldedit.core.util.task.InterruptableCondition;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.session.SessionOwner;
import com.sk89q.worldedit.session.request.Request;
@ -250,8 +249,8 @@ public interface Actor extends Identifiable, SessionOwner, Subject, MapMetadatab
for (Request request : Request.getAll()) {
EditSession editSession = request.getEditSession();
if (editSession != null) {
Player player = editSession.getPlayer();
if (equals(player)) {
Actor actor = editSession.getActor();
if (equals(actor)) {
editSession.cancel();
cancelled++;
}

View File

@ -798,7 +798,7 @@ public final class PlatformCommandManager {
// Require null CommandEvent#getSession as it means the editsession is being handled somewhere else.
if (editSessionOpt.isPresent() && event.getSession() == null) {
EditSession editSession = editSessionOpt.get();
editSession.flushQueue();
editSession.close();
session.remember(editSession);
long time = System.currentTimeMillis() - start;

View File

@ -26,9 +26,10 @@ import com.fastasyncworldedit.core.extent.clipboard.MemoryOptimizedClipboard;
import com.fastasyncworldedit.core.extent.clipboard.ReadOnlyClipboard;
import com.fastasyncworldedit.core.function.visitor.Order;
import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.util.EditSessionBuilder;
import com.fastasyncworldedit.core.util.MaskTraverser;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EditSessionBuilder;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
@ -75,8 +76,12 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable, Fl
region.getWorld(),
"World cannot be null (use the other constructor for the region)"
);
EditSession session = new EditSessionBuilder(region.getWorld()).allowedRegionsEverywhere()
.autoQueue(false).build();
EditSession session = WorldEdit
.getInstance()
.newEditSessionBuilder()
.world(region.getWorld())
.allowedRegionsEverywhere()
.build();
return ReadOnlyClipboard.of(session, region);
}
@ -252,12 +257,17 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable, Fl
if (world instanceof EditSession) {
editSession = (EditSession) world;
} else {
EditSessionBuilder builder = new EditSessionBuilder(world).autoQueue(true)
.checkMemory(false).allowedRegionsEverywhere().limitUnlimited();
EditSessionBuilder builder = WorldEdit
.getInstance()
.newEditSessionBuilder()
.world(world)
.checkMemory(false)
.allowedRegionsEverywhere()
.limitUnlimited();
if (allowUndo) {
editSession = builder.build();
} else {
editSession = builder.changeSetNull().fastmode(true).build();
editSession = builder.changeSetNull().fastMode(true).build();
}
}
Extent extent = this;
@ -297,8 +307,14 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable, Fl
@Nullable Transform transform
) {
if (extent instanceof World) {
EditSessionBuilder builder = new EditSessionBuilder((World) extent).autoQueue(true)
.checkMemory(false).allowedRegionsEverywhere().limitUnlimited().changeSetNull();
EditSessionBuilder builder = WorldEdit
.getInstance()
.newEditSessionBuilder()
.world((World) extent)
.checkMemory(false)
.allowedRegionsEverywhere()
.limitUnlimited()
.changeSetNull();
extent = builder.build();
}
@ -334,8 +350,14 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable, Fl
default void paste(Extent extent, BlockVector3 to, boolean pasteAir, boolean pasteEntities, boolean pasteBiomes) {
if (extent instanceof World) {
EditSessionBuilder builder = new EditSessionBuilder((World) extent).autoQueue(true)
.checkMemory(false).allowedRegionsEverywhere().limitUnlimited().changeSetNull();
EditSessionBuilder builder = WorldEdit
.getInstance()
.newEditSessionBuilder()
.world((World) extent)
.checkMemory(false)
.allowedRegionsEverywhere()
.limitUnlimited()
.changeSetNull();
extent = builder.build();
}

View File

@ -121,8 +121,8 @@ public enum BuiltInClipboardFormat implements ClipboardFormat {
/**
* @deprecated Slow, resource intensive, but sometimes safer than using the recommended
* {@link BuiltInClipboardFormat#FAST}.
* Avoid using with any large schematics/clipboards for reading/writing.
* {@link BuiltInClipboardFormat#FAST}.
* Avoid using with any large schematics/clipboards for reading/writing.
*/
@Deprecated
SPONGE_SCHEMATIC("slow", "safe") {

View File

@ -70,8 +70,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
* Reads schematic files using the Sponge Schematic Specification.
*
* @deprecated Slow, resource intensive, but sometimes safer than using the recommended
* {@link com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader}.
* Avoid reading large schematics with this reader.
* {@link com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReader}.
* Avoid reading large schematics with this reader.
*/
@Deprecated
public class SpongeSchematicReader extends NBTSchematicReader {

View File

@ -55,8 +55,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
* Writes schematic files using the Sponge schematic format.
*
* @deprecated Slow, resource intensive, but sometimes safer than using the recommended
* {@link com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter}.
* Avoid using large clipboards to create schematics with this writer.
* {@link com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicWriter}.
* Avoid using large clipboards to create schematics with this writer.
*/
@Deprecated
public class SpongeSchematicWriter implements ClipboardWriter {

View File

@ -68,10 +68,11 @@ public class CraftScriptContext extends CraftScriptEnvironment {
* @return an edit session
*/
public EditSession remember() {
EditSession editSession = controller.getEditSessionFactory()
.getEditSession(player.getWorld(),
session.getBlockChangeLimit(), session.getBlockBag(player), player
);
EditSession editSession = controller.newEditSessionBuilder()
.locatableActor(player)
.maxBlocks(session.getBlockChangeLimit())
.blockBag(session.getBlockBag(player))
.build();
Request.request().setEditSession(editSession);
editSession.enableStandardMode();
editSessions.add(editSession);