mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-04 03:56:41 +00:00
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:
@ -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")
|
||||
|
Reference in New Issue
Block a user