mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-07-05 16:40:04 +00:00
85f5006a0b
- Add regionExtent process to the queue (fixes #2227) - Correctly wrap extents in each other
755 lines
28 KiB
Java
755 lines
28 KiB
Java
/*
|
|
* 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.DisallowedBlocksExtent;
|
|
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.limit.FaweLimit;
|
|
import com.fastasyncworldedit.core.limit.PropertyRemap;
|
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
|
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.HashSet;
|
|
import java.util.Locale;
|
|
import java.util.Set;
|
|
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 Region[] disallowedRegions;
|
|
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.settings().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 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 disallowedRegions(@Nullable Region[] disallowedRegions) {
|
|
this.disallowedRegions = disallowedRegions;
|
|
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 disallowedRegions(@Nullable RegionWrapper[] disallowedRegions) {
|
|
this.disallowedRegions = disallowedRegions;
|
|
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 disallowedRegions(@Nullable RegionWrapper disallowedRegion) {
|
|
this.disallowedRegions = disallowedRegion == null ? null : disallowedRegion.toArray();
|
|
return setDirty();
|
|
}
|
|
|
|
/**
|
|
* Set the edit to be allowed to edit everywhere
|
|
*/
|
|
public EditSessionBuilder allowedRegionsEverywhere() {
|
|
return allowedRegions(new Region[]{RegionWrapper.GLOBAL()});
|
|
}
|
|
|
|
/**
|
|
* 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.settings().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.settings().QUEUE.PARALLEL_THREADS > 1 && !Fawe.isMainThread()) {
|
|
ParallelQueueExtent parallel = new ParallelQueueExtent(Fawe.instance().getQueueHandler(), world, fastMode);
|
|
queue = parallel.getExtent();
|
|
extent = parallel;
|
|
} else {
|
|
extent = queue = Fawe.instance().getQueueHandler().getQueue(world);
|
|
}
|
|
} else {
|
|
wnaMode = true;
|
|
extent = world;
|
|
}
|
|
if (combineStages == null) {
|
|
combineStages =
|
|
// If it's enabled in the settings
|
|
Settings.settings().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.settings().HISTORY.USE_DISK) {
|
|
UUID uuid = actor == null ? Identifiable.CONSOLE : actor.getUniqueId();
|
|
if (Settings.settings().HISTORY.USE_DATABASE) {
|
|
changeSet = new RollbackOptimizedHistory(world, uuid);
|
|
} else {
|
|
changeSet = new DiskStorageHistory(world, uuid);
|
|
}
|
|
// } else if (combineStages && Settings.settings().HISTORY.COMPRESSION_LEVEL == 0) {
|
|
// changeSet = new CPUOptimizedChangeSet(world);
|
|
} else {
|
|
if (combineStages && Settings.settings().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 (this.blockBag != null) {
|
|
// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1);
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
if (allowedRegions == null && Settings.settings().REGION_RESTRICTIONS) {
|
|
if (actor != null && !actor.hasPermission("fawe.bypass.regions")) {
|
|
if (actor instanceof Player player) {
|
|
allowedRegions = player.getAllowedRegions();
|
|
}
|
|
}
|
|
}
|
|
if (disallowedRegions == null && Settings.settings().REGION_RESTRICTIONS && Settings.settings().REGION_RESTRICTIONS_OPTIONS.ALLOW_BLACKLISTS) {
|
|
if (actor != null && !actor.hasPermission("fawe.bypass.regions")) {
|
|
if (actor instanceof Player player) {
|
|
disallowedRegions = player.getDisallowedRegions();
|
|
}
|
|
}
|
|
}
|
|
FaweRegionExtent regionExtent = null;
|
|
if (disallowedRegions != null) { // Always use MultiRegionExtent if we have blacklist regions
|
|
regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions, disallowedRegions);
|
|
} else if (allowedRegions == null) {
|
|
allowedRegions = new Region[]{RegionWrapper.GLOBAL()};
|
|
} else {
|
|
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, null);
|
|
}
|
|
}
|
|
}
|
|
if (placeChunks && regionExtent != null) {
|
|
queue.addProcessor(regionExtent);
|
|
}
|
|
// There's no need to do the below (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.settings().LIGHTING.MODE > 0))) {
|
|
relighter = WorldEdit.getInstance().getPlatformManager()
|
|
.queryCapability(Capability.WORLD_EDITING)
|
|
.getRelighterFactory().createRelighter(relightMode, world, queue);
|
|
queue.addProcessor(new RelightProcessor(relighter));
|
|
}
|
|
queue.addProcessor(new HeightmapProcessor(world.getMinY(), world.getMaxY()));
|
|
IBatchProcessor platformProcessor = WorldEdit
|
|
.getInstance()
|
|
.getPlatformManager()
|
|
.queryCapability(Capability.WORLD_EDITING)
|
|
.getPlatformProcessor(fastMode);
|
|
if (platformProcessor != null) {
|
|
queue.addProcessor(platformProcessor);
|
|
}
|
|
IBatchProcessor platformPostProcessor = WorldEdit
|
|
.getInstance()
|
|
.getPlatformManager()
|
|
.queryCapability(Capability.WORLD_EDITING)
|
|
.getPlatformPostProcessor(fastMode);
|
|
if (platformPostProcessor != null) {
|
|
queue.addPostProcessor(platformPostProcessor);
|
|
}
|
|
} 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()) {
|
|
this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT);
|
|
if (placeChunks) {
|
|
queue.addProcessor((IBatchProcessor) this.extent);
|
|
}
|
|
}
|
|
if (this.limit != null && !this.limit.isUnlimited()) {
|
|
Set<String> limitBlocks = new HashSet<>();
|
|
if ((getActor() == null || getActor().hasPermission("worldedit.anyblock")) && this.limit.UNIVERSAL_DISALLOWED_BLOCKS) {
|
|
limitBlocks.addAll(WorldEdit.getInstance().getConfiguration().disallowedBlocks);
|
|
}
|
|
if (this.limit.DISALLOWED_BLOCKS != null && !this.limit.DISALLOWED_BLOCKS.isEmpty()) {
|
|
limitBlocks.addAll(this.limit.DISALLOWED_BLOCKS);
|
|
}
|
|
Set<PropertyRemap<?>> remaps = this.limit.REMAP_PROPERTIES;
|
|
if (!limitBlocks.isEmpty() || (remaps != null && !remaps.isEmpty())) {
|
|
this.extent = new DisallowedBlocksExtent(this.extent, limitBlocks, remaps);
|
|
if (placeChunks) {
|
|
queue.addProcessor((IBatchProcessor) this.extent);
|
|
}
|
|
}
|
|
}
|
|
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.settings().EXTENT.ALLOWED_PLUGINS) {
|
|
if (className.contains(allowed.toLowerCase(Locale.ROOT))) {
|
|
this.wrapped = true;
|
|
return toReturn;
|
|
}
|
|
}
|
|
if (Settings.settings().EXTENT.DEBUG) {
|
|
if (event.getActor() != null) {
|
|
event.getActor().printDebug(TextComponent.of("Potentially unsafe extent blocked: " + toReturn
|
|
.getClass()
|
|
.getName()));
|
|
event.getActor().print(TextComponent.of(
|
|
"- For area restrictions and block logging, it is recommended that third party plugins use the FAWE" +
|
|
" API"));
|
|
event.getActor().print(TextComponent.of("- Add the following line to the `allowed-plugins` list in the " +
|
|
"FAWE config.yml to let FAWE recognize the extent:"));
|
|
event.getActor().print(toReturn.getClass().getName());
|
|
} else {
|
|
LOGGER.warn("Potentially unsafe extent blocked: {}", toReturn.getClass().getName());
|
|
LOGGER.warn(
|
|
" - For area restrictions and block logging, it is recommended that third party plugins use the FAWE API");
|
|
LOGGER.warn(
|
|
" - Add the following classpath to the `allowed-plugins` list in the FAWE config.yml to let FAWE " +
|
|
"recognize the extent:");
|
|
LOGGER.warn(toReturn.getClass().getName());
|
|
}
|
|
}
|
|
}
|
|
return extent;
|
|
}
|
|
|
|
}
|