Major command changes that don't work yet.

This commit is contained in:
MattBDev
2019-07-05 20:46:48 -04:00
parent ffc2092d93
commit 8108d0a936
399 changed files with 13558 additions and 7985 deletions

View File

@@ -19,6 +19,12 @@
package com.sk89q.worldedit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC;
@@ -26,7 +32,6 @@ import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.MappedFaweQueue;
import com.boydti.fawe.jnbt.anvil.MCAQueue;
import com.boydti.fawe.jnbt.anvil.MCAWorld;
import com.boydti.fawe.logging.LoggingChangeSet;
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.FawePlayer;
@@ -44,7 +49,17 @@ import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.extent.*;
import com.boydti.fawe.object.extent.FastWorldEditExtent;
import com.boydti.fawe.object.extent.FaweRegionExtent;
import com.boydti.fawe.object.extent.HeightBoundExtent;
import com.boydti.fawe.object.extent.MultiRegionExtent;
import com.boydti.fawe.object.extent.NullExtent;
import com.boydti.fawe.object.extent.ProcessedWEExtent;
import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.object.extent.SingleRegionExtent;
import com.boydti.fawe.object.extent.SlowExtent;
import com.boydti.fawe.object.extent.SourceMaskExtent;
import com.boydti.fawe.object.extent.StripNBTExtent;
import com.boydti.fawe.object.function.SurfaceRegionFunction;
import com.boydti.fawe.object.mask.ResettableMask;
import com.boydti.fawe.object.pattern.ExistingPattern;
@@ -58,9 +73,6 @@ import com.boydti.fawe.util.Perm;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.WorldWrapper;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Supplier;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.blocks.BaseItemStack;
@@ -81,7 +93,16 @@ import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.block.Naturalizer;
import com.sk89q.worldedit.function.generator.ForestGenerator;
import com.sk89q.worldedit.function.generator.GardenPatchGenerator;
import com.sk89q.worldedit.function.mask.*;
import com.sk89q.worldedit.function.mask.BlockMaskBuilder;
import com.sk89q.worldedit.function.mask.BlockTypeMask;
import com.sk89q.worldedit.function.mask.BoundedHeightMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.mask.MaskUnion;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.NoiseFilter2D;
import com.sk89q.worldedit.function.mask.RegionMask;
import com.sk89q.worldedit.function.operation.ChangeSetExecutor;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operation;
@@ -122,15 +143,13 @@ import com.sk89q.worldedit.regions.EllipsoidRegion;
import com.sk89q.worldedit.regions.FlatRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.Regions;
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
import com.sk89q.worldedit.regions.shape.ArbitraryBiomeShape;
import com.sk89q.worldedit.regions.shape.ArbitraryShape;
import com.sk89q.worldedit.regions.shape.RegionShape;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.SimpleWorld;
@@ -144,11 +163,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.weather.WeatherType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -156,6 +171,11 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An {@link Extent} that handles history, {@link BlockBag}s, change limits,
@@ -229,20 +249,17 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
public static final UUID CONSOLE = UUID.fromString("1-1-3-3-7");
@Deprecated
public EditSession(@Nonnull World world, @Nullable FaweQueue queue, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) {
public EditSession(@Nonnull World world, @Nullable FaweQueue queue, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable RegionWrapper[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @NotNull EventBus bus, @Nullable EditSessionEvent event) {
this(null, world, queue, player, limit, changeSet, allowedRegions, autoQueue, fastmode, checkMemory, combineStages, blockBag, bus, event);
}
public EditSession(@Nullable String worldName, @Nullable World world, @Nullable FaweQueue queue, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable Region[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @Nullable EventBus bus, @Nullable EditSessionEvent event) {
public EditSession(@Nullable String worldName, @Nullable World world, @Nullable FaweQueue queue, @Nullable FawePlayer player, @Nullable FaweLimit limit, @Nullable FaweChangeSet changeSet, @Nullable Region[] allowedRegions, @Nullable Boolean autoQueue, @Nullable Boolean fastmode, @Nullable Boolean checkMemory, @Nullable Boolean combineStages, @Nullable BlockBag blockBag, @NotNull EventBus bus, @Nullable EditSessionEvent event) {
super(world);
this.worldName = worldName == null ? world == null ? queue == null ? "" : queue.getWorldName() : world.getName() : worldName;
if (world == null && this.worldName != null) world = FaweAPI.getWorld(this.worldName);
this.world = world;
if (bus == null) {
bus = WorldEdit.getInstance().getEventBus();
}
if (event == null) {
event = new EditSessionEvent(world, player == null ? null : (player.getPlayer()), -1, null);
}
@@ -344,13 +361,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
if (this.limit.SPEED_REDUCTION > 0) {
this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION);
}
if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) {
changeSet = LoggingChangeSet.wrap(player, changeSet);
}
if (!(changeSet instanceof NullChangeSet)) {
if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) {
changeSet = LoggingChangeSet.wrap(player, changeSet);
}
if (this.blockBag != null) {
changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1);
}
@@ -416,7 +427,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
public void resetLimit() {
this.limit.set(this.originalLimit);
ExtentTraverser<ProcessedWEExtent> find = new ExtentTraverser(extent).find(ProcessedWEExtent.class);
ExtentTraverser<ProcessedWEExtent> find = new ExtentTraverser<>(extent).find(ProcessedWEExtent.class);
if (find != null && find.get() != null) {
find.get().setLimit(this.limit);
}
@@ -455,7 +466,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @return FaweRegionExtent (may be null)
*/
public FaweRegionExtent getRegionExtent() {
ExtentTraverser<FaweRegionExtent> traverser = new ExtentTraverser(this.extent).find(FaweRegionExtent.class);
ExtentTraverser<FaweRegionExtent> traverser = new ExtentTraverser<>(this.extent).find(FaweRegionExtent.class);
return traverser == null ? null : traverser.get();
}
@@ -467,6 +478,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return bypassHistory;
}
@Override
public Extent getExtent() {
return extent;
}
@@ -532,27 +544,17 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
}
/**
* Send a debug message to the Actor responsible for this EditSession (or Console)
*
* @param message
* @param args
*/
public void debug(BBC message, Object... args) {
message.send(player, args);
}
/**
* Get the FaweQueue this EditSession uses to queue the changes<br>
* - Note: All implementation queues for FAWE are instances of NMSMappedFaweQueue
*
* @return
*/
@Override
public FaweQueue getQueue() {
return queue;
}
@Deprecated
private AbstractDelegateExtent wrapExtent(Extent extent, EventBus eventBus, EditSessionEvent event, Stage stage) {
event = event.clone(stage);
event.setExtent(extent);
@@ -739,7 +741,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @return mask, may be null
*/
public Mask getMask() {
ExtentTraverser<MaskingExtent> maskingExtent = new ExtentTraverser(this.extent).find(MaskingExtent.class);
ExtentTraverser<MaskingExtent> maskingExtent = new ExtentTraverser<>(this.extent).find(MaskingExtent.class);
return maskingExtent != null ? maskingExtent.get().getMask() : null;
}
@@ -749,18 +751,18 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @return mask, may be null
*/
public Mask getSourceMask() {
ExtentTraverser<SourceMaskExtent> maskingExtent = new ExtentTraverser(this.extent).find(SourceMaskExtent.class);
ExtentTraverser<SourceMaskExtent> maskingExtent = new ExtentTraverser<>(this.extent).find(SourceMaskExtent.class);
return maskingExtent != null ? maskingExtent.get().getMask() : null;
}
public void addTransform(ResettableExtent transform) {
wrapped = true;
if (transform == null) {
ExtentTraverser<AbstractDelegateExtent> traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class);
ExtentTraverser traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class);
AbstractDelegateExtent next = extent;
while (traverser != null && traverser.get() instanceof ResettableExtent) {
traverser = traverser.next();
next = traverser.get();
next = (AbstractDelegateExtent) traverser.get();
}
this.extent = next;
return;
@@ -770,7 +772,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
public @Nullable ResettableExtent getTransform() {
ExtentTraverser<AbstractDelegateExtent> traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class);
ExtentTraverser traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class);
if (traverser != null) {
return (ResettableExtent) traverser.get();
}
@@ -788,7 +790,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
} else {
new MaskTraverser(mask).reset(this);
}
ExtentTraverser<SourceMaskExtent> maskingExtent = new ExtentTraverser(this.extent).find(SourceMaskExtent.class);
ExtentTraverser<SourceMaskExtent> maskingExtent = new ExtentTraverser<>(this.extent).find(SourceMaskExtent.class);
if (maskingExtent != null && maskingExtent.get() != null) {
Mask oldMask = maskingExtent.get().getMask();
if (oldMask instanceof ResettableMask) {
@@ -845,7 +847,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @return the survival simulation extent
*/
public SurvivalModeExtent getSurvivalExtent() {
ExtentTraverser<SurvivalModeExtent> survivalExtent = new ExtentTraverser(this.extent).find(SurvivalModeExtent.class);
ExtentTraverser<SurvivalModeExtent> survivalExtent = new ExtentTraverser<>(this.extent).find(SurvivalModeExtent.class);
if (survivalExtent != null) {
return survivalExtent.get();
} else {
@@ -878,7 +880,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
if (history == null) {
return;
}
ExtentTraverser traverseHistory = new ExtentTraverser(this.extent).find(HistoryExtent.class);
ExtentTraverser<HistoryExtent> traverseHistory = new ExtentTraverser<>(this.extent).find(HistoryExtent.class);
if (disableHistory) {
if (traverseHistory != null && traverseHistory.exists()) {
ExtentTraverser beforeHistory = traverseHistory.previous();
@@ -890,7 +892,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
}
} else if (traverseHistory == null || !traverseHistory.exists()) {
ExtentTraverser traverseBypass = new ExtentTraverser(this.extent).find(bypassHistory);
ExtentTraverser traverseBypass = new ExtentTraverser<>(this.extent).find(bypassHistory);
if (traverseBypass != null) {
ExtentTraverser beforeHistory = traverseBypass.previous();
beforeHistory.setNext(history);
@@ -939,19 +941,19 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
*
* @return a map of missing blocks
*/
public Map<com.sk89q.worldedit.world.block.BlockType, Integer> popMissingBlocks() {
public Map<BlockType, Integer> popMissingBlocks() {
BlockBag bag = getBlockBag();
if (bag != null) {
bag.flushChanges();
Map<com.sk89q.worldedit.world.block.BlockType, Integer> missingBlocks;
Map<BlockType, Integer> missingBlocks;
ChangeSet changeSet = getChangeSet();
if (changeSet instanceof BlockBagChangeSet) {
missingBlocks = ((BlockBagChangeSet) changeSet).popMissing();
} else {
ExtentTraverser<BlockBagExtent> find = new ExtentTraverser(extent).find(BlockBagExtent.class);
ExtentTraverser<BlockBagExtent> find = new ExtentTraverser<>(extent).find(BlockBagExtent.class);
if (find != null && find.get() != null) {
missingBlocks = find.get().popMissing();
} else {
@@ -1065,6 +1067,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ());
}
@Override
public BlockState getLazyBlock(int x, int y, int z) {
return extent.getLazyBlock(x, y, z);
}
@@ -1083,18 +1086,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return extent.getFullBlock(position);
}
/**
* Get a block type at the given position.
*
* @param position the position
* @return the block type
* @deprecated Use {@link #getLazyBlock(BlockVector3)} or {@link #getBlock(BlockVector3)}
*/
@Deprecated
public BlockType getBlockType(final BlockVector3 position) {
return getBlockType(position.getBlockX(), position.getBlockY(), position.getBlockZ());
}
/**
* Returns the highest solid 'terrain' block.
*
@@ -1104,6 +1095,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @param maxY maximal height
* @return height of highest block found or 'minY'
*/
@Override
public int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
for (int y = maxY; y >= minY; --y) {
if (getBlock(x, y, z).getBlockType().getMaterial().isMovementBlocker()) {
@@ -1123,6 +1115,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @param filter a mask of blocks to consider, or null to consider any solid (movement-blocking) block
* @return height of highest block found or 'minY'
*/
@Override
public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
for (int y = maxY; y >= minY; --y) {
if (filter.test(mutablebv.setComponents(x, y, z))) {
@@ -1209,6 +1202,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(int x, int y, int z, B block) {
this.changes++;
try {
@@ -1301,7 +1295,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
@Override
@Nullable
public Entity createEntity(com.sk89q.worldedit.util.Location location, final BaseEntity entity) {
public Entity createEntity(Location location, final BaseEntity entity) {
return this.extent.createEntity(location, entity);
}
@@ -1472,12 +1466,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
if (searchIDs.size() == 1) {
final BlockType id = searchIDs.iterator().next();
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(BlockVector3 position) throws WorldEditException {
return getBlockType(position) == id;
}
}, this);
RegionVisitor visitor = new RegionVisitor(region, position -> getBlock(position).getBlockType() == id, this);
Operations.completeBlindly(visitor);
return visitor.getAffected();
}
@@ -1489,23 +1478,14 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
public int countBlock(final Region region, final boolean[] ids) {
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(BlockVector3 position) throws WorldEditException {
return ids[getBlockType(position).getInternalId()];
}
}, this);
RegionVisitor visitor = new RegionVisitor(region,
position -> ids[getBlock(position).getInternalId()], this);
Operations.completeBlindly(visitor);
return visitor.getAffected();
}
public int countBlock(final Region region, final Mask mask) {
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(BlockVector3 position) throws WorldEditException {
return mask.test(position);
}
}, this);
RegionVisitor visitor = new RegionVisitor(region, mask::test, this);
Operations.completeBlindly(visitor);
return visitor.getAffected();
}
@@ -1519,12 +1499,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
*/
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
Mask mask = new BlockMaskBuilder().addBlocks(searchBlocks).build(extent);
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(BlockVector3 position) throws WorldEditException {
return mask.test(position);
}
}, this);
RegionVisitor visitor = new RegionVisitor(region, mask::test, this);
Operations.completeBlindly(visitor);
return visitor.getAffected();
}
@@ -1534,30 +1509,27 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
final int startPerformY = region.getMinimumPoint().getBlockY();
final int startCheckY = fullHeight ? 0 : startPerformY;
final int endY = region.getMaximumPoint().getBlockY();
RegionVisitor visitor = new RegionVisitor(flat, new RegionFunction() {
@Override
public boolean apply(BlockVector3 pos) throws WorldEditException {
int x = pos.getBlockX();
int z = pos.getBlockZ();
int freeSpot = startCheckY;
for (int y = startCheckY; y <= endY; y++) {
if (y < startPerformY) {
if (!getBlockType(x, y, z).getMaterial().isAir()) {
freeSpot = y + 1;
}
continue;
}
BlockType block = getBlockType(x, y, z);
if (!block.getMaterial().isAir()) {
if (freeSpot != y) {
setBlock(x, freeSpot, z, block);
setBlock(x, y, z, replace);
}
freeSpot++;
RegionVisitor visitor = new RegionVisitor(flat, pos -> {
int x = pos.getBlockX();
int z = pos.getBlockZ();
int freeSpot = startCheckY;
for (int y = startCheckY; y <= endY; y++) {
if (y < startPerformY) {
if (!getBlockType(x, y, z).getMaterial().isAir()) {
freeSpot = y + 1;
}
continue;
}
BlockType block = getBlockType(x, y, z);
if (!block.getMaterial().isAir()) {
if (freeSpot != y) {
setBlock(x, freeSpot, z, block);
setBlock(x, y, z, replace);
}
freeSpot++;
}
return true;
}
return true;
}, this);
Operations.completeBlindly(visitor);
return this.changes;
@@ -1574,7 +1546,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int fillDirection(final BlockVector3 origin, final Pattern pattern, final double radius, final int depth, BlockVector3 direction) {
public int fillDirection(final BlockVector3 origin, final Pattern pattern, final double radius, final int depth, BlockVector3 direction) throws MaxChangedBlocksException {
checkNotNull(origin);
checkNotNull(pattern);
checkArgument(radius >= 0, "radius >= 0");
@@ -1727,12 +1699,11 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
FaweRegionExtent regionExtent = getRegionExtent();
if (!(region instanceof CuboidRegion)) return false;
if (regionExtent != null) {
if (!(region instanceof CuboidRegion)) return false;
BlockVector3 pos1 = region.getMinimumPoint();
BlockVector3 pos2 = region.getMaximumPoint();
boolean contains = false;
for (Region current : regionExtent.getRegions()) {
if (current.contains((int) pos1.getX(), pos1.getBlockY(), pos1.getBlockZ()) && current.contains(pos2.getBlockX(), pos2.getBlockY(), pos2.getBlockZ())) {
if (current.contains(pos1.getX(), pos1.getBlockY(), pos1.getBlockZ()) && current.contains(pos2.getBlockX(), pos2.getBlockY(), pos2.getBlockZ())) {
contains = true;
break;
}
@@ -1745,8 +1716,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return false;
if (getChangeTask() != getChangeSet()) return false;
if (!Masks.isNull(getMask()) || !Masks.isNull(getSourceMask())) return false;
if (getBlockBag() != null) return false;
return true;
return getBlockBag() == null;
}
public boolean hasExtraExtents() {
@@ -1772,7 +1742,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
getWorld(), // Causes clamping of Y range
position.add(adjustment.multiply(-1)),
position.add(adjustment));
Pattern pattern = (BlockTypes.AIR.getDefaultState());
Pattern pattern = BlockTypes.AIR.getDefaultState();
return replaceBlocks(region, mask, pattern);
}
@@ -1787,7 +1757,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
public <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
checkNotNull(region);
checkNotNull(block);
boolean hasNbt = block instanceof BaseBlock && ((BaseBlock)block).hasNbtData();
boolean hasNbt = block instanceof BaseBlock && block.hasNbtData();
if (canBypassAll(region, false, true) && !hasNbt) {
return changes = queue.setBlocks((CuboidRegion) region, block.getInternalId());
@@ -1845,7 +1815,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException {
return replaceBlocks(region, filter, (replacement));
return replaceBlocks(region, filter, replacement);
}
/**
@@ -1917,7 +1887,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public <B extends BlockStateHolder<B>> int makeCuboidFaces(Region region, B block) throws MaxChangedBlocksException {
return makeCuboidFaces(region, (block));
return makeCuboidFaces(region, block);
}
/**
@@ -1969,7 +1939,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public <B extends BlockStateHolder<B>> int makeCuboidWalls(Region region, B block) throws MaxChangedBlocksException {
return makeCuboidWalls(region, (block));
return makeCuboidWalls(region, block);
}
/**
@@ -2094,7 +2064,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
BlockVector3 to = region.getMinimumPoint();
ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to);
copy.setCopyingEntities(copyEntities);
copy.setCopyBiomes(copyBiomes);
copy.setCopyingBiomes(copyBiomes);
copy.setRepetitions(count);
copy.setTransform(new AffineTransform().translate(dir.multiply(size)));
Mask sourceMask = getSourceMask();
@@ -2140,8 +2110,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
ForwardExtentCopy copy = new ForwardExtentCopy(this, region, this, to);
if (replacement == null) replacement = BlockTypes.AIR.getDefaultState();
final BlockReplace remove = replacement instanceof ExistingPattern ? null : new BlockReplace(this, replacement);
copy.setCopyBiomes(copyBiomes);
BlockReplace remove = replacement instanceof ExistingPattern ? null : new BlockReplace(this, replacement);
copy.setCopyingBiomes(copyBiomes);
copy.setCopyingEntities(copyEntities);
copy.setSourceFunction(remove); // Remove
copy.setRemovingEntities(true);
@@ -2170,7 +2140,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @return number of blocks moved
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int moveCuboidRegion(Region region, BlockVector3 dir, int distance, boolean copyAir, Pattern replacement) {
public int moveCuboidRegion(Region region, BlockVector3 dir, int distance, boolean copyAir, Pattern replacement) throws MaxChangedBlocksException {
return moveRegion(region, dir, distance, copyAir, true, false, replacement);
}
@@ -2214,7 +2184,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
if (waterlogged) {
replace = new BlockReplace(this, new WaterloggedRemover(this));
} else {
replace = new BlockReplace(this, (BlockTypes.AIR.getDefaultState()));
replace = new BlockReplace(this, BlockTypes.AIR.getDefaultState());
}
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this);
@@ -2256,7 +2226,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
blockMask
);
BlockReplace replace = new BlockReplace(this, (fluid.getDefaultState()));
BlockReplace replace = new BlockReplace(this, fluid.getDefaultState());
NonRisingVisitor visitor = new NonRisingVisitor(mask, replace);
// Around the origin in a 3x3 block
@@ -2298,15 +2268,15 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @return number of blocks changed
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int makeCylinder(BlockVector3 pos, Pattern block, double radiusX, double radiusZ, int height, boolean filled) throws MaxChangedBlocksException{
public int makeCylinder(BlockVector3 pos, Pattern block, double radiusX, double radiusZ, int height, boolean filled) throws MaxChangedBlocksException {
return makeCylinder(pos, block, radiusX, radiusZ, height, 0, filled);
}
public int makeHollowCylinder(BlockVector3 pos, final Pattern block, double radiusX, double radiusZ, int height, double thickness) {
public int makeHollowCylinder(BlockVector3 pos, final Pattern block, double radiusX, double radiusZ, int height, double thickness) throws MaxChangedBlocksException {
return makeCylinder(pos, block, radiusX, radiusZ, height, thickness, false);
}
private int makeCylinder(BlockVector3 pos, final Pattern block, double radiusX, double radiusZ, int height, double thickness, final boolean filled) {
private int makeCylinder(BlockVector3 pos, Pattern block, double radiusX, double radiusZ, int height, double thickness, boolean filled) throws MaxChangedBlocksException {
int affected = 0;
radiusX += 0.5;
@@ -2322,12 +2292,12 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
if (posv.getBlockY() < 0) {
posv.mutY(0);
} else if (((posv.getBlockY() + height) - 1) > maxY) {
height = (maxY - posv.getBlockY()) + 1;
} else if (posv.getBlockY() + height - 1 > maxY) {
height = maxY - posv.getBlockY() + 1;
}
final double invRadiusX = 1 / (radiusX);
final double invRadiusZ = 1 / (radiusZ);
final double invRadiusX = 1 / radiusX;
final double invRadiusZ = 1 / radiusZ;
int px = posv.getBlockX();
int py = posv.getBlockY();
@@ -2336,7 +2306,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
final int ceilRadiusX = (int) Math.ceil(radiusX);
final int ceilRadiusZ = (int) Math.ceil(radiusZ);
double dx, dxz, dz;
double distanceSq;
double nextXn = 0;
if (thickness != 0) {
@@ -2350,15 +2320,13 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
nextMinXn = (x + 1) * minInvRadiusX;
double nextZn = 0;
double nextMinZn = 0;
dx = xn * xn;
forZ: for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
double dz2 = nextMinZn * nextMinZn;
nextZn = (z + 1) * invRadiusZ;
nextMinZn = (z + 1) * minInvRadiusZ;
dz = zn * zn;
dxz = dx + dz;
if (dxz > 1) {
distanceSq = lengthSq(xn, zn);
if (distanceSq > 1) {
if (z == 0) {
break forX;
}
@@ -2381,14 +2349,14 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
forX: for (int x = 0; x <= ceilRadiusX; ++x) {
final double xn = nextXn;
nextXn = (x + 1) * invRadiusX;
double dx = xn * xn;
double nextZn = 0;
dx = xn * xn;
forZ: for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
nextZn = (z + 1) * invRadiusZ;
dz = zn * zn;
dxz = dx + dz;
if (dxz > 1) {
double dz = zn * zn;
distanceSq = lengthSq(xn,zn);
if (distanceSq > 1) {
if (z == 0) {
break forX;
}
@@ -2414,7 +2382,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return this.changes;
}
public int makeCircle(BlockVector3 pos, final Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled, Vector3 normal) {
public int makeCircle(BlockVector3 pos, final Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled, Vector3 normal) throws MaxChangedBlocksException {
radiusX += 0.5;
radiusY += 0.5;
radiusZ += 0.5;
@@ -2549,20 +2517,18 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
double nextXn = invRadiusX;
forX: for (int x = 0; x <= ceilRadiusX; ++x) {
final double xn = nextXn;
double dx = xn * xn;
nextXn = (x + 1) * invRadiusX;
double nextZn = invRadiusZ;
double dx = xn * xn;
forZ: for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
double dz = zn * zn;
double dxz = dx + dz;
nextZn = (z + 1) * invRadiusZ;
double nextYn = invRadiusY;
forY: for (int y = 0; y <= ceilRadiusY; ++y) {
final double yn = nextYn;
double dy = yn * yn;
double dxyz = dxz + dy;
double dxyz = lengthSq(zn, yn, zn);
nextYn = (y + 1) * invRadiusY;
if (dxyz > 1) {
@@ -2576,7 +2542,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
if (!filled) {
if (nextXn * nextXn + dy + dz <= 1 && nextYn * nextYn + dx + dz <= 1 && nextZn * nextZn + dx + dy <= 1) {
double dy = yn * yn;
if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) {
continue;
}
}
@@ -2763,11 +2730,13 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int green(BlockVector3 position, double radius, final boolean onlyNormalDirt)
public int green(BlockVector3 position, double radius, boolean onlyNormalDirt)
throws MaxChangedBlocksException {
int affected = 0;
final double radiusSq = radius * radius;
final int ox = position.getBlockX();
final int oy = position.getBlockY();
final int oz = position.getBlockZ();
final BlockState grass = BlockTypes.GRASS_BLOCK.getDefaultState();
@@ -2776,27 +2745,25 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
for (int x = ox - ceilRadius; x <= ox + ceilRadius; ++x) {
int dx = x - ox;
int dx2 = dx * dx;
for (int z = oz - ceilRadius; z <= (oz + ceilRadius); ++z) {
for (int z = oz - ceilRadius; z <= oz + ceilRadius; ++z) {
int dz = z - oz;
int dz2 = dz * dz;
if (dx2 + dz2 > radiusSq) {
continue;
}
loop:
for (int y = maxY; y >= 1; --y) {
BlockType block = getBlockType(x, y, z);
switch (block.getInternalId()) {
case BlockID.COARSE_DIRT:
if (onlyNormalDirt) break loop;
case BlockID.DIRT:
this.setBlock(x, y, z, BlockTypes.GRASS_BLOCK.getDefaultState());
break loop;
case BlockID.WATER:
case BlockID.LAVA:
default:
if (block.getMaterial().isMovementBlocker()) {
break loop;
}
final BlockState block = getBlock(x, y, z);
if (block.getBlockType() == BlockTypes.DIRT ||
(!onlyNormalDirt && block.getBlockType() == BlockTypes.COARSE_DIRT)) {
this.setBlock(x, y, z, grass);
break;
} else if (block.getBlockType() == BlockTypes.WATER || block.getBlockType() == BlockTypes.LAVA) {
break;
} else if (block.getBlockType().getMaterial().isMovementBlocker()) {
break;
}
}
}
@@ -2813,11 +2780,11 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @return number of patches created
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int makePumpkinPatches(final BlockVector3 position, final int apothem) {
public int makePumpkinPatches(BlockVector3 position, int apothem) throws MaxChangedBlocksException {
return makePumpkinPatches(position, apothem, 0.02);
}
public int makePumpkinPatches(final BlockVector3 position, final int apothem, double density) {
public int makePumpkinPatches(BlockVector3 position, int apothem, double density) throws MaxChangedBlocksException {
// We want to generate pumpkins
GardenPatchGenerator generator = new GardenPatchGenerator(this);
generator.setPlant(GardenPatchGenerator.getPumpkinPattern());
@@ -2846,7 +2813,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int makeForest(BlockVector3 basePosition, int size, double density, TreeGenerator.TreeType treeType) throws MaxChangedBlocksException {
try {
for (int x = basePosition.getBlockX() - size; x <= (basePosition.getBlockX() + size); ++x) {
for (int z = basePosition.getBlockZ() - size; z <= (basePosition.getBlockZ() + size); ++z) {
// Don't want to be in the ground
@@ -2873,7 +2839,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
}
}
} catch (MaxChangedBlocksException ignore) {}
return this.changes;
}
@@ -2928,7 +2893,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
} else {
for (final BlockVector3 pt : region) {
BlockType type = getBlockType(pt);
BlockType type = getBlock(pt).getBlockType();
counter[type.getInternalId()]++;
}
}
@@ -3100,6 +3065,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
final RValue x = expression.getVariable("x", false).optimize();
final RValue y = expression.getVariable("y", false).optimize();
final RValue z = expression.getVariable("z", false).optimize();
final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero);
expression.setEnvironment(environment);
final Vector3 zero2 = zero.add(0.5, 0.5, 0.5);
@@ -3142,7 +3108,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int hollowOutRegion(Region region, int thickness, Pattern pattern) throws MaxChangedBlocksException {
try {
final Set<BlockVector3> outside = new LocalBlockVectorSet();
final BlockVector3 min = region.getMinimumPoint();
@@ -3201,12 +3166,12 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
}
this.changes++;
try {
pattern.apply(this.extent, position, position);
} catch (WorldEditException e) {
e.printStackTrace();
}
} catch (WorldEditException e) {
throw new RuntimeException(e);
}
return changes;
}
@@ -3276,12 +3241,12 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
}
Set<BlockVector3> newVset;
if (flat) {
newVset = this.getStretched(vset, radius);
newVset = getStretched(vset, radius);
if (!filled) {
newVset = this.getOutline(newVset);
}
} else {
newVset = this.getBallooned(vset, radius);
newVset = getBallooned(vset, radius);
if (!filled) {
newVset = this.getHollowed(newVset);
}
@@ -3324,16 +3289,20 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
interpol.setNodes(nodes);
double splinelength = interpol.arcLength(0, 1);
for (double loop = 0; loop <= 1; loop += 1D / splinelength / quality) {
final BlockVector3 tipv = interpol.getPosition(loop).toBlockPoint();
BlockVector3 tipv = interpol.getPosition(loop).toBlockPoint();
if (radius == 0) {
pattern.apply(this, tipv, tipv);
try {
pattern.apply(this, tipv, tipv);
} catch (WorldEditException e) {
e.printStackTrace();
}
} else {
vset.add(tipv);
}
}
Set<BlockVector3> newVset;
if (radius != 0) {
newVset = this.getBallooned(vset, radius);
newVset = getBallooned(vset, radius);
if (!filled) {
newVset = this.getHollowed(newVset);
}
@@ -3342,7 +3311,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return changes;
}
private Set<BlockVector3> getBallooned(Set<BlockVector3> vset, double radius) {
private static Set<BlockVector3> getBallooned(Set<BlockVector3> vset, double radius) {
if (radius < 1) {
return vset;
}
@@ -3352,9 +3321,9 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
for (BlockVector3 v : vset) {
int tipx = v.getBlockX(), tipy = v.getBlockY(), tipz = v.getBlockZ();
for (int loopx = tipx - ceilrad; loopx <= (tipx + ceilrad); loopx++) {
for (int loopy = tipy - ceilrad; loopy <= (tipy + ceilrad); loopy++) {
for (int loopz = tipz - ceilrad; loopz <= (tipz + ceilrad); loopz++) {
for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) {
for (int loopy = tipy - ceilrad; loopy <= tipy + ceilrad; loopy++) {
for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) {
if (MathMan.hypot(loopx - tipx, loopy - tipy, loopz - tipz) <= radius) {
returnset.add(loopx, loopy, loopz);
}
@@ -3365,7 +3334,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return returnset;
}
public Set<BlockVector3> getStretched(final Set<BlockVector3> vset, final double radius) {
public static Set<BlockVector3> getStretched(Set<BlockVector3> vset, double radius) {
if (radius < 1) {
return vset;
}
@@ -3373,8 +3342,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
final int ceilrad = (int) Math.ceil(radius);
for (final BlockVector3 v : vset) {
final int tipx = v.getBlockX(), tipy = v.getBlockY(), tipz = v.getBlockZ();
for (int loopx = tipx - ceilrad; loopx <= (tipx + ceilrad); loopx++) {
for (int loopz = tipz - ceilrad; loopz <= (tipz + ceilrad); loopz++) {
for (int loopx = tipx - ceilrad; loopx <= tipx + ceilrad; loopx++) {
for (int loopz = tipz - ceilrad; loopz <= tipz + ceilrad; loopz++) {
if (MathMan.hypot(loopx - tipx, 0, loopz - tipz) <= radius) {
returnset.add(loopx, v.getBlockY(), loopz);
}
@@ -3384,7 +3353,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return returnset;
}
public Set<BlockVector3> getOutline(final Set<BlockVector3> vset) {
public Set<BlockVector3> getOutline(Set<BlockVector3> vset) {
final LocalBlockVectorSet returnset = new LocalBlockVectorSet();
final LocalBlockVectorSet newset = new LocalBlockVectorSet();
newset.addAll(vset);
@@ -3400,7 +3369,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return returnset;
}
public Set<BlockVector3> getHollowed(final Set<BlockVector3> vset) {
public Set<BlockVector3> getHollowed(Set<BlockVector3> vset) {
final Set<BlockVector3> returnset = new LocalBlockVectorSet();
final LocalBlockVectorSet newset = new LocalBlockVectorSet();
newset.addAll(vset);
@@ -3421,6 +3390,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
private void recurseHollow(Region region, BlockVector3 origin, Set<BlockVector3> outside) {
final LocalBlockVectorSet queue = new LocalBlockVectorSet();
queue.add(origin);
while (!queue.isEmpty()) {
final BlockVector3 current = queue.getIndex(0);
queue.remove(current);
@@ -3518,6 +3488,10 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return worldName;
}
@Override public @org.jetbrains.annotations.Nullable Path getStoragePath() {
return null;
}
@Override
public int getBlockLightLevel(BlockVector3 position) {
return queue.getEmmittedLight(position.getBlockX(), position.getBlockY(), position.getBlockZ());
@@ -3666,12 +3640,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
return false;
}
// public void dropItem(BlockVector3 position, BaseItemStack item) {
// if (getWorld() != null) {
// getWorld().dropItem(position, item);
// }
// }
@Override
public void simulateBlockMine(BlockVector3 position) {
TaskManager.IMP.sync((Supplier<Object>) () -> {

View File

@@ -20,13 +20,13 @@
package com.sk89q.worldedit;
import com.google.common.collect.Lists;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extent.NullExtent;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.BlockMaskBuilder;
import com.sk89q.worldedit.util.logging.LogFormat;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import com.sk89q.worldedit.world.snapshot.SnapshotRepository;
@@ -59,11 +59,10 @@ public abstract class LocalConfiguration {
public boolean logCommands = false;
public String logFile = "";
public String logFormat = LogFormat.DEFAULT_FORMAT;
public boolean registerHelp = true; // what is the point of this, it's not even used
public boolean registerHelp = true; // unused
public String wandItem = "minecraft:wooden_axe";
public boolean superPickaxeDrop = true;
public boolean superPickaxeManyDrop = true;
public boolean noDoubleSlash = false;
public boolean useInventory = false;
public boolean useInventoryOverride = false;
public boolean useInventoryCreativeOverride = false;
@@ -76,7 +75,7 @@ public abstract class LocalConfiguration {
public Set<String> allowedDataCycleBlocks = new HashSet<>();
public String saveDir = "schematics";
public String scriptsDir = "craftscripts";
public boolean showHelpInfo = true;
public boolean showHelpInfo = true; // unused
public int butcherDefaultRadius = -1;
public int butcherMaxRadius = -1;
public boolean allowSymlinks = false;
@@ -158,7 +157,11 @@ public abstract class LocalConfiguration {
if (disallowedBlocksMask == null) {
BlockMaskBuilder builder = new BlockMaskBuilder();
for (String blockRegex : disallowedBlocks) {
builder.addRegex(blockRegex);
try {
builder.addRegex(blockRegex);
} catch (InputParseException e) {
e.printStackTrace();
}
}
disallowedBlocksMask = builder.build(new NullExtent());
}

View File

@@ -19,6 +19,8 @@
package com.sk89q.worldedit;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweInputStream;
@@ -39,8 +41,6 @@ import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TextureHolder;
import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.wrappers.WorldWrapper;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.jchronic.Chronic;
import com.sk89q.jchronic.Options;
import com.sk89q.jchronic.utils.Span;
@@ -71,19 +71,19 @@ import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.RegionSelectorType;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Collections;
import java.util.LinkedList;
@@ -93,17 +93,19 @@ import java.util.Map;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Stores session information.
*/
public class LocalSession implements TextureHolder {
public transient static int MAX_HISTORY_SIZE = 15;
public static transient int MAX_HISTORY_SIZE = 15;
// Non-session related fields
private transient LocalConfiguration config;
private transient final AtomicBoolean dirty = new AtomicBoolean();
private final transient AtomicBoolean dirty = new AtomicBoolean();
private transient int failedCuiAttempts = 0;
// Session related
@@ -127,7 +129,6 @@ public class LocalSession implements TextureHolder {
});
private transient volatile Integer historyNegativeIndex;
private transient ClipboardHolder clipboard;
private transient boolean toolControl = true;
private transient boolean superPickaxe = false;
private transient BlockTool pickaxeMode = new SinglePickaxe();
private transient boolean hasTool = false;
@@ -143,18 +144,21 @@ public class LocalSession implements TextureHolder {
private transient Mask sourceMask;
private transient TextureUtil texture;
private transient ResettableExtent transform = null;
private transient TimeZone timezone = TimeZone.getDefault();
private transient ZoneId timezone = ZoneId.systemDefault();
private transient World currentWorld;
private transient UUID uuid;
private transient volatile long historySize = 0;
private transient VirtualWorld virtual;
private transient BlockVector3 cuiTemporaryBlock;
private transient List<Countable<BlockState>> lastDistribution;
// Saved properties
private String lastScript;
private RegionSelectorType defaultSelector;
private boolean useServerCUI = false; // Save this to not annoy players.
private String wandItem;
private String navWandItem;
/**
* Construct the object.
@@ -193,11 +197,6 @@ public class LocalSession implements TextureHolder {
}
}
/**
* @param uuid
* @param world
* @return If any loading occured
*/
public boolean loadSessionHistoryFromDisk(UUID uuid, World world) {
if (world == null || uuid == null) {
return false;
@@ -344,7 +343,7 @@ public class LocalSession implements TextureHolder {
*
* @return the timezone
*/
public TimeZone getTimeZone() {
public ZoneId getTimeZone() {
return timezone;
}
@@ -353,7 +352,7 @@ public class LocalSession implements TextureHolder {
*
* @param timezone the user's timezone
*/
public void setTimezone(TimeZone timezone) {
public void setTimezone(ZoneId timezone) {
checkNotNull(timezone);
this.timezone = timezone;
}
@@ -409,7 +408,6 @@ public class LocalSession implements TextureHolder {
}
loadSessionHistoryFromDisk(player.getUniqueId(), world);
if (changeSet instanceof FaweChangeSet) {
int size = getHistoryNegativeIndex();
ListIterator<Object> iter = history.listIterator();
int i = 0;
int cutoffIndex = history.size() - getHistoryNegativeIndex();
@@ -454,9 +452,8 @@ public class LocalSession implements TextureHolder {
return;
}
// Don't store anything if no changes were made
if (editSession.size() == 0) {
return;
}
if (editSession.size() == 0) return;
FaweChangeSet changeSet = (FaweChangeSet) editSession.getChangeSet();
if (changeSet.isEmpty()) {
return;
@@ -468,7 +465,6 @@ public class LocalSession implements TextureHolder {
}
// Destroy any sessions after this undo point
if (append) {
int size = getHistoryNegativeIndex();
ListIterator<Object> iter = history.listIterator();
int i = 0;
int cutoffIndex = history.size() - getHistoryNegativeIndex();
@@ -518,7 +514,7 @@ public class LocalSession implements TextureHolder {
loadSessionHistoryFromDisk(player.getUniqueId(), fp.getWorldForEditing());
if (getHistoryNegativeIndex() < history.size()) {
FaweChangeSet changeSet = getChangeSet(history.get(getHistoryIndex()));
EditSession newEditSession = new EditSessionBuilder(changeSet.getWorld())
try (EditSession newEditSession = new EditSessionBuilder(changeSet.getWorld())
.allowedRegionsEverywhere()
.checkMemory(false)
.changeSetNull()
@@ -526,11 +522,12 @@ public class LocalSession implements TextureHolder {
.limitUnprocessed(fp)
.player(fp)
.blockBag(getBlockBag(player))
.build();
newEditSession.setBlocks(changeSet, ChangeSetExecutor.Type.UNDO);
setDirty();
historyNegativeIndex++;
return newEditSession;
.build()) {
newEditSession.setBlocks(changeSet, ChangeSetExecutor.Type.UNDO);
setDirty();
historyNegativeIndex++;
return newEditSession;
}
} else {
int size = history.size();
if (getHistoryNegativeIndex() != size) {
@@ -556,7 +553,7 @@ public class LocalSession implements TextureHolder {
setDirty();
historyNegativeIndex--;
FaweChangeSet changeSet = getChangeSet(history.get(getHistoryIndex()));
EditSession newEditSession = new EditSessionBuilder(changeSet.getWorld())
try (EditSession newEditSession = new EditSessionBuilder(changeSet.getWorld())
.allowedRegionsEverywhere()
.checkMemory(false)
.changeSetNull()
@@ -564,9 +561,10 @@ public class LocalSession implements TextureHolder {
.limitUnprocessed(fp)
.player(fp)
.blockBag(getBlockBag(player))
.build();
newEditSession.setBlocks(changeSet, ChangeSetExecutor.Type.REDO);
return newEditSession;
.build()) {
newEditSession.setBlocks(changeSet, ChangeSetExecutor.Type.REDO);
return newEditSession;
}
}
return null;
@@ -707,27 +705,6 @@ public class LocalSession implements TextureHolder {
return world;
}
/**
* Get the world selection.
*
* @return the current selection
*/
public Region getWorldSelection() throws IncompleteRegionException {
return getSelection(getSelectionWorld());
}
/**
* This is an alias for {@link #getSelection(World)}.
* It enables CraftScripts to get a world selection as it is
* not possible to use getSelection which have two default
* implementations.
*
* @return Get the selection region in the world.
*/
public Region getWorldSelection(World world) throws IncompleteRegionException {
return getSelection(world);
}
/**
* Gets the clipboard.
*
@@ -783,21 +760,20 @@ public class LocalSession implements TextureHolder {
}
/**
* See if tool control is enabled.
*
* @return true if enabled
* @return true always - see deprecation notice
* @deprecated The wand is now a tool that can be bound/unbound.
*/
@Deprecated
public boolean isToolControlEnabled() {
return toolControl;
return true;
}
/**
* Change tool control setting.
*
* @param toolControl true to enable tool control
* @param toolControl unused - see deprecation notice
* @deprecated The wand is now a tool that can be bound/unbound.
*/
@Deprecated
public void setToolControl(boolean toolControl) {
this.toolControl = toolControl;
}
/**
@@ -962,15 +938,12 @@ public class LocalSession implements TextureHolder {
@Nullable
public Tool getTool(Player player) {
if (!Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && !hasTool) {
return null;
}
BaseItem item = player.getItemInHand(HandSide.MAIN_HAND);
return getTool(item, player);
}
public Tool getTool(BaseItem item, Player player) {
if (Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && item.getNativeItem() != null) {
if (item.getNativeItem() != null) {
BrushTool tool = BrushCache.getTool(player, this, item);
if (tool != null) return tool;
}
@@ -987,7 +960,7 @@ public class LocalSession implements TextureHolder {
* @throws InvalidToolBindException if the item can't be bound to that item
*/
public BrushTool getBrushTool(ItemType item) throws InvalidToolBindException {
return getBrushTool(item.getDefaultState(), null, true);
return getBrushTool(item, null, true);
}
public BrushTool getBrushTool(Player player) throws InvalidToolBindException {
@@ -995,17 +968,19 @@ public class LocalSession implements TextureHolder {
}
public BrushTool getBrushTool(Player player, boolean create) throws InvalidToolBindException {
BaseItem item = player.getItemInHand(HandSide.MAIN_HAND);
ItemType item = player.getItemInHand(HandSide.MAIN_HAND).getType();
return getBrushTool(item, player, create);
}
public BrushTool getBrushTool(ItemType item, boolean create) throws InvalidToolBindException {
return getBrushTool(item, null, create);
}
public BrushTool getBrushTool(BaseItem item, Player player, boolean create) throws InvalidToolBindException {
Tool tool = getTool(item, player);
public BrushTool getBrushTool(ItemType item, Player player, boolean create) throws InvalidToolBindException {
Tool tool = getTool(item.getDefaultState(), player);
if (!(tool instanceof BrushTool)) {
if (create) {
tool = new BrushTool();
setTool(item, tool, player);
setTool(item.getDefaultState(), tool, player);
} else {
return null;
}
@@ -1032,7 +1007,7 @@ public class LocalSession implements TextureHolder {
setTool(item.getDefaultState(), tool, null);
}
public void setTool(@Nullable Tool tool, Player player) throws InvalidToolBindException {
public void setTool(Player player, @Nullable Tool tool) throws InvalidToolBindException {
BaseItemStack item = player.getItemInHand(HandSide.MAIN_HAND);
setTool(item, tool, player);
}
@@ -1047,7 +1022,7 @@ public class LocalSession implements TextureHolder {
throw new InvalidToolBindException(type, "Already used for the navigation wand");
}
Tool previous;
if (player != null && (tool instanceof BrushTool || tool == null) && Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && item.getNativeItem() != null) {
if (player != null && (tool instanceof BrushTool || tool == null) && item.getNativeItem() != null) {
previous = BrushCache.getCachedTool(item);
BrushCache.setTool(item, (BrushTool) tool);
if (tool != null) {
@@ -1068,7 +1043,7 @@ public class LocalSession implements TextureHolder {
}
}
}
if (previous != null && player != null && previous instanceof BrushTool) {
if (player != null && previous instanceof BrushTool) {
BrushTool brushTool = (BrushTool) previous;
brushTool.clear(player);
}
@@ -1259,9 +1234,9 @@ public class LocalSession implements TextureHolder {
*
* @param text the message
*/
public void handleCUIInitializationMessage(String text) {
public void handleCUIInitializationMessage(String text, Actor actor) {
checkNotNull(text);
if (this.failedCuiAttempts > 3) {
if (this.hasCUISupport || this.failedCuiAttempts > 3) {
return;
}
@@ -1271,13 +1246,18 @@ public class LocalSession implements TextureHolder {
this.failedCuiAttempts ++;
return;
}
setCUISupport(true);
int version;
try {
setCUIVersion(Integer.parseInt(split[1]));
version = Integer.parseInt(split[1]);
} catch (NumberFormatException e) {
WorldEdit.logger.warn("Error while reading CUI init message: " + e.getMessage());
this.failedCuiAttempts ++;
return;
}
setCUISupport(true);
setCUIVersion(version);
dispatchCUISelection(actor);
}
}
@@ -1327,9 +1307,10 @@ public class LocalSession implements TextureHolder {
public Calendar detectDate(String input) {
checkNotNull(input);
Time.setTimeZone(getTimeZone());
TimeZone tz = TimeZone.getTimeZone(getTimeZone());
Time.setTimeZone(tz);
Options opt = new com.sk89q.jchronic.Options();
opt.setNow(Calendar.getInstance(getTimeZone()));
opt.setNow(Calendar.getInstance(tz));
Span date = Chronic.parse(input, opt);
if (date == null) {
return null;
@@ -1349,16 +1330,13 @@ public class LocalSession implements TextureHolder {
BlockBag blockBag = getBlockBag(player);
World world = player.getWorld();
boolean isPlayer = player.isPlayer();
EditSessionBuilder builder = new EditSessionBuilder(world);
if (player.isPlayer()) builder.player(FawePlayer.wrap(player));
builder.blockBag(blockBag);
builder.fastmode(fastMode);
EditSession editSession = builder.build();
// Create an edit session
EditSession editSession = WorldEdit.getInstance().getEditSessionFactory()
.getEditSession(player.isPlayer() ? player.getWorld() : null,
getBlockChangeLimit(), blockBag, player);
Request.request().setEditSession(editSession);
editSession.setFastMode(fastMode);
if (mask != null) {
editSession.setMask(mask);
}
@@ -1368,6 +1346,7 @@ public class LocalSession implements TextureHolder {
if (transform != null) {
editSession.addTransform(transform);
}
return editSession;
}
@@ -1465,6 +1444,38 @@ public class LocalSession implements TextureHolder {
return tmp;
}
/**
* Get the preferred wand item for this user, or {@code null} to use the default
* @return item id of wand item, or {@code null}
*/
public String getWandItem() {
return wandItem;
}
/**
* Get the preferred navigation wand item for this user, or {@code null} to use the default
* @return item id of nav wand item, or {@code null}
*/
public String getNavWandItem() {
return navWandItem;
}
/**
* Get the last block distribution stored in this session.
*
* @return block distribution or {@code null}
*/
public List<Countable<BlockState>> getLastDistribution() {
return lastDistribution == null ? null : Collections.unmodifiableList(lastDistribution);
}
/**
* Store a block distribution in this session.
*/
public void setLastDistribution(List<Countable<BlockState>> dist) {
lastDistribution = dist;
}
public ResettableExtent getTransform() {
return transform;
}

View File

@@ -32,6 +32,7 @@ public class UnknownDirectionException extends WorldEditException {
* @param dir the input that was tried
*/
public UnknownDirectionException(String dir) {
super("Unknown direction: " + dir);
this.dir = dir;
}

View File

@@ -19,9 +19,13 @@
package com.sk89q.worldedit;
import com.boydti.fawe.config.BBC;
import static com.sk89q.worldedit.event.platform.Interaction.HIT;
import static com.sk89q.worldedit.event.platform.Interaction.OPEN;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.BlockInteractEvent;
@@ -48,6 +52,7 @@ import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine;
import com.sk89q.worldedit.session.SessionManager;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.concurrency.EvenMoreExecutors;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException;
import com.sk89q.worldedit.util.io.file.FilenameException;
@@ -60,11 +65,6 @@ import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BundledBlockData;
import com.sk89q.worldedit.world.registry.BundledItemData;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.script.ScriptException;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -76,10 +76,12 @@ import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static com.sk89q.worldedit.event.platform.Interaction.HIT;
import static com.sk89q.worldedit.event.platform.Interaction.OPEN;
import javax.annotation.Nullable;
import javax.script.ScriptException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The entry point and container for a working implementation of WorldEdit.
@@ -105,6 +107,7 @@ public final class WorldEdit {
private final PlatformManager platformManager = new PlatformManager(this);
private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl(eventBus);
private final SessionManager sessions = new SessionManager(this);
private final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20));
private final Supervisor supervisor = new SimpleSupervisor();
private final BlockFactory blockFactory = new BlockFactory(this);
@@ -155,7 +158,7 @@ public final class WorldEdit {
}
/**
* Get the supervisor.
* Get the supervisor. Internal, not for API use.
*
* @return the supervisor
*/
@@ -163,6 +166,15 @@ public final class WorldEdit {
return supervisor;
}
/**
* Get the executor service. Internal, not for API use.
*
* @return the executor service
*/
public ListeningExecutorService getExecutorService() {
return executorService;
}
/**
* Get the block factory from which new {@link BlockStateHolder}s can be
* constructed.
@@ -307,6 +319,17 @@ public final class WorldEdit {
if (exts.size() != 1) {
exts = exts.subList(0, 1);
}
} else {
int dot = filename.lastIndexOf('.');
if (dot < 0 || dot == filename.length() - 1) {
String currentExt = filename.substring(dot + 1);
if (exts.contains(currentExt) && checkFilename(filename)) {
File f = new File(dir, filename);
if (f.exists()) {
return f;
}
}
}
}
File result = null;
for (Iterator<String> iter = exts.iterator(); iter.hasNext() && (result == null || (!isSave && !result.exists()));) {
@@ -321,7 +344,7 @@ public final class WorldEdit {
private File getSafeFileWithExtension(File dir, String filename, String extension) {
if (extension != null) {
int dot = filename.lastIndexOf('.');
if (dot < 0 || !filename.substring(dot).equalsIgnoreCase(extension)) {
if (dot < 0 || dot == filename.length() - 1 || !filename.substring(dot + 1).equalsIgnoreCase(extension)) {
filename += "." + extension;
}
}
@@ -396,16 +419,15 @@ public final class WorldEdit {
}
/**
* Get the direction vector for a player's direction. May return
* null if a direction could not be found.
* Get the direction vector for a player's direction.
*
* @param player the player
* @param dirStr the direction string
* @return a direction vector
* @throws UnknownDirectionException thrown if the direction is not known
* @throws UnknownDirectionException thrown if the direction is not known, or a relative direction is used with null player
*/
public BlockVector3 getDirection(Player player, String dirStr) throws UnknownDirectionException {
dirStr = dirStr.toLowerCase();
public BlockVector3 getDirection(@Nullable Player player, String dirStr) throws UnknownDirectionException {
dirStr = dirStr.toLowerCase(Locale.ROOT);
final Direction dir = getPlayerDirection(player, dirStr);
@@ -417,16 +439,15 @@ public final class WorldEdit {
}
/**
* Get the direction vector for a player's direction. May return
* null if a direction could not be found.
* Get the direction vector for a player's direction.
*
* @param player the player
* @param dirStr the direction string
* @return a direction vector
* @throws UnknownDirectionException thrown if the direction is not known
* @throws UnknownDirectionException thrown if the direction is not known, or a relative direction is used with null player
*/
public BlockVector3 getDiagonalDirection(Player player, String dirStr) throws UnknownDirectionException {
dirStr = dirStr.toLowerCase();
public BlockVector3 getDiagonalDirection(@Nullable Player player, String dirStr) throws UnknownDirectionException {
dirStr = dirStr.toLowerCase(Locale.ROOT);
final Direction dir = getPlayerDirection(player, dirStr);
@@ -438,15 +459,14 @@ public final class WorldEdit {
}
/**
* Get the direction vector for a player's direction. May return
* null if a direction could not be found.
* Get the direction vector for a player's direction.
*
* @param player the player
* @param dirStr the direction string
* @return a direction enum value
* @throws UnknownDirectionException thrown if the direction is not known
* @throws UnknownDirectionException thrown if the direction is not known, or a relative direction is used with null player
*/
private Direction getPlayerDirection(Player player, String dirStr) throws UnknownDirectionException {
private Direction getPlayerDirection(@Nullable Player player, String dirStr) throws UnknownDirectionException {
final Direction dir;
switch (dirStr.charAt(0)) {
@@ -490,19 +510,19 @@ public final class WorldEdit {
case 'm': // me
case 'f': // forward
dir = player.getCardinalDirection(0);
dir = getDirectionRelative(player, 0);
break;
case 'b': // back
dir = player.getCardinalDirection(180);
dir = getDirectionRelative(player, 180);
break;
case 'l': // left
dir = player.getCardinalDirection(-90);
dir = getDirectionRelative(player, -90);
break;
case 'r': // right
dir = player.getCardinalDirection(90);
dir = getDirectionRelative(player, 90);
break;
default:
@@ -511,6 +531,13 @@ public final class WorldEdit {
return dir;
}
private Direction getDirectionRelative(Player player, int yawOffset) throws UnknownDirectionException {
if (player != null) {
return player.getCardinalDirection(yawOffset);
}
throw new UnknownDirectionException("Only a player can use relative directions");
}
/**
* Flush a block bag's changes to a player.
*
@@ -650,9 +677,9 @@ public final class WorldEdit {
try {
engine = new RhinoCraftScriptEngine();
} catch (NoClassDefFoundError e) {
} catch (NoClassDefFoundError ignored) {
player.printError("Failed to find an installed script engine.");
player.printError("Please see http://wiki.sk89q.com/wiki/WorldEdit/Installation");
player.printError("Please see https://worldedit.readthedocs.io/en/latest/usage/other/craftscripts/");
return;
}

View File

@@ -19,16 +19,13 @@
package com.sk89q.worldedit.blocks;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.command.tool.Tool;
import com.sk89q.worldedit.world.NbtValued;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Represents an item, without an amount value. See {@link BaseItemStack}
* for an instance with stack amount information.

View File

@@ -0,0 +1,144 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.command.factory.ItemUseFactory;
import com.sk89q.worldedit.command.factory.ReplaceFactory;
import com.sk89q.worldedit.command.factory.TreeGeneratorFactory;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.factory.Apply;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.command.CommandRegistrationHandler;
import com.sk89q.worldedit.regions.factory.RegionFactory;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.CommandManagerService;
import org.enginehub.piston.CommandParameters;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.inject.Key;
import org.enginehub.piston.part.CommandArgument;
import org.enginehub.piston.part.SubCommandPart;
import java.util.stream.Collectors;
import static java.util.Objects.requireNonNull;
import static org.enginehub.piston.part.CommandParts.arg;
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ApplyBrushCommands {
private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TextComponent.of("The shape of the region"))
.defaultsTo(ImmutableList.of())
.ofTypes(ImmutableList.of(Key.of(RegionFactory.class)))
.build();
private static final CommandArgument RADIUS = arg(TranslatableComponent.of("radius"), TextComponent.of("The size of the brush"))
.defaultsTo(ImmutableList.of("5"))
.ofTypes(ImmutableList.of(Key.of(double.class)))
.build();
public static void register(CommandManagerService service, CommandManager commandManager, CommandRegistrationHandler registration) {
commandManager.register("apply", builder -> {
builder.description(TextComponent.of("Apply brush, apply a function to every block"));
builder.action(org.enginehub.piston.Command.Action.NULL_ACTION);
CommandManager manager = service.newCommandManager();
registration.register(
manager,
ApplyBrushCommandsRegistration.builder(),
new ApplyBrushCommands()
);
builder.condition(new PermissionCondition(ImmutableSet.of("worldedit.brush.apply")));
builder.addParts(REGION_FACTORY, RADIUS);
builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TextComponent.of("Type of brush to use"))
.withCommands(manager.getAllCommands().collect(Collectors.toList()))
.required()
.build());
});
}
private void setApplyBrush(CommandParameters parameters, Player player, LocalSession localSession,
Contextual<? extends RegionFunction> generatorFactory) throws WorldEditException {
double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class));
RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class);
BrushCommands.setOperationBasedBrush(player, localSession, radius,
new Apply(generatorFactory), regionFactory, "worldedit.brush.apply");
}
@Command(
name = "forest",
desc = "Plant trees"
)
public void forest(CommandParameters parameters,
Player player, LocalSession localSession,
@Arg(desc = "The type of tree to plant")
TreeGenerator.TreeType type) throws WorldEditException {
setApplyBrush(parameters, player, localSession, new TreeGeneratorFactory(type));
}
@Command(
name = "item",
desc = "Use an item"
)
@CommandPermissions("worldedit.brush.item")
public void item(CommandParameters parameters,
Player player, LocalSession localSession,
@Arg(desc = "The type of item to use")
BaseItem item,
@Arg(desc = "The direction in which the item will be applied", def = "up")
@Direction(includeDiagonals = true)
com.sk89q.worldedit.util.Direction direction) throws WorldEditException {
player.print(TextComponent.builder().append("WARNING: ", TextColor.RED, TextDecoration.BOLD)
.append("This brush simulates item usages. Its effects may not work on all platforms, may not be undo-able," +
" and may cause strange interactions with other mods/plugins. Use at your own risk.").build());
setApplyBrush(parameters, player, localSession, new ItemUseFactory(item, direction));
}
@Command(
name = "set",
desc = "Place a block"
)
public void set(CommandParameters parameters,
Player player, LocalSession localSession,
@Arg(desc = "The pattern of blocks to use")
Pattern pattern) throws WorldEditException {
setApplyBrush(parameters, player, localSession, new ReplaceFactory(pattern));
}
}

View File

@@ -19,25 +19,23 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Commands;
import com.boydti.fawe.object.visitor.Fast2DIterator;
import com.boydti.fawe.util.chat.Message;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.visitor.Fast2DIterator;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
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.Logging;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.function.FlatRegionFunction;
import com.sk89q.worldedit.function.FlatRegionMaskingFilter;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.biome.BiomeReplace;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
@@ -45,106 +43,84 @@ import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.FlatRegionVisitor;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.FlatRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.Regions;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeData;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch;
/**
* Implements biome-related commands such as "/biomelist".
*/
@Command(aliases = {}, desc = "Change, list and inspect biomes")
public class BiomeCommands extends MethodCommands {
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class BiomeCommands {
/**
* Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/
public BiomeCommands(WorldEdit worldEdit) {
super(worldEdit);
}
private BiomeRegistry getBiomeRegistry() {
return worldEdit.getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
public BiomeCommands() {
}
@Command(
aliases = { "biomelist", "biomels" },
usage = "[page]",
desc = "Gets all biomes available.",
max = 1
name = "biomelist",
aliases = { "biomels" },
desc = "Gets all biomes available."
)
@CommandPermissions("worldedit.biome.list")
public void biomeList(Player player, CommandContext args) throws WorldEditException {
int page;
int offset;
int count = 0;
public void biomeList(Actor actor,
@ArgFlag(name = 'p', desc = "Page number.", def = "1")
int page) {
WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> {
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
if (args.argsLength() == 0 || (page = args.getInteger(0)) < 2) {
page = 1;
offset = 0;
} else {
offset = (page - 1) * 19;
}
BiomeRegistry biomeRegistry = getBiomeRegistry();
Collection<BiomeType> biomes = BiomeTypes.values();
int totalPages = biomes.size() / 19 + 1;
Message msg = BBC.BIOME_LIST_HEADER.m(page, totalPages);
String setBiome = Commands.getAlias(BiomeCommands.class, "/setbiome");
for (BiomeType biome : biomes) {
if (offset > 0) {
offset--;
} else {
BiomeData data = biomeRegistry.getData(biome);
if (data != null) {
msg.newline().text(data.getName()).cmdTip(setBiome + " " + data.getName());
} else {
msg.newline().text("<? #" + biome.getId() + ">").cmdTip(setBiome + " " + biome.getId());
}
if (++count == 18) {
break;
}
}
}
msg.newline().paginate(getCommand().aliases()[0], page, totalPages);
msg.send(player);
PaginationBox paginationBox = PaginationBox.fromStrings("Available Biomes", "/biomelist -p %page%",
BiomeType.REGISTRY.values().stream()
.map(biomeType -> {
String id = biomeType.getId();
final BiomeData data = biomeRegistry.getData(biomeType);
if (data != null) {
String name = data.getName();
return id + " (" + name + ")";
} else {
return id;
}
})
.collect(Collectors.toList()));
return paginationBox.create(page);
}, null);
}
@Command(
aliases = { "biomeinfo" },
flags = "pt",
name = "biomeinfo",
desc = "Get the biome of the targeted block.",
help =
"Get the biome of the block.\n" +
"By default use all the blocks contained in your selection.\n" +
"-t use the block you are looking at.\n" +
"-p use the block you are currently in",
max = 0
descFooter = "By default, uses all blocks in your selection."
)
@CommandPermissions("worldedit.biome.info")
public void biomeInfo(Player player, LocalSession session, final EditSession editSession, CommandContext args) throws WorldEditException {
BiomeRegistry biomeRegistry = getBiomeRegistry();
Collection<BiomeType> values = BiomeTypes.values();
final int[] biomes = new int[values.size()];
public void biomeInfo(Player player, LocalSession session, EditSession editSession,
@Switch(name = 't', desc = "Use the block you are looking at.")
boolean useLineOfSight,
@Switch(name = 'p', desc = "Use the block you are currently in.")
boolean usePosition) throws WorldEditException {
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
Set<BiomeType> biomes = new HashSet<>();
String qualifier;
int size = 0;
if (args.hasFlag('t')) {
if (useLineOfSight) {
Location blockPosition = player.getBlockTrace(300);
if (blockPosition == null) {
BBC.NO_BLOCK.send(player);
@@ -152,68 +128,56 @@ public class BiomeCommands extends MethodCommands {
}
BiomeType biome = player.getWorld().getBiome(blockPosition.toBlockPoint().toBlockVector2());
biomes[biome.getInternalId()]++;
size = 1;
} else if (args.hasFlag('p')) {
biomes.add(biome);
qualifier = "at line of sight point";
} else if (usePosition) {
BiomeType biome = player.getWorld().getBiome(player.getLocation().toBlockPoint().toBlockVector2());
biomes[biome.getInternalId()]++;
size = 1;
biomes.add(biome);
qualifier = "at your position";
} else {
World world = player.getWorld();
Region region = session.getSelection(world);
if (region instanceof FlatRegion) {
for (BlockVector2 pt : new Fast2DIterator(((FlatRegion) region).asFlatRegion(), editSession)) {
biomes[editSession.getBiome(pt).getInternalId()]++;
size++;
biomes.add(world.getBiome(pt));
}
} else {
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(BlockVector3 position) throws WorldEditException {
biomes[editSession.getBiome(position.toBlockVector2()).getInternalId()]++;
return true;
}
RegionVisitor visitor = new RegionVisitor(region, position -> {
biomes.add(world.getBiome(position.toBlockVector2()));
return true;
}, editSession);
Operations.completeBlindly(visitor);
size += visitor.getAffected();
}
qualifier = "in your selection";
}
BBC.BIOME_LIST_HEADER.send(player, 1, 1);
List<Countable<BiomeType>> distribution = new ArrayList<>();
for (int i = 0; i < biomes.length; i++) {
int count = biomes[i];
if (count != 0) {
distribution.add(new Countable<>(BiomeTypes.get(i), count));
player.print(biomes.size() != 1 ? "Biomes " + qualifier + ":" : "Biome " + qualifier + ":");
for (BiomeType biome : biomes) {
BiomeData data = biomeRegistry.getData(biome);
if (data != null) {
player.print(" " + data.getName());
} else {
player.print(" <unknown #" + biome.getId() + ">");
}
}
Collections.sort(distribution);
for (Countable<BiomeType> c : distribution) {
BiomeData data = biomeRegistry.getData(c.getID());
String str = String.format("%-7s (%.3f%%) %s #%d",
String.valueOf(c.getAmount()),
c.getAmount() / (double) size * 100,
data == null ? "Unknown" : data.getName(),
c.getID().getInternalId());
player.print(str);
}
}
@Command(
aliases = { "/setbiome" },
usage = "<biome>",
flags = "p",
desc = "Sets the biome of the player's current block or region.",
help =
"Set the biome of the region.\n" +
"By default use all the blocks contained in your selection.\n" +
"-p use the block you are currently in"
name = "/setbiome",
desc = "Sets the biome of your current block or region.",
descFooter = "By default, uses all the blocks in your selection"
)
@Logging(REGION)
@CommandPermissions("worldedit.biome.set")
public void setBiome(Player player, LocalSession session, EditSession editSession, BiomeType target, @Switch('p') boolean atPosition) throws WorldEditException {
public void setBiome(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "Biome type.") BiomeType target,
@Switch(name = 'p', desc = "Use your current position")
boolean atPosition) throws WorldEditException {
World world = player.getWorld();
Region region;
Mask mask = editSession.getMask();
@@ -233,8 +197,9 @@ public class BiomeCommands extends MethodCommands {
Operations.completeLegacy(visitor);
BBC.BIOME_CHANGED.send(player, visitor.getAffected());
if (!player.hasPermission("fawe.tips"))
if (!player.hasPermission("fawe.tips")) {
BBC.TIP_BIOME_PATTERN.or(BBC.TIP_BIOME_MASK).send(player);
}
}
}

View File

@@ -11,30 +11,27 @@ import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.object.io.PGZIPOutputStream;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.sk89q.minecraft.util.commands.Command;
import org.enginehub.piston.annotation.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.command.binding.Range;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -163,16 +160,14 @@ public class BrushOptionsCommands extends MethodCommands {
max = 0
)
public void none(Player player, LocalSession session, CommandContext args) throws WorldEditException {
session.setTool(null, player);
session.setTool(player, null);
BBC.TOOL_NONE.send(player);
}
@Command(
aliases = {"/", ","},
usage = "[on|off]",
desc = "Toggle the super pickaxe function",
min = 0,
max = 1
desc = "Toggle the super pickaxe function"
)
@CommandPermissions("worldedit.superpickaxe")
public void togglePickaxe(Player player, LocalSession session, CommandContext args) throws WorldEditException {
@@ -210,8 +205,8 @@ public class BrushOptionsCommands extends MethodCommands {
session.setTool(item, null, player);
String cmd = "brush " + args.getJoinedStrings(0);
CommandEvent event = new CommandEvent(player, cmd);
CommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item, player, false);
PlatformCommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item.getType(), player, false);
if (newTool != null && tool != null) {
newTool.setSecondary(tool.getSecondary());
}
@@ -231,8 +226,8 @@ public class BrushOptionsCommands extends MethodCommands {
session.setTool(item, null, player);
String cmd = "brush " + args.getJoinedStrings(0);
CommandEvent event = new CommandEvent(player, cmd);
CommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item, player, false);
PlatformCommandManager.getInstance().handleCommandOnCurrentThread(event);
BrushTool newTool = session.getBrushTool(item.getType(), player, false);
if (newTool != null && tool != null) {
newTool.setPrimary(tool.getPrimary());
}

View File

@@ -1,77 +0,0 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.brush.BrushSettings;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
import com.sk89q.worldedit.command.tool.brush.Brush;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.command.CallableProcessor;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.parametric.AParametricCallable;
public class BrushProcessor extends MethodCommands implements CallableProcessor<BrushSettings> {
private final WorldEdit worldEdit;
public BrushProcessor(WorldEdit worldEdit) {
this.worldEdit = worldEdit;
}
public WorldEdit getWorldEdit() {
return worldEdit;
}
@Override
public BrushSettings process(CommandLocals locals, BrushSettings settings) throws WorldEditException {
Actor actor = locals.get(Actor.class);
LocalSession session = worldEdit.getSessionManager().get(actor);
session.setTool(null, (Player) actor);
BrushTool tool = session.getBrushTool((Player) actor);
if (tool != null) {
tool.setPrimary(settings);
tool.setSecondary(settings);
BBC.BRUSH_EQUIPPED.send(actor, ((String) locals.get("arguments")).split(" ")[1]);
}
return null;
}
public BrushSettings set(LocalSession session, CommandContext context, Brush brush) throws InvalidToolBindException {
CommandLocals locals = context.getLocals();
Actor actor = locals.get(Actor.class);
BrushSettings bs = new BrushSettings();
BrushTool tool = session.getBrushTool((Player) actor, false);
if (tool != null) {
BrushSettings currentContext = tool.getContext();
if (currentContext != null) {
Brush currentBrush = currentContext.getBrush();
if (currentBrush != null && currentBrush.getClass() == brush.getClass()) {
bs = currentContext;
}
}
}
CommandCallable callable = locals.get(CommandCallable.class);
String[] perms;
if (callable != null && callable instanceof AParametricCallable) {
perms = ((AParametricCallable) callable).getPermissions();
} else {
perms = getPermissions();
}
bs.addPermissions(perms);
if (locals != null) {
String args = (String) locals.get("arguments");
if (args != null) {
bs.addSetting(BrushSettings.SettingType.BRUSH, args.substring(args.indexOf(' ') + 1));
}
}
return bs.setBrush(brush);
}
}

View File

@@ -19,36 +19,47 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
import com.google.gson.JsonIOException;
import com.sk89q.worldedit.LocalSession;
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.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.internal.anvil.ChunkDeleter;
import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.MathUtils;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.storage.LegacyChunkStore;
import com.sk89q.worldedit.world.storage.McRegionChunkStore;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
import java.util.stream.Collectors;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.exception.StopExecutionException;
/**
* Commands for working with chunks.
*/
@Command(aliases = {}, desc = "[legacy] Inspect chunks: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Chunk_tools)")
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ChunkCommands {
private final WorldEdit worldEdit;
@@ -59,131 +70,101 @@ public class ChunkCommands {
}
@Command(
aliases = {"chunkinfo"},
usage = "",
desc = "Get information about the chunk that you are inside",
min = 0,
max = 0
name = "chunkinfo",
desc = "Get information about the chunk you're inside"
)
@CommandPermissions("worldedit.chunkinfo")
public void chunkInfo(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void chunkInfo(Player player) {
Location pos = player.getBlockIn();
int chunkX = (int) Math.floor(pos.getBlockX() / 16.0);
int chunkZ = (int) Math.floor(pos.getBlockZ() / 16.0);
String folder1 = Integer.toString(MathUtils.divisorMod(chunkX, 64), 36);
String folder2 = Integer.toString(MathUtils.divisorMod(chunkZ, 64), 36);
String filename = "c." + Integer.toString(chunkX, 36)
+ "." + Integer.toString(chunkZ, 36) + ".dat";
final BlockVector2 chunkPos = BlockVector2.at(chunkX, chunkZ);
player.print("Chunk: " + chunkX + ", " + chunkZ);
player.print("Old format: " + folder1 + "/" + folder2 + "/" + filename);
player.print("McRegion: region/" + McRegionChunkStore.getFilename(
BlockVector2.at(chunkX, chunkZ)));
player.print("Old format: " + LegacyChunkStore.getFilename(chunkPos));
player.print("McRegion: region/" + McRegionChunkStore.getFilename(chunkPos));
}
@Command(
aliases = {"listchunks"},
usage = "",
desc = "List chunks that your selection includes",
min = 0,
max = 0
name = "listchunks",
desc = "List chunks that your selection includes"
)
@CommandPermissions("worldedit.listchunks")
public void listChunks(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
public void listChunks(Player player, LocalSession session,
@ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException {
Set<BlockVector2> chunks = session.getSelection(player.getWorld()).getChunks();
for (BlockVector2 chunk : chunks) {
player.print(LegacyChunkStore.getFilename(chunk));
}
PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks -p %page%",
chunks.stream().map(LegacyChunkStore::getFilename).collect(Collectors.toList()));
player.print(paginationBox.create(page));
}
@Command(
aliases = {"delchunks"},
usage = "",
desc = "Deprecated, use anvil commands",
min = 0,
max = 0
name = "delchunks",
desc = "Delete chunks that your selection includes"
)
@CommandPermissions("worldedit.delchunks")
@Logging(REGION)
public void deleteChunks(Player player, LocalSession session) throws WorldEditException {
player.print("Note that this command does not yet support the mcregion format.");
LocalConfiguration config = worldEdit.getConfiguration();
Set<BlockVector2> chunks = session.getSelection(player.getWorld()).getChunks();
FileOutputStream out = null;
if (config.shellSaveType == null) {
player.printError("Shell script type must be configured: 'bat' or 'bash' expected.");
} else if (config.shellSaveType.equalsIgnoreCase("bat")) {
try {
out = new FileOutputStream("worldedit-delchunks.bat");
OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
writer.write("@ECHO off\r\n");
writer.write("ECHO This batch file was generated by FAWE.\r\n");
writer.write("ECHO It contains a list of chunks that were in the selected region\r\n");
writer.write("ECHO at the time that the /delchunks command was used. Run this file\r\n");
writer.write("ECHO in order to delete the chunk files listed in this file.\r\n");
writer.write("ECHO.\r\n");
writer.write("PAUSE\r\n");
for (BlockVector2 chunk : chunks) {
String filename = LegacyChunkStore.getFilename(chunk);
writer.write("ECHO " + filename + "\r\n");
writer.write("DEL \"world/" + filename + "\"\r\n");
}
writer.write("ECHO Complete.\r\n");
writer.write("PAUSE\r\n");
writer.close();
player.print("worldedit-delchunks.bat written. Run it when no one is near the region.");
} catch (IOException e) {
player.printError("Error occurred: " + e.getMessage());
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ignored) {
}
}
}
} else if (config.shellSaveType.equalsIgnoreCase("bash")) {
try {
out = new FileOutputStream("worldedit-delchunks.sh");
OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
writer.write("#!/bin/bash\n");
writer.write("echo This shell file was generated by FAWE.\n");
writer.write("echo It contains a list of chunks that were in the selected region\n");
writer.write("echo at the time that the /delchunks command was used. Run this file\n");
writer.write("echo in order to delete the chunk files listed in this file.\n");
writer.write("echo\n");
writer.write("read -p \"Press any key to continue...\"\n");
for (BlockVector2 chunk : chunks) {
String filename = LegacyChunkStore.getFilename(chunk);
writer.write("echo " + filename + "\n");
writer.write("rm \"world/" + filename + "\"\n");
}
writer.write("echo Complete.\n");
writer.write("read -p \"Press any key to continue...\"\n");
writer.close();
player.print("worldedit-delchunks.sh written. Run it when no one is near the region.");
player.print("You will have to chmod it to be executable.");
} catch (IOException e) {
player.printError("Error occurred: " + e.getMessage());
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ignored) {
}
}
}
} else {
player.printError("Shell script type must be configured: 'bat' or 'bash' expected.");
public void deleteChunks(Player player, LocalSession session,
@ArgFlag(name = 'o', desc = "Only delete chunks older than the specified time.", def = "")
ZonedDateTime beforeTime) throws WorldEditException {
Path worldDir = player.getWorld().getStoragePath();
if (worldDir == null) {
throw new StopExecutionException(TextComponent.of("Couldn't find world folder for this world."));
}
File chunkFile = worldEdit.getWorkingDirectoryFile(DELCHUNKS_FILE_NAME);
Path chunkPath = chunkFile.toPath();
ChunkDeletionInfo currentInfo = null;
if (Files.exists(chunkPath)) {
try {
currentInfo = ChunkDeleter.readInfo(chunkFile.toPath());
} catch (IOException e) {
throw new StopExecutionException(TextComponent.of("Error reading existing chunk file."));
}
}
if (currentInfo == null) {
currentInfo = new ChunkDeletionInfo();
currentInfo.batches = new ArrayList<>();
}
ChunkDeletionInfo.ChunkBatch newBatch = new ChunkDeletionInfo.ChunkBatch();
newBatch.worldPath = worldDir.toAbsolutePath().normalize().toString();
newBatch.backup = true;
final Region selection = session.getSelection(player.getWorld());
if (selection instanceof CuboidRegion) {
newBatch.minChunk = BlockVector2.at(selection.getMinimumPoint().getBlockX() >> 4, selection.getMinimumPoint().getBlockZ() >> 4);
newBatch.maxChunk = BlockVector2.at(selection.getMaximumPoint().getBlockX() >> 4, selection.getMaximumPoint().getBlockZ() >> 4);
} else {
// this has a possibility to OOM for very large selections still
Set<BlockVector2> chunks = selection.getChunks();
newBatch.chunks = new ArrayList<>(chunks);
}
if (beforeTime != null) {
newBatch.deletionPredicates = new ArrayList<>();
ChunkDeletionInfo.DeletionPredicate timePred = new ChunkDeletionInfo.DeletionPredicate();
timePred.property = "modification";
timePred.comparison = "<";
timePred.value = String.valueOf((int) beforeTime.toOffsetDateTime().toEpochSecond());
newBatch.deletionPredicates.add(timePred);
}
currentInfo.batches.add(newBatch);
try {
ChunkDeleter.writeInfo(currentInfo, chunkPath);
} catch (IOException | JsonIOException e) {
throw new StopExecutionException(TextComponent.of("Failed to write chunk list: " + e.getMessage()));
}
player.print(String.format("%d chunk(s) have been marked for deletion the next time the server starts.",
newBatch.getChunkCount()));
if (currentInfo.batches.size() > 1) {
player.printDebug(String.format("%d chunks total marked for deletion. (May have overlaps).",
currentInfo.batches.stream().mapToInt(ChunkDeletionInfo.ChunkBatch::getChunkCount).sum()));
}
player.print(TextComponent.of("You can mark more chunks for deletion, or to stop now, run: ", TextColor.LIGHT_PURPLE)
.append(TextComponent.of("/stop", TextColor.AQUA)
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop"))));
}
}

View File

@@ -36,16 +36,18 @@ import com.boydti.fawe.util.ImgurUtility;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MaskTraverser;
import com.sk89q.minecraft.util.commands.Command;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
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.Logging;
import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.PasteEvent;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
@@ -71,8 +73,11 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch;
import java.io.File;
import java.io.IOException;
@@ -86,16 +91,11 @@ import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
/**
* Clipboard commands.
*/
@Command(aliases = {}, desc = "Related commands to copy and pasting blocks: [More Info](https://goo.gl/z2ScQR)")
public class ClipboardCommands extends MethodCommands {
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ClipboardCommands {
/**
* Create a new instance.
@@ -107,79 +107,36 @@ public class ClipboardCommands extends MethodCommands {
checkNotNull(worldEdit);
}
@Command(
aliases = { "/lazycopy" },
flags = "em",
desc = "Lazily copy the selection to the clipboard",
help = "Lazily copy the selection to the clipboard\n" +
"Flags:\n" +
" -e skips copying entities\n" +
" -m sets a source mask so that excluded blocks become air\n" +
" -b copies biomes\n" +
"WARNING: Pasting entities cannot yet be undone!",
max = 0
)
@CommandPermissions("worldedit.clipboard.lazycopy")
public void lazyCopy(Player player, LocalSession session, EditSession editSession,
@Selection final Region region, @Switch('e') boolean skipEntities,
@Switch('m') Mask mask, @Switch('b') boolean copyBiomes) throws WorldEditException {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1));
FaweLimit limit = FawePlayer.wrap(player).getLimit();
if (volume >= limit.MAX_CHECKS) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
}
session.setClipboard(null);
final BlockVector3 origin = region.getMinimumPoint();
final int mx = origin.getBlockX();
final int my = origin.getBlockY();
final int mz = origin.getBlockZ();
ReadOnlyClipboard lazyClipboard = ReadOnlyClipboard.of(editSession, region, !skipEntities, copyBiomes);
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, lazyClipboard);
clipboard.setOrigin(session.getPlacementPosition(player));
session.setClipboard(new ClipboardHolder(clipboard));
BBC.COMMAND_COPY.send(player, region.getArea());
if (!player.hasPermission("fawe.tips"))
BBC.TIP_PASTE.or(BBC.TIP_LAZYCOPY, BBC.TIP_DOWNLOAD, BBC.TIP_ROTATE, BBC.TIP_COPYPASTE, BBC.TIP_REPLACE_MARKER, BBC.TIP_COPY_PATTERN).send(player);
}
@Command(
aliases = { "/copy", "/c" },
flags = "em",
desc = "Copy the selection to the clipboard",
help = "Copy the selection to the clipboard\n" +
"Flags:\n" +
" -e skips copying entities\n" +
" -m sets a source mask so that excluded blocks become air\n" +
" -b copies biomes\n" +
"WARNING: Pasting entities cannot yet be undone!",
min = 0,
max = 0
name = "/copy",
desc = "Copy the selection to the clipboard"
)
@CommandPermissions("worldedit.clipboard.copy")
public void copy(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Selection Region region, @Switch('e') boolean skipEntities,
@Switch('m') Mask mask, CommandContext context, @Switch('b') boolean copyBiomes) throws WorldEditException {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
@Selection Region region,
@Switch(name = 'e', desc = "Also copy entities")
boolean copyEntities,
@Switch(name = 'b', desc = "Also copy biomes")
boolean copyBiomes,
@ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "")
Mask mask, CommandContext context) throws WorldEditException {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1));
FaweLimit limit = FawePlayer.wrap(player).getLimit();
if (volume >= limit.MAX_CHECKS) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
}
BlockVector3 pos = session.getPlacementPosition(player);
fp.checkConfirmationRegion(() -> {
session.setClipboard(null);
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, player.getUniqueId());
session.setClipboard(new ClipboardHolder(clipboard));
clipboard.setOrigin(pos);
clipboard.setOrigin(session.getPlacementPosition(player));
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
copy.setCopyingEntities(!skipEntities);
copy.setCopyBiomes(copyBiomes);
copy.setCopyingEntities(copyEntities);
copy.setCopyingBiomes(copyBiomes);
Mask sourceMask = editSession.getSourceMask();
if (sourceMask != null) {
new MaskTraverser(sourceMask).reset(editSession);
@@ -198,23 +155,52 @@ public class ClipboardCommands extends MethodCommands {
}
@Command(
aliases = {"/lazycut"},
flags = "em",
desc = "Lazily cut the selection to the clipboard",
help = "Lazily cut the selection to the clipboard\n" +
"Flags:\n" +
" -e skips entity copy\n" +
" -m sets a source mask so that excluded blocks become air\n" +
" -b copies biomes\n" +
"WARNING: Pasting entities cannot yet be undone!",
max = 0
name = "/lazycopy",
desc = "Lazily copy the selection to the clipboard"
)
@CommandPermissions("worldedit.clipboard.lazycopy")
public void lazyCopy(Player player, LocalSession session, EditSession editSession,
@Selection Region region,
@Switch(name = 'e', desc = "Also copy entities")
boolean copyEntities,
@ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "")
Mask mask,
@Switch(name = 'b', desc = "Also copy biomes")
boolean copyBiomes) throws WorldEditException {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1));
FaweLimit limit = FawePlayer.wrap(player).getLimit();
if (volume >= limit.MAX_CHECKS) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
}
session.setClipboard(null);
ReadOnlyClipboard lazyClipboard = ReadOnlyClipboard.of(editSession, region, copyEntities, copyBiomes);
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, lazyClipboard);
clipboard.setOrigin(session.getPlacementPosition(player));
session.setClipboard(new ClipboardHolder(clipboard));
BBC.COMMAND_COPY.send(player, region.getArea());
if (!player.hasPermission("fawe.tips")) {
BBC.TIP_PASTE.or(BBC.TIP_LAZYCOPY, BBC.TIP_DOWNLOAD, BBC.TIP_ROTATE, BBC.TIP_COPYPASTE, BBC.TIP_REPLACE_MARKER, BBC.TIP_COPY_PATTERN).send(player);
}
}
@Command(
name = "/lazycut",
desc = "Lazily cut the selection to the clipboard"
)
@CommandPermissions("worldedit.clipboard.lazycut")
public void lazyCut(Player player, LocalSession session, EditSession editSession,
@Selection final Region region, @Switch('e') boolean skipEntities,
@Switch('m') Mask mask, @Switch('b') boolean copyBiomes) throws WorldEditException {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
@Selection final Region region,
@Switch(name = 'e', desc = "Also copy entities")
boolean copyEntities,
@ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "")
Mask mask,
@Switch(name = 'b', desc = "Also copy biomes")
boolean copyBiomes) throws WorldEditException {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1));
FaweLimit limit = FawePlayer.wrap(player).getLimit();
if (volume >= limit.MAX_CHECKS) {
@@ -224,11 +210,7 @@ public class ClipboardCommands extends MethodCommands {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
}
session.setClipboard(null);
final BlockVector3 origin = region.getMinimumPoint();
final int mx = origin.getBlockX();
final int my = origin.getBlockY();
final int mz = origin.getBlockZ();
ReadOnlyClipboard lazyClipboard = new WorldCutClipboard(editSession, region, !skipEntities, copyBiomes);
ReadOnlyClipboard lazyClipboard = new WorldCutClipboard(editSession, region, copyEntities, copyBiomes);
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, lazyClipboard);
clipboard.setOrigin(session.getPlacementPosition(player));
session.setClipboard(new ClipboardHolder(clipboard));
@@ -236,25 +218,25 @@ public class ClipboardCommands extends MethodCommands {
}
@Command(
aliases = { "/cut" },
flags = "em",
usage = "[leave-id]",
name = "/cut",
desc = "Cut the selection to the clipboard",
help = "Copy the selection to the clipboard\n" +
"Flags:\n" +
" -e skips entity copy\n" +
" -m sets a source mask so that excluded blocks become air\n" +
" -b copies biomes\n" +
"WARNING: Cutting and pasting entities cannot yet be undone!",
max = 1
descFooter = "WARNING: Cutting and pasting entities cannot be undone!"
)
@CommandPermissions("worldedit.clipboard.cut")
@Logging(REGION)
public void cut(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean skipEntities,
@Switch('m') Mask mask, @Switch('b') boolean copyBiomes, CommandContext context) throws WorldEditException {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
@Selection Region region,
@Arg(desc = "Pattern to leave in place of the selection", def = "air")
Pattern leavePattern,
@Switch(name = 'e', desc = "Also cut entities")
boolean copyEntities,
@Switch(name = 'b', desc = "Also copy biomes, source biomes are unaffected")
boolean copyBiomes,
@ArgFlag(name = 'm', desc = "Set the exclude mask, matching blocks become air", def = "")
Mask mask,
CommandContext context) throws WorldEditException {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
long volume = (((long) max.getX() - (long) min.getX() + 1) * ((long) max.getY() - (long) min.getY() + 1) * ((long) max.getZ() - (long) min.getZ() + 1));
FaweLimit limit = FawePlayer.wrap(player).getLimit();
if (volume >= limit.MAX_CHECKS) {
@@ -263,16 +245,15 @@ public class ClipboardCommands extends MethodCommands {
if (volume >= limit.MAX_CHANGES) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHANGES);
}
BlockVector3 pos = session.getPlacementPosition(player);
fp.checkConfirmationRegion(() -> {
session.setClipboard(null);
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, player.getUniqueId());
clipboard.setOrigin(pos);
clipboard.setOrigin(session.getPlacementPosition(player));
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
copy.setSourceFunction(new BlockReplace(editSession, leavePattern));
copy.setCopyingEntities(!skipEntities);
copy.setCopyingEntities(copyEntities);
copy.setRemovingEntities(true);
copy.setCopyBiomes(copyBiomes);
copy.setCopyingBiomes(copyBiomes);
Mask sourceMask = editSession.getSourceMask();
if (sourceMask != null) {
new MaskTraverser(sourceMask).reset(editSession);
@@ -286,18 +267,20 @@ public class ClipboardCommands extends MethodCommands {
session.setClipboard(new ClipboardHolder(clipboard));
BBC.COMMAND_CUT_SLOW.send(player, region.getArea());
if (!player.hasPermission("fawe.tips")) BBC.TIP_LAZYCUT.send(player);
if (!player.hasPermission("fawe.tips")) {
BBC.TIP_LAZYCUT.send(player);
}
}, getArguments(context), region, context);
}
@Command(
aliases = {"download"},
name = "download",
desc = "Downloads your clipboard through the configured web interface"
)
@Deprecated
@CommandPermissions({"worldedit.clipboard.download"})
public void download(final Player player, final LocalSession session, @Optional("schem") final String formatName) throws CommandException, WorldEditException {
public void download(final Player player, final LocalSession session, @Optional("schem") final String formatName) throws WorldEditException {
final ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
if (format == null) {
BBC.CLIPBOARD_INVALID_FORMAT.send(player, formatName);
@@ -334,7 +317,9 @@ public class ClipboardCommands extends MethodCommands {
try (ZipOutputStream zos = new ZipOutputStream(out)) {
for (File file : files) {
String fileName = file.getName();
if (MainUtil.isInSubDirectory(working, file)) fileName = working.toURI().relativize(file.toURI()).getPath();
if (MainUtil.isInSubDirectory(working, file)) {
fileName = working.toURI().relativize(file.toURI()).getPath();
}
ZipEntry ze = new ZipEntry(fileName);
zos.putNextEntry(ze);
Files.copy(file.toPath(), zos);
@@ -376,32 +361,28 @@ public class ClipboardCommands extends MethodCommands {
}
url = FaweAPI.upload(target, format);
}
if (url == null) {
BBC.GENERATING_LINK_FAILED.send(player);
} else {
String urlText = url.toString();
if (Settings.IMP.WEB.SHORTEN_URLS) {
try {
urlText = MainUtil.getText("https://empcraft.com/s/?" + URLEncoder.encode(url.toString(), "UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
BBC.DOWNLOAD_LINK.send(player, urlText);
}
}
if (url == null) {
BBC.GENERATING_LINK_FAILED.send(player);
} else {
String urlText = url.toString();
if (Settings.IMP.WEB.SHORTEN_URLS) {
try {
urlText = MainUtil.getText("https://empcraft.com/s/?" + URLEncoder.encode(url.toString(), "UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
BBC.DOWNLOAD_LINK.send(player, urlText);
}
}
}
@Command(
aliases = {"asset", "createasset", "makeasset"},
usage = "[category]",
desc = "Create an asset",
help = "Saves your clipboard to the asset web interface",
min = 1,
max = 1
name = "asset",
desc = "Saves your clipboard to the asset web interface",
)
@CommandPermissions({"worldedit.clipboard.asset"})
public void asset(final Player player, final LocalSession session, String category) throws CommandException, WorldEditException {
public void asset(final Player player, final LocalSession session, String category) throws WorldEditException {
final ClipboardFormat format = BuiltInClipboardFormat.MCEDIT_SCHEMATIC;
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
@@ -429,35 +410,25 @@ public class ClipboardCommands extends MethodCommands {
}
}
@Deprecated
public void paste(Player player, LocalSession session, EditSession editSession,
@Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin,
@Switch('s') boolean selectPasted) throws WorldEditException {
this.paste(player, session, editSession, ignoreAirBlocks, false, false, atOrigin, selectPasted);
}
@Command(
aliases = { "/paste" },
usage = "",
flags = "saobe",
desc = "Paste the clipboard's contents",
help =
"Pastes the clipboard's contents.\n" +
"Flags:\n" +
" -a skips air blocks\n" +
" -b skips pasting biomes\n" +
" -e skips pasting entities\n" +
" -o pastes at the original position\n" +
" -s selects the region after pasting",
min = 0,
max = 0
name = "/paste",
desc = "Paste the clipboard's contents"
)
@CommandPermissions("worldedit.clipboard.paste")
@Logging(PLACEMENT)
public void paste(Player player, LocalSession session, EditSession editSession,
@Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin,
@Switch('b') boolean ignoreBiomes, @Switch('e') boolean ignoreEntities,
@Switch('s') boolean selectPasted) throws WorldEditException {
@Switch(name = 'a', desc = "Skip air blocks")
boolean ignoreAirBlocks,
@Switch(name = 'o', desc = "Paste at the original position")
boolean atOrigin,
@Switch(name = 's', desc = "Select the region after pasting")
boolean selectPasted,
@Switch(name = 'e', desc = "Paste entities if available")
boolean pasteEntities,
@Switch(name = 'b', desc = "Paste biomes if available")
boolean pasteBiomes,
@ArgFlag(name = 'm', desc = "Only paste blocks matching this mask", def = "")
Mask sourceMask) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
if (holder.getTransform().isIdentity() && editSession.getSourceMask() == null) {
@@ -473,8 +444,9 @@ public class ClipboardCommands extends MethodCommands {
.createPaste(editSession)
.to(to)
.ignoreAirBlocks(ignoreAirBlocks)
.ignoreBiomes(ignoreBiomes)
.ignoreEntities(ignoreEntities)
.copyBiomes(pasteBiomes)
.copyEntities(pasteEntities)
.maskSource(sourceMask)
.build();
Operations.completeLegacy(operation);
@@ -488,39 +460,36 @@ public class ClipboardCommands extends MethodCommands {
selector.explainRegionAdjust(player, session);
}
BBC.COMMAND_PASTE.send(player, to);
if (!player.hasPermission("fawe.tips"))
if (!player.hasPermission("fawe.tips")) {
BBC.TIP_COPYPASTE.or(BBC.TIP_SOURCE_MASK, BBC.TIP_REPLACE_MARKER).send(player, to);
}
}
private void checkPaste(Player player, EditSession editSession, BlockVector3 to, ClipboardHolder holder, Clipboard clipboard) {
URI uri = null;
if (holder instanceof URIClipboardHolder) uri = ((URIClipboardHolder) holder).getURI(clipboard);
if (holder instanceof URIClipboardHolder) {
uri = ((URIClipboardHolder) holder).getURI(clipboard);
}
PasteEvent event = new PasteEvent(player, clipboard, uri, editSession, to);
worldEdit.getEventBus().post(event);
if (event.isCancelled()) throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
if (event.isCancelled()) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
}
}
@Command(
aliases = {"/place"},
usage = "",
flags = "sao",
name = "/place",
desc = "Place the clipboard's contents without applying transformations (e.g. rotate)",
help =
"Places the clipboard's contents without applying transformations (e.g. rotate).\n" +
"Flags:\n" +
" -a skips air blocks\n" +
" -o pastes at the original position\n" +
" -s selects the region after pasting",
min = 0,
max = 0
)
// Skips all transforms
@CommandPermissions("worldedit.clipboard.place")
@Logging(PLACEMENT)
public void place(Player player, LocalSession session, final EditSession editSession,
@Switch('a') final boolean ignoreAirBlocks, @Switch('o') boolean atOrigin,
@Switch('s') boolean selectPasted) throws WorldEditException {
@Switch(name = 'a', desc = "Skip air blocks")
boolean ignoreAirBlocks,
@Switch(name = 'o', desc = "Paste at the original position")
boolean atOrigin,
@Switch(name = 's', desc = "Select the region after pasting")
boolean selectPasted) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
final Clipboard clipboard = holder.getClipboard();
final BlockVector3 origin = clipboard.getOrigin();
@@ -532,8 +501,8 @@ public class ClipboardCommands extends MethodCommands {
Region region = clipboard.getRegion().clone();
if (selectPasted) {
BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
BlockVector3 realTo = to.add(holder.getTransform().apply(clipboardOffset.toVector3()).toBlockPoint());
BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
BlockVector3 realTo = to.add(holder.getTransform().apply(clipboardOffset.toVector3()).toBlockPoint());
BlockVector3 max = realTo.add(holder.getTransform().apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3()).toBlockPoint());
RegionSelector selector = new CuboidRegionSelector(player.getWorld(), realTo, max);
session.setRegionSelector(player.getWorld(), selector);
@@ -548,38 +517,46 @@ public class ClipboardCommands extends MethodCommands {
}
@Command(
aliases = { "/rotate" },
usage = "<y-axis> [<x-axis>] [<z-axis>]",
name = "/rotate",
desc = "Rotate the contents of the clipboard",
help = "Non-destructively rotate the contents of the clipboard.\n" +
"Angles are provided in degrees and a positive angle will result in a clockwise rotation. " +
"Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n"
descFooter = "Non-destructively rotate the contents of the clipboard.\n" +
"Angles are provided in degrees and a positive angle will result in a clockwise rotation. " +
"Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n"
)
@CommandPermissions("worldedit.clipboard.rotate")
public void rotate(Player player, LocalSession session, Double yRotate, @Optional Double xRotate, @Optional Double zRotate) throws WorldEditException {
public void rotate(Player player, LocalSession session,
@Arg(desc = "Amount to rotate on the y-axis")
double yRotate,
@Arg(desc = "Amount to rotate on the x-axis", def = "0")
double xRotate,
@Arg(desc = "Amount to rotate on the z-axis", def = "0")
double zRotate) throws WorldEditException {
if (Math.abs(yRotate % 90) > 0.001 ||
Math.abs(xRotate % 90) > 0.001 ||
Math.abs(zRotate % 90) > 0.001) {
player.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended.");
}
ClipboardHolder holder = session.getClipboard();
AffineTransform transform = new AffineTransform();
transform = transform.rotateY(-(yRotate != null ? yRotate : 0));
transform = transform.rotateX(-(xRotate != null ? xRotate : 0));
transform = transform.rotateZ(-(zRotate != null ? zRotate : 0));
transform = transform.rotateY(-yRotate);
transform = transform.rotateX(-xRotate);
transform = transform.rotateZ(-zRotate);
holder.setTransform(holder.getTransform().combine(transform));
BBC.COMMAND_ROTATE.send(player);
if (!player.hasPermission("fawe.tips"))
if (!player.hasPermission("fawe.tips")) {
BBC.TIP_FLIP.or(BBC.TIP_DEFORM, BBC.TIP_TRANSFORM).send(player);
}
}
@Command(
aliases = { "/flip" },
usage = "[<direction>]",
desc = "Flip the contents of the clipboard",
help =
"Flips the contents of the clipboard across the point from which the copy was made.\n",
min = 0,
max = 1
name = "/flip",
desc = "Flip the contents of the clipboard across the origin"
)
@CommandPermissions("worldedit.clipboard.flip")
public void flip(Player player, LocalSession session,
@Optional(Direction.AIM) @Direction BlockVector3 direction) throws WorldEditException {
@Arg(desc = "The direction to flip, defaults to look direction.", def = Direction.AIM)
@Direction BlockVector3 direction) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
AffineTransform transform = new AffineTransform();
transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3());
@@ -588,11 +565,8 @@ public class ClipboardCommands extends MethodCommands {
}
@Command(
aliases = { "clearclipboard" },
usage = "",
desc = "Clear your clipboard",
min = 0,
max = 0
name = "clearclipboard",
desc = "Clear your clipboard"
)
@CommandPermissions("worldedit.clipboard.clear")
public void clearClipboard(Player player, LocalSession session) throws WorldEditException {

View File

@@ -0,0 +1,152 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.MultiDirection;
import com.sk89q.worldedit.internal.command.CommandRegistrationHandler;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import org.enginehub.piston.Command;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.CommandManagerService;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.inject.Key;
import org.enginehub.piston.part.SubCommandPart;
import java.util.List;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import static com.sk89q.worldedit.internal.command.CommandUtil.requireIV;
/**
* Extracted from {@link SelectionCommands} to allow importing of {@link Command}.
*/
@CommandContainer
public class ExpandCommands {
public static void register(CommandRegistrationHandler registration,
CommandManager commandManager,
CommandManagerService commandManagerService) {
// Collect the general expand command
CommandManager collect = commandManagerService.newCommandManager();
registration.register(
collect,
ExpandCommandsRegistration.builder(),
new ExpandCommands()
);
Command expandBaseCommand = collect.getCommand("/expand")
.orElseThrow(() -> new IllegalStateException("No /expand command"));
commandManager.register("/expand", command -> {
command.condition(new PermissionCondition(ImmutableSet.of("worldedit.selection.expand")));
command.addPart(SubCommandPart.builder(
TranslatableComponent.of("vert"),
TextComponent.of("Vertical expansion sub-command")
)
.withCommands(ImmutableSet.of(createVertCommand(commandManager)))
.optional()
.build());
command.addParts(expandBaseCommand.getParts());
command.action(expandBaseCommand.getAction());
command.description(expandBaseCommand.getDescription());
});
}
private static Command createVertCommand(CommandManager commandManager) {
return commandManager.newCommand("vert")
.description(TextComponent.of("Vertically expand the selection to world limits."))
.action(parameters -> {
expandVert(
requireIV(Key.of(LocalSession.class), "localSession", parameters),
requireIV(Key.of(Player.class), "localSession", parameters)
);
return 1;
})
.build();
}
private static void expandVert(LocalSession session, Player player) throws IncompleteRegionException {
Region region = session.getSelection(player.getWorld());
try {
int oldSize = region.getArea();
region.expand(
BlockVector3.at(0, (player.getWorld().getMaxY() + 1), 0),
BlockVector3.at(0, -(player.getWorld().getMaxY() + 1), 0));
session.getRegionSelector(player.getWorld()).learnChanges();
int newSize = region.getArea();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
player.print("Region expanded " + (newSize - oldSize)
+ " blocks [top-to-bottom].");
} catch (RegionOperationException e) {
player.printError(e.getMessage());
}
}
@org.enginehub.piston.annotation.Command(
name = "/expand",
desc = "Expand the selection area"
)
@Logging(REGION)
public void expand(Player player, LocalSession session,
@Arg(desc = "Amount to expand the selection by, can be `vert` to expand to the whole vertical column")
int amount,
@Arg(desc = "Amount to expand the selection by in the other direction", def = "0")
int reverseAmount,
@Arg(desc = "Direction to expand", def = Direction.AIM)
@MultiDirection
List<BlockVector3> direction) throws WorldEditException {
Region region = session.getSelection(player.getWorld());
int oldSize = region.getArea();
if (reverseAmount == 0) {
for (BlockVector3 dir : direction) {
region.expand(dir.multiply(amount));
}
} else {
for (BlockVector3 dir : direction) {
region.expand(dir.multiply(amount), dir.multiply(-reverseAmount));
}
}
session.getRegionSelector(player.getWorld()).learnChanges();
int newSize = region.getArea();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
player.print("Region expanded " + (newSize - oldSize) + " block(s).");
}
}

View File

@@ -33,12 +33,9 @@ import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Helper class to 'bake' a transform into a clipboard.
* <p>
*
* <p>This class needs a better name and may need to be made more generic.</p>
*
* @see Clipboard
@@ -52,7 +49,7 @@ public class FlattenedClipboardTransform {
/**
* Create a new instance.
*
* @param original the original clipboard
* @param original the original clipboard
* @param transform the transform
*/
private FlattenedClipboardTransform(Clipboard original, Transform transform) {
@@ -94,10 +91,10 @@ public class FlattenedClipboardTransform {
Vector3 newMinimum = corners[0];
Vector3 newMaximum = corners[0];
for (int i = 1; i < corners.length; i++) {
Vector3 cbv = corners[i];
newMinimum = newMinimum.getMinimum(cbv);
newMaximum = newMaximum.getMaximum(cbv);
newMinimum = newMinimum.getMinimum(corners[i]);
newMaximum = newMaximum.getMaximum(corners[i]);
}
// After transformation, the points may not really sit on a block,
@@ -119,13 +116,16 @@ public class FlattenedClipboardTransform {
if (transform != null && !transform.isIdentity()) extent = new BlockTransformExtent(original, transform);
ForwardExtentCopy copy = new ForwardExtentCopy(extent, original.getRegion(), original.getOrigin(), target, original.getOrigin());
copy.setTransform(transform);
if (original.hasBiomes()) {
copy.setCopyingBiomes(true);
}
return copy;
}
/**
* Create a new instance to bake the transform with.
*
* @param original the original clipboard
* @param original the original clipboard
* @param transform the transform
* @return a builder
*/
@@ -133,5 +133,4 @@ public class FlattenedClipboardTransform {
return new FlattenedClipboardTransform(original, transform);
}
}

View File

@@ -0,0 +1,284 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
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.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.DisallowedUsageException;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.item.ItemType;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* General WorldEdit commands.
*/
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class GeneralCommands {
private final WorldEdit worldEdit;
/**
* Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/
public GeneralCommands(WorldEdit worldEdit) {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
}
@Command(
name = "/limit",
desc = "Modify block change limit"
)
@CommandPermissions("worldedit.limit")
public void limit(Player player, LocalSession session,
@Arg(desc = "The limit to set", def = "")
Integer limit) {
LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.limit.unrestricted");
limit = limit == null ? config.defaultChangeLimit : Math.max(-1, limit);
if (!mayDisable && config.maxChangeLimit > -1) {
if (limit > config.maxChangeLimit) {
player.printError("Your maximum allowable limit is " + config.maxChangeLimit + ".");
return;
}
}
session.setBlockChangeLimit(limit);
player.print("Block change limit set to " + limit + "."
+ (limit == config.defaultChangeLimit ? "" : " (Use //limit to go back to the default.)"));
}
@Command(
name = "/timeout",
desc = "Modify evaluation timeout time."
)
@CommandPermissions("worldedit.timeout")
public void timeout(Player player, LocalSession session,
@Arg(desc = "The timeout time to set", def = "")
Integer limit) {
LocalConfiguration config = worldEdit.getConfiguration();
boolean mayDisable = player.hasPermission("worldedit.timeout.unrestricted");
limit = limit == null ? config.calculationTimeout : Math.max(-1, limit);
if (!mayDisable && config.maxCalculationTimeout > -1) {
if (limit > config.maxCalculationTimeout) {
player.printError("Your maximum allowable timeout is " + config.maxCalculationTimeout + " ms.");
return;
}
}
session.setTimeout(limit);
player.print("Timeout time set to " + limit + " ms."
+ (limit == config.calculationTimeout ? "" : " (Use //timeout to go back to the default.)"));
}
@Command(
name = "/fast",
desc = "Toggle fast mode"
)
@CommandPermissions("worldedit.fast")
public void fast(Player player, LocalSession session,
@Arg(desc = "The new fast mode state", def = "")
Boolean fastMode) {
boolean hasFastMode = session.hasFastMode();
if (fastMode != null && fastMode == hasFastMode) {
player.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + ".");
return;
}
if (hasFastMode) {
session.setFastMode(false);
player.print("Fast mode disabled.");
} else {
session.setFastMode(true);
player.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.");
}
}
@Command(
name = "/reorder",
desc = "Sets the reorder mode of WorldEdit"
)
@CommandPermissions("worldedit.reorder")
public void reorderMode(Player player, LocalSession session,
@Arg(desc = "The reorder mode", def = "")
EditSession.ReorderMode reorderMode) {
if (reorderMode == null) {
player.print("The reorder mode is " + session.getReorderMode().getDisplayName());
} else {
session.setReorderMode(reorderMode);
player.print("The reorder mode is now " + session.getReorderMode().getDisplayName());
}
}
@Command(
name = "/drawsel",
desc = "Toggle drawing the current selection"
)
@CommandPermissions("worldedit.drawsel")
public void drawSelection(Player player, LocalSession session,
@Arg(desc = "The new draw selection state", def = "")
Boolean drawSelection) throws WorldEditException {
if (!WorldEdit.getInstance().getConfiguration().serverSideCUI) {
throw new DisallowedUsageException("This functionality is disabled in the configuration!");
}
boolean useServerCui = session.shouldUseServerCUI();
if (drawSelection != null && drawSelection == useServerCui) {
player.printError("Server CUI already " + (useServerCui ? "enabled" : "disabled") + ".");
return;
}
if (useServerCui) {
session.setUseServerCUI(false);
session.updateServerCUI(player);
player.print("Server CUI disabled.");
} else {
session.setUseServerCUI(true);
session.updateServerCUI(player);
player.print("Server CUI enabled. This only supports cuboid regions, with a maximum size of 32x32x32.");
}
}
@Command(
name = "gmask",
aliases = {"/gmask"},
desc = "Set the global mask"
)
@CommandPermissions("worldedit.global-mask")
public void gmask(Player player, LocalSession session,
@Arg(desc = "The mask to set", def = "")
Mask mask) {
if (mask == null) {
session.setMask(null);
player.print("Global mask disabled.");
} else {
session.setMask(mask);
player.print("Global mask set.");
}
}
@Command(
name = "toggleplace",
aliases = {"/toggleplace"},
desc = "Switch between your position and pos1 for placement"
)
public void togglePlace(Player player, LocalSession session) {
if (session.togglePlacementPosition()) {
player.print("Now placing at pos #1.");
} else {
player.print("Now placing at the block you stand in.");
}
}
@Command(
name = "searchitem",
aliases = {"/searchitem", "/l", "/search"},
desc = "Search for an item"
)
@CommandPermissions("worldedit.searchitem")
public void searchItem(Actor actor,
@Switch(name = 'b', desc = "Only search for blocks")
boolean blocksOnly,
@Switch(name = 'i', desc = "Only search for items")
boolean itemsOnly,
@ArgFlag(name = 'p', desc = "Page of results to return", def = "1")
int page,
@Arg(desc = "Search query", variable = true)
List<String> query) {
String search = String.join(" ", query);
if (search.length() <= 2) {
actor.printError("Enter a longer search string (len > 2).");
return;
}
if (blocksOnly && itemsOnly) {
actor.printError("You cannot use both the 'b' and 'i' flags simultaneously.");
return;
}
WorldEditAsyncCommandBuilder.createAndSendMessage(actor, new ItemSearcher(search, blocksOnly, itemsOnly, page),
"(Please wait... searching items.)");
}
private static class ItemSearcher implements Callable<Component> {
private final boolean blocksOnly;
private final boolean itemsOnly;
private final String search;
private final int page;
ItemSearcher(String search, boolean blocksOnly, boolean itemsOnly, int page) {
this.blocksOnly = blocksOnly;
this.itemsOnly = itemsOnly;
this.search = search;
this.page = page;
}
@Override
public Component call() throws Exception {
String command = "/searchitem " + (blocksOnly ? "-b " : "") + (itemsOnly ? "-i " : "") + "-p %page% " + search;
Map<String, String> results = new TreeMap<>();
String idMatch = search.replace(' ', '_');
String nameMatch = search.toLowerCase(Locale.ROOT);
for (ItemType searchType : ItemType.REGISTRY) {
if (blocksOnly && !searchType.hasBlockType()) {
continue;
}
if (itemsOnly && searchType.hasBlockType()) {
continue;
}
final String id = searchType.getId();
String name = searchType.getName();
final boolean hasName = !name.equals(id);
name = name.toLowerCase(Locale.ROOT);
if (id.contains(idMatch) || (hasName && name.contains(nameMatch))) {
results.put(id, name + (hasName ? " (" + id + ")" : ""));
}
}
List<String> list = new ArrayList<>(results.values());
return PaginationBox.fromStrings("Search results for '" + search + "'", command, list).create(page);
}
}
}

View File

@@ -27,21 +27,27 @@ import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.util.image.ImageUtil;
import com.sk89q.minecraft.util.commands.Command;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
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.Logging;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.internal.annotation.Radii;
import com.sk89q.worldedit.internal.annotation.Selection;
import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
@@ -49,29 +55,26 @@ import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.util.command.binding.Range;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.binding.Text;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.util.command.parametric.ParameterException;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockType;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
import java.awt.*;
import java.util.List;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION;
/**
* Commands for the generation of shapes and other objects.
*/
@Command(aliases = {}, desc = "Create structures and features: [More Info](https://goo.gl/KuLFRW)")
public class GenerationCommands extends MethodCommands {
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class GenerationCommands {
private final WorldEdit worldEdit;
/**
* Create a new instance.
@@ -79,18 +82,28 @@ public class GenerationCommands extends MethodCommands {
* @param worldEdit reference to WorldEdit
*/
public GenerationCommands(WorldEdit worldEdit) {
super(worldEdit);
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
}
@Command(
aliases = {"/caves"},
name = "/caves",
usage = "[size=8] [freq=40] [rarity=7] [minY=8] [maxY=127] [sysFreq=1] [sysRarity=25] [pocketRarity=0] [pocketMin=0] [pocketMax=3]",
desc = "Generates caves",
help = "Generates a cave network"
desc = "Generates a cave network"
)
@CommandPermissions("worldedit.generation.caves")
@Logging(PLACEMENT)
public void caves(FawePlayer fp, LocalSession session, EditSession editSession, @Selection Region region, @Optional("8") int size, @Optional("40") int frequency, @Optional("7") int rarity, @Optional("8") int minY, @Optional("127") int maxY, @Optional("1") int systemFrequency, @Optional("25") int individualRarity, @Optional("0") int pocketChance, @Optional("0") int pocketMin, @Optional("3") int pocketMax, CommandContext context) throws WorldEditException {
public void caves(FawePlayer fp, LocalSession session, EditSession editSession, @Selection Region region,
@Arg(desc = "TODO", def = "8") int size,
@Arg(desc = "TODO", def = "40") int frequency,
@Arg(desc = "TODO", def = "7") int rarity,
@Arg(desc = "TODO", def = "8") int minY,
@Arg(desc = "TODO", def = "127") int maxY,
@Arg(desc = "TODO", def = "1") int systemFrequency,
@Arg(desc = "TODO", def = "25") int individualRarity,
@Arg(desc = "TODO", def = "0") int pocketChance,
@Arg(desc = "TODO", def = "0") int pocketMin,
@Arg(desc = "TODO", def = "3") int pocketMax, CommandContext context) throws WorldEditException {
fp.checkConfirmationRegion(() -> {
CavesGen gen = new CavesGen(size, frequency, rarity, minY, maxY, systemFrequency, individualRarity, pocketChance, pocketMin, pocketMax);
editSession.generate(region, gen);
@@ -98,14 +111,10 @@ public class GenerationCommands extends MethodCommands {
}, getArguments(context), region, context);
}
// public void addOre(Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
@Command(
aliases = {"/ores"},
desc = "Generates ores",
help = "Generates ores",
min = 1,
max = 1
name = "/ores",
desc = "Generates ores"
)
@CommandPermissions("worldedit.generation.ore")
@Logging(PLACEMENT)
@@ -119,59 +128,49 @@ public class GenerationCommands extends MethodCommands {
@Command(
aliases = {"/image", "/img"},
desc = "Generate an image",
usage = "<imgur> [randomize=true] [complexity=100] [dimensions=100,100]",
min = 1,
max = 4
usage = "<imgur> [randomize=true] [complexity=100] [dimensions=100,100]"
)
@CommandPermissions("worldedit.generation.image")
@Logging(PLACEMENT)
public void image(Player player, LocalSession session, EditSession editSession, String arg, @Optional("true") boolean randomize, @Optional("100") int threshold, @Optional BlockVector2 dimensions) throws WorldEditException, IOException {
public void image(Player player, LocalSession session, EditSession editSession, String arg, @Optional("true") boolean randomize,
@Arg(desc = "TODO", def = "100") int threshold, @Optional BlockVector2 dimensions) throws WorldEditException, IOException {
TextureUtil tu = Fawe.get().getCachedTextureUtil(randomize, 0, threshold);
URL url = new URL(arg);
if (!url.getHost().equalsIgnoreCase("i.imgur.com") && !url.getHost().equalsIgnoreCase("empcraft.com")) {
throw new IOException("Only i.imgur.com or empcraft.com/ui links are allowed!");
}
FawePlayer<Object> fp = FawePlayer.wrap(player);
BufferedImage image = MainUtil.readImage(url);
if (dimensions != null) {
image = ImageUtil.getScaledInstance(image, dimensions.getBlockX(), dimensions.getBlockZ(), RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
}
// MutableBlockVector3 pos1 = new MutableBlockVector3(player.getLocation().toBlockPoint());
// MutableBlockVector3 pos2 = new MutableBlockVector3(pos1.add(image.getWidth() - 1, 0, image.getHeight() - 1));
BlockVector3 pos1 = player.getLocation().toBlockPoint();
BlockVector3 pos2 = pos1.add(image.getWidth() - 1, 0, image.getHeight() - 1);
CuboidRegion region = new CuboidRegion(pos1, pos2);
int[] count = new int[1];
final BufferedImage finalImage = image;
RegionVisitor visitor = new RegionVisitor(region, new RegionFunction() {
@Override
public boolean apply(BlockVector3 pos) throws WorldEditException {
try {
int x = pos.getBlockX() - pos1.getBlockX();
int z = pos.getBlockZ() - pos1.getBlockZ();
int color = finalImage.getRGB(x, z);
BlockType block = tu.getNearestBlock(color);
count[0]++;
if (block != null) return editSession.setBlock(pos, block.getDefaultState());
return false;
} catch (Throwable e) {
e.printStackTrace();
}
RegionVisitor visitor = new RegionVisitor(region, pos -> {
try {
int x = pos.getBlockX() - pos1.getBlockX();
int z = pos.getBlockZ() - pos1.getBlockZ();
int color = finalImage.getRGB(x, z);
BlockType block = tu.getNearestBlock(color);
count[0]++;
if (block != null) return editSession.setBlock(pos, block.getDefaultState());
return false;
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}, editSession);
Operations.completeBlindly(visitor);
BBC.VISITOR_BLOCK.send(player, editSession.getBlockChangeCount());
}
@Command(
aliases = {"/ore"},
name = "/ore",
usage = "<mask> <pattern> <size> <freq> <rarity> <minY> <maxY>",
desc = "Generates ores",
help = "Generates ores",
min = 7,
max = 7
desc = "Generates ores"
)
@CommandPermissions("worldedit.generation.ore")
@Logging(PLACEMENT)
@@ -183,20 +182,24 @@ public class GenerationCommands extends MethodCommands {
}
@Command(
aliases = { "/hcyl" },
name = "/hcyl",
usage = "<pattern> <radius>[,<radius>] [height]",
desc = "Generates a hollow cylinder.",
help =
"Generates a hollow cylinder.\n" +
"By specifying 2 radii, separated by a comma,\n" +
"you can generate elliptical cylinders.\n" +
"The 1st radius is north/south, the 2nd radius is east/west.",
min = 2,
max = 4
"The 1st radius is north/south, the 2nd radius is east/west."
)
@CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT)
public void hcyl(FawePlayer fp, Player player, LocalSession session, EditSession editSession, Pattern pattern, BlockVector2 radius, @Optional("1") int height, @Range(min = 1) @Optional("1") double thickness, CommandContext context) throws WorldEditException {
public void hcyl(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
BlockVector2 radius,
@Arg(desc = "The height of the cylinder", def = "1")
int height,
@Range(min = 1) @Optional("1") double thickness, CommandContext context) throws WorldEditException {
double max = MathMan.max(radius.getBlockX(), radius.getBlockZ());
worldEdit.checkMaxRadius(max);
BlockVector3 pos = session.getPlacementPosition(player);
@@ -207,21 +210,24 @@ public class GenerationCommands extends MethodCommands {
}
@Command(
aliases = { "/cyl" },
usage = "<pattern> <radius>[,<radius>] [height]",
flags = "h",
name = "/cyl",
desc = "Generates a cylinder.",
help =
"Generates a cylinder.\n" +
"By specifying 2 radii, separated by a comma,\n" +
"you can generate elliptical cylinders.\n" +
"The 1st radius is north/south, the 2nd radius is east/west.",
min = 2,
max = 3
"The 1st radius is north/south, the 2nd radius is east/west."
)
@CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT)
public void cyl(FawePlayer fp, Player player, LocalSession session, EditSession editSession, Pattern pattern, BlockVector2 radius, @Optional("1") int height, @Switch('h') boolean hollow, CommandContext context) throws WorldEditException {
public void cyl(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
BlockVector2 radius,
@Arg(desc = "The height of the cylinder", def = "1")
int height,
@Switch(name = 'h', desc = "Make a hollow cylinder")
boolean hollow, CommandContext context) throws WorldEditException {
double max = Math.max(radius.getBlockX(), radius.getBlockZ());
worldEdit.checkMaxRadius(max);
BlockVector3 pos = session.getPlacementPosition(player);
@@ -232,104 +238,151 @@ public class GenerationCommands extends MethodCommands {
}
@Command(
aliases = { "/hsphere" },
name = "/hsphere",
usage = "<pattern> <radius>[,<radius>,<radius>] [raised?]",
desc = "Generates a hollow sphere.",
help =
"Generates a hollow sphere.\n" +
"By specifying 3 radii, separated by commas,\n" +
"you can generate an ellipsoid. The order of the ellipsoid radii\n" +
"is north/south, up/down, east/west.",
min = 2,
max = 3
"is north/south, up/down, east/west."
)
@CommandPermissions("worldedit.generation.sphere")
@Logging(PLACEMENT)
public void hsphere(FawePlayer fp, Player player, LocalSession session, EditSession editSession, Pattern pattern, BlockVector3 radius, @Optional("false") boolean raised, CommandContext context) throws WorldEditException {
sphere(fp, player, session, editSession, pattern, radius, raised, true, context);
public void hsphere(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
@Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W")
@Radii(3)
List<Double> radii,
@Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position")
boolean raised,
CommandContext context) throws WorldEditException {
sphere(fp, player, session, editSession, pattern, radii, raised, true, context);
}
@Command(
aliases = { "/sphere" },
usage = "<pattern> <radius>[,<radius>,<radius>] [raised?]",
flags = "h",
name = "/sphere",
desc = "Generates a filled sphere.",
help =
"Generates a filled sphere.\n" +
"By specifying 3 radii, separated by commas,\n" +
"you can generate an ellipsoid. The order of the ellipsoid radii\n" +
"is north/south, up/down, east/west.",
min = 2,
max = 3
"is north/south, up/down, east/west."
)
@CommandPermissions("worldedit.generation.sphere")
@Logging(PLACEMENT)
public void sphere(FawePlayer fp, Player player, LocalSession session, EditSession editSession, Pattern pattern, BlockVector3 radius, @Optional("false") boolean raised, @Switch('h') boolean hollow, CommandContext context) throws WorldEditException {
double max = MathMan.max(radius.getBlockX(), radius.getBlockY(), radius.getBlockZ());
worldEdit.checkMaxRadius(max);
public int sphere(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
@Arg(desc = "The radii of the sphere. Order is N/S, U/D, E/W")
@Radii(3)
List<Double> radii,
@Switch(name = 'r', desc = "Raise the bottom of the sphere to the placement position")
boolean raised,
@Switch(name = 'h', desc = "Make a hollow sphere")
boolean hollow) throws WorldEditException {
final double radiusX, radiusY, radiusZ;
switch (radii.size()) {
case 1:
radiusX = radiusY = radiusZ = Math.max(1, radii.get(0));
break;
case 3:
radiusX = Math.max(1, radii.get(0));
radiusY = Math.max(1, radii.get(1));
radiusZ = Math.max(1, radii.get(2));
break;
default:
player.printError("You must either specify 1 or 3 radius values.");
return 0;
}
worldEdit.checkMaxRadius(radiusX);
worldEdit.checkMaxRadius(radiusY);
worldEdit.checkMaxRadius(radiusZ);
BlockVector3 pos = session.getPlacementPosition(player);
BlockVector3 finalPos = raised ? pos.add(0, radius.getY(), 0) : pos;
BlockVector3 finalPos;
if (raised) {
finalPos = pos.add(0, (int) radiusY, 0);
} else {
finalPos = pos;
}
fp.checkConfirmationRadius(() -> {
int affected = editSession.makeSphere(finalPos, pattern, radius.getX(), radius.getY(), radius.getZ(), !hollow);
int affected = editSession.makeSphere(finalPos, pattern, radiusX, radiusY, radiusZ, !hollow);
player.findFreePosition();
BBC.VISITOR_BLOCK.send(fp, affected);
}, getArguments(context), (int) max, context);
}
@Command(
aliases = { "forestgen" },
usage = "[size] [type] [density]",
desc = "Generate a forest",
min = 0,
max = 3
name = "forestgen",
desc = "Generate a forest"
)
@CommandPermissions("worldedit.generation.forest")
@Logging(POSITION)
public void forestGen(Player player, LocalSession session, EditSession editSession, @Optional("10") int size,
@Optional("tree") TreeType type, @Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException {
public int forestGen(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The size of the forest, in blocks", def = "10")
int size,
@Arg(desc = "The type of forest", def = "tree")
TreeType type,
@Arg(desc = "The density of the forest, between 0 and 100", def = "5")
double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100");
density = density / 100;
int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type);
player.print(affected + " trees created.");
return affected;
}
@Command(
aliases = { "pumpkins" },
usage = "[size=10] [density=0.02]",
desc = "Generate pumpkin patches",
min = 0,
max = 2
name = "pumpkins",
desc = "Generate pumpkin patches"
)
@CommandPermissions("worldedit.generation.pumpkins")
@Logging(POSITION)
public void pumpkins(Player player, LocalSession session, EditSession editSession, @Optional("10") int apothem, @Optional("0.02") double density) throws WorldEditException, ParameterException {
public int pumpkins(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The size of the patch", def = "10")
int size,
@Arg(desc = "//TODO", def = "10")
int apothem,
@Arg(desc = "//TODO ", def = "0.02")
double density) throws WorldEditException {
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(player), apothem, density);
BBC.COMMAND_PUMPKIN.send(player, affected);
return affected;
}
@Command(
aliases = { "/hpyramid" },
usage = "<pattern> <size>",
desc = "Generate a hollow pyramid",
min = 2,
max = 2
name = "/hpyramid",
desc = "Generate a hollow pyramid"
)
@CommandPermissions("worldedit.generation.pyramid")
@Logging(PLACEMENT)
public void hollowPyramid(FawePlayer fp, Player player, LocalSession session, EditSession editSession, Pattern pattern, @Range(min = 1) int size, CommandContext context) throws WorldEditException {
public void hollowPyramid(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern,
@Arg(desc = "The size of the pyramid")
int size, CommandContext context) throws WorldEditException {
pyramid(fp, player, session, editSession, pattern, size, true, context);
}
@Command(
aliases = { "/pyramid" },
usage = "<pattern> <size>",
flags = "h",
desc = "Generate a filled pyramid",
min = 2,
max = 2
name = "/pyramid",
desc = "Generate a filled pyramid"
)
@CommandPermissions("worldedit.generation.pyramid")
@Logging(PLACEMENT)
public void pyramid(FawePlayer fp, Player player, LocalSession session, EditSession editSession, Pattern pattern, @Range(min = 1) int size, @Switch('h') boolean hollow, CommandContext context) throws WorldEditException {
public void pyramid(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern,
@Arg(desc = "The size of the pyramid")
int size,
@Switch(name = 'h', desc = "Make a hollow pyramid")
boolean hollow,
CommandContext context) throws WorldEditException {
BlockVector3 pos = session.getPlacementPosition(player);
worldEdit.checkMaxRadius(size);
fp.checkConfirmationRadius(() -> {
@@ -339,36 +392,28 @@ public class GenerationCommands extends MethodCommands {
}, getArguments(context), size, context);
}
@Command(
aliases = { "/generate", "/gen", "/g" },
usage = "<pattern> <expression>",
name = "/generate",
aliases = { "/gen", "/g" },
desc = "Generates a shape according to a formula.",
help =
"Generates a shape according to a formula that is expected to\n" +
"return positive numbers (true) if the point is inside the shape\n" +
"Optionally set type/data to the desired block.\n" +
"Flags:\n" +
" -h to generate a hollow shape\n" +
" -r to use raw minecraft coordinates\n" +
" -o is like -r, except offset from placement.\n" +
" -c is like -r, except offset selection center.\n" +
"If neither -r nor -o is given, the selection is mapped to -1..1\n" +
"See also tinyurl.com/wesyntax.",
flags = "hroc",
min = 2,
max = -1
descFooter = "See also https://tinyurl.com/wesyntax."
)
@CommandPermissions("worldedit.generation.shape")
@Logging(ALL)
public void generate(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Selection Region region,
Pattern pattern,
@Text String expression,
@Switch('h') boolean hollow,
@Switch('r') boolean useRawCoords,
@Switch('o') boolean offset,
@Switch('c') boolean offsetCenter, CommandContext context) throws WorldEditException {
public int generate(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern,
@Arg(desc = "Expression to test block placement locations and set block type", variable = true)
List<String> expression,
@Switch(name = 'h', desc = "Generate a hollow shape")
boolean hollow,
@Switch(name = 'r', desc = "Use the game's coordinate origin")
boolean useRawCoords,
@Switch(name = 'o', desc = "Use the placement's coordinate origin")
boolean offset,
@Switch(name = 'c', desc = "Use the selection's center as origin")
boolean offsetCenter) throws WorldEditException {
final Vector3 zero;
Vector3 unit;
@@ -399,47 +444,42 @@ public class GenerationCommands extends MethodCommands {
final Vector3 unit1 = unit;
final int affected = 0;
fp.checkConfirmationRegion(() -> {
try {
final int affected = editSession.makeShape(region, zero, unit1, pattern, expression, hollow);
affected = editSession.makeShape(region, zero, unit1, pattern, String.join(" ", expression), hollow, session.getTimeout());
player.findFreePosition();
BBC.VISITOR_BLOCK.send(fp, affected);
} catch (ExpressionException e) {
fp.sendMessage(e.getMessage());
player.printError(e.getMessage());
return 0;
}
}, getArguments(context), region, context);
return affected;
}
@Command(
aliases = { "/generatebiome", "/genbiome", "/gb" },
usage = "<biome> <expression>",
name = "/generatebiome",
aliases = { "/genbiome", "/gb" },
desc = "Sets biome according to a formula.",
help =
"Generates a shape according to a formula that is expected to\n" +
"return positive numbers (true) if the point is inside the shape\n" +
"Sets the biome of blocks in that shape.\n" +
"Flags:\n" +
" -h to generate a hollow shape\n" +
" -r to use raw minecraft coordinates\n" +
" -o is like -r, except offset from placement.\n" +
" -c is like -r, except offset selection center.\n" +
"If neither -r nor -o is given, the selection is mapped to -1..1\n" +
"See also tinyurl.com/wesyntax.",
flags = "hroc",
min = 2,
max = -1
descFooter = "See also https://tinyurl.com/wesyntax."
)
@CommandPermissions("worldedit.generation.shape.biome")
@Logging(ALL)
public void generateBiome(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Selection Region region,
BiomeType target,
@Text String expression,
@Switch('h') boolean hollow,
@Switch('r') boolean useRawCoords,
@Switch('o') boolean offset,
@Switch('c') boolean offsetCenter,
CommandContext context) throws WorldEditException {
public int generateBiome(Player player, LocalSession session, EditSession editSession,
@Selection Region region,
@Arg(desc = "The biome type to set")
BiomeType target,
@Arg(desc = "Expression to test block placement locations and set biome type", variable = true)
List<String> expression,
@Switch(name = 'h', desc = "Generate a hollow shape")
boolean hollow,
@Switch(name = 'r', desc = "Use the game's coordinate origin")
boolean useRawCoords,
@Switch(name = 'o', desc = "Use the placement's coordinate origin")
boolean offset,
@Switch(name = 'c', desc = "Use the selection's center as origin")
boolean offsetCenter) throws WorldEditException {
final Vector3 zero;
Vector3 unit;
@@ -475,7 +515,7 @@ public class GenerationCommands extends MethodCommands {
player.findFreePosition();
BBC.VISITOR_FLAT.send(fp, affected);
} catch (ExpressionException e) {
fp.toWorldEditPlayer().printError(e.getMessage());
player.printError(e.getMessage());
}
}, getArguments(context), region, context);
}

View File

@@ -2,16 +2,29 @@ package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.util.StringMan;
import com.google.common.base.Joiner;
import com.sk89q.minecraft.util.commands.Command;
import org.enginehub.piston.annotation.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.util.command.*;
import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
import com.sk89q.worldedit.util.command.CommandCallable;
import com.sk89q.worldedit.util.command.CommandMapping;
import com.sk89q.worldedit.util.command.DelegateCallable;
import com.sk89q.worldedit.util.command.Dispatcher;
import com.sk89q.worldedit.util.command.PrimaryAliasComparator;
import com.sk89q.worldedit.util.command.parametric.AParametricCallable;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public abstract class HelpBuilder implements Runnable {
private final CommandCallable callable;
@@ -45,7 +58,6 @@ public abstract class HelpBuilder implements Runnable {
} catch (Exception ignored) {
}
boolean isRootLevel = true;
List<String> visited = new ArrayList<>();
// Create the message
@@ -61,10 +73,10 @@ public abstract class HelpBuilder implements Runnable {
Map<String, Map<CommandMapping, String>> grouped = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
for (CommandMapping mapping : aliases) {
CommandCallable c = mapping.getCallable();
String group;
if (c instanceof DelegateCallable) {
c = ((DelegateCallable) c).getParent();
}
String group;
if (c instanceof AParametricCallable) {
Command command = ((AParametricCallable) c).getCommand();
if (command != null && command.aliases().length != 0) {
@@ -94,6 +106,7 @@ public abstract class HelpBuilder implements Runnable {
Map<CommandMapping, String> mappings = effectiveLength == 1 ? grouped.get(cat) : null;
if (mappings == null) {
// Drill down to the command
boolean isRootLevel = true;
for (int i = 0; i < effectiveLength; i++) {
String command = args.getString(i);
@@ -142,12 +155,11 @@ public abstract class HelpBuilder implements Runnable {
found.add(closest);
displayFailure(BBC.HELP_SUGGEST.f(arg, StringMan.join(found, ", ")));
return;
} else {
String msg = String.format("The sub-command '%s' under '%s' could not be found.",
command, Joiner.on(" ").join(visited));
displayFailure(msg);
return;
}
String msg = String.format("The sub-command '%s' under '%s' could not be found.",
command, Joiner.on(" ").join(visited));
displayFailure(msg);
return;
}
visited.add(args.getString(i));
isRootLevel = false;
@@ -160,7 +172,7 @@ public abstract class HelpBuilder implements Runnable {
}
if (!(callable instanceof Dispatcher)) {
// TODO interactive box
String cmd = (WorldEdit.getInstance().getConfiguration().noDoubleSlash ? "" : "/") + Joiner.on(" ").join(visited);
String cmd = "/" + Joiner.on(" ").join(visited);
displayUsage(callable, cmd);
return;
}
@@ -181,7 +193,7 @@ public abstract class HelpBuilder implements Runnable {
return;
}
}
aliases.sort(new PrimaryAliasComparator(CommandManager.COMMAND_CLEAN_PATTERN));
aliases.sort(new PrimaryAliasComparator(PlatformCommandManager.COMMAND_CLEAN_PATTERN));
// Calculate pagination
int offset = perPage * Math.max(0, page);
@@ -194,15 +206,12 @@ public abstract class HelpBuilder implements Runnable {
int end = Math.min(offset + perPage, aliases.size());
List<CommandMapping> subAliases = aliases.subList(offset, end);
List<String> subPrefixes = prefixes.subList(offset, end);
Map<CommandMapping, String> commandMap = new LinkedHashMap<>();
for (int i = 0; i < subAliases.size(); i++) {
commandMap.put(subAliases.get(i), subPrefixes.get(i));
}
Map<CommandMapping, String> commandMap = IntStream.range(0, subAliases.size()).boxed().collect(Collectors.toMap(subAliases::get, subPrefixes::get, (a, b) -> b, LinkedHashMap::new));
String visitedString = Joiner.on(" ").join(visited);
displayCommands(commandMap, visitedString, page, pageTotal, effectiveLength);
}
} else {
String cmd = (WorldEdit.getInstance().getConfiguration().noDoubleSlash ? "" : "/") + Joiner.on(" ").join(visited);
String cmd = "/" + Joiner.on(" ").join(visited);
displayUsage(callable, cmd);
}
} catch (Throwable e) {

View File

@@ -27,17 +27,18 @@ import com.boydti.fawe.database.DBHandler;
import com.boydti.fawe.database.RollbackDatabase;
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.changeset.DiskStorageHistory;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
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.entity.Player;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
@@ -49,11 +50,14 @@ import com.sk89q.worldedit.world.World;
import java.io.File;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
/**
* Commands to undo, redo, and clear history.
*/
@Command(aliases = {}, desc = "Commands to undo, redo, and clear history: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Features#History)")
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class HistoryCommands extends MethodCommands {
/**
@@ -66,13 +70,12 @@ public class HistoryCommands extends MethodCommands {
}
@Command(
name = "fawerollback",
aliases = {"/frb", "frb", "fawerollback", "/fawerollback", "/rollback"},
usage = "<user=Empire92> <radius=5> <time=3d4h>",
desc = "Undo a specific edit. " +
" - The time uses s, m, h, d, y.\n" +
" - Import from disk: /frb #import",
min = 1,
max = 3
" - The time uses s, m, h, d, y.\n" +
" - Import from disk: /frb #import"
)
@CommandPermissions("worldedit.history.rollback")
public void faweRollback(final Player player, LocalSession session, final String user, @Optional("0") @Range(min = 0) int radius, @Optional("0") String time, @Switch('r') boolean restore) throws WorldEditException {
@@ -80,74 +83,71 @@ public class HistoryCommands extends MethodCommands {
BBC.SETTING_DISABLE.send(player, "history.use-database (Import with /frb #import )");
return;
}
switch (user.charAt(0)) {
case '#': {
if (user.equals("#import")) {
if (!player.hasPermission("fawe.rollback.import")) {
BBC.NO_PERM.send(player, "fawe.rollback.import");
return;
if (user.charAt(0) == '#') {
if (user.equals("#import")) {
if (!player.hasPermission("fawe.rollback.import")) {
BBC.NO_PERM.send(player, "fawe.rollback.import");
return;
}
File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY);
if (!folder.exists()) {
return;
}
for (File worldFolder : folder.listFiles()) {
if (!worldFolder.isDirectory()) {
continue;
}
File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY);
if (!folder.exists()) {
return;
}
for (File worldFolder : folder.listFiles()) {
if (!worldFolder.isDirectory()) {
continue;
}
String worldName = worldFolder.getName();
World world = FaweAPI.getWorld(worldName);
if (world != null) {
for (File userFolder : worldFolder.listFiles()) {
if (!userFolder.isDirectory()) {
continue;
}
String userUUID = userFolder.getName();
try {
UUID uuid = UUID.fromString(userUUID);
for (File historyFile : userFolder.listFiles()) {
String name = historyFile.getName();
if (!name.endsWith(".bd")) {
continue;
}
RollbackOptimizedHistory rollback = new RollbackOptimizedHistory(world, uuid, Integer.parseInt(name.substring(0, name.length() - 3)));
DiskStorageHistory.DiskStorageSummary summary = rollback.summarize(RegionWrapper.GLOBAL(), false);
if (summary != null) {
rollback.setDimensions(BlockVector3.at(summary.minX, 0, summary.minZ), BlockVector3.at(summary.maxX, 255, summary.maxZ));
rollback.setTime(historyFile.lastModified());
RollbackDatabase db = DBHandler.IMP.getDatabase(world);
db.logEdit(rollback);
player.print("Logging: " + historyFile);
}
String worldName = worldFolder.getName();
World world = FaweAPI.getWorld(worldName);
if (world != null) {
for (File userFolder : worldFolder.listFiles()) {
if (!userFolder.isDirectory()) {
continue;
}
String userUUID = userFolder.getName();
try {
UUID uuid = UUID.fromString(userUUID);
for (File historyFile : userFolder.listFiles()) {
String name = historyFile.getName();
if (!name.endsWith(".bd")) {
continue;
}
RollbackOptimizedHistory rollback = new RollbackOptimizedHistory(world, uuid, Integer.parseInt(name.substring(0, name.length() - 3)));
DiskStorageHistory.DiskStorageSummary summary = rollback.summarize(RegionWrapper.GLOBAL(), false);
if (summary != null) {
rollback.setDimensions(BlockVector3.at(summary.minX, 0, summary.minZ), BlockVector3.at(summary.maxX, 255, summary.maxZ));
rollback.setTime(historyFile.lastModified());
RollbackDatabase db = DBHandler.IMP.getDatabase(world);
db.logEdit(rollback);
player.print("Logging: " + historyFile);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
continue;
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
player.print("Done import!");
return;
}
String toParse = user.substring(1);
if (!MathMan.isInteger(toParse)) {
BBC.COMMAND_SYNTAX.send(player, "/frb #<index>");
return;
}
int index = Integer.parseInt(toParse);
final World world = player.getWorld();
UUID uuid = player.getUniqueId();
DiskStorageHistory file = new DiskStorageHistory(world, uuid, index);
if (file.getBDFile().exists()) {
if (restore) file.redo(FawePlayer.wrap(player));
else file.undo(FawePlayer.wrap(player));
BBC.ROLLBACK_ELEMENT.send(player, world.getName() + "/" + user + "-" + index);
} else {
BBC.TOOL_INSPECT_INFO_FOOTER.send(player, 0);
}
player.print("Done import!");
return;
}
String toParse = user.substring(1);
if (!MathMan.isInteger(toParse)) {
BBC.COMMAND_SYNTAX.send(player, "/frb #<index>");
return;
}
int index = Integer.parseInt(toParse);
final World world = player.getWorld();
UUID uuid = player.getUniqueId();
DiskStorageHistory file = new DiskStorageHistory(world, uuid, index);
if (file.getBDFile().exists()) {
if (restore) file.redo(FawePlayer.wrap(player));
else file.undo(FawePlayer.wrap(player));
BBC.ROLLBACK_ELEMENT.send(player, world.getName() + "/" + user + "-" + index);
} else {
BBC.TOOL_INSPECT_INFO_FOOTER.send(player, 0);
}
return;
}
UUID other = Fawe.imp().getUUID(user);
if (other == null) {
@@ -168,15 +168,12 @@ public class HistoryCommands extends MethodCommands {
Location origin = player.getLocation();
BlockVector3 bot = origin.toBlockPoint().subtract(radius, radius, radius);
bot = bot.withY(Math.max(0, bot.getY()));
// bot.mutY(Math.max(0, bot.getY()));
BlockVector3 top = origin.toBlockPoint().add(radius, radius, radius);
bot = bot.withY(Math.min(255, top.getY()));
// top.mutY(Math.min(255, top.getY()));
RollbackDatabase database = DBHandler.IMP.getDatabase(world);
final AtomicInteger count = new AtomicInteger();
final FawePlayer fp = FawePlayer.wrap(player);
final FaweQueue finalQueue;
Region[] allowedRegions = fp.getCurrentRegions(FaweMaskManager.MaskType.OWNER);
if (allowedRegions == null) {
BBC.NO_REGION.send(fp);
@@ -200,13 +197,12 @@ public class HistoryCommands extends MethodCommands {
}
@Command(
aliases = {"/fawerestore", "/frestore"},
name = "fawerestore",
alias = {"/fawerestore", "/frestore"},
usage = "<user=Empire92|*> <radius=5> <time=3d4h>",
desc = "Redo a specific edit. " +
" - The time uses s, m, h, d, y.\n" +
" - Import from disk: /frb #import",
min = 1,
max = 3
" - The time uses s, m, h, d, y.\n" +
" - Import from disk: /frb #import"
)
@CommandPermissions("worldedit.history.rollback")
public void restore(final Player player, LocalSession session, final String user, @Optional("0") @Range(min = 0) int radius, @Optional("0") String time) throws WorldEditException {
@@ -214,30 +210,35 @@ public class HistoryCommands extends MethodCommands {
}
@Command(
aliases = {"/undo", "undo"},
usage = "[times] [player]",
desc = "Undoes the last action",
min = 0,
max = 2
name = "undo",
aliases = { "/undo" },
desc = "Undoes the last action (from history)"
)
@CommandPermissions("worldedit.history.undo")
public void undo(Player player, LocalSession session, CommandContext context) throws WorldEditException {
@CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"})
public void undo(Player player, LocalSession session,
@Arg(desc = "Number of undoes to perform", def = "1")
int times,
@Arg(name = "player", desc = "Undo this player's operations", def = "")
String playerName,
CommandContext context) throws WorldEditException {
if (session.hasFastMode()) {
BBC.COMMAND_UNDO_DISABLED.send(player);
return;
}
int times = Math.max(1, context.getInteger(0, 1));
times = Math.max(1, times);
LocalSession undoSession = session;
int finalTimes = times;
FawePlayer.wrap(player).checkConfirmation(() -> {
player.checkPermission("worldedit.history.undo.other");
EditSession undone = null;
int i = 0;
for (; i < times; ++i) {
for (; i < finalTimes; ++i) {
if (context.argsLength() < 2) {
undone = session.undo(session.getBlockBag(player), player);
undone = undoSession.undo(undoSession.getBlockBag(player), player);
} else {
player.checkPermission("worldedit.history.undo.other");
LocalSession sess = worldEdit.getSessionManager().findByName(context.getString(1));
LocalSession sess = worldEdit.getSessionManager().findByName(playerName);
if (sess == null) {
BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, context.getString(1));
BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, playerName);
break;
}
undone = sess.undo(session.getBlockBag(player), player);
@@ -256,54 +257,52 @@ public class HistoryCommands extends MethodCommands {
}
@Command(
aliases = {"/redo", "redo"},
usage = "[times] [player]",
desc = "Redoes the last action (from history)",
min = 0,
max = 2
name = "redo",
aliases = { "/redo" },
desc = "Redoes the last action (from history)"
)
@CommandPermissions("worldedit.history.redo")
public void redo(Player player, LocalSession session, CommandContext args) throws WorldEditException {
int times = Math.max(1, args.getInteger(0, 1));
EditSession redone = null;
int i = 0;
for (; i < times; ++i) {
if (args.argsLength() < 2) {
redone = session.redo(session.getBlockBag(player), player);
} else {
player.checkPermission("worldedit.history.redo.other");
LocalSession sess = worldEdit.getSessionManager().findByName(args.getString(1));
if (sess == null) {
BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, args.getString(1));
break;
}
redone = sess.redo(session.getBlockBag(player), player);
if (redone == null) break;
@CommandPermissions({"worldedit.history.redo", "worldedit.history.redo.self"})
public void redo(Player player, LocalSession session,
@Arg(desc = "Number of redoes to perform", def = "1")
int times,
@Arg(name = "player", desc = "Redo this player's operations", def = "")
String playerName) throws WorldEditException {
times = Math.max(1, times);
LocalSession redoSession = session;
if (playerName != null) {
player.checkPermission("worldedit.history.redo.other");
redoSession = worldEdit.getSessionManager().findByName(playerName);
if (redoSession == null) {
player.printError("Unable to find session for " + playerName);
return;
}
}
if (redone == null) i--;
if (i > 0) {
BBC.COMMAND_REDO_SUCCESS.send(player, i == 1 ? "" : " x" + i);
worldEdit.flushBlockBag(player, redone);
int timesRedone = 0;
for (int i = 0; i < times; ++i) {
EditSession redone = redoSession.redo(redoSession.getBlockBag(player), player);
if (redone != null) {
timesRedone++;
worldEdit.flushBlockBag(player, redone);
} else {
break;
}
}
if (redone == null) {
if (timesRedone > 0) {
player.print("Redid " + timesRedone + " available edits.");
} else {
BBC.COMMAND_REDO_ERROR.send(player);
}
}
@Command(
aliases = {"/clearhistory", "clearhistory"},
usage = "",
desc = "Clear your history",
min = 0,
max = 0
name = "clearhistory",
aliases = { "/clearhistory" },
desc = "Clear your history"
)
@CommandPermissions("worldedit.history.clear")
public void clearHistory(Player player, LocalSession session) throws WorldEditException {
public void clearHistory(Player player, LocalSession session) {
session.clearHistory();
BBC.COMMAND_HISTORY_CLEAR.send(player);
}
}

View File

@@ -1,7 +1,7 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.object.mask.*;
import com.sk89q.minecraft.util.commands.Command;
import org.enginehub.piston.annotation.Command;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;

View File

@@ -1,7 +1,7 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.config.Commands;
import com.sk89q.minecraft.util.commands.Command;
import org.enginehub.piston.annotation.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandLocals;
import com.sk89q.minecraft.util.commands.CommandPermissions;
@@ -97,4 +97,4 @@ public class MethodCommands {
}
return new String[0];
}
}
}

View File

@@ -20,28 +20,26 @@
package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION;
import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.util.MathMan;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
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.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
/**
* Commands for moving the player around.
*/
@Command(aliases = {}, desc = "Commands for moving the player around: [More Info](https://goo.gl/uQTUiT)")
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class NavigationCommands {
private final WorldEdit worldEdit;
@@ -57,11 +55,9 @@ public class NavigationCommands {
}
@Command(
aliases = { "unstuck", "!" },
usage = "",
desc = "Escape from being stuck inside a block",
min = 0,
max = 0
name = "unstuck",
aliases = { "!" },
desc = "Escape from being stuck inside a block"
)
@CommandPermissions("worldedit.navigation.unstuck")
public void unstuck(Player player) throws WorldEditException {
@@ -70,18 +66,18 @@ public class NavigationCommands {
}
@Command(
aliases = {"ascend", "asc"},
usage = "[# of levels]",
desc = "Go up a floor",
min = 0,
max = 1
name = "ascend",
aliases = { "asc" },
desc = "Go up a floor"
)
@CommandPermissions("worldedit.navigation.ascend")
public void ascend(Player player, @Optional("1") int levelsToAscend) throws WorldEditException {
public void ascend(Player player,
@Arg(desc = "# of levels to ascend", def = "1")
int levels) throws WorldEditException {
int ascentLevels = 0;
while (player.ascendLevel()) {
++ascentLevels;
if (levelsToAscend == ascentLevels) {
if (levels == ascentLevels) {
break;
}
}
@@ -97,48 +93,46 @@ public class NavigationCommands {
}
@Command(
aliases = {"descend", "desc"},
usage = "[# of floors]",
desc = "Go down a floor",
min = 0,
max = 1
name = "descend",
aliases = { "desc" },
desc = "Go down a floor"
)
@CommandPermissions("worldedit.navigation.descend")
public void descend(Player player, @Optional("1") int levelsToDescend) throws WorldEditException {
public void descend(Player player,
@Arg(desc = "# of levels to descend", def = "1")
int levels) throws WorldEditException {
int descentLevels = 0;
while (player.descendLevel()) {
++descentLevels;
if (levelsToDescend == descentLevels) {
if (levels == descentLevels) {
break;
}
}
if (descentLevels == 0) {
BBC.DESCEND_FAIL.send(player);
} else if (descentLevels == 1) {
BBC.DESCEND_SINGULAR.send(player);
} else {
if (descentLevels == 1) {
BBC.DESCEND_SINGULAR.send(player);
} else {
BBC.DESCEND_PLURAL.send(player, descentLevels);
}
BBC.DESCEND_PLURAL.send(player, descentLevels);
}
}
@Command(
aliases = {"ceil"},
usage = "[clearance]",
desc = "Go to the celing",
flags = "fg",
min = 0,
max = 1
name = "ceil",
desc = "Go to the ceiling"
)
@CommandPermissions("worldedit.navigation.ceiling")
@Logging(POSITION)
public void ceiling(Player player, CommandContext args) throws WorldEditException {
public void ceiling(Player player,
@Arg(desc = "# of blocks to leave above you", def = "0")
int clearance,
@Switch(name = 'f', desc = "Force using flight to keep you still")
boolean forceFlight,
@Switch(name = 'g', desc = "Force using glass to keep you still")
boolean forceGlass) throws WorldEditException {
clearance = Math.max(0, clearance);
final int clearance = args.argsLength() > 0 ?
Math.max(0, args.getInteger(0)) : 0;
final boolean alwaysGlass = getAlwaysGlass(args);
boolean alwaysGlass = getAlwaysGlass(forceFlight, forceGlass);
if (player.ascendToCeiling(clearance, alwaysGlass)) {
BBC.WHOOSH.send(player);
} else {
@@ -147,11 +141,8 @@ public class NavigationCommands {
}
@Command(
aliases = {"thru"},
usage = "",
desc = "Passthrough walls",
min = 0,
max = 0
name = "thru",
desc = "Pass through walls"
)
@CommandPermissions("worldedit.navigation.thru.command")
public void thru(Player player) throws WorldEditException {
@@ -163,33 +154,16 @@ public class NavigationCommands {
}
@Command(
aliases = {"jumpto", "j"},
usage = "[world,x,y,z]",
desc = "Teleport to a location\n" +
"Flags:" +
" -f forces the specified position to be used",
flags = "f",
min = 0,
max = 1
name = "jumpto",
aliases = { "j" },
desc = "Teleport to a location"
)
@CommandPermissions("worldedit.navigation.jumpto.command")
public void jumpTo(Player player, LocalSession session, CommandContext args) throws WorldEditException {
Location pos;
if (args.argsLength() == 1) {
String arg = args.getString(0);
String[] split = arg.split(",");
World world = FaweAPI.getWorld(split[0]);
if (world != null && split.length == 4 && MathMan.isInteger(split[1]) && MathMan.isInteger(split[2]) && MathMan.isInteger(split[3])) {
pos = new Location(world, Integer.parseInt(split[1]), Integer.parseInt(split[2]), Integer.parseInt(split[3]));
} else {
BBC.SELECTOR_INVALID_COORDINATES.send(player, args.getString(0));
return;
}
} else {
pos = player.getSolidBlockTrace(300);
}
public void jumpTo(Player player) throws WorldEditException {
Location pos = player.getSolidBlockTrace(300);
if (pos != null) {
if(args.hasFlag('f')) player.setPosition(pos); else player.findFreePosition(pos);
player.findFreePosition(pos);
BBC.POOF.send(player);
} else {
BBC.NO_BLOCK.send(player);
@@ -197,19 +171,19 @@ public class NavigationCommands {
}
@Command(
aliases = {"up"},
usage = "<number>",
desc = "Go upwards some distance",
flags = "fg",
min = 1,
max = 1
name = "up",
desc = "Go upwards some distance"
)
@CommandPermissions("worldedit.navigation.up")
@Logging(POSITION)
public void up(Player player, CommandContext args) throws WorldEditException {
final int distance = args.getInteger(0);
final boolean alwaysGlass = getAlwaysGlass(args);
public void up(Player player,
@Arg(desc = "Distance to go upwards")
int distance,
@Switch(name = 'f', desc = "Force using flight to keep you still")
boolean forceFlight,
@Switch(name = 'g', desc = "Force using glass to keep you still")
boolean forceGlass) throws WorldEditException {
boolean alwaysGlass = getAlwaysGlass(forceFlight, forceGlass);
if (player.ascendUpwards(distance, alwaysGlass)) {
BBC.WHOOSH.send(player);
} else {
@@ -220,17 +194,13 @@ public class NavigationCommands {
/**
* Helper function for /up and /ceil.
*
* @param args The {@link CommandContext} to extract the flags from.
* @param forceFlight if flight should be used, rather than the default config option
* @param forceGlass if glass should always be placed, rather than the default config option
* @return true, if glass should always be put under the player
*/
private boolean getAlwaysGlass(CommandContext args) {
private boolean getAlwaysGlass(boolean forceFlight, boolean forceGlass) {
final LocalConfiguration config = worldEdit.getConfiguration();
final boolean forceFlight = args.hasFlag('f');
final boolean forceGlass = args.hasFlag('g');
return forceGlass || (config.navigationUseGlass && !forceFlight);
}
}

View File

@@ -12,7 +12,7 @@ import com.boydti.fawe.util.TextureUtil;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Sets;
import com.sk89q.minecraft.util.commands.Command;
import org.enginehub.piston.annotation.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession;

View File

@@ -0,0 +1,150 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.command.factory.ItemUseFactory;
import com.sk89q.worldedit.command.factory.ReplaceFactory;
import com.sk89q.worldedit.command.factory.TreeGeneratorFactory;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.PermissionCondition;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.factory.Paint;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.command.CommandRegistrationHandler;
import com.sk89q.worldedit.regions.factory.RegionFactory;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.CommandManagerService;
import org.enginehub.piston.CommandParameters;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.inject.Key;
import org.enginehub.piston.part.CommandArgument;
import org.enginehub.piston.part.SubCommandPart;
import java.util.stream.Collectors;
import static java.util.Objects.requireNonNull;
import static org.enginehub.piston.part.CommandParts.arg;
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class PaintBrushCommands {
private static final CommandArgument REGION_FACTORY = arg(TranslatableComponent.of("shape"), TextComponent.of("The shape of the region"))
.defaultsTo(ImmutableList.of())
.ofTypes(ImmutableList.of(Key.of(RegionFactory.class)))
.build();
private static final CommandArgument RADIUS = arg(TranslatableComponent.of("radius"), TextComponent.of("The size of the brush"))
.defaultsTo(ImmutableList.of("5"))
.ofTypes(ImmutableList.of(Key.of(double.class)))
.build();
private static final CommandArgument DENSITY = arg(TranslatableComponent.of("density"), TextComponent.of("The density of the brush"))
.defaultsTo(ImmutableList.of("20"))
.ofTypes(ImmutableList.of(Key.of(double.class)))
.build();
public static void register(CommandManagerService service, CommandManager commandManager, CommandRegistrationHandler registration) {
commandManager.register("paint", builder -> {
builder.description(TextComponent.of("Paint brush, apply a function to a surface"));
builder.action(org.enginehub.piston.Command.Action.NULL_ACTION);
CommandManager manager = service.newCommandManager();
registration.register(
manager,
PaintBrushCommandsRegistration.builder(),
new PaintBrushCommands()
);
builder.condition(new PermissionCondition(ImmutableSet.of("worldedit.brush.paint")));
builder.addParts(REGION_FACTORY, RADIUS, DENSITY);
builder.addPart(SubCommandPart.builder(TranslatableComponent.of("type"), TextComponent.of("Type of brush to use"))
.withCommands(manager.getAllCommands().collect(Collectors.toList()))
.required()
.build());
});
}
private void setPaintBrush(CommandParameters parameters, Player player, LocalSession localSession,
Contextual<? extends RegionFunction> generatorFactory) throws WorldEditException {
double radius = requireNonNull(RADIUS.value(parameters).asSingle(double.class));
double density = requireNonNull(DENSITY.value(parameters).asSingle(double.class)) / 100;
RegionFactory regionFactory = REGION_FACTORY.value(parameters).asSingle(RegionFactory.class);
BrushCommands.setOperationBasedBrush(player, localSession, radius,
new Paint(generatorFactory, density), regionFactory, "worldedit.brush.paint");
}
@Command(
name = "forest",
desc = "Plant trees"
)
public void forest(CommandParameters parameters,
Player player, LocalSession localSession,
@Arg(desc = "The type of tree to plant")
TreeGenerator.TreeType type) throws WorldEditException {
setPaintBrush(parameters, player, localSession, new TreeGeneratorFactory(type));
}
@Command(
name = "item",
desc = "Use an item"
)
@CommandPermissions("worldedit.brush.item")
public void item(CommandParameters parameters,
Player player, LocalSession localSession,
@Arg(desc = "The type of item to use")
BaseItem item,
@Arg(desc = "The direction in which the item will be applied", def = "up")
@Direction(includeDiagonals = true)
com.sk89q.worldedit.util.Direction direction) throws WorldEditException {
player.print(TextComponent.builder().append("WARNING: ", TextColor.RED, TextDecoration.BOLD)
.append("This brush simulates item usages. Its effects may not work on all platforms, may not be undo-able," +
" and may cause strange interactions with other mods/plugins. Use at your own risk.").build());
setPaintBrush(parameters, player, localSession, new ItemUseFactory(item, direction));
}
@Command(
name = "set",
desc = "Place a block"
)
public void set(CommandParameters parameters,
Player player, LocalSession localSession,
@Arg(desc = "The pattern of blocks to use")
Pattern pattern) throws WorldEditException {
setPaintBrush(parameters, player, localSession, new ReplaceFactory(pattern));
}
}

View File

@@ -8,7 +8,7 @@ import com.boydti.fawe.object.pattern.*;
import com.boydti.fawe.object.random.SimplexRandom;
import com.boydti.fawe.util.ColorUtil;
import com.boydti.fawe.util.TextureUtil;
import com.sk89q.minecraft.util.commands.Command;
import org.enginehub.piston.annotation.Command;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.InputParseException;
@@ -47,7 +47,7 @@ public class PatternCommands extends MethodCommands {
public PatternCommands(WorldEdit worldEdit) {
super(worldEdit);
}
@Command(
aliases = {"#existing", "#*", "*", ".*"},
desc = "Use the block that is already there",

View File

@@ -19,6 +19,16 @@
package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ORIENTATION_REGION;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument;
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.example.NMSMappedFaweQueue;
@@ -28,20 +38,14 @@ import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.visitor.Fast2DIterator;
import com.boydti.fawe.util.MathMan;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.ORIENTATION_REGION;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
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.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.function.GroundFunction;
@@ -67,31 +71,27 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.regions.Regions;
import static com.sk89q.worldedit.regions.Regions.asFlatRegion;
import static com.sk89q.worldedit.regions.Regions.maximumBlockY;
import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.util.command.binding.Range;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.binding.Text;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.biome.Biomes;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
/**
* Commands that operate on regions.
*/
@Command(aliases = {}, desc = "Commands that operate on regions: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Region_operations)")
public class RegionCommands extends MethodCommands {
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class RegionCommands {
private final WorldEdit worldEdit;
@@ -101,16 +101,13 @@ public class RegionCommands extends MethodCommands {
* @param worldEdit reference to WorldEdit
*/
public RegionCommands(WorldEdit worldEdit) {
super(worldEdit);
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
}
@Command(
aliases = {"/fixlighting"},
desc = "Get the light at a position",
min = 0,
max = 0
name = "/fixlighting",
desc = "Get the light at a position"
)
@CommandPermissions("worldedit.light.fix")
public void fixlighting(Player player) throws WorldEditException {
@@ -127,10 +124,8 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = {"/getlighting"},
desc = "Get the light at a position",
min = 0,
max = 0
name = "/getlighting",
desc = "Get the light at a position"
)
@CommandPermissions("worldedit.light.fix")
public void getlighting(Player player) throws WorldEditException {
@@ -141,10 +136,8 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = {"/removelight", "/removelighting"},
desc = "Removing lighting in a selection",
min = 0,
max = 0
name = "/removelighting",
desc = "Removing lighting in a selection"
)
@CommandPermissions("worldedit.light.remove")
public void removelighting(Player player) {
@@ -160,7 +153,7 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = {"/nbtinfo", "/nbt"},
name = "/nbtinfo",
desc = "View nbt info for a block"
)
@CommandPermissions("worldedit.nbtinfo")
@@ -179,10 +172,8 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = {"/setblocklight", "/setlight"},
desc = "Set block lighting in a selection",
min = 1,
max = 1
name = "/setblocklight",
desc = "Set block lighting in a selection"
)
@CommandPermissions("worldedit.light.set")
public void setlighting(Player player, @Selection Region region, @Range(min = 0, max = 15) int value) {
@@ -200,10 +191,8 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = {"/setskylight"},
desc = "Set sky lighting in a selection",
min = 1,
max = 1
name = "/setskylight"
desc = "Set sky lighting in a selection"
)
@CommandPermissions("worldedit.light.set")
public void setskylighting(Player player, @Selection Region region, @Range(min = 0, max = 15) int value) {
@@ -221,30 +210,25 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = { "/line" },
usage = "<pattern> [thickness]",
desc = "Draws a line segment between cuboid selection corners",
help =
"Draws a line segment between cuboid selection corners.\n" +
"Can only be used with cuboid selections.\n" +
"Flags:\n" +
" -h generates only a shell",
flags = "h",
min = 1,
max = 2
name = "/line",
desc = "Draws a line segment between cuboid selection corners",
descFooter = "Can only be used with a cuboid selection"
)
@CommandPermissions("worldedit.region.line")
@Logging(REGION)
public void line(Player player, EditSession editSession,
@Selection Region region,
Pattern pattern,
@Optional("0") @Range(min = 0) int thickness,
@Switch('h') boolean shell) throws WorldEditException {
public int line(Player player, EditSession editSession,
@Selection Region region,
@Arg(desc = "The pattern of blocks to place")
Pattern pattern,
@Arg(desc = "The thickness of the line", def = "0")
int thickness,
@Switch(name = 'h', desc = "Generate only a shell")
boolean shell) throws WorldEditException {
if (!(region instanceof CuboidRegion)) {
player.printError("//line only works with cuboid selections");
return;
return 0;
}
checkCommandArgument(thickness >= 0, "Thickness must be >= 0");
CuboidRegion cuboidregion = (CuboidRegion) region;
BlockVector3 pos1 = cuboidregion.getPos1();
@@ -252,34 +236,30 @@ public class RegionCommands extends MethodCommands {
int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell);
BBC.VISITOR_BLOCK.send(player, blocksChanged);
return blocksChanged;
}
@Command(
aliases = {"/curve", "/spline"},
usage = "<pattern> [thickness]",
desc = "Draws a spline through selected points",
help =
"Draws a spline through selected points.\n" +
"Can only be used with convex polyhedral selections.\n" +
"Flags:\n" +
" -h generates only a shell",
flags = "h",
min = 1,
max = 2
name = "/curve",
desc = "Draws a spline through selected points",
descFooter = "Can only be used with a convex polyhedral selection"
)
@CommandPermissions("worldedit.region.curve")
@Logging(REGION)
public void curve(FawePlayer player, EditSession editSession,
@Selection Region region,
Pattern pattern,
@Optional("0") @Range(min = 0) int thickness,
@Switch('h') boolean shell,
@Arg(desc = "The pattern of blocks to place")
Pattern pattern,
@Arg(desc = "The thickness of the curve", def = "0")
int thickness,
@Switch(name = 'h', desc = "Generate only a shell")
boolean shell,
CommandContext context) throws WorldEditException {
if (!(region instanceof ConvexPolyhedralRegion)) {
player.sendMessage("//curve only works with convex polyhedral selections");
player.printError("//curve only works with convex polyhedral selections");
return;
}
worldEdit.checkMaxRadius(thickness);
checkCommandArgument(thickness >= 0, "Thickness must be >= 0");
player.checkConfirmationRegion(() -> {
ConvexPolyhedralRegion cpregion = (ConvexPolyhedralRegion) region;
@@ -292,12 +272,9 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = { "/replace", "/re", "/rep" },
usage = "[from-mask] <to-pattern>",
desc = "Replace all blocks in the selection with another",
flags = "f",
min = 1,
max = 2
name = "/replace",
aliases = { "/re", "/rep" },
desc = "Replace all blocks in the selection with another"
)
@CommandPermissions("worldedit.region.replace")
@Logging(REGION)
@@ -337,15 +314,14 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = { "/overlay" },
usage = "<pattern>",
desc = "Set a block on top of blocks in the region",
min = 1,
max = 1
name = "/overlay",
desc = "Set a block on top of blocks in the region"
)
@CommandPermissions("worldedit.region.overlay")
@Logging(REGION)
public void overlay(FawePlayer player, EditSession editSession, @Selection Region region, Pattern pattern, CommandContext context) throws WorldEditException {
public void overlay(FawePlayer player, EditSession editSession, @Selection Region region,
@Arg(desc = "The pattern of blocks to overlay")
Pattern pattern, CommandContext context) throws WorldEditException {
player.checkConfirmationRegion(() -> {
int affected = editSession.overlayCuboidBlocks(region, pattern);
BBC.VISITOR_BLOCK.send(player, affected);
@@ -363,13 +339,8 @@ public class RegionCommands extends MethodCommands {
@Logging(REGION)
public void lay(FawePlayer player, EditSession editSession, @Selection Region region, Pattern pattern, CommandContext context) throws WorldEditException {
player.checkConfirmationRegion(() -> {
BlockVector3 min = region.getMinimumPoint();
BlockVector3 max = region.getMaximumPoint();
BlockVector3 max = region.getMaximumPoint();
int maxY = max.getBlockY();
int width = region.getWidth();
int height = region.getLength();
int bx = min.getBlockX();
int bz = min.getBlockZ();
Iterable<BlockVector2> flat = Regions.asFlatRegion(region).asFlatRegion();
Iterator<BlockVector2> iter = new Fast2DIterator(flat, editSession).iterator();
int y = 0;
@@ -386,12 +357,10 @@ public class RegionCommands extends MethodCommands {
}, getArguments(context), region, context);
}
@Command(
aliases = { "/center", "/middle" },
usage = "<pattern>",
desc = "Set the center block(s)",
min = 1,
max = 1
@org.enginehub.piston.annotation.Command(
name = "/center",
aliases = { "/middle" },
desc = "Set the center block(s)"
)
@Logging(REGION)
@CommandPermissions("worldedit.region.center")
@@ -401,11 +370,8 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = { "/naturalize" },
usage = "",
desc = "3 layers of dirt on top then rock below",
min = 0,
max = 0
name = "/naturalize",
desc = "3 layers of dirt on top then rock below"
)
@CommandPermissions("worldedit.region.naturalize")
@Logging(REGION)
@@ -417,11 +383,8 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = { "/walls" },
usage = "<pattern>",
desc = "Build the four sides of the selection",
min = 1,
max = 1
name = "/walls",
desc = "Build the four sides of the selection"
)
@CommandPermissions("worldedit.region.walls")
@Logging(REGION)
@@ -433,11 +396,9 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = { "/faces", "/outline" },
usage = "<pattern>",
desc = "Build the walls, ceiling, and floor of a selection",
min = 1,
max = 1
name = "/faces",
aliases = { "/outline" },
desc = "Build the walls, ceiling, and floor of a selection"
)
@CommandPermissions("worldedit.region.faces")
@Logging(REGION)
@@ -449,15 +410,9 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = { "/smooth" },
usage = "[iterations] [filter]",
name = "/smooth",
desc = "Smooth the elevation in the selection",
help =
"Smooths the elevation in the selection.\n" +
"Optionally, restricts the height map to a set of blocks specified with mask syntax.\n" +
"For example, '//smooth 1 grass_block,dirt,stone' would only smooth natural surface terrain.",
min = 0,
max = 2
descFooter = "Example: '//smooth 1 grass_block,dirt,stone' would only smooth natural surface terrain."
)
@CommandPermissions("worldedit.region.smooth")
@Logging(REGION)
@@ -524,20 +479,27 @@ public class RegionCommands extends MethodCommands {
"The -e ignores entities\n" +
"The -a ignores air blocks.\n" +
"Optionally fills the old location with <leave-id>.",
min = 0,
max = 3
)
@CommandPermissions("worldedit.region.move")
@Logging(ORIENTATION_REGION)
public void move(FawePlayer player, LocalSession session, EditSession editSession,
@Selection Region region,
@Optional("1") @Range(min = 1) int count,
@Optional(Direction.AIM) @Direction(includeDiagonals = true) BlockVector3 direction,
@Optional("air") Pattern replace,
@Switch('b') boolean copyBiomes,
@Arg(desc = "# of blocks to move", def = "1")
int count,
@Arg(desc = "The direction to move", def = Direction.AIM)
@Direction(includeDiagonals = true)
BlockVector3 direction,
@Arg(desc = "The pattern of blocks to leave", def = "air")
Pattern replace,
@Switch(name = 's', desc = "Shift the selection to the target location")
boolean moveSelection,
@Switch(name = 'a', desc = "Ignore air blocks")
boolean ignoreAirBlocks
@Switch('b') boolean copyBiomes,
@Switch('e') boolean skipEntities,
@Switch('a') boolean skipAir,
@Switch('s') boolean moveSelection,
CommandContext context) throws WorldEditException {
player.checkConfirmationRegion(() -> {
int affected = editSession.moveRegion(region, direction, count, !skipAir, !skipEntities, copyBiomes, replace);
@@ -549,7 +511,7 @@ public class RegionCommands extends MethodCommands {
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player.getPlayer(), session);
} catch (RegionOperationException e) {
player.sendMessage(e.getMessage());
player.printError(e.getMessage());
}
}
@@ -562,10 +524,8 @@ public class RegionCommands extends MethodCommands {
usage = "[replace]",
flags = "m",
desc = "Have the blocks in the selection fall",
help =
"Make the blocks in the selection fall\n" +
"The -m flag will only fall within the vertical selection.",
min = 0,
help = "Make the blocks in the selection fall\n" +
"The -m flag will only fall within the vertical selection.",
max = 2
)
@CommandPermissions("worldedit.region.fall")
@@ -582,28 +542,24 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = { "/stack" },
usage = "[count] [direction]",
flags = "sam",
desc = "Repeat the contents of the selection",
help =
"Repeats the contents of the selection.\n" +
"Flags:\n" +
" -s shifts the selection to the last stacked copy\n" +
" -a skips air blocks",
min = 0,
max = 2
name = "/stack",
desc = "Repeat the contents of the selection"
)
@CommandPermissions("worldedit.region.stack")
@Logging(ORIENTATION_REGION)
public void stack(FawePlayer player, EditSession editSession, LocalSession session,
@Selection Region region,
@Optional("1") @Range(min = 1) int count,
@Optional(Direction.AIM) @Direction(includeDiagonals = true) BlockVector3 direction,
@Switch('s') boolean moveSelection,
@Switch('b') boolean copyBiomes,
@Switch('e') boolean skipEntities,
@Switch('a') boolean ignoreAirBlocks, @Switch('m') Mask sourceMask, CommandContext context) throws WorldEditException {
@Arg(desc = "# of copies to stack", def = "1")
int count,
@Arg(desc = "The direction to stack", def = Direction.AIM)
@Direction(includeDiagonals = true)
BlockVector3 direction,
@Switch(name = 's', desc = "Shift the selection to the last stacked copy")
boolean moveSelection,
@Switch(name = 'b', desc = "//TODO") boolean copyBiomes,
@Switch(name = 'e', desc = "//TODO") boolean skipEntities,
@Switch(name = 'a', desc = "Ignore air blocks")
boolean ignoreAirBlocks, @Switch('m') Mask sourceMask, CommandContext context) throws WorldEditException {
player.checkConfirmationStack(() -> {
if (sourceMask != null) {
editSession.addSourceMask(sourceMask);
@@ -637,17 +593,18 @@ public class RegionCommands extends MethodCommands {
"to modify the variables x, y and z to point to a new block\n" +
"to fetch. See also tinyurl.com/wesyntax.",
flags = "ro",
min = 1,
max = -1
min = 1
)
@CommandPermissions("worldedit.region.deform")
@Logging(ALL)
public void deform(FawePlayer fp, Player player, LocalSession session, EditSession editSession,
@Selection Region region,
@Text String expression,
@Switch('r') boolean useRawCoords,
@Switch('o') boolean offset,
CommandContext context) throws WorldEditException {
@Arg(desc = "The expression to use", variable = true)
List<String> expression,
@Switch(name = 'r', desc = "Use the game's coordinate origin")
boolean useRawCoords,
@Switch(name = 'o', desc = "Use the selection's center as origin")
boolean offset) throws WorldEditException {
final Vector3 zero;
Vector3 unit;
@@ -676,7 +633,7 @@ public class RegionCommands extends MethodCommands {
player.findFreePosition();
BBC.VISITOR_BLOCK.send(fp, affected);
} catch (ExpressionException e) {
fp.sendMessage(e.getMessage());
player.printError(e.getMessage());
}
}, getArguments(context), region, context);
}
@@ -689,7 +646,6 @@ public class RegionCommands extends MethodCommands {
"Regenerates the contents of the current selection.\n" +
"This command might affect things outside the selection,\n" +
"if they are within the same chunk.",
min = 0,
max = 2
)
@CommandPermissions("worldedit.regen")
@@ -697,7 +653,6 @@ public class RegionCommands extends MethodCommands {
public void regenerateChunk(FawePlayer player, LocalSession session, EditSession editSession, @Selection Region region, CommandContext context) throws WorldEditException {
player.checkConfirmationRegion(() -> {
Mask mask = session.getMask();
Mask sourceMask = session.getSourceMask();
session.setMask((Mask) null);
session.setSourceMask((Mask) null);
BiomeType biome = null;
@@ -730,19 +685,19 @@ public class RegionCommands extends MethodCommands {
aliases = { "/hollow" },
usage = "[<thickness>[ <pattern>]]",
desc = "Hollows out the object contained in this selection",
help =
"Hollows out the object contained in this selection.\n" +
help = "Hollows out the object contained in this selection.\n" +
"Optionally fills the hollowed out part with the given block.\n" +
"Thickness is measured in manhattan distance.",
min = 0,
max = 2
)
@CommandPermissions("worldedit.region.hollow")
@Logging(REGION)
public void hollow(FawePlayer player, EditSession editSession,
@Selection Region region,
@Optional("0") @Range(min = 0) int thickness,
@Optional("air") Pattern pattern,
@Arg(desc = "Thickness of the shell to leave", def = "0")
int thickness,
@Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air")
Pattern pattern,
CommandContext context) throws WorldEditException {
player.checkConfirmationRegion(() -> {
int affected = editSession.hollowOutRegion(region, thickness, pattern);
@@ -751,30 +706,29 @@ public class RegionCommands extends MethodCommands {
}
@Command(
aliases = { "/forest" },
usage = "[type] [density]",
desc = "Make a forest within the region",
min = 0,
max = 2
name = "/forest",
desc = "Make a forest within the region"
)
@CommandPermissions("worldedit.region.forest")
@Logging(REGION)
public void forest(Player player, EditSession editSession, @Selection Region region, @Optional("tree") TreeType type,
@Optional("5") @Range(min = 0, max = 100) double density) throws WorldEditException {
public void forest(Player player, EditSession editSession, @Selection Region region,
@Arg(desc = "The type of tree to place", def = "tree")
TreeType type,
@Arg(desc = "The density of the forest", def = "5")
double density) throws WorldEditException {
int affected = editSession.makeForest(region, density / 100, type);
BBC.COMMAND_TREE.send(player, affected);
}
@Command(
aliases = { "/flora" },
usage = "[density]",
desc = "Make flora within the region",
min = 0,
max = 1
name = "/flora",
desc = "Make flora within the region"
)
@CommandPermissions("worldedit.region.flora")
@Logging(REGION)
public void flora(FawePlayer player, EditSession editSession, @Selection Region region, @Optional("10") @Range(min = 0, max = 100) double density, CommandContext context) throws WorldEditException {
public void flora(FawePlayer player, EditSession editSession, @Selection Region region,
@Arg(desc = "The density of the forest", def = "5")
double density, CommandContext context) throws WorldEditException {
player.checkConfirmationRegion(() -> {
FloraGenerator generator = new FloraGenerator(editSession);
GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator);

View File

@@ -19,6 +19,9 @@
package com.sk89q.worldedit.command;
import static com.boydti.fawe.util.ReflectionUtils.as;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Commands;
import com.boydti.fawe.config.Settings;
@@ -28,79 +31,101 @@ import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
import com.boydti.fawe.object.clipboard.URIClipboardHolder;
import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper;
import com.boydti.fawe.object.schematic.StructureFormat;
//import com.boydti.fawe.object.schematic.visualizer.SchemVis;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.chat.Message;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
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.entity.Player;
import com.sk89q.worldedit.event.extent.PlayerSaveClipboardEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.io.Closer;
import com.sk89q.worldedit.util.io.file.FilenameException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.atomic.LongAdder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.regex.Pattern;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.exception.StopExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.boydti.fawe.util.ReflectionUtils.as;
//import com.boydti.fawe.object.schematic.visualizer.SchemVis;
/**
* Commands that work with schematic files.
*/
@Command(aliases = {"schematic", "schem", "/schematic", "/schem", "clipboard", "/clipboard"}, desc = "Commands that work with schematic files")
public class SchematicCommands extends MethodCommands {
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SchematicCommands {
/**
* 9 schematics per page fits in the MC chat window.
*/
private static final int SCHEMATICS_PER_PAGE = 9;
private static final Logger log = LoggerFactory.getLogger(SchematicCommands.class);
private final WorldEdit worldEdit;
/**
* Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/
public SchematicCommands(final WorldEdit worldEdit) {
super(worldEdit);
public SchematicCommands(WorldEdit worldEdit) {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
}
@Command(
aliases = {"loadall"},
usage = "[<format>] <filename|url>",
help = "Load multiple clipboards\n" +
"The -r flag will apply random rotation",
desc = "Load multiple clipboards (paste will randomly choose one)"
name = "loadall",
desc = "Load multiple clipboards (paste will randomly choose one)",
descFooter = "Load multiple clipboards (paste will randomly choose one)\n" +
"The -r flag will apply random rotation"
)
@Deprecated
@CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.load.web", "worldedit.schematic.load.asset"})
public void loadall(final Player player, final LocalSession session, @Optional("schematic") final String formatName, final String filename, @Switch('r') boolean randomRotate) throws FilenameException {
public void loadall(final Player player, final LocalSession session,
@Arg(desc = "Format name.", def = "schematic")
final String formatName,
@Arg(desc = "File name.")
final String filename,
@Switch(name = 'r', desc = "Apply random rotation")
boolean randomRotate) throws FilenameException {
final ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
if (format == null) {
BBC.CLIPBOARD_INVALID_FORMAT.send(player, formatName);
@@ -118,9 +143,8 @@ public class SchematicCommands extends MethodCommands {
}
@Command(
aliases = {"clear"},
desc = "Clear your clipboard",
max = 0
name = "clear",
desc = "Clear your clipboard"
)
@CommandPermissions({"worldedit.clipboard.clear", "worldedit.schematic.clear"})
public void clear(Player player, LocalSession session) throws WorldEditException {
@@ -129,11 +153,8 @@ public class SchematicCommands extends MethodCommands {
}
@Command(
aliases = {"unload"},
usage = "[file]",
desc = "Remove a clipboard from your multi-clipboard",
min = 1,
max = 1
name = "unload",
desc = "Remove a clipboard from your multi-clipboard"
)
@CommandPermissions({"worldedit.clipboard.clear", "worldedit.schematic.clear"})
public void unload(Player player, LocalSession session, String fileName) throws WorldEditException {
@@ -166,19 +187,13 @@ public class SchematicCommands extends MethodCommands {
}
@Command(
aliases = {"remap"},
help = "Remap a clipboard between MCPE/PC values",
name = "remap",
desc = "Remap a clipboard between MCPE/PC values"
)
@Deprecated
@CommandPermissions({"worldedit.schematic.remap"})
public void remap(final Player player, final LocalSession session) throws WorldEditException {
ClipboardRemapper remapper;
if (false) {
remapper = new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PC, ClipboardRemapper.RemapPlatform.PE);
} else {
remapper = new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PE, ClipboardRemapper.RemapPlatform.PC);
}
ClipboardRemapper remapper = new ClipboardRemapper(ClipboardRemapper.RemapPlatform.PE, ClipboardRemapper.RemapPlatform.PC);
for (Clipboard clip : session.getClipboard().getClipboards()) {
remapper.apply(clip);
@@ -187,13 +202,15 @@ public class SchematicCommands extends MethodCommands {
}
@Command(
aliases = {"load"},
usage = "[<format>] <filename>",
desc = "Load a schematic into your clipboard"
name = "load",
desc = "Load a schematic into your clipboard"
)
@Deprecated
@CommandPermissions({"worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.load.asset", "worldedit.schematic.load.web", "worldedit.schematic.load.other"})
public void load(Player player, LocalSession session, @Optional() String formatName, String filename) throws FilenameException {
public void load(Player player, LocalSession session,
@Arg(desc = "File name.")
String filename,
@Arg(desc = "Format name.", def = "sponge")
String formatName) throws FilenameException {
LocalConfiguration config = worldEdit.getConfiguration();
ClipboardFormat format = formatName == null ? null : ClipboardFormats.findByAlias(formatName);
InputStream in = null;
@@ -236,7 +253,7 @@ public class SchematicCommands extends MethodCommands {
return;
}
if (format == null && filename.matches(".*\\.[\\w].*")) {
String extension = filename.substring(filename.lastIndexOf('.') + 1, filename.length());
String extension = filename.substring(filename.lastIndexOf('.') + 1);
format = ClipboardFormats.findByExtension(extension);
}
f = MainUtil.resolve(dir, filename, format, false);
@@ -248,7 +265,7 @@ public class SchematicCommands extends MethodCommands {
}
}
if (f == null || !f.exists() || !MainUtil.isInSubDirectory(working, f)) {
player.printError("Schematic " + filename + " does not exist! (" + ((f != null) && f.exists()) + "|" + f + "|" + (f != null && !MainUtil.isInSubDirectory(working, f)) + ")");
player.printError("Schematic " + filename + " does not exist! (" + (f != null && f.exists()) + "|" + f + "|" + (f != null && !MainUtil.isInSubDirectory(working, f)) + ")");
return;
}
if (format == null) {
@@ -279,33 +296,58 @@ public class SchematicCommands extends MethodCommands {
}
@Command(
aliases = {"save"},
usage = "[format] <filename>",
desc = "Save a schematic into your clipboard",
help = "The default format for 1.13 is schem"
name = "save",
desc = "Save a schematic into your clipboard"
)
@Deprecated
@CommandPermissions({"worldedit.clipboard.save", "worldedit.schematic.save", "worldedit.schematic.save.other"})
public void save(Player player, LocalSession session, @Optional("schem") String formatName, String filename, @Switch('g') boolean global, @Switch('f') boolean allowOverwrite) throws CommandException, WorldEditException {
public void save(Player player, LocalSession session,
@Arg(desc = "File name.")
String filename,
@Arg(desc = "Format name.", def = "sponge")
String formatName,
@Switch(name = 'f', desc = "Overwrite an existing file.")
boolean allowOverwrite,
@Switch(name = 'g', desc = "//TODO")
boolean global
) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
if (!global && Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS) {
dir = new File(dir, player.getUniqueId().toString());
}
ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
if (format == null) {
player.printError("Unknown schematic format: " + formatName);
return;
}
File working = worldEdit.getWorkingDirectoryFile(config.saveDir);
File dir = !global && Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
if (filename.contains("../")) {
if (!player.hasPermission("worldedit.schematic.save.other")) {
BBC.NO_PERM.send(player, "worldedit.schematic.save.other");
return;
}
if (filename.startsWith("../")) {
dir = working;
dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
filename = filename.substring(3);
}
}
File f = worldEdit.getSafeSaveFile(player, dir, filename, format.getPrimaryFileExtension(), format.getPrimaryFileExtension());
File f = worldEdit.getSafeSaveFile(player, dir, filename, format.getPrimaryFileExtension());
boolean overwrite = f.exists();
if (overwrite) {
if (!player.hasPermission("worldedit.schematic.delete")) {
throw new StopExecutionException(TextComponent.of("That schematic already exists!"));
}
if (!allowOverwrite) {
player.printError("That schematic already exists. Use the -f flag to overwrite it.");
return;
}
}
if (f.getName().replaceAll("." + format.getPrimaryFileExtension(), "").isEmpty()) {
File directory = f.getParentFile();
if (directory.exists()) {
@@ -315,16 +357,13 @@ public class SchematicCommands extends MethodCommands {
f = new File(directory, "1." + format.getPrimaryFileExtension());
}
}
final File parent = f.getParentFile();
if ((parent != null) && !parent.exists()) {
// Create parent directories
File parent = f.getParentFile();
if (parent != null && !parent.exists()) {
if (!parent.mkdirs()) {
try {
Files.createDirectories(parent.toPath());
} catch (IOException e) {
e.printStackTrace();
log.info("Could not create folder for schematics!");
return;
}
throw new StopExecutionException(TextComponent.of(
"Could not create folder for schematics!"));
}
}
try {
@@ -333,8 +372,10 @@ public class SchematicCommands extends MethodCommands {
} else if (!allowOverwrite) {
BBC.SCHEMATIC_MOVE_EXISTS.send(player, f.getName());
}
ClipboardHolder holder = session.getClipboard();
try (FileOutputStream fos = new FileOutputStream(f)) {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
Transform transform = holder.getTransform();
Clipboard target;
@@ -350,7 +391,9 @@ public class SchematicCommands extends MethodCommands {
}
URI uri = null;
if (holder instanceof URIClipboardHolder) uri = ((URIClipboardHolder) holder).getURI(clipboard);
if (holder instanceof URIClipboardHolder) {
uri = ((URIClipboardHolder) holder).getURI(clipboard);
}
if (new PlayerSaveClipboardEvent(player, clipboard, uri, f.toURI()).call()) {
try (ClipboardWriter writer = format.getWriter(fos)) {
if (writer instanceof StructureFormat) {
@@ -376,12 +419,9 @@ public class SchematicCommands extends MethodCommands {
}
@Command(
aliases = {"move", "m"},
usage = "<directory>",
desc = "Move your loaded schematic",
help = "Move your currently loaded schematics",
min = 1,
max = 1
name = "move",
aliases = {"m"},
desc = "Move your loaded schematic"
)
@CommandPermissions({"worldedit.schematic.move", "worldedit.schematic.move.other"})
public void move(Player player, LocalSession session, String directory) throws WorldEditException, IOException {
@@ -429,55 +469,53 @@ public class SchematicCommands extends MethodCommands {
}
@Command(
aliases = {"delete", "d"},
usage = "<filename|*>",
desc = "Delete a saved schematic",
help = "Delete a schematic from the schematic list",
min = 1,
max = 1
name = "delete",
aliases = {"d"},
desc = "Delete a saved schematic"
)
@CommandPermissions({"worldedit.schematic.delete", "worldedit.schematic.delete.other"})
public void delete(final Player player, final LocalSession session, final CommandContext args) throws WorldEditException, IOException {
final LocalConfiguration config = this.worldEdit.getConfiguration();
final File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
final File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
public void delete(Actor actor, LocalSession session,
@Arg(desc = "File name.")
String filename) throws WorldEditException, IOException {
LocalConfiguration config = worldEdit.getConfiguration();
File working = worldEdit.getWorkingDirectoryFile(config.saveDir);
File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, actor.getUniqueId().toString()) : working;
List<File> files = new ArrayList<>();
final String filename = args.getString(0);
if (filename.equalsIgnoreCase("*")) {
files.addAll(getFiles(session.getClipboard()));
} else {
File f = MainUtil.resolveRelative(new File(dir, filename));
files.add(f);
}
if (files.isEmpty()) {
BBC.SCHEMATIC_NONE.send(player);
BBC.SCHEMATIC_NONE.send(actor);
return;
}
for (File f : files) {
if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) {
player.printError("Schematic " + filename + " does not exist! (" + f.exists() + "|" + f + "|" + (!MainUtil.isInSubDirectory(working, f)) + ")");
actor.printError("Schematic " + filename + " does not exist! (" + f.exists() + "|" + f + "|" + (!MainUtil.isInSubDirectory(working, f)) + ")");
continue;
}
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !player.hasPermission("worldedit.schematic.delete.other")) {
BBC.NO_PERM.send(player, "worldedit.schematic.delete.other");
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !actor.hasPermission("worldedit.schematic.delete.other")) {
BBC.NO_PERM.send(actor, "worldedit.schematic.delete.other");
continue;
}
if (!delete(f)) {
player.printError("Deletion of " + filename + " failed! Maybe it is read-only.");
if (!f.delete()) {
actor.printError("Deletion of " + filename + " failed! Maybe it is read-only.");
continue;
}
BBC.FILE_DELETED.send(player, filename);
BBC.FILE_DELETED.send(actor, filename);
}
}
private List<File> getFiles(ClipboardHolder clipboard) {
List<File> files = new ArrayList<>();
Collection<URI> uris = Collections.emptyList();
if (clipboard instanceof URIClipboardHolder) {
uris = ((URIClipboardHolder) clipboard).getURIs();
}
List<File> files = new ArrayList<>();
for (URI uri : uris) {
File file = new File(uri);
if (file.exists()) files.add(file);
@@ -485,40 +523,29 @@ public class SchematicCommands extends MethodCommands {
return files;
}
private boolean delete(File file) {
if (file.delete()) {
new File(file.getParentFile(), "." + file.getName() + ".cached").delete();
return true;
}
return false;
}
@Command(
aliases = {"formats", "listformats", "f"},
desc = "List available formats",
max = 0
name = "formats",
aliases = {"listformats", "f"},
desc = "List available formats"
)
@CommandPermissions("worldedit.schematic.formats")
public void formats(final Actor actor) throws WorldEditException {
BBC.SCHEMATIC_FORMAT.send(actor);
Message m = new Message(BBC.SCHEMATIC_FORMAT).newline();
String baseCmd = Commands.getAlias(SchematicCommands.class, "schematic") + " " + Commands.getAlias(SchematicCommands.class, "save");
public void formats(Actor actor) {
actor.print("Available clipboard formats (Name: Lookup names)");
StringBuilder builder;
boolean first = true;
for (final ClipboardFormat format : ClipboardFormats.getAll()) {
StringBuilder builder = new StringBuilder();
for (ClipboardFormat format : ClipboardFormats.getAll()) {
builder = new StringBuilder();
builder.append(format.getName()).append(": ");
for (final String lookupName : format.getAliases()) {
for (String lookupName : format.getAliases()) {
if (!first) {
builder.append(", ");
}
builder.append(lookupName);
first = false;
}
String cmd = baseCmd + " " + format.getName() + " <filename>";
m.text(builder).suggestTip(cmd).newline();
first = true;
actor.print(builder.toString());
}
m.send(actor);
}
@@ -587,25 +614,21 @@ public class SchematicCommands extends MethodCommands {
*/
@Command(
aliases = {"list", "ls", "all"},
desc = "List saved schematics",
usage = "[global|mine|<filter>] [page=1]",
flags = "dnp",
help = "List all schematics in the schematics directory\n" +
" -p <page> prints the requested page\n" +
" -f <format> restricts by format\n"
name = "list",
aliases = {"all", "ls"},
desc = "List saved schematics",
descFooter = "Note: Format is not fully verified until loading."
)
@CommandPermissions("worldedit.schematic.list")
public void list(FawePlayer fp, Actor actor, CommandContext args, @Switch('p') @Optional("1") int page, @Switch('f') String formatName) throws WorldEditException {
if (args.argsLength() == 0) {
BBC.COMMAND_SYNTAX.send(fp, getCommand().usage());
return;
}
public void list(FawePlayer fp, Actor actor, CommandContext args,
@ArgFlag(name = 'p', desc = "Page to view.", def = "1")
int page,
@Switch(name = 'f', desc = "Restricts by format.")
String formatName) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
String prefix = config.noDoubleSlash ? "" : "/";
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
String schemCmd = prefix + Commands.getAlias(SchematicCommands.class, "schematic");
String schemCmd = "/" + Commands.getAlias(SchematicCommands.class, "schematic");
String loadSingle = schemCmd + " " + Commands.getAlias(SchematicCommands.class, "load");
String loadMulti = schemCmd + " " + Commands.getAlias(SchematicCommands.class, "loadall");
String unload = schemCmd + " " + Commands.getAlias(SchematicCommands.class, "unload");
@@ -623,7 +646,6 @@ public class SchematicCommands extends MethodCommands {
boolean loaded = multi != null && multi.contains(uri);
String name = relFilePath;
String color;
String uriStr = uri.toString();
if (uriStr.startsWith("file:/")) {
File file = new File(uri.getPath());
@@ -635,38 +657,163 @@ public class SchematicCommands extends MethodCommands {
} catch (IOException ignore) {}
if (file.isDirectory()) {
isDir = true;
color = "&6";
} else {
color = "&a";
if (name.indexOf('.') != -1) name = name.substring(0, name.lastIndexOf('.'));
} else if (name.indexOf('.') != -1) {
name = name.substring(0, name.lastIndexOf('.'));
}
} else if (uriStr.startsWith("http://") || uriStr.startsWith("https://")) {
// url
color = "&9";
} else {
color = "&7";
}
} // url
msg.text("&8 - ");
msg.text(" - ");
if (msg.supportsInteraction()) {
if (loaded) {
msg.text("&7[&c-&7]").command(unload + " " + relFilePath).tooltip("Unload");
msg.text("[-]").command(unload + " " + relFilePath).tooltip("Unload");
} else {
msg.text("&7[&a+&7]").command(loadMulti + " " + relFilePath).tooltip("Add to clipboard");
msg.text("[+]").command(loadMulti + " " + relFilePath).tooltip("Add to clipboard");
}
if (!isDir) msg.text("&7[&cX&7]").suggest("/" + delete + " " + relFilePath).tooltip("Delete");
else if (hasShow) msg.text("&7[&3O&7]").command(showCmd + " " + args.getJoinedStrings(0) + " " + relFilePath).tooltip("Show");
msg.text(color + name);
if (!isDir) msg.text("[X]").suggest("/" + delete + " " + relFilePath).tooltip("Delete");
else if (hasShow) msg.text("[O]").command(showCmd + " " + args.getJoinedStrings(0) + " " + relFilePath).tooltip("Show");
msg.text(name);
if (isDir) {
msg.command(list + " " + relFilePath).tooltip("List");
} else {
msg.command(loadSingle + " " + relFilePath).tooltip("Load");
}
} else {
msg.text(color).text(name);
msg.text(name);
}
}
});
}
private static class SchematicLoadTask implements Callable<ClipboardHolder> {
private final Player player;
private final File file;
private final ClipboardFormat format;
SchematicLoadTask(Player player, File file, ClipboardFormat format) {
this.player = player;
this.file = file;
this.format = format;
}
@Override
public ClipboardHolder call() throws Exception {
try (Closer closer = Closer.create()) {
FileInputStream fis = closer.register(new FileInputStream(file));
BufferedInputStream bis = closer.register(new BufferedInputStream(fis));
ClipboardReader reader = closer.register(format.getReader(bis));
Clipboard clipboard = reader.read();
log.info(player.getName() + " loaded " + file.getCanonicalPath());
return new ClipboardHolder(clipboard);
}
}
}
private static class SchematicSaveTask implements Callable<Void> {
private final Player player;
private final File file;
private final ClipboardFormat format;
private final ClipboardHolder holder;
private final boolean overwrite;
SchematicSaveTask(Player player, File file, ClipboardFormat format, ClipboardHolder holder, boolean overwrite) {
this.player = player;
this.file = file;
this.format = format;
this.holder = holder;
this.overwrite = overwrite;
}
@Override
public Void call() throws Exception {
Clipboard clipboard = holder.getClipboard();
Transform transform = holder.getTransform();
Clipboard target;
// If we have a transform, bake it into the copy
if (transform.isIdentity()) {
target = clipboard;
} else {
FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform);
target = new BlockArrayClipboard(result.getTransformedRegion());
target.setOrigin(clipboard.getOrigin());
Operations.completeLegacy(result.copyTo(target));
}
try (Closer closer = Closer.create()) {
FileOutputStream fos = closer.register(new FileOutputStream(file));
BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
ClipboardWriter writer = closer.register(format.getWriter(bos));
writer.write(target);
log.info(player.getName() + " saved " + file.getCanonicalPath() + (overwrite ? " (overwriting previous file)" : ""));
}
return null;
}
}
private static class SchematicListTask implements Callable<Component> {
private final String prefix;
private final int sortType;
private final int page;
private final File rootDir;
private final String pageCommand;
SchematicListTask(String prefix, int sortType, int page, String pageCommand) {
this.prefix = prefix;
this.sortType = sortType;
this.page = page;
this.rootDir = WorldEdit.getInstance().getWorkingDirectoryFile(prefix);
this.pageCommand = pageCommand;
}
@Override
public Component call() throws Exception {
List<File> fileList = allFiles(rootDir);
if (fileList == null || fileList.isEmpty()) {
return ErrorFormat.wrap("No schematics found.");
}
File[] files = new File[fileList.size()];
fileList.toArray(files);
// cleanup file list
Arrays.sort(files, (f1, f2) -> {
// http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified
int res;
if (sortType == 0) { // use name by default
int p = f1.getParent().compareTo(f2.getParent());
if (p == 0) { // same parent, compare names
res = f1.getName().compareTo(f2.getName());
} else { // different parent, sort by that
res = p;
}
} else {
res = Long.compare(f1.lastModified(), f2.lastModified()); // use date if there is a flag
if (sortType == 1) res = -res; // flip date for newest first instead of oldest first
}
return res;
});
PaginationBox paginationBox = new SchematicPaginationBox(prefix, files, pageCommand);
return paginationBox.create(page);
}
}
private static List<File> allFiles(File root) {
File[] files = root.listFiles();
if (files == null) return null;
List<File> fileList = new ArrayList<>();
for (File f : files) {
if (f.isDirectory()) {
List<File> subFiles = allFiles(f);
if (subFiles == null) continue; // empty subdir
fileList.addAll(subFiles);
} else {
fileList.add(f);
}
}
return fileList;
}
}

View File

@@ -19,39 +19,48 @@
package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.wrappers.LocationMaskedPlayerWrapper;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.LocalSession;
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.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
import com.sk89q.worldedit.scripting.CraftScriptContext;
import com.sk89q.worldedit.scripting.CraftScriptEngine;
import com.sk89q.worldedit.scripting.RhinoCraftScriptEngine;
import com.sk89q.worldedit.session.request.Request;
import org.mozilla.javascript.NativeJavaObject;
import javax.annotation.Nullable;
import javax.script.ScriptException;
import java.io.*;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import javax.script.ScriptException;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.mozilla.javascript.NativeJavaObject;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.ALL;
/**
* Commands related to scripting.
*/
@Command(aliases = {}, desc = "Run craftscripts: [More Info](https://goo.gl/dHDxLG)")
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ScriptingCommands {
private final WorldEdit worldEdit;
@@ -61,21 +70,18 @@ public class ScriptingCommands {
*
* @param worldEdit reference to WorldEdit
*/
public ScriptingCommands(final WorldEdit worldEdit) {
public ScriptingCommands(WorldEdit worldEdit) {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
}
@Command(
aliases = {"setupdispatcher"},
desc = "",
usage = "",
min = 1,
max = 1
name = "setupdispatcher",
desc = ""
)
@CommandPermissions("fawe.setupdispatcher")
public void setupdispatcher(Player player, LocalSession session, final CommandContext args) throws WorldEditException {
CommandManager.getInstance().setupDispatcher();
PlatformCommandManager.getInstance().setupDispatcher();
}
public static <T> T runScript(Player player, File f, String[] args) throws WorldEditException {
@@ -112,7 +118,7 @@ public class ScriptingCommands {
byte[] data = new byte[in.available()];
in.readFully(data);
in.close();
script = new String(data, 0, data.length, "utf-8");
script = new String(data, 0, data.length, StandardCharsets.UTF_8);
} catch (IOException e) {
actor.printError("Script read error: " + e.getMessage());
return null;
@@ -157,9 +163,7 @@ public class ScriptingCommands {
e.printStackTrace();
actor.printError("Failed to execute:");
actor.printRaw(e.getMessage());
} catch (NumberFormatException e) {
throw e;
} catch (WorldEditException e) {
} catch (NumberFormatException | WorldEditException e) {
throw e;
} catch (Throwable e) {
actor.printError("Failed to execute (see console):");
@@ -172,22 +176,25 @@ public class ScriptingCommands {
return (T) result;
}
@Command(aliases = {"cs"}, usage = "<filename> [args...]", desc = "Execute a CraftScript", min = 1, max = -1)
@Command(
name = "cs",
desc = "Execute a CraftScript"
)
@CommandPermissions("worldedit.scripting.execute")
@Logging(ALL)
public void execute(final Player player, final LocalSession session, final CommandContext args) throws WorldEditException {
public void execute(Player player, LocalSession session, CommandContext args) throws WorldEditException {
final String[] scriptArgs = args.getSlice(1);
final String name = args.getString(0);
final String filename = args.getString(0);
if (!player.hasPermission("worldedit.scripting.execute." + name)) {
if (!player.hasPermission("worldedit.scripting.execute." + filename)) {
BBC.SCRIPTING_NO_PERM.send(player);
return;
}
session.setLastScript(name);
session.setLastScript(filename);
final File dir = this.worldEdit.getWorkingDirectoryFile(this.worldEdit.getConfiguration().scriptsDir);
final File f = this.worldEdit.getSafeOpenFile(player, dir, name, "js", "js");
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
File f = worldEdit.getSafeOpenFile(player, dir, filename, "js", "js");
try {
new RhinoCraftScriptEngine();
} catch (NoClassDefFoundError e) {
@@ -200,10 +207,15 @@ public class ScriptingCommands {
runScript(LocationMaskedPlayerWrapper.unwrap(player), f, scriptArgs);
}
@Command(aliases = {".s"}, usage = "[args...]", desc = "Execute last CraftScript", min = 0, max = -1)
@Command(
name = ".s",
desc = "Execute last CraftScript"
)
@CommandPermissions("worldedit.scripting.execute")
@Logging(ALL)
public void executeLast(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void executeLast(Player player, LocalSession session,
@Arg(desc = "Arguments to the CraftScript", def = "", variable = true)
List<String> args) throws WorldEditException {
String lastScript = session.getLastScript();
@@ -217,17 +229,10 @@ public class ScriptingCommands {
return;
}
final String[] scriptArgs = args.getSlice(0);
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js");
final File dir = this.worldEdit.getWorkingDirectoryFile(this.worldEdit.getConfiguration().scriptsDir);
final File f = this.worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js");
try {
this.worldEdit.runScript(LocationMaskedPlayerWrapper.unwrap(player), f, scriptArgs);
} catch (final WorldEditException ex) {
BBC.SCRIPTING_ERROR.send(player);
}
worldEdit.runScript(player, f, Stream.concat(Stream.of(lastScript), args.stream())
.toArray(String[]::new));
}
}

View File

@@ -19,27 +19,31 @@
package com.sk89q.worldedit.command;
import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.clipboard.URIClipboardHolder;
import com.boydti.fawe.object.mask.IdMask;
import com.boydti.fawe.object.regions.selector.FuzzyRegionSelector;
import com.boydti.fawe.object.regions.selector.PolyhedralRegionSelector;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.command.argument.SelectorChoice;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.MultiDirection;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
@@ -55,28 +59,29 @@ import com.sk89q.worldedit.regions.selector.RegionSelectorType;
import com.sk89q.worldedit.regions.selector.SphereRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.formatting.ColorCodeBuilder;
import com.sk89q.worldedit.util.formatting.Style;
import com.sk89q.worldedit.util.formatting.StyledFragment;
import com.sk89q.worldedit.util.formatting.component.CommandListBox;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.component.TextComponentProducer;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.storage.ChunkStore;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.POSITION;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
import java.util.stream.Stream;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
/**
* Selection commands.
*/
@Command(aliases = {}, desc = "Change your selection points, mode or view info about your selection: [More Info](http://wiki.sk89q.com/wiki/WorldEdit/Selection)")
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SelectionCommands {
private final WorldEdit we;
@@ -86,26 +91,17 @@ public class SelectionCommands {
}
@Command(
aliases = {"/pos1", "posa", "/1"},
usage = "[coordinates]",
desc = "Set position 1",
min = 0,
max = 1
name = "/pos1",
desc = "Set position 1"
)
@Logging(POSITION)
@CommandPermissions("worldedit.selection.pos")
public void pos1(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void pos1(Player player, LocalSession session,
@Arg(desc = "Coordinates to set position 1 to", def = "")
BlockVector3 coordinates) throws WorldEditException {
BlockVector3 pos;
if (args.argsLength() == 1) {
if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) {
String[] coords = args.getString(0).split(",");
pos = BlockVector3.at(Integer.parseInt(coords[0]), Integer.parseInt(coords[1]), Integer.parseInt(coords[2]));
} else {
BBC.SELECTOR_INVALID_COORDINATES.send(player, args.getString(0));
return;
}
if (coordinates != null) {
pos = coordinates;
} else {
pos = player.getBlockIn().toBlockPoint();
}
@@ -115,31 +111,22 @@ public class SelectionCommands {
return;
}
session.getRegionSelector(player.getWorld()).explainPrimarySelection(player, session, pos);
session.getRegionSelector(player.getWorld())
.explainPrimarySelection(player, session, pos);
}
@Command(
aliases = {"/pos2", "posb", "/2"},
usage = "[coordinates]",
desc = "Set position 2",
min = 0,
max = 1
name = "/pos2",
desc = "Set position 2"
)
@Logging(POSITION)
@CommandPermissions("worldedit.selection.pos")
public void pos2(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void pos2(Player player, LocalSession session,
@Arg(desc = "Coordinates to set position 2 to", def = "")
BlockVector3 coordinates) throws WorldEditException {
BlockVector3 pos;
if (args.argsLength() == 1) {
if (args.getString(0).matches("-?\\d+,-?\\d+,-?\\d+")) {
String[] coords = args.getString(0).split(",");
pos = BlockVector3.at(Integer.parseInt(coords[0]),
Integer.parseInt(coords[1]),
Integer.parseInt(coords[2]));
} else {
BBC.SELECTOR_INVALID_COORDINATES.send(player, args.getString(0));
return;
}
if (coordinates != null) {
pos = coordinates;
} else {
pos = player.getBlockIn().toBlockPoint();
}
@@ -154,15 +141,13 @@ public class SelectionCommands {
}
@Command(
aliases = {"/hpos1"},
usage = "",
desc = "Set position 1 to targeted block",
min = 0,
max = 0
name = "/hpos1",
desc = "Set position 1 to targeted block"
)
@CommandPermissions("worldedit.selection.hpos")
public void hpos1(Player player, LocalSession session, CommandContext args) throws WorldEditException {
BlockVector3 pos = player.getBlockTrace(300).toBlockPoint();
public void hpos1(Player player, LocalSession session) throws WorldEditException {
BlockVector3 pos = player.getBlockTrace(300).toBlockPoint();
if (pos != null) {
if (!session.getRegionSelector(player.getWorld()).selectPrimary(pos, ActorSelectorLimits.forActor(player))) {
@@ -178,15 +163,13 @@ public class SelectionCommands {
}
@Command(
aliases = {"/hpos2"},
usage = "",
desc = "Set position 2 to targeted block",
min = 0,
max = 0
name = "/hpos2",
desc = "Set position 2 to targeted block"
)
@CommandPermissions("worldedit.selection.hpos")
public void hpos2(Player player, LocalSession session, CommandContext args) throws WorldEditException {
BlockVector3 pos = player.getBlockTrace(300).toBlockPoint();
public void hpos2(Player player, LocalSession session) throws WorldEditException {
BlockVector3 pos = player.getBlockTrace(300).toBlockPoint();
if (pos != null) {
if (!session.getRegionSelector(player.getWorld()).selectSecondary(pos, ActorSelectorLimits.forActor(player))) {
@@ -202,28 +185,22 @@ public class SelectionCommands {
}
@Command(
aliases = {"/chunk"},
usage = "[x,z coordinates]",
flags = "sc",
desc = "Set the selection to your current chunk.",
help =
"Set the selection to the chunk you are currently in.\n" +
"With the -s flag, your current selection is expanded\n" +
"to encompass all chunks that are part of it.\n\n" +
"Specifying coordinates will use those instead of your\n" +
"current position. Use -c to specify chunk coordinates,\n" +
"otherwise full coordinates will be implied.\n" +
"(for example, the coordinates 5,5 are the same as -c 0,0)",
min = 0,
max = 1
name = "/chunk",
desc = "Set the selection to your current chunk."
)
@Logging(POSITION)
@CommandPermissions("worldedit.selection.chunk")
public void chunk(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void chunk(Player player, LocalSession session,
@Arg(desc = "The chunk to select", def = "")
BlockVector2 coordinates,
@Switch(name = 's', desc = "Expand your selection to encompass all chunks that are part of it")
boolean expandSelection,
@Switch(name = 'c', desc = "Use chunk coordinates instead of block coordinates")
boolean useChunkCoordinates) throws WorldEditException {
final BlockVector3 min;
final BlockVector3 max;
final World world = player.getWorld();
if (args.hasFlag('s')) {
if (expandSelection) {
Region region = session.getSelection(world);
final BlockVector2 min2D = ChunkStore.toChunk(region.getMinimumPoint());
@@ -235,16 +212,11 @@ public class SelectionCommands {
BBC.SELECTION_CHUNKS.send(player, min2D.getBlockX() + ", " + min2D.getBlockZ(), max2D.getBlockX() + ", " + max2D.getBlockZ());
} else {
final BlockVector2 min2D;
if (args.argsLength() == 1) {
if (coordinates != null) {
// coords specified
String[] coords = args.getString(0).split(",");
if (coords.length != 2) {
BBC.SELECTOR_INVALID_COORDINATES.send(player, args.getString(0));
}
int x = Integer.parseInt(coords[0]);
int z = Integer.parseInt(coords[1]);
BlockVector2 pos = BlockVector2.at(x, z);
min2D = (args.hasFlag('c')) ? pos : ChunkStore.toChunk(pos.toBlockVector3());
min2D = useChunkCoordinates
? coordinates
: ChunkStore.toChunk(coordinates.toBlockVector3());
} else {
// use player loc
min2D = ChunkStore.toChunk(player.getBlockIn().toBlockPoint());
@@ -271,14 +243,12 @@ public class SelectionCommands {
}
@Command(
aliases = {"/wand", "/w"},
usage = "",
desc = "Get the wand object",
min = 0,
max = 0
name = "/wand",
desc = "Get the wand object"
)
@CommandPermissions("worldedit.wand")
public void wand(Player player) throws WorldEditException {
public void wand(Player player, LocalSession session,
@Switch(name = 'n', desc = "Get a navigation wand") boolean navWand) throws WorldEditException {
player.giveItem(new BaseItemStack(ItemTypes.parse(we.getConfiguration().wandItem), 1));
BBC.SELECTION_WAND.send(player);
if (!player.hasPermission("fawe.tips"))
@@ -286,176 +256,46 @@ public class SelectionCommands {
}
@Command(
aliases = {"toggleeditwand"},
usage = "",
desc = "Toggle functionality of the edit wand",
min = 0,
max = 0
name = "toggleeditwand",
desc = "Remind the user that the wand is now a tool and can be unbound with /none."
)
@CommandPermissions("worldedit.wand.toggle")
public void toggleWand(Player player, LocalSession session, CommandContext args) throws WorldEditException {
session.setToolControl(!session.isToolControlEnabled());
if (session.isToolControlEnabled()) {
BBC.SELECTION_WAND_ENABLE.m().send(player);
} else {
BBC.SELECTION_WAND_DISABLE.send(player);
}
public void toggleWand(Player player) {
player.print(TextComponent.of("The selection wand is now a normal tool. You can disable it with ")
.append(TextComponent.of("/none", TextColor.AQUA).clickEvent(
ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/none")))
.append(TextComponent.of(" and rebind it to any item with "))
.append(TextComponent.of("//selwand", TextColor.AQUA).clickEvent(
ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//selwand")))
.append(TextComponent.of(" or get a new wand with "))
.append(TextComponent.of("//wand", TextColor.AQUA).clickEvent(
ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//wand"))));
}
@Command(
aliases = {"/expand"},
usage = "<amount> [reverse-amount] <direction>",
desc = "Expand the selection area",
min = 1,
max = 3
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.expand")
public void expand(Player player, LocalSession session, CommandContext args) throws WorldEditException {
// Special syntax (//expand vert) to expand the selection between
// sky and bedrock.
if (args.getString(0).equalsIgnoreCase("vert") || args.getString(0).equalsIgnoreCase("vertical")) {
Region region = session.getSelection(player.getWorld());
try {
int oldSize = region.getArea();
region.expand(
BlockVector3.at(0, (player.getWorld().getMaxY() + 1), 0),
BlockVector3.at(0, -(player.getWorld().getMaxY() + 1), 0));
session.getRegionSelector(player.getWorld()).learnChanges();
int newSize = region.getArea();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
BBC.SELECTION_EXPAND_VERT.send(player, (newSize - oldSize));
} catch (RegionOperationException e) {
player.printError(e.getMessage());
}
return;
}
List<BlockVector3> dirs = new ArrayList<>();
int change = args.getInteger(0);
int reverseChange = 0;
switch (args.argsLength()) {
case 2:
// Either a reverse amount or a direction
try {
reverseChange = args.getInteger(1);
dirs.add(we.getDirection(player, "me"));
} catch (NumberFormatException e) {
if (args.getString(1).contains(",")) {
String[] split = args.getString(1).split(",");
for (String s : split) {
dirs.add(we.getDirection(player, s.toLowerCase()));
}
} else {
dirs.add(we.getDirection(player, args.getString(1).toLowerCase()));
}
}
break;
case 3:
// Both reverse amount and direction
reverseChange = args.getInteger(1);
if (args.getString(2).contains(",")) {
String[] split = args.getString(2).split(",");
for (String s : split) {
dirs.add(we.getDirection(player, s.toLowerCase()));
}
} else {
dirs.add(we.getDirection(player, args.getString(2).toLowerCase()));
}
break;
default:
dirs.add(we.getDirection(player, "me"));
break;
}
Region region = session.getSelection(player.getWorld());
int oldSize = region.getArea();
if (reverseChange == 0) {
for (BlockVector3 dir : dirs) {
region.expand(dir.multiply(change));
}
} else {
for (BlockVector3 dir : dirs) {
region.expand(dir.multiply(change), dir.multiply(-reverseChange));
}
}
session.getRegionSelector(player.getWorld()).learnChanges();
int newSize = region.getArea();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
BBC.SELECTION_EXPAND.send(player, (newSize - oldSize));
}
@Command(
aliases = {"/contract"},
usage = "<amount> [reverse-amount] [direction]",
desc = "Contract the selection area",
min = 1,
max = 3
name = "/contract",
desc = "Contract the selection area"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.contract")
public void contract(Player player, LocalSession session, CommandContext args) throws WorldEditException {
List<BlockVector3> dirs = new ArrayList<>();
int change = args.getInteger(0);
int reverseChange = 0;
switch (args.argsLength()) {
case 2:
// Either a reverse amount or a direction
try {
reverseChange = args.getInteger(1);
dirs.add(we.getDirection(player, "me"));
} catch (NumberFormatException e) {
if (args.getString(1).contains(",")) {
String[] split = args.getString(1).split(",");
for (String s : split) {
dirs.add(we.getDirection(player, s.toLowerCase()));
}
} else {
dirs.add(we.getDirection(player, args.getString(1).toLowerCase()));
}
}
break;
case 3:
// Both reverse amount and direction
reverseChange = args.getInteger(1);
if (args.getString(2).contains(",")) {
String[] split = args.getString(2).split(",");
for (String s : split) {
dirs.add(we.getDirection(player, s.toLowerCase()));
}
} else {
dirs.add(we.getDirection(player, args.getString(2).toLowerCase()));
}
break;
default:
dirs.add(we.getDirection(player, "me"));
break;
}
public void contract(Player player, LocalSession session,
@Arg(desc = "Amount to contract the selection by")
int amount,
@Arg(desc = "Amount to contract the selection by in the other direction", def = "0")
int reverseAmount,
@Arg(desc = "Direction to contract", def = Direction.AIM)
@MultiDirection
List<BlockVector3> direction) throws WorldEditException {
try {
Region region = session.getSelection(player.getWorld());
int oldSize = region.getArea();
if (reverseChange == 0) {
for (BlockVector3 dir : dirs) {
region.contract(dir.multiply(change));
if (reverseAmount == 0) {
for (BlockVector3 dir : direction) {
region.contract(dir.multiply(amount));
}
} else {
for (BlockVector3 dir : dirs) {
region.contract(dir.multiply(change), dir.multiply(-reverseChange));
for (BlockVector3 dir : direction) {
region.contract(dir.multiply(amount), dir.multiply(-reverseAmount));
}
}
session.getRegionSelector(player.getWorld()).learnChanges();
@@ -463,6 +303,7 @@ public class SelectionCommands {
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
BBC.SELECTION_CONTRACT.send(player, (oldSize - newSize));
} catch (RegionOperationException e) {
player.printError(e.getMessage());
@@ -470,40 +311,28 @@ public class SelectionCommands {
}
@Command(
aliases = {"/shift"},
usage = "<amount> [direction]",
desc = "Shift the selection area",
min = 1,
max = 2
name = "/shift",
desc = "Shift the selection area"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.shift")
public void shift(Player player, LocalSession session, CommandContext args) throws WorldEditException {
List<BlockVector3> dirs = new ArrayList<>();
int change = args.getInteger(0);
if (args.argsLength() == 2) {
if (args.getString(1).contains(",")) {
for (String s : args.getString(1).split(",")) {
dirs.add(we.getDirection(player, s.toLowerCase()));
}
} else {
dirs.add(we.getDirection(player, args.getString(1).toLowerCase()));
}
} else {
dirs.add(we.getDirection(player, "me"));
}
public void shift(Player player, LocalSession session,
@Arg(desc = "Amount to shift the selection by")
int amount,
@Arg(desc = "Direction to contract", def = Direction.AIM)
@MultiDirection
List<BlockVector3> direction) throws WorldEditException {
try {
Region region = session.getSelection(player.getWorld());
for (BlockVector3 dir : dirs) {
region.shift(dir.multiply(change));
for (BlockVector3 dir : direction) {
region.shift(dir.multiply(amount));
}
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
BBC.SELECTION_SHIFT.send(player);
} catch (RegionOperationException e) {
player.printError(e.getMessage());
@@ -511,81 +340,73 @@ public class SelectionCommands {
}
@Command(
aliases = {"/outset"},
usage = "<amount>",
desc = "Outset the selection area",
help =
"Expands the selection by the given amount in all directions.\n" +
"Flags:\n" +
" -h only expand horizontally\n" +
" -v only expand vertically\n",
flags = "hv",
min = 1,
max = 1
name = "/outset",
desc = "Outset the selection area"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.outset")
public void outset(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void outset(Player player, LocalSession session,
@Arg(desc = "Amount to expand the selection by in all directions")
int amount,
@Switch(name = 'h', desc = "Only expand horizontally")
boolean onlyHorizontal,
@Switch(name = 'v', desc = "Only expand vertically")
boolean onlyVertical) throws WorldEditException {
Region region = session.getSelection(player.getWorld());
region.expand(getChangesForEachDir(args));
region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical));
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
BBC.SELECTION_OUTSET.send(player);
}
@Command(
aliases = {"/inset"},
usage = "<amount>",
desc = "Inset the selection area",
help =
"Contracts the selection by the given amount in all directions.\n" +
"Flags:\n" +
" -h only contract horizontally\n" +
" -v only contract vertically\n",
flags = "hv",
min = 1,
max = 1
name = "/inset",
desc = "Inset the selection area"
)
@Logging(REGION)
@CommandPermissions("worldedit.selection.inset")
public void inset(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void inset(Player player, LocalSession session,
@Arg(desc = "Amount to contract the selection by in all directions")
int amount,
@Switch(name = 'h', desc = "Only contract horizontally")
boolean onlyHorizontal,
@Switch(name = 'v', desc = "Only contract vertically")
boolean onlyVertical) throws WorldEditException {
Region region = session.getSelection(player.getWorld());
region.contract(getChangesForEachDir(args));
region.contract(getChangesForEachDir(amount, onlyHorizontal, onlyVertical));
session.getRegionSelector(player.getWorld()).learnChanges();
session.getRegionSelector(player.getWorld()).explainRegionAdjust(player, session);
BBC.SELECTION_INSET.send(player);
}
private BlockVector3[] getChangesForEachDir(CommandContext args) {
List<BlockVector3> changes = new ArrayList<>(6);
int change = args.getInteger(0);
private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal, boolean onlyVertical) {
Stream.Builder<BlockVector3> changes = Stream.builder();
if (!args.hasFlag('h')) {
changes.add((BlockVector3.at(0, 1, 0)).multiply(change));
changes.add((BlockVector3.at(0, -1, 0)).multiply(change));
if (!onlyHorizontal) {
changes.add(BlockVector3.UNIT_Y);
changes.add(BlockVector3.UNIT_MINUS_Y);
}
if (!args.hasFlag('v')) {
changes.add((BlockVector3.at(1, 0, 0)).multiply(change));
changes.add((BlockVector3.at(-1, 0, 0)).multiply(change));
changes.add((BlockVector3.at(0, 0, 1)).multiply(change));
changes.add((BlockVector3.at(0, 0, -1)).multiply(change));
if (!onlyVertical) {
changes.add(BlockVector3.UNIT_X);
changes.add(BlockVector3.UNIT_MINUS_X);
changes.add(BlockVector3.UNIT_Z);
changes.add(BlockVector3.UNIT_MINUS_Z);
}
return changes.toArray(new BlockVector3[0]);
return changes.build().map(v -> v.multiply(amount)).toArray(BlockVector3[]::new);
}
@Command(
aliases = {"/size"},
flags = "c",
usage = "",
desc = "Get information about the selection",
min = 0,
max = 0
name = "/size",
desc = "Get information about the selection"
)
@CommandPermissions("worldedit.selection.size")
public void size(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
if (args.hasFlag('c')) {
public void size(Player player, LocalSession session,
@Switch(name = 'c', desc = "Get clipboard info instead")
boolean clipboardInfo) throws WorldEditException {
Region region;
if (clipboardInfo) {
ClipboardHolder root = session.getClipboard();
// Clipboard clipboard = holder.getClipboard();
int index = 0;
@@ -603,8 +424,10 @@ public class SelectionCommands {
name = Integer.toString(index);
}
Region region = clipboard.getRegion();
BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(BlockVector3.ONE);
region = clipboard.getRegion();
BlockVector3 size = region.getMaximumPoint()
.subtract(region.getMinimumPoint()).
add(1, 1, 1);
BlockVector3 origin = clipboard.getOrigin();
String sizeStr = size.getBlockX() + "*" + size.getBlockY() + "*" + size.getBlockZ();
@@ -617,30 +440,10 @@ public class SelectionCommands {
index++;
}
// player.print("Cuboid dimensions (max - min): " + size);
// player.print("Offset: " + origin);
// player.print("Cuboid distance: " + size.distance(Vector.ONE));
// player.print("# of blocks: " + (int) (size.getX() * size.getY() * size.getZ()));
//=======
// public void size(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
// if (args.hasFlag('c')) {
// ClipboardHolder holder = session.getClipboard();
// Clipboard clipboard = holder.getClipboard();
// Region region = clipboard.getRegion();
// BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint());
// BlockVector3 origin = clipboard.getOrigin();
//
// player.print("Cuboid dimensions (max - min): " + size);
// player.print("Offset: " + origin);
// player.print("Cuboid distance: " + size.distance(BlockVector3.ONE));
// player.print("# of blocks: " + (int) (size.getX() * size.getY() * size.getZ()));
return;
}
Region region = session.getSelection(player.getWorld());
region = session.getSelection(player.getWorld());
BlockVector3 size = region.getMaximumPoint()
.subtract(region.getMinimumPoint())
.add(1, 1, 1);
@@ -660,57 +463,53 @@ public class SelectionCommands {
@Command(
aliases = {"/count"},
usage = "<mask>",
desc = "Counts the number of a certain type of block",
flags = "d",
min = 1,
max = 1
name = "/count",
desc = "Counts the number of a certain type of block"
)
@CommandPermissions("worldedit.analysis.count")
public void count(Player player, LocalSession session, EditSession editSession, Mask mask) throws WorldEditException {
public void count(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "The mask of blocks to match")
Mask mask) throws WorldEditException {
int count = editSession.countBlock(session.getSelection(player.getWorld()), mask);
BBC.SELECTION_COUNT.send(player, count);
player.print("Counted: " + count);
}
@Command(
aliases = {"/distr"},
usage = "",
desc = "Get the distribution of blocks in the selection",
help =
"Gets the distribution of blocks in the selection.\n" +
"The -c flag gets the distribution of your clipboard.",
flags = "c",
min = 0,
max = 0
name = "/distr",
desc = "Get the distribution of blocks in the selection"
)
@CommandPermissions("worldedit.analysis.distr")
public void distr(Player player, LocalSession session, EditSession editSession, @Switch('c') boolean useClipboard, @Switch('d') boolean useData) throws WorldEditException, CommandException {
int size;
List<Countable> distributionData;
public void distr(Player player, LocalSession session, EditSession editSession,
@Switch(name = 'c', desc = "Get the distribution of the clipboard instead")
boolean clipboardDistr,
@Switch(name = 'd', desc = "Separate blocks by state")
boolean separateStates) throws WorldEditException {
List<Countable> distribution;
Region region;
if (useClipboard) {
if (clipboardDistr) {
// TODO multi clipboard distribution
Clipboard clipboard = session.getClipboard().getClipboard();
Clipboard clipboard = session.getClipboard().getClipboard(); // throws if missing
region = clipboard.getRegion();
editSession.setExtent(new AbstractDelegateExtent(clipboard));
} else {
region = session.getSelection(player.getWorld());
}
if (useData)
distributionData = (List) editSession.getBlockDistributionWithData(region);
if (separateStates)
distribution = (List) editSession.getBlockDistributionWithData(region);
else
distributionData = (List) editSession.getBlockDistribution(region);
size = session.getSelection(player.getWorld()).getArea();
distribution = (List) editSession.getBlockDistribution(region);
if (distributionData.size() <= 0) {
if (distribution.isEmpty()) { // *Should* always be false
player.printError("No blocks counted.");
return;
}
// note: doing things like region.getArea is inaccurate for non-cuboids.
int size = session.getSelection(player.getWorld()).getArea();
BBC.SELECTION_DISTR.send(player, size);
for (Countable c : distributionData) {
for (Countable c : distribution) {
String name = c.getID().toString();
String str = String.format("%-7s (%.3f%%) %s",
String.valueOf(c.getAmount()),
@@ -721,16 +520,17 @@ public class SelectionCommands {
}
@Command(
aliases = {"/sel", ";", "/desel", "/deselect"},
flags = "d",
usage = "[cuboid|extend|poly|polyhedron|ellipsoid|sphere|cyl|convex|fuzzy]",
desc = "Choose a region selector",
min = 0,
max = 1
name = "/sel",
aliases = { ";", "/desel", "/deselect" },
desc = "Choose a region selector"
)
public void select(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
public void select(Player player, LocalSession session, EditSession editSession,
@Arg(desc = "Selector to switch to", def = "")
SelectorChoice selector,
@Switch(name = 'd', desc = "Set default selector")
boolean setDefaultSelector) throws WorldEditException {
final World world = player.getWorld();
if (args.argsLength() == 0) {
if (selector == null) {
session.getRegionSelector(world).clear();
session.dispatchCUISelection(player);
BBC.SELECTION_CLEARED.send(player);
@@ -740,79 +540,93 @@ public class SelectionCommands {
final String typeName = args.getString(0);
final RegionSelector oldSelector = session.getRegionSelector(world);
final RegionSelector selector;
if (typeName.equalsIgnoreCase("cuboid")) {
selector = new CuboidRegionSelector(oldSelector);
player.print(BBC.SEL_CUBOID.s());
} else if (typeName.equalsIgnoreCase("extend")) {
selector = new ExtendingCuboidRegionSelector(oldSelector);
player.print(BBC.SEL_CUBOID_EXTEND.s());
} else if (typeName.equalsIgnoreCase("poly")) {
selector = new Polygonal2DRegionSelector(oldSelector);
player.print(BBC.SEL_2D_POLYGON.s());
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit();
limit.ifPresent(integer -> player.print(BBC.SEL_MAX.f(integer)));
player.print(BBC.SEL_LIST.s());
} else if (typeName.equalsIgnoreCase("ellipsoid")) {
selector = new EllipsoidRegionSelector(oldSelector);
player.print(BBC.SEL_ELLIPSIOD.s());
} else if (typeName.equalsIgnoreCase("sphere")) {
selector = new SphereRegionSelector(oldSelector);
player.print(BBC.SEL_SPHERE.s());
} else if (typeName.equalsIgnoreCase("cyl")) {
selector = new CylinderRegionSelector(oldSelector);
player.print(BBC.SEL_CYLINDRICAL.s());
} else if (typeName.equalsIgnoreCase("convex") || typeName.equalsIgnoreCase("hull")) {
selector = new ConvexPolyhedralRegionSelector(oldSelector);
player.print(BBC.SEL_CONVEX_POLYHEDRAL.s());
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit();
limit.ifPresent(integer -> player.print(BBC.SEL_MAX.f(integer)));
player.print(BBC.SEL_LIST.s());
} else if (typeName.equalsIgnoreCase("polyhedral") || typeName.equalsIgnoreCase("polyhedron")) {
selector = new PolyhedralRegionSelector(player.getWorld());
player.print(BBC.SEL_CONVEX_POLYHEDRAL.s());
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit();
limit.ifPresent(integer -> player.print(BBC.SEL_MAX.f(integer)));
player.print(BBC.SEL_LIST.s());
} else if (typeName.startsWith("fuzzy") || typeName.startsWith("magic")) {
Mask mask;
if (typeName.length() > 6) {
ParserContext parserContext = new ParserContext();
parserContext.setActor(player);
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
mask = we.getMaskFactory().parseFromInput(typeName.substring(6), parserContext);
} else {
mask = new IdMask(editSession);
final RegionSelector newSelector;
switch (selector) {
case CUBOID:
newSelector = new CuboidRegionSelector(oldSelector);
player.print(BBC.SEL_CUBOID.s());
break;
case EXTEND:
newSelector = new ExtendingCuboidRegionSelector(oldSelector);
player.print(BBC.SEL_CUBOID_EXTEND.s());
break;
case POLY: {
newSelector = new Polygonal2DRegionSelector(oldSelector);
player.print(BBC.SEL_2D_POLYGON.s());
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolygonVertexLimit();
limit.ifPresent(integer -> player.print(BBC.SEL_MAX.f(integer)));
break;
}
selector = new FuzzyRegionSelector(player, editSession, mask);
player.print(BBC.SEL_FUZZY.f());
player.print(BBC.SEL_LIST.f());
} else {
CommandListBox box = new CommandListBox("Selection modes");
StyledFragment contents = box.getContents();
StyledFragment tip = contents.createFragment(Style.RED);
tip.append(BBC.SEL_MODES.s()).newLine();
case ELLIPSOID:
newSelector = new EllipsoidRegionSelector(oldSelector);
player.print(BBC.SEL_ELLIPSIOD.s());
break;
case SPHERE:
newSelector = new SphereRegionSelector(oldSelector);
player.print(BBC.SEL_SPHERE.s());
break;
case CYL:
newSelector = new CylinderRegionSelector(oldSelector);
player.print(BBC.SEL_CYLINDRICAL.s());
break;
case CONVEX:
case HULL:
case POLYHEDRON: {
newSelector = new ConvexPolyhedralRegionSelector(oldSelector);
player.print(BBC.SEL_CONVEX_POLYHEDRAL.s());
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit();
limit.ifPresent(integer -> player.print(BBC.SEL_MAX.f(integer)));
break;
}
case POLYHEDRAL:
newSelector = new PolyhedralRegionSelector(player.getWorld());
player.print(BBC.SEL_CONVEX_POLYHEDRAL.s());
Optional<Integer> limit = ActorSelectorLimits.forActor(player).getPolyhedronVertexLimit();
limit.ifPresent(integer -> player.print(BBC.SEL_MAX.f(integer)));
player.print(BBC.SEL_LIST.s());
break;
case FUZZY:
case MAGIC:
Mask mask;
if (typeName.length() > 6) {
ParserContext parserContext = new ParserContext();
parserContext.setActor(player);
parserContext.setWorld(player.getWorld());
parserContext.setSession(session);
parserContext.setExtent(editSession);
mask = we.getMaskFactory().parseFromInput(typeName.substring(6), parserContext);
} else {
mask = new IdMask(world);
}
newSelector = new FuzzyRegionSelector(player, editSession, mask);
player.print(BBC.SEL_FUZZY.f());
player.print(BBC.SEL_LIST.f());
break;
case LIST:
default:
CommandListBox box = new CommandListBox("Selection modes", null);
box.setHidingHelp(true);
TextComponentProducer contents = box.getContents();
contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline();
box.appendCommand("//sel cuboid", "Select two corners of a cuboid");
box.appendCommand("//sel extend", "Fast cuboid selection mode");
box.appendCommand("//sel poly", "Select a 2D polygon with height");
box.appendCommand("//sel ellipsoid", "Select an ellipsoid");
box.appendCommand("//sel sphere", "Select a sphere");
box.appendCommand("//sel cyl", "Select a cylinder");
box.appendCommand("//sel convex", "Select a convex polyhedral");
box.appendCommand("//sel polyhedral", "Select a hollow polyhedral");
box.appendCommand("//sel fuzzy[=<mask>]", "Select all connected blocks (magic wand)");
box.appendCommand("cuboid", "Select two corners of a cuboid", "//sel cuboid");
box.appendCommand("extend", "Fast cuboid selection mode", "//sel extend");
box.appendCommand("poly", "Select a 2D polygon with height", "//sel poly");
box.appendCommand("ellipsoid", "Select an ellipsoid", "//sel ellipsoid");
box.appendCommand("sphere", "Select a sphere", "//sel sphere");
box.appendCommand("cyl", "Select a cylinder", "//sel cyl");
box.appendCommand("convex", "Select a convex polyhedral", "//sel convex");
box.appendCommand("polyhedral", "Select a hollow polyhedral", "//sel polyhedral");
box.appendCommand("fuzzy[=<mask>]", "Select all connected blocks (magic wand)", "//sel fuzzy[=<mask>]");
player.printRaw(ColorCodeBuilder.asColorCodes(box));
return;
player.print(box.create(1));
return;
}
if (args.hasFlag('d')) {
if (setDefaultSelector) {
RegionSelectorType found = null;
for (RegionSelectorType type : RegionSelectorType.values()) {
if (type.getSelectorClass() == selector.getClass()) {
if (type.getSelectorClass() == newSelector.getClass()) {
found = type;
break;
}
@@ -826,9 +640,8 @@ public class SelectionCommands {
}
}
session.setRegionSelector(world, selector);
session.setRegionSelector(world, newSelector);
session.dispatchCUISelection(player);
}
}

View File

@@ -1,5 +0,0 @@
package com.sk89q.worldedit.command;
public class SelectionTypeCommands {
}

View File

@@ -22,32 +22,33 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
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.entity.Player;
import com.sk89q.worldedit.world.snapshot.InvalidSnapshotException;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import com.sk89q.worldedit.world.storage.MissingWorldException;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
/**
* Snapshot commands.
*/
@Command(aliases = {"snapshot", "snap"}, desc = "List, load and view information related to snapshots")
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SnapshotCommands {
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
private final WorldEdit we;
@@ -56,14 +57,13 @@ public class SnapshotCommands {
}
@Command(
aliases = {"list"},
usage = "[num]",
desc = "List snapshots",
min = 0,
max = 1
name = "list",
desc = "List snapshots"
)
@CommandPermissions("worldedit.snapshots.list")
public void list(Player player, CommandContext args) throws WorldEditException {
public void list(Player player,
@Arg(desc = "# of snapshots to list", def = "5")
int num) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -77,7 +77,7 @@ public class SnapshotCommands {
if (!snapshots.isEmpty()) {
int num = args.argsLength() > 0 ? Math.min(40, Math.max(5, args.getInteger(0))) : 5;
num = Math.min(40, Math.max(5, num));
BBC.SNAPSHOT_LIST_HEADER.send(player, player.getWorld().getName());
for (byte i = 0; i < Math.min(num, snapshots.size()); i++) {
@@ -92,7 +92,8 @@ public class SnapshotCommands {
File dir = config.snapshotRepo.getDirectory();
try {
WorldEdit.logger.info("WorldEdit found no snapshots: looked in: " + dir.getCanonicalPath());
WorldEdit.logger.info("WorldEdit found no snapshots: looked in: "
+ dir.getCanonicalPath());
} catch (IOException e) {
WorldEdit.logger.info("WorldEdit found no snapshots: looked in "
+ "(NON-RESOLVABLE PATH - does it exist?): "
@@ -105,14 +106,13 @@ public class SnapshotCommands {
}
@Command(
aliases = { "use" },
usage = "<snapshot>",
desc = "Choose a snapshot to use",
min = 1,
max = 1
name = "use",
desc = "Choose a snapshot to use"
)
@CommandPermissions("worldedit.snapshots.restore")
public void use(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void use(Player player, LocalSession session,
@Arg(desc = "Snapeshot to use")
String name) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -121,8 +121,6 @@ public class SnapshotCommands {
return;
}
String name = args.getString(0);
// Want the latest snapshot?
if (name.equalsIgnoreCase("latest")) {
try {
@@ -148,14 +146,13 @@ public class SnapshotCommands {
}
@Command(
aliases = { "sel" },
usage = "<index>",
desc = "Choose the snapshot based on the list id",
min = 1,
max = 1
name = "sel",
desc = "Choose the snapshot based on the list id"
)
@CommandPermissions("worldedit.snapshots.restore")
public void sel(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void sel(Player player, LocalSession session,
@Arg(desc = "The list ID to select")
int index) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) {
@@ -163,14 +160,6 @@ public class SnapshotCommands {
return;
}
int index = -1;
try {
index = Integer.parseInt(args.getString(0));
} catch (NumberFormatException e) {
player.printError("Invalid index, " + args.getString(0) + " is not a valid integer.");
return;
}
if (index < 1) {
BBC.SNAPSHOT_INVALID_INDEX.send(player);
return;
@@ -195,14 +184,13 @@ public class SnapshotCommands {
}
@Command(
aliases = { "before" },
usage = "<date>",
desc = "Choose the nearest snapshot before a date",
min = 1,
max = -1
name = "before",
desc = "Choose the nearest snapshot before a date"
)
@CommandPermissions("worldedit.snapshots.restore")
public void before(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void before(Player player, LocalSession session,
@Arg(desc = "The soonest date that may be used")
ZonedDateTime date) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -211,18 +199,12 @@ public class SnapshotCommands {
return;
}
Calendar date = session.detectDate(args.getJoinedStrings(0));
if (date == null) {
BBC.SNAPSHOT_ERROR_DATE.send(player);
} else {
try {
Snapshot snapshot = config.snapshotRepo.getSnapshotBefore(date, player.getWorld().getName());
if (snapshot == null) {
dateFormat.setTimeZone(session.getTimeZone());
player.printError("Couldn't find a snapshot before "
+ dateFormat.format(date.getTime()) + ".");
+ dateFormat.withZone(session.getTimeZone().toZoneId()).format(date) + ".");
} else {
session.setSnapshot(snapshot);
BBC.SNAPSHOT_SET.send(player, snapshot.getName());
@@ -230,18 +212,16 @@ public class SnapshotCommands {
} catch (MissingWorldException ex) {
BBC.SNAPSHOT_NOT_FOUND_WORLD.send(player);
}
}
}
@Command(
aliases = { "after" },
usage = "<date>",
desc = "Choose the nearest snapshot after a date",
min = 1,
max = -1
name = "after",
desc = "Choose the nearest snapshot after a date"
)
@CommandPermissions("worldedit.snapshots.restore")
public void after(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void after(Player player, LocalSession session,
@Arg(desc = "The soonest date that may be used")
ZonedDateTime date) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -250,24 +230,17 @@ public class SnapshotCommands {
return;
}
Calendar date = session.detectDate(args.getJoinedStrings(0));
if (date == null) {
BBC.SNAPSHOT_ERROR_DATE.send(player);
} else {
try {
Snapshot snapshot = config.snapshotRepo.getSnapshotAfter(date, player.getWorld().getName());
if (snapshot == null) {
dateFormat.setTimeZone(session.getTimeZone());
player.printError("Couldn't find a snapshot after "
+ dateFormat.format(date.getTime()) + ".");
+ dateFormat.withZone(session.getTimeZone().toZoneId()).format(date) + ".");
} else {
session.setSnapshot(snapshot);
BBC.SNAPSHOT_SET.send(player, snapshot.getName());
}
} catch (MissingWorldException ex) {
BBC.SNAPSHOT_NOT_FOUND_WORLD.send(player);
}
}
}

View File

@@ -19,16 +19,17 @@
package com.sk89q.worldedit.command;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import com.boydti.fawe.config.BBC;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
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.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.DataException;
@@ -37,13 +38,13 @@ import com.sk89q.worldedit.world.snapshot.Snapshot;
import com.sk89q.worldedit.world.snapshot.SnapshotRestore;
import com.sk89q.worldedit.world.storage.ChunkStore;
import com.sk89q.worldedit.world.storage.MissingWorldException;
import java.io.File;
import java.io.IOException;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
@Command(aliases = {}, desc = "[More Info](http://wiki.sk89q.com/wiki/WorldEdit/Snapshots)")
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class SnapshotUtilCommands {
private final WorldEdit we;
@@ -53,14 +54,15 @@ public class SnapshotUtilCommands {
}
@Command(
aliases = { "restore", "/restore" },
usage = "[snapshot]",
desc = "Restore the selection from a snapshot",
max = 1
name = "restore",
aliases = { "/restore" },
desc = "Restore the selection from a snapshot"
)
@Logging(REGION)
@CommandPermissions("worldedit.snapshots.restore")
public void restore(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
public void restore(Player player, LocalSession session, EditSession editSession,
@Arg(name = "snapshot", desc = "The snapshot to restore", def = "")
String snapshotName) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
@@ -72,9 +74,9 @@ public class SnapshotUtilCommands {
Region region = session.getSelection(player.getWorld());
Snapshot snapshot;
if (args.argsLength() > 0) {
if (snapshotName != null) {
try {
snapshot = config.snapshotRepo.getSnapshot(args.getString(0));
snapshot = config.snapshotRepo.getSnapshot(snapshotName);
} catch (InvalidSnapshotException e) {
BBC.SNAPSHOT_NOT_AVAILABLE.send(player);
return;
@@ -113,27 +115,28 @@ public class SnapshotUtilCommands {
// Load chunk store
SnapshotRestore restore;
try (ChunkStore chunkStore = snapshot.getChunkStore()) {
BBC.SNAPSHOT_LOADED.send(player, snapshot.getName());
// Restore snapshot
restore = new SnapshotRestore(chunkStore, editSession, region);
SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region);
//player.print(restore.getChunksAffected() + " chunk(s) will be loaded.");
restore.restore();
if (restore.hadTotalFailure()) {
String error = restore.getLastErrorMessage();
if (error != null) {
BBC.SNAPSHOT_ERROR_RESTORE.send(player);
if (!restore.getMissingChunks().isEmpty()) {
player.printError("Chunks were not present in snapshot.");
} else if (error != null) {
player.printError("Errors prevented any blocks from being restored.");
player.printError("Last error: " + error);
} else {
BBC.SNAPSHOT_ERROR_RESTORE_CHUNKS.send(player);
player.printError("No chunks could be loaded. (Bad archive?)");
}
} else {
player.print(String.format("Restored; %d "
+ "missing chunks and %d other errors.",
+ "missing chunks and %d other errors.",
restore.getMissingChunks().size(),
restore.getErrorChunks().size()));
}

View File

@@ -20,7 +20,7 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.sk89q.minecraft.util.commands.Command;
import org.enginehub.piston.annotation.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalConfiguration;
@@ -42,14 +42,11 @@ public class SuperPickaxeCommands {
@Command(
aliases = {"single"},
usage = "",
desc = "Enable the single block super pickaxe mode",
min = 0,
max = 0
)
@CommandPermissions("worldedit.superpickaxe")
public void single(Player player, LocalSession session) throws WorldEditException {
session.setSuperPickaxe(new SinglePickaxe());
session.enableSuperPickAxe();
BBC.SUPERPICKAXE_AREA_ENABLED.send(player);

View File

@@ -21,16 +21,10 @@ package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.brush.InspectBrush;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.command.tool.BlockDataCyler;
import com.sk89q.worldedit.command.tool.BlockReplacer;
@@ -38,20 +32,22 @@ import com.sk89q.worldedit.command.tool.DistanceWand;
import com.sk89q.worldedit.command.tool.FloatingTreeRemover;
import com.sk89q.worldedit.command.tool.FloodFillTool;
import com.sk89q.worldedit.command.tool.LongRangeBuildTool;
import com.sk89q.worldedit.command.tool.NavigationWand;
import com.sk89q.worldedit.command.tool.QueryTool;
import com.sk89q.worldedit.command.tool.SelectionWand;
import com.sk89q.worldedit.command.tool.TreePlanter;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.item.ItemType;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
@Command(aliases = {"brush", "br", "tool"}, desc = "Bind functions to held items: [More Info](https://goo.gl/xPnPxj)")
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ToolCommands {
private final WorldEdit we;
@@ -60,132 +56,169 @@ public class ToolCommands {
}
@Command(
aliases = {"info", "/info"},
usage = "",
desc = "Block information tool",
min = 0,
max = 0
name = "none",
desc = "Unbind a bound tool from your current item"
)
public void none(Player player, LocalSession session) throws WorldEditException {
session.setTool(player.getItemInHand(HandSide.MAIN_HAND).getType(), null);
player.print("Tool unbound from your current item.");
}
@Command(
name = "/selwand",
aliases = "selwand",
desc = "Selection wand tool"
)
@CommandPermissions("worldedit.setwand")
public void selwand(Player player, LocalSession session) throws WorldEditException {
final ItemType itemType = player.getItemInHand(HandSide.MAIN_HAND).getType();
session.setTool(itemType, new SelectionWand());
player.print("Selection wand bound to " + itemType.getName() + ".");
}
@Command(
name = "/navwand",
aliases = "navwand",
desc = "Navigation wand tool"
)
@CommandPermissions("worldedit.setwand")
public void navwand(Player player, LocalSession session) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new NavigationWand());
player.print("Navigation wand bound to " + itemStack.getType().getName() + ".");
}
@Command(
name = "info",
desc = "Block information tool"
)
@CommandPermissions("worldedit.tool.info")
public void info(Player player, LocalSession session) throws WorldEditException {
session.setTool(new QueryTool(), player);
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new QueryTool());
BBC.TOOL_INFO.send(player, itemStack.getType().getName());
}
@Command(
aliases = {"inspect"},
usage = "",
desc = "Inspect edits within a radius",
help =
"Chooses the inspect brush",
min = 0,
max = 0
name = "inspect",
desc = "Inspect edits within a radius"
)
@CommandPermissions("worldedit.tool.inspect")
public void inspectBrush(Player player, LocalSession session, @Optional("1") double radius) throws WorldEditException {
session.setTool(new InspectBrush(), player);
BBC.TOOL_INSPECT.send(player, player.getItemInHand(HandSide.MAIN_HAND).getType().getName());
public void inspectBrush(Player player, LocalSession session,
@Arg(desc = "The radius of the brush", def = "1")
double radius) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new InspectBrush());
BBC.TOOL_INSPECT.send(player, itemStack.getType().getName());
}
@Command(
aliases = {"tree"},
usage = "[type]",
desc = "Tree generator tool",
min = 0,
max = 1
name = "tree",
desc = "Tree generator tool"
)
@CommandPermissions("worldedit.tool.tree")
@SuppressWarnings("deprecation")
public void tree(Player player, LocalSession session, @Optional("tree") TreeGenerator.TreeType type, CommandContext args) throws WorldEditException {
session.setTool(new TreePlanter(type), player);
BBC.TOOL_TREE.send(player, player.getItemInHand(HandSide.MAIN_HAND).getType().getName());
public void tree(Player player, LocalSession session,
@Arg(desc = "Type of tree to generate", def = "tree")
TreeGenerator.TreeType type) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new TreePlanter(type));
BBC.TOOL_TREE.send(player, itemStack.getType().getName());
}
@Command(
aliases = {"repl"},
usage = "<pattern>",
desc = "Block replacer tool",
min = 1,
max = 1
name = "repl",
desc = "Block replacer tool"
)
@CommandPermissions("worldedit.tool.replacer")
public void repl(Player player, LocalSession session, Pattern pattern) throws WorldEditException {
session.setTool(new BlockReplacer(pattern), player);
BBC.TOOL_REPL.send(player, player.getItemInHand(HandSide.MAIN_HAND).getType().getName());
public void repl(Player player, LocalSession session,
@Arg(desc = "The pattern of blocks to place")
Pattern pattern) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new BlockReplacer(pattern));
BBC.TOOL_REPL.send(player, itemStack.getType().getName());
}
@Command(
aliases = {"cycler"},
usage = "",
desc = "Block data cycler tool",
min = 0,
max = 0
name = "cycler",
desc = "Block data cycler tool"
)
@CommandPermissions("worldedit.tool.data-cycler")
public void cycler(Player player, LocalSession session) throws WorldEditException {
session.setTool(new BlockDataCyler(), player);
BBC.TOOL_CYCLER.send(player, player.getItemInHand(HandSide.MAIN_HAND).getType().getName());
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new BlockDataCyler());
BBC.TOOL_CYCLER.send(player, itemStack.getType().getName());
}
@Command(
aliases = {"floodfill", "flood"},
usage = "<pattern> <range>",
desc = "Flood fill tool",
min = 2,
max = 2
name = "floodfill",
aliases = { "flood" },
desc = "Flood fill tool"
)
@CommandPermissions("worldedit.tool.flood-fill")
public void floodFill(Player player, EditSession editSession, LocalSession session, Pattern pattern, int range) throws WorldEditException {
public void floodFill(Player player, LocalSession session,
@Arg(desc = "The pattern to flood fill")
Pattern pattern,
@Arg(desc = "The range to perform the fill")
int range) throws WorldEditException {
LocalConfiguration config = we.getConfiguration();
if (range > config.maxSuperPickaxeSize) {
BBC.TOOL_RANGE_ERROR.send(player, config.maxSuperPickaxeSize);
return;
}
session.setTool(new FloodFillTool(range, pattern), player);
BBC.TOOL_FLOOD_FILL.send(player, player.getItemInHand(HandSide.MAIN_HAND).getType().getName());
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new FloodFillTool(range, pattern));
BBC.TOOL_FLOOD_FILL.send(player, itemStack.getType().getName());
}
@Command(
aliases = {"deltree"},
usage = "",
desc = "Floating tree remover tool",
min = 0,
max = 0
name = "deltree",
desc = "Floating tree remover tool"
)
@CommandPermissions("worldedit.tool.deltree")
public void deltree(Player player, LocalSession session, CommandContext args) throws WorldEditException {
session.setTool(new FloatingTreeRemover(), player);
BBC.TOOL_DELTREE.send(player, player.getItemInHand(HandSide.MAIN_HAND).getType().getName());
public void deltree(Player player, LocalSession session) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new FloatingTreeRemover());
BBC.TOOL_DELTREE.send(player, itemStack.getType().getName());
}
@Command(
aliases = {"farwand"},
usage = "",
desc = "Wand at a distance tool",
min = 0,
max = 0
name = "farwand",
desc = "Wand at a distance tool"
)
@CommandPermissions("worldedit.tool.farwand")
public void farwand(Player player, LocalSession session, CommandContext args) throws WorldEditException {
session.setTool(new DistanceWand(), player);
BBC.TOOL_FARWAND.send(player, player.getItemInHand(HandSide.MAIN_HAND).getType().getName());
public void farwand(Player player, LocalSession session) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new DistanceWand());
BBC.TOOL_FARWAND.send(player, itemStack.getType().getName());
}
@Command(
aliases = {"lrbuild", "/lrbuild"},
usage = "<leftclick block> <rightclick block>",
desc = "Long-range building tool",
min = 2,
max = 2
name = "lrbuild",
aliases = { "/lrbuild" },
desc = "Long-range building tool"
)
@CommandPermissions("worldedit.tool.lrbuild")
public void longrangebuildtool(Player player, LocalSession session, Pattern secondary, Pattern primary) throws WorldEditException {
session.setTool(new LongRangeBuildTool(primary, secondary), player);
BBC.TOOL_LRBUILD_BOUND.send(player, player.getItemInHand(HandSide.MAIN_HAND).getType().getName());
public void longrangebuildtool(Player player, LocalSession session,
@Arg(desc = "Pattern to set on left-click")
Pattern primary,
@Arg(desc = "Pattern to set on right-click")
Pattern secondary) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(itemStack.getType(), new LongRangeBuildTool(primary, secondary));
BBC.TOOL_LRBUILD_BOUND.send(player, itemStack.getType().getName());
BBC.TOOL_LRBUILD_INFO.send(player, secondary, primary);
}
}

View File

@@ -19,23 +19,23 @@
package com.sk89q.worldedit.command;
import com.boydti.fawe.config.BBC;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalSession;
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.entity.Player;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.command.parametric.Optional;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
/**
* Tool commands.
*/
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ToolUtilCommands {
private final WorldEdit we;
@@ -44,93 +44,98 @@ public class ToolUtilCommands {
}
@Command(
aliases = { "/", "," },
usage = "[on|off]",
desc = "Toggle the super pickaxe function",
min = 0,
max = 1
name = "/",
aliases = { "," },
desc = "Toggle the super pickaxe function"
)
@CommandPermissions("worldedit.superpickaxe")
public void togglePickaxe(Player player, LocalSession session, CommandContext args) throws WorldEditException {
String newState = args.getString(0, null);
if (session.hasSuperPickAxe()) {
if ("on".equals(newState)) {
player.printError("Super pick axe already enabled.");
return;
}
public void togglePickaxe(Player player, LocalSession session,
@Arg(desc = "The new super pickaxe state", def = "")
Boolean superPickaxe) {
boolean hasSuperPickAxe = session.hasSuperPickAxe();
if (superPickaxe != null && superPickaxe == hasSuperPickAxe) {
player.printError("Super pickaxe already " + (superPickaxe ? "enabled" : "disabled") + ".");
return;
}
if (hasSuperPickAxe) {
session.disableSuperPickAxe();
player.print("Super pick axe disabled.");
player.print("Super pickaxe disabled.");
} else {
if ("off".equals(newState)) {
player.printError("Super pick axe already disabled.");
return;
}
session.enableSuperPickAxe();
player.print("Super pick axe enabled.");
player.print("Super pickaxe enabled.");
}
}
@Command(
aliases = { "mask" },
usage = "[mask]",
desc = "Set the brush mask",
min = 0,
max = -1
name = "mask",
desc = "Set the brush mask"
)
@CommandPermissions("worldedit.brush.options.mask")
public void mask(Player player, LocalSession session, @Optional Mask mask) throws WorldEditException {
public void mask(Player player, LocalSession session,
@Arg(desc = "The mask to set", def = "")
Mask mask) throws WorldEditException {
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setMask(mask);
if (mask == null) {
session.getBrushTool(player).setMask(null);
player.print("Brush mask disabled.");
} else {
session.getBrushTool(player).setMask(mask);
player.print("Brush mask set.");
}
}
@Command(
aliases = { "mat", "material" },
usage = "[pattern]",
desc = "Set the brush material",
min = 1,
max = 1
name = "material",
aliases = { "/material" },
desc = "Set the brush material"
)
@CommandPermissions("worldedit.brush.options.material")
public void material(Player player, LocalSession session, Pattern pattern) throws WorldEditException {
session.getBrushTool(player).setFill(pattern);
public void material(Player player, LocalSession session,
@Arg(desc = "The pattern of blocks to use")
Pattern pattern) throws WorldEditException {
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setFill(pattern);
player.print("Brush material set.");
}
@Command(
aliases = { "range" },
usage = "[pattern]",
desc = "Set the brush range",
min = 1,
max = 1
)
name = "range",
desc = "Set the brush range"
)
@CommandPermissions("worldedit.brush.options.range")
public void range(Player player, LocalSession session, CommandContext args) throws WorldEditException {
int range = args.getInteger(0);
session.getBrushTool(player).setRange(range);
public void range(Player player, LocalSession session,
@Arg(desc = "The range of the brush")
int range) throws WorldEditException {
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setRange(range);
player.print("Brush range set.");
}
@Command(
aliases = { "size" },
usage = "[size]",
desc = "Set the brush size",
min = 1,
max = 1
name = "size",
desc = "Set the brush size"
)
@CommandPermissions("worldedit.brush.options.size")
public void size(Player player, LocalSession session, CommandContext args) throws WorldEditException {
public void size(Player player, LocalSession session,
@Arg(desc = "The size of the brush")
int size) throws WorldEditException {
we.checkMaxBrushRadius(size);
int radius = args.getInteger(0);
we.checkMaxBrushRadius(radius);
session.getBrushTool(player).setSize(radius);
session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setSize(size);
player.print("Brush size set.");
}
@Command(
name = "tracemask",
desc = "Set the mask used to stop tool traces"
)
@CommandPermissions("worldedit.brush.options.tracemask")
public void traceMask(Player player, LocalSession session,
@Arg(desc = "The trace mask to set", def = "")
Mask mask) throws WorldEditException {
//TODO TraceMask
//session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType()).setTraceMask(mask);
if (mask == null) {
player.print("Trace mask disabled.");
} else {
player.print("Trace mask set.");
}
}
}

View File

@@ -10,7 +10,7 @@ import com.boydti.fawe.object.extent.ResettableExtent;
import com.boydti.fawe.object.extent.ScaleTransform;
import com.boydti.fawe.object.extent.TransformExtent;
import com.boydti.fawe.util.ExtentTraverser;
import com.sk89q.minecraft.util.commands.Command;
import org.enginehub.piston.annotation.Command;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;

View File

@@ -24,36 +24,40 @@ import com.boydti.fawe.FaweVersion;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.util.IncendoPaster;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.worldedit.LocalSession;
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.PrintCommandHelp;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.platform.ConfigurationLoadEvent;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.time.zone.ZoneRulesException;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch;
@Command(aliases = {"worldedit", "we", "fawe"}, desc = "Updating, informational, debug and help commands")
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class WorldEditCommands {
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
private static final DateTimeFormatter dateFormat = DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss z");
private final WorldEdit we;
@@ -62,21 +66,20 @@ public class WorldEditCommands {
}
@Command(
aliases = { "version", "ver" },
usage = "",
desc = "Get WorldEdit/FAWE version",
min = 0,
max = 0,
queued = false
name = "version",
aliases = { "ver" },
desc = "Get WorldEdit/FAWE version"
//queued = false
)
public void version(Actor actor) throws WorldEditException {
public void version(Actor actor) {
FaweVersion fVer = Fawe.get().getVersion();
String fVerStr = fVer == null ? "unknown" : "-" + fVer.build;
actor.print("FastAsyncWorldEdit-1.13" + fVerStr + " by Empire92");
actor.print("FastAsyncWorldEdit" + fVerStr + " created by Empire92");
if (fVer != null) {
actor.printDebug("----------- Platforms -----------");
FaweVersion version = Fawe.get().getVersion();
Date date = new GregorianCalendar(2000 + version.year, version.month - 1, version.day).getTime();
Date date = new GregorianCalendar(2000 + version.year, version.month - 1, version.day)
.getTime();
actor.printDebug(" - DATE: " + date.toLocaleString());
actor.printDebug(" - COMMIT: " + Integer.toHexString(version.hash));
actor.printDebug(" - BUILD: " + version.build);
@@ -87,61 +90,55 @@ public class WorldEditCommands {
actor.printDebug("----------- Platforms -----------");
for (Platform platform : pm.getPlatforms()) {
actor.printDebug(String.format("* %s", platform.getPlatformName()));
actor.printDebug(String.format("* %s (%s)", platform.getPlatformName(), platform.getPlatformVersion()));
}
actor.printDebug("----------- Capabilities -----------");
for (Capability capability : Capability.values()) {
Platform platform = pm.queryCapability(capability);
actor.printDebug(String.format(" - %s: %s", capability.name(), platform != null ? platform.getPlatformName() : "NONE"));
actor.printDebug(String.format("%s: %s", capability.name(), platform != null ? platform.getPlatformName() : "NONE"));
}
actor.printDebug("------------------------------------");
actor.printDebug("Wiki: " + "https://github.com/boy0001/FastAsyncWorldedit/wiki");
}
@Command(
aliases = { "reload" },
usage = "",
desc = "Reload configuration and translations",
min = 0,
max = 0
name = "reload",
desc = "Reload configuration and translations"
)
@CommandPermissions("worldedit.reload")
public void reload(Actor actor) throws WorldEditException {
public void reload(Actor actor) {
we.getPlatformManager().queryCapability(Capability.CONFIGURATION).reload();
we.getEventBus().post(new ConfigurationLoadEvent(we.getPlatformManager().queryCapability(Capability.CONFIGURATION).getConfiguration()));
Fawe.get().setupConfigs();
CommandManager.getInstance().register(we.getPlatformManager().queryCapability(Capability.USER_COMMANDS));
actor.print("Configuration and translations reloaded!");
}
@Command(
aliases = {"debugpaste"},
usage = "",
desc = "Upload latest.log, config.yml, message.yml and your commands.yml to https://athion.net/ISPaster/paste",
min = 0,
max = 0
name = "report",
aliases = { "debugpaste" },
desc = "Writes a report of latest.log, config.yml, message.yml and your commands.yml to https://athion.net/ISPaster/paste"
)
@CommandPermissions("worldedit.debugpaste")
public void debugpaste(Actor actor) throws WorldEditException, IOException {
@CommandPermissions({"worldedit.report", "worldedit.debugpaste"})
public void report(Actor actor) throws WorldEditException, IOException {
BBC.DOWNLOAD_LINK.send(actor, IncendoPaster.debugPaste());
}
@Command(
aliases = {"threads"},
usage = "",
desc = "Print all thread stacks",
min = 0,
max = 0,
queued = false
name = "threads",
desc = "Print all thread stacks"
//queued = false
)
@CommandPermissions("worldedit.threads")
public void threads(Actor actor) throws WorldEditException {
Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
for (Map.Entry<Thread, StackTraceElement[]> entry : stacks.entrySet()) {
Thread thread = entry.getKey();
actor.printDebug("--------------------------------------------------------------------------------------------");
actor.printDebug("Thread: " + thread.getName() + " | Id: " + thread.getId() + " | Alive: " + thread.isAlive());
actor.printDebug(
"--------------------------------------------------------------------------------------------");
actor.printDebug(
"Thread: " + thread.getName() + " | Id: " + thread.getId() + " | Alive: " + thread
.isAlive());
for (StackTraceElement elem : entry.getValue()) {
actor.printDebug(elem.toString());
}
@@ -149,41 +146,47 @@ public class WorldEditCommands {
}
@Command(
aliases = { "cui" },
usage = "",
desc = "Complete CUI handshake (internal usage)",
min = 0,
max = 0
name = "cui",
desc = "Complete CUI handshake (internal usage)"
)
public void cui(Player player, LocalSession session) throws WorldEditException {
public void cui(Player player, LocalSession session) {
session.setCUISupport(true);
session.dispatchCUISetup(player);
}
@Command(
aliases = { "tz" },
usage = "[timezone]",
desc = "Set your timezone for snapshots",
min = 1,
max = 1
name = "tz",
desc = "Set your timezone for snapshots"
)
public void tz(Player player, LocalSession session, CommandContext args) throws WorldEditException {
TimeZone tz = TimeZone.getTimeZone(args.getString(0));
session.setTimezone(tz);
BBC.TIMEZONE_SET.send(player, tz.getDisplayName());
BBC.TIMEZONE_DISPLAY.send(player, dateFormat.format(Calendar.getInstance(tz).getTime()));
public void tz(Player player, LocalSession session,
@Arg(desc = "The timezone to set")
String timezone) {
try {
ZoneId tz = ZoneId.of(timezone);
session.setTimezone(tz);
BBC.TIMEZONE_SET.send(player, tz.getDisplayName(
TextStyle.FULL, Locale.ENGLISH
));
BBC.TIMEZONE_DISPLAY
.send(player, dateFormat.format(ZonedDateTime.now(tz)));
} catch (ZoneRulesException e) {
player.printError("Invalid timezone");
}
}
@Command(
aliases = { "help" },
usage = "[<command>]",
desc = "Displays help for FAWE commands",
min = 0,
max = -1,
queued = false
name = "help",
desc = "Displays help for FAWE commands"
//queued = false
)
@CommandPermissions("worldedit.help")
public void help(Actor actor, CommandContext args) throws WorldEditException {
UtilityCommands.help(args, we, actor);
public void help(Actor actor,
@Switch(name = 's', desc = "List sub-commands of the given command, if applicable")
boolean listSubCommands,
@ArgFlag(name = 'p', desc = "The page to retrieve", def = "1")
int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true)
List<String> command) throws WorldEditException {
PrintCommandHelp.help(command, page, listSubCommands, we, actor);
}
}

View File

@@ -0,0 +1,119 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.auto.value.AutoAnnotation;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.UnknownDirectionException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.MultiDirection;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import javax.annotation.Nullable;
import java.util.List;
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
public abstract class AbstractDirectionConverter<D> implements ArgumentConverter<D> {
@AutoAnnotation
private static Direction direction(boolean includeDiagonals) {
return new AutoAnnotation_AbstractDirectionConverter_direction(includeDiagonals);
}
@AutoAnnotation
private static MultiDirection multiDirection(boolean includeDiagonals) {
return new AutoAnnotation_AbstractDirectionConverter_multiDirection(includeDiagonals);
}
protected static <D> void register(CommandManager commandManager, AbstractDirectionConverter<D> converter,
Class<D> keyClass, boolean includeDiagonals) {
commandManager.registerConverter(
Key.of(keyClass, direction(includeDiagonals)),
converter
);
commandManager.registerConverter(
Key.of(keyClass, multiDirection(includeDiagonals)),
CommaSeparatedValuesConverter.wrap(converter)
);
}
private static final ImmutableSet<String> ORTHOGONAL = ImmutableSet.of(
"north", "south", "east", "west", "up", "down"
);
private static final ImmutableSet<String> RELATIVE = ImmutableSet.of(
"me", "forward", "back", "left", "right"
);
private static final ImmutableSet<String> DIAGONAL = ImmutableSet.of(
"northeast", "northwest", "southeast", "southwest"
);
private final WorldEdit worldEdit;
private final boolean includeDiagonals;
private final ImmutableList<String> suggestions;
protected AbstractDirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) {
this.worldEdit = worldEdit;
this.includeDiagonals = includeDiagonals;
suggestions = ImmutableList.<String>builder()
.addAll(ORTHOGONAL)
.addAll(RELATIVE)
.addAll(includeDiagonals ? DIAGONAL : ImmutableList.of())
.build();
}
@Override
public ConversionResult<D> convert(String argument, InjectedValueAccess context) {
Player player = context.injectedValue(Key.of(Player.class)).orElse(null);
try {
return SuccessfulConversion.fromSingle(convertDirection(argument, player, includeDiagonals));
} catch (Exception e) {
return FailedConversion.from(e);
}
}
protected abstract D convertDirection(String argument, @Nullable Player player, boolean includeDiagonals) throws UnknownDirectionException;
@Override
public Component describeAcceptableArguments() {
return TextComponent.of("`me` to use facing direction, or any "
+ (includeDiagonals ? "direction" : "non-diagonal direction"));
}
@Override
public List<String> getSuggestions(String input) {
return limitByPrefix(suggestions.stream(), input);
}
protected WorldEdit getWorldEdit() {
return worldEdit;
}
}

View File

@@ -17,21 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.formatting.component;
package com.sk89q.worldedit.command.argument;
import com.sk89q.worldedit.util.formatting.Style;
import com.sk89q.worldedit.util.formatting.StyledFragment;
import org.enginehub.piston.inject.InjectedValueAccess;
/**
* Represents a fragment representing a label.
* Key-interface for {@link InjectedValueAccess} for the String arguments.
*/
public class Label extends StyledFragment {
public interface Arguments {
/**
* Create a new instance.
*/
public Label() {
super(Style.YELLOW);
}
String get();
}

View File

@@ -0,0 +1,45 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.common.collect.ImmutableSetMultimap;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.MultiKeyConverter;
import org.enginehub.piston.inject.Key;
public class BooleanConverter {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(Boolean.class),
MultiKeyConverter.builder(
ImmutableSetMultimap.<Boolean, String>builder()
.putAll(false, "off", "f", "false", "n", "no")
.putAll(true, "on", "t", "true", "y", "yes")
.build()
)
.errorMessage(arg -> "Not a boolean value: " + arg)
.build()
);
}
private BooleanConverter() {
}
}

View File

@@ -0,0 +1,90 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import static com.google.common.base.Preconditions.checkArgument;
import static com.sk89q.worldedit.util.formatting.text.TextComponent.space;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import java.util.List;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess;
public class CommaSeparatedValuesConverter<T> implements ArgumentConverter<T> {
public static <T> CommaSeparatedValuesConverter<T> wrap(ArgumentConverter<T> delegate) {
return wrapAndLimit(delegate, -1);
}
public static <T> CommaSeparatedValuesConverter<T> wrapAndLimit(ArgumentConverter<T> delegate, int maximum) {
return new CommaSeparatedValuesConverter<>(delegate, maximum);
}
private static final Splitter COMMA = Splitter.on(',');
private final ArgumentConverter<T> delegate;
private final int maximum;
private CommaSeparatedValuesConverter(ArgumentConverter<T> delegate, int maximum) {
checkArgument(maximum == -1 || maximum > 1,
"Maximum must be bigger than 1, or exactly -1");
this.delegate = delegate;
this.maximum = maximum;
}
@Override
public Component describeAcceptableArguments() {
TextComponent.Builder result = TextComponent.builder("");
if (maximum > -1) {
result.append(TextComponent.of("up to "))
.append(TextComponent.of(maximum))
.append(space());
}
result.append(TextComponent.of("comma separated values of: "))
.append(delegate.describeAcceptableArguments());
return result.build();
}
@Override
public List<String> getSuggestions(String input) {
String lastInput = Iterables.getLast(COMMA.split(input), "");
return delegate.getSuggestions(lastInput);
}
@Override
public ConversionResult<T> convert(String argument, InjectedValueAccess context) {
ImmutableList.Builder<T> result = ImmutableList.builder();
for (String input : COMMA.split(argument)) {
ConversionResult<T> temp = delegate.convert(input, context);
if (!temp.isSuccessful()) {
return temp;
}
result.addAll(temp.get());
}
return SuccessfulConversion.from(result.build());
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.sk89q.worldedit.UnknownDirectionException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Direction;
import org.enginehub.piston.CommandManager;
import javax.annotation.Nullable;
import java.util.Optional;
public final class DirectionConverter extends AbstractDirectionConverter<Direction> {
private DirectionConverter(WorldEdit worldEdit, boolean includeDiagonals) {
super(worldEdit, includeDiagonals);
}
public static void register(WorldEdit worldEdit, CommandManager commandManager) {
for (boolean includeDiagonals : new boolean[] { false, true }) {
DirectionConverter directionConverter = new DirectionConverter(worldEdit, includeDiagonals);
register(commandManager, directionConverter, Direction.class, includeDiagonals);
}
}
@Override
protected Direction convertDirection(String argument, @Nullable Player player, boolean includeDiagonals) throws UnknownDirectionException {
final BlockVector3 vec = includeDiagonals
? getWorldEdit().getDiagonalDirection(player, argument)
: getWorldEdit().getDirection(player, argument);
return Optional.ofNullable(Direction.findClosest(vec.toVector3(), Direction.Flag.ALL))
.orElseThrow(() -> new UnknownDirectionException(argument));
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.sk89q.worldedit.UnknownDirectionException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.math.BlockVector3;
import org.enginehub.piston.CommandManager;
import javax.annotation.Nullable;
public final class DirectionVectorConverter extends AbstractDirectionConverter<BlockVector3> {
private DirectionVectorConverter(WorldEdit worldEdit, boolean includeDiagonals) {
super(worldEdit, includeDiagonals);
}
public static void register(WorldEdit worldEdit, CommandManager commandManager) {
for (boolean includeDiagonals : new boolean[] { false, true }) {
DirectionVectorConverter directionConverter = new DirectionVectorConverter(worldEdit, includeDiagonals);
register(commandManager, directionConverter, BlockVector3.class, includeDiagonals);
}
}
@Override
protected BlockVector3 convertDirection(String argument, @Nullable Player player, boolean includeDiagonals) throws UnknownDirectionException {
return includeDiagonals
? getWorldEdit().getDiagonalDirection(player, argument)
: getWorldEdit().getDirection(player, argument);
}
}

View File

@@ -0,0 +1,87 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import java.util.concurrent.locks.StampedLock;
/**
* Lazily-created {@link EditSession}.
*/
public class EditSessionHolder {
private final StampedLock lock = new StampedLock();
private final WorldEdit worldEdit;
private final Player player;
public EditSessionHolder(WorldEdit worldEdit, Player player) {
this.worldEdit = worldEdit;
this.player = player;
}
private EditSession session;
/**
* Get the session, but does not create it if it doesn't exist.
*/
public EditSession getSession() {
long stamp = lock.tryOptimisticRead();
EditSession result = session;
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
result = session;
} finally {
lock.unlockRead(stamp);
}
}
return result;
}
public EditSession getOrCreateSession() {
// use the already-generated result if possible
EditSession result = getSession();
if (result != null) {
return result;
}
// otherwise, acquire write lock
long stamp = lock.writeLock();
try {
// check session field again -- maybe another writer hit it in between
result = session;
if (result != null) {
return result;
}
// now we can do the actual creation
LocalSession localSession = worldEdit.getSessionManager().get(player);
EditSession editSession = localSession.createEditSession(player);
editSession.enableStandardMode();
localSession.tellVersion(player);
return session = editSession;
} finally {
lock.unlockWrite(stamp);
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.command.util.EntityRemover;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion;
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import java.util.List;
public class EntityRemoverConverter implements ArgumentConverter<EntityRemover> {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(EntityRemover.class), new EntityRemoverConverter());
}
private final List<String> suggestions
= ImmutableList.of("projectiles", "items", "paintings", "itemframes", "boats", "minecarts", "tnt", "xp", "all");
private EntityRemoverConverter() {
}
@Override
public Component describeAcceptableArguments() {
return TextComponent.of(
"projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all"
);
}
@Override
public List<String> getSuggestions(String input) {
return limitByPrefix(suggestions.stream(), input);
}
@Override
public ConversionResult<EntityRemover> convert(String argument, InjectedValueAccess context) {
try {
return SuccessfulConversion.fromSingle(EntityRemover.fromString(argument));
} catch (Exception e) {
return FailedConversion.from(e);
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.util.TreeGenerator;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.MultiKeyConverter;
import org.enginehub.piston.inject.Key;
import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Set;
import java.util.function.Function;
public final class EnumConverter {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(SelectorChoice.class),
basic(SelectorChoice.class));
commandManager.registerConverter(Key.of(TreeGenerator.TreeType.class),
full(TreeGenerator.TreeType.class,
t -> ImmutableSet.copyOf(t.lookupKeys),
null));
commandManager.registerConverter(Key.of(EditSession.ReorderMode.class),
full(EditSession.ReorderMode.class,
r -> ImmutableSet.of(r.getDisplayName()),
null));
}
private static <E extends Enum<E>> ArgumentConverter<E> basic(Class<E> enumClass) {
return full(enumClass, e -> ImmutableSet.of(e.name().toLowerCase(Locale.ROOT)), null);
}
private static <E extends Enum<E>> ArgumentConverter<E> basic(Class<E> enumClass, @Nullable E unknownValue) {
return full(enumClass, e -> ImmutableSet.of(e.name().toLowerCase(Locale.ROOT)), unknownValue);
}
private static <E extends Enum<E>> ArgumentConverter<E> full(Class<E> enumClass,
Function<E, Set<String>> lookupKeys,
@Nullable E unknownValue) {
return MultiKeyConverter.from(
EnumSet.allOf(enumClass),
lookupKeys,
unknownValue
);
}
private EnumConverter() {
}
}

View File

@@ -0,0 +1,105 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.registry.AbstractFactory;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import java.util.List;
import java.util.function.Function;
public class FactoryConverter<T> implements ArgumentConverter<T> {
public static void register(WorldEdit worldEdit, CommandManager commandManager) {
commandManager.registerConverter(Key.of(Pattern.class),
new FactoryConverter<>(worldEdit, WorldEdit::getPatternFactory, "pattern"));
commandManager.registerConverter(Key.of(Mask.class),
new FactoryConverter<>(worldEdit, WorldEdit::getMaskFactory, "mask"));
commandManager.registerConverter(Key.of(BaseItem.class),
new FactoryConverter<>(worldEdit, WorldEdit::getItemFactory, "item"));
}
private final WorldEdit worldEdit;
private final Function<WorldEdit, AbstractFactory<T>> factoryExtractor;
private final String description;
private FactoryConverter(WorldEdit worldEdit,
Function<WorldEdit, AbstractFactory<T>> factoryExtractor,
String description) {
this.worldEdit = worldEdit;
this.factoryExtractor = factoryExtractor;
this.description = description;
}
@Override
public ConversionResult<T> convert(String argument, InjectedValueAccess context) {
Actor actor = context.injectedValue(Key.of(Actor.class))
.orElseThrow(() -> new IllegalStateException("No actor"));
LocalSession session = WorldEdit.getInstance().getSessionManager().get(actor);
ParserContext parserContext = new ParserContext();
parserContext.setActor(actor);
if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) {
parserContext.setWorld((World) extent);
}
}
parserContext.setSession(session);
parserContext.setRestricted(true);
try {
return SuccessfulConversion.fromSingle(
factoryExtractor.apply(worldEdit).parseFromInput(argument, parserContext)
);
} catch (InputParseException e) {
return FailedConversion.from(e);
}
}
@Override
public List<String> getSuggestions(String input) {
return factoryExtractor.apply(worldEdit).getSuggestions(input);
}
@Override
public Component describeAcceptableArguments() {
return TextComponent.of("any " + description);
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.common.collect.ImmutableSetMultimap;
import com.sk89q.worldedit.regions.factory.CuboidRegionFactory;
import com.sk89q.worldedit.regions.factory.CylinderRegionFactory;
import com.sk89q.worldedit.regions.factory.RegionFactory;
import com.sk89q.worldedit.regions.factory.SphereRegionFactory;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.MultiKeyConverter;
import org.enginehub.piston.inject.Key;
public class RegionFactoryConverter {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(RegionFactory.class),
MultiKeyConverter.builder(
ImmutableSetMultimap.<RegionFactory, String>builder()
.put(new CuboidRegionFactory(), "cuboid")
.put(new SphereRegionFactory(), "sphere")
.putAll(new CylinderRegionFactory(1), "cyl", "cylinder")
.build()
)
.errorMessage(arg -> "Not a known region type: " + arg)
.build()
);
}
private RegionFactoryConverter() {
}
}

View File

@@ -0,0 +1,111 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.command.util.SuggestionHelper;
import com.sk89q.worldedit.registry.Keyed;
import com.sk89q.worldedit.registry.Registry;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockCategory;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.fluid.FluidCategory;
import com.sk89q.worldedit.world.fluid.FluidType;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.item.ItemCategory;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.weather.WeatherType;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;
public final class RegistryConverter<V extends Keyed> implements ArgumentConverter<V> {
@SuppressWarnings("unchecked")
public static void register(CommandManager commandManager) {
ImmutableList.of(
BlockType.class,
BlockCategory.class,
ItemType.class,
ItemCategory.class,
BiomeType.class,
EntityType.class,
FluidType.class,
FluidCategory.class,
GameMode.class,
WeatherType.class
).stream()
.map(c -> (Class<Keyed>) c)
.forEach(registryType ->
commandManager.registerConverter(Key.of(registryType), from(registryType))
);
}
@SuppressWarnings("unchecked")
private static <V extends Keyed> RegistryConverter<V> from(Class<Keyed> registryType) {
try {
Field registryField = registryType.getDeclaredField("REGISTRY");
Registry<V> registry = (Registry<V>) registryField.get(null);
return new RegistryConverter<>(registry);
} catch (NoSuchFieldException e) {
throw new IllegalArgumentException("Not a registry-backed type: " + registryType.getName());
} catch (IllegalAccessException e) {
throw new IllegalStateException("Registry field inaccessible on " + registryType.getName());
}
}
private final Registry<V> registry;
private final TextComponent choices;
private RegistryConverter(Registry<V> registry) {
this.registry = registry;
this.choices = TextComponent.of("any " + registry.getName());
}
@Override
public Component describeAcceptableArguments() {
return this.choices;
}
@Override
public ConversionResult<V> convert(String argument, InjectedValueAccess injectedValueAccess) {
V result = registry.get(argument);
return result == null
? FailedConversion.from(new IllegalArgumentException(
"Not a valid " + registry.getName() + ": " + argument))
: SuccessfulConversion.fromSingle(result);
}
@Override
public List<String> getSuggestions(String input) {
return SuggestionHelper.getRegistrySuggestions(registry, input).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
public enum SelectorChoice {
CUBOID,
EXTEND,
POLY,
ELLIPSOID,
SPHERE,
CYL,
CONVEX,
HULL,
POLYHEDRON,
LIST,
FUZZY,
MAGIC,
POLYHEDRAL
}

View File

@@ -0,0 +1,110 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.TypeToken;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector2;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ArgumentConverters;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import java.util.List;
import java.util.function.Function;
public class VectorConverter<C, T> implements ArgumentConverter<T> {
public static void register(CommandManager commandManager) {
CommaSeparatedValuesConverter<Integer> intConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(int.class)));
CommaSeparatedValuesConverter<Double> doubleConverter = CommaSeparatedValuesConverter.wrap(ArgumentConverters.get(TypeToken.of(double.class)));
commandManager.registerConverter(Key.of(BlockVector2.class),
new VectorConverter<>(
intConverter,
2,
cmps -> BlockVector2.at(cmps.get(0), cmps.get(1)),
"block vector with x and z"
));
commandManager.registerConverter(Key.of(Vector2.class),
new VectorConverter<>(
doubleConverter,
2,
cmps -> Vector2.at(cmps.get(0), cmps.get(1)),
"vector with x and z"
));
commandManager.registerConverter(Key.of(BlockVector3.class),
new VectorConverter<>(
intConverter,
3,
cmps -> BlockVector3.at(cmps.get(0), cmps.get(1), cmps.get(2)),
"block vector with x, y, and z"
));
commandManager.registerConverter(Key.of(Vector3.class),
new VectorConverter<>(
doubleConverter,
3,
cmps -> Vector3.at(cmps.get(0), cmps.get(1), cmps.get(2)),
"vector with x, y, and z"
));
}
private final ArgumentConverter<C> componentConverter;
private final int componentCount;
private final Function<List<C>, T> vectorConstructor;
private final String acceptableArguments;
private VectorConverter(ArgumentConverter<C> componentConverter,
int componentCount,
Function<List<C>, T> vectorConstructor,
String acceptableArguments) {
this.componentConverter = componentConverter;
this.componentCount = componentCount;
this.vectorConstructor = vectorConstructor;
this.acceptableArguments = acceptableArguments;
}
@Override
public Component describeAcceptableArguments() {
return TextComponent.of("any " + acceptableArguments);
}
@Override
public ConversionResult<T> convert(String argument, InjectedValueAccess context) {
ConversionResult<C> components = componentConverter.convert(argument, context);
if (!components.isSuccessful()) {
return components.failureAsAny();
}
if (components.get().size() != componentCount) {
return FailedConversion.from(new IllegalArgumentException(
"Must have exactly " + componentCount + " vector components"));
}
T vector = vectorConstructor.apply(ImmutableList.copyOf(components.get()));
return SuccessfulConversion.fromSingle(vector);
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Calendar;
public class ZonedDateTimeConverter implements ArgumentConverter<ZonedDateTime> {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(ZonedDateTime.class), new ZonedDateTimeConverter());
}
private ZonedDateTimeConverter() {
}
@Override
public Component describeAcceptableArguments() {
return TextComponent.of("any date");
}
@Override
public ConversionResult<ZonedDateTime> convert(String argument, InjectedValueAccess context) {
LocalSession session = context.injectedValue(Key.of(LocalSession.class))
.orElseThrow(() -> new IllegalStateException("Need a local session"));
Calendar date = session.detectDate(argument);
if (date == null) {
return FailedConversion.from(new IllegalArgumentException("Not a date: " + argument));
}
return SuccessfulConversion.fromSingle(date.toInstant().atZone(ZoneOffset.UTC));
}
}

View File

@@ -0,0 +1,21 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@org.enginehub.piston.util.NonnullByDefault
package com.sk89q.worldedit.command.argument;

View File

@@ -165,7 +165,7 @@ public class SelectionCommand extends SimpleCommand<Operation> {
return operation;
} catch (IncompleteRegionException e) {
WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter().convert(e);
WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter().convert(e);
return null;
}
} else {

View File

@@ -37,7 +37,6 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.regions.factory.RegionFactory;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.command.argument.CommandArgs;
import com.sk89q.worldedit.util.command.composition.CommandExecutor;
import com.sk89q.worldedit.util.command.composition.SimpleCommand;
@@ -77,7 +76,7 @@ public class ShapedBrushCommand extends SimpleCommand<Object> {
tool.setFill(null);
tool.setBrush(new OperationFactoryBrush(factory, regionFactory, session), permission);
} catch (MaxBrushRadiusException | InvalidToolBindException e) {
WorldEdit.getInstance().getPlatformManager().getCommandManager().getExceptionConverter().convert(e);
WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter().convert(e);
}
player.print("Set brush to " + factory);

View File

@@ -0,0 +1,54 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.factory;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.function.ItemUseFunction;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.World;
public final class ItemUseFactory implements Contextual<RegionFunction> {
private final BaseItem item;
private final Direction dir;
public ItemUseFactory(BaseItem item) {
this(item, Direction.UP);
}
public ItemUseFactory(BaseItem item, Direction dir) {
this.item = item;
this.dir = dir;
}
@Override
public RegionFunction createFromContext(EditContext input) {
World world = ((EditSession) input.getDestination()).getWorld();
return new ItemUseFunction(world, item, dir);
}
@Override
public String toString() {
return "application of the item " + item.getType();
}
}

View File

@@ -0,0 +1,49 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.factory;
import static com.sk89q.worldedit.util.GuavaUtil.firstNonNull;
import com.sk89q.worldedit.extent.NullExtent;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.pattern.Pattern;
public class ReplaceFactory implements Contextual<RegionFunction> {
private final Pattern fill;
public ReplaceFactory(Pattern fill) {
this.fill = fill;
}
@Override
public RegionFunction createFromContext(EditContext context) {
return new BlockReplace(
firstNonNull(context.getDestination(), new NullExtent()),
firstNonNull(context.getFill(), fill));
}
@Override
public String toString() {
return "replace blocks";
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.factory;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.function.Contextual;
import com.sk89q.worldedit.function.EditContext;
import com.sk89q.worldedit.function.generator.ForestGenerator;
import com.sk89q.worldedit.util.TreeGenerator;
public final class TreeGeneratorFactory implements Contextual<ForestGenerator> {
private final TreeGenerator.TreeType type;
public TreeGeneratorFactory(TreeGenerator.TreeType type) {
this.type = type;
}
@Override
public ForestGenerator createFromContext(EditContext input) {
return new ForestGenerator((EditSession) input.getDestination(), type);
}
@Override
public String toString() {
return "tree of type " + type;
}
}

View File

@@ -26,7 +26,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
@@ -47,18 +47,18 @@ public class AreaPickaxe implements BlockTool {
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) {
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
int ox = clicked.getBlockX();
int oy = clicked.getBlockY();
int oz = clicked.getBlockZ();
BlockType initialType = clicked.getExtent().getBlock(clicked.toVector().toBlockPoint()).getBlockType();
if (initialType.getMaterial().isAir()) {
return true;
return false;
}
if (initialType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) {
return true;
return false;
}
try (EditSession editSession = session.createEditSession(player)) {
@@ -71,7 +71,9 @@ public class AreaPickaxe implements BlockTool {
if (editSession.getLazyBlock(x, y, z).getBlockType() != initialType) {
continue;
}
editSession.setBlock(x, y, z, BlockTypes.AIR.getDefaultState());
}
}
}

View File

@@ -51,8 +51,8 @@ public class BlockDataCyler implements DoubleActionBlockTool {
private Map<UUID, Property<?>> selectedProperties = new HashMap<>();
private boolean handleCycle(Platform server, LocalConfiguration config,
Player player, LocalSession session, Location clicked, boolean forward) {
private boolean handleCycle(LocalConfiguration config, Player player, LocalSession session,
Location clicked, boolean forward) {
World world = (World) clicked.getExtent();
@@ -89,7 +89,7 @@ public class BlockDataCyler implements DoubleActionBlockTool {
try {
editSession.setBlock(blockPoint, newBlock);
player.print("Value of " + currentProperty.getName() + " is now " + currentProperty.getValues().get(index).toString());
player.print("Value of " + currentProperty.getName() + " is now " + currentProperty.getValues().get(index));
} catch (MaxChangedBlocksException e) {
BBC.BLOCK_CYCLER_LIMIT.send(player);
} finally {
@@ -111,12 +111,12 @@ public class BlockDataCyler implements DoubleActionBlockTool {
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
return handleCycle(server, config, player, session, clicked, true);
return handleCycle(config, player, session, clicked, true);
}
@Override
public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
return handleCycle(server, config, player, session, clicked, false);
return handleCycle(config, player, session, clicked, false);
}
}

View File

@@ -27,9 +27,9 @@ import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.block.BlockState;
/**
@@ -49,7 +49,7 @@ public class BlockReplacer implements DoubleActionBlockTool {
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) {
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
BlockBag bag = session.getBlockBag(player);
try (EditSession editSession = session.createEditSession(player)) {
@@ -71,12 +71,12 @@ public class BlockReplacer implements DoubleActionBlockTool {
@Override
public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) {
public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
EditSession editSession = session.createEditSession(player);
BlockState targetBlock = editSession.getBlock(clicked.toVector().toBlockPoint());
if (targetBlock != null) {
pattern = (targetBlock);
pattern = targetBlock;
player.print("Replacer tool switched to: " + targetBlock.getBlockType().getName());
}

View File

@@ -27,5 +27,15 @@ import com.sk89q.worldedit.util.Location;
public interface BlockTool extends Tool {
/**
* Perform the primary action of this tool.
*
* @param server
* @param config
* @param player
* @param session
* @param clicked
* @return true to cancel the original event which triggered this action (if possible)
*/
boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked);
}

View File

@@ -19,6 +19,8 @@
package com.sk89q.worldedit.command.tool;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FawePlayer;
@@ -40,14 +42,13 @@ import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.MaskTraverser;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TaskManager;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem;
@@ -67,15 +68,15 @@ import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.block.BlockType;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nullable;
/**
* Builds a shape at the place being looked at.
@@ -92,7 +93,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
}
protected static int MAX_RANGE = 500;
protected int range = 240;
protected int range = -1;
private VisualMode visualMode = VisualMode.NONE;
private TargetMode targetMode = TargetMode.TARGET_BLOCK_RANGE;
private Mask targetMask = null;
@@ -202,7 +203,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
}
}
private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
lock = new ReentrantLock();
boolean multi = stream.readBoolean();
primary = (BrushSettings) stream.readObject();
@@ -323,18 +324,12 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
* @param permission the permission
*/
public void setBrush(Brush brush, String permission) {
setBrush(brush, permission, null);
update();
}
@Deprecated
public void setBrush(Brush brush, String permission, Player player) {
if (player != null) clear(player);
BrushSettings current = getContext();
current.clearPerms();
current.setBrush(brush);
current.addPermission(permission);
update();
update();
}
/**
@@ -360,8 +355,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
*
* @return the material
*/
@Nullable
public Pattern getMaterial() {
@Nullable public Pattern getMaterial() {
return getContext().getMaterial();
}
@@ -410,6 +404,11 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
this.range = range;
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
return act(BrushAction.PRIMARY, server, config, player, session);
}
public BlockVector3 getPosition(EditSession editSession, Player player) {
Location loc = player.getLocation();
switch (targetMode) {
@@ -456,84 +455,79 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
return TaskManager.IMP.sync(new RunnableVal<Vector3>() {
@Override
public void run(Vector3 value) {
Location result = tb.getMaskedTargetBlock(useLastBlock);
this.value = result;
this.value = tb.getMaskedTargetBlock(useLastBlock);
}
});
}
public boolean act(BrushAction action, Platform server, LocalConfiguration config, Player player, LocalSession session) {
switch (action) {
case PRIMARY:
setContext(primary);
break;
case SECONDARY:
setContext(secondary);
break;
if (action == BrushAction.PRIMARY) {
setContext(primary);
} else if (action == BrushAction.SECONDARY) {
setContext(secondary);
}
BrushSettings current = getContext();
Brush brush = current.getBrush();
if (brush == null) return false;
EditSession editSession = session.createEditSession(player);
if (current.setWorld(editSession.getWorld().getName()) && !current.canUse(player)) {
BBC.NO_PERM.send(player, StringMan.join(current.getPermissions(), ","));
return false;
}
BlockVector3 target = getPosition(editSession, player);
if (target == null) {
editSession.cancel();
BBC.NO_BLOCK.send(player);
return false;
}
BlockBag bag = session.getBlockBag(player);
Request.request().setEditSession(editSession);
Mask mask = current.getMask();
if (mask != null) {
Mask existingMask = editSession.getMask();
if (existingMask == null) {
editSession.setMask(mask);
} else if (existingMask instanceof MaskIntersection) {
((MaskIntersection) existingMask).add(mask);
} else {
MaskIntersection newMask = new MaskIntersection(existingMask);
newMask.add(mask);
editSession.setMask(newMask);
try (EditSession editSession = session.createEditSession(player)) {
if (current.setWorld(editSession.getWorld().getName()) && !current.canUse(player)) {
BBC.NO_PERM.send(player, StringMan.join(current.getPermissions(), ","));
return false;
}
BlockVector3 target = getPosition(editSession, player);
if (target == null) {
editSession.cancel();
BBC.NO_BLOCK.send(player);
return true;
}
Request.request().setEditSession(editSession);
Mask mask = current.getMask();
if (mask != null) {
Mask existingMask = editSession.getMask();
if (existingMask == null) {
editSession.setMask(mask);
} else if (existingMask instanceof MaskIntersection) {
((MaskIntersection) existingMask).add(mask);
} else {
MaskIntersection newMask = new MaskIntersection(existingMask);
newMask.add(mask);
editSession.setMask(newMask);
}
}
Mask sourceMask = current.getSourceMask();
if (sourceMask != null) {
editSession.addSourceMask(sourceMask);
}
ResettableExtent transform = current.getTransform();
if (transform != null) {
editSession.addTransform(transform);
}
try {
new PatternTraverser(current).reset(editSession);
double size = current.getSize();
WorldEdit.getInstance().checkMaxBrushRadius(size);
brush.build(editSession, target, current.getMaterial(), size);
} catch (MaxChangedBlocksException e) {
player.printError("Max blocks change limit reached.");
} finally {
session.remember(editSession);
}
}
Mask sourceMask = current.getSourceMask();
if (sourceMask != null) {
editSession.addSourceMask(sourceMask);
}
ResettableExtent transform = current.getTransform();
if (transform != null) {
editSession.addTransform(transform);
}
try {
new PatternTraverser(current).reset(editSession);
double size = current.getSize();
WorldEdit.getInstance().checkMaxBrushRadius(size);
brush.build(editSession, target, current.getMaterial(), size);
} catch (WorldEditException e) {
player.printError("Max blocks change limit reached."); // Never happens
} finally {
if (bag != null) {
bag.flushChanges();
}
session.remember(editSession);
Request.reset();
}
return true;
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
return act(BrushAction.PRIMARY, server, config, player, session);
return true;
}
@Override
@@ -569,7 +563,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
if (this.visualMode != VisualMode.NONE) {
clear(player);
}
this.visualMode = visualMode != null ? visualMode : VisualMode.NONE;
this.visualMode = visualMode;
if (visualMode != VisualMode.NONE) {
try {
queueVisualization(FawePlayer.wrap(player));
@@ -647,10 +641,9 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
if (position != null) {
editSession.setExtent(newVisualExtent);
switch (mode) {
case POINT: {
case POINT:
editSession.setBlock(position, VisualChunk.VISUALIZE_BLOCK);
break;
}
case OUTLINE: {
new PatternTraverser(current).reset(editSession);
brush.build(editSession, position, current.getMaterial(), current.getSize());

View File

@@ -36,7 +36,7 @@ import com.sk89q.worldedit.util.Location;
public class DistanceWand extends BrushTool implements DoubleActionTraceTool {
public DistanceWand() {
super("worldedit.wand");
super("worldedit.selection.pos");
}
@Override
@@ -46,40 +46,31 @@ public class DistanceWand extends BrushTool implements DoubleActionTraceTool {
@Override
public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
if (session.isToolControlEnabled() && player.hasPermission("worldedit.selection.pos")) {
Location target = getTarget(player);
if (target == null) return true;
RegionSelector selector = session.getRegionSelector(player.getWorld());
BlockVector3 blockPoint = target.toVector().toBlockPoint();
if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) {
selector.explainPrimarySelection(player, session, blockPoint);
}
return true;
Location target = getTarget(player);
if (target == null) return true;
RegionSelector selector = session.getRegionSelector(player.getWorld());
BlockVector3 blockPoint = target.toVector().toBlockPoint();
if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) {
selector.explainPrimarySelection(player, session, blockPoint);
}
return false;
return true;
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
if (session.isToolControlEnabled() && player.hasPermission("worldedit.selection.pos")) {
Location target = getTarget(player);
if (target == null) return true;
RegionSelector selector = session.getRegionSelector(player.getWorld());
BlockVector3 blockPoint = target.toVector().toBlockPoint();
if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) {
selector.explainSecondarySelection(player, session, blockPoint);
}
return true;
Location target = getTarget(player);
if (target == null) return true;
RegionSelector selector = session.getRegionSelector(player.getWorld());
BlockVector3 blockPoint = target.toVector().toBlockPoint();
if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) {
selector.explainSecondarySelection(player, session, blockPoint);
}
return false;
return true;
}
public Location getTarget(Player player) {
private Location getTarget(Player player) {
Location target;
if (this.range > -1) {
target = player.getBlockTrace(getRange(), true);

View File

@@ -30,6 +30,16 @@ import com.sk89q.worldedit.util.Location;
*/
public interface DoubleActionBlockTool extends BlockTool {
/**
* Perform the secondary action of this block tool.
*
* @param server
* @param config
* @param player
* @param session
* @param clicked
* @return true to cancel the original event which triggered this action (if possible)
*/
boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked);
}

View File

@@ -29,6 +29,15 @@ import com.sk89q.worldedit.extension.platform.Platform;
*/
public interface DoubleActionTraceTool extends TraceTool {
/**
* Perform the secondary function of this tool.
*
* @param server
* @param config
* @param player
* @param session
* @return true to cancel the original event which triggered this action (if possible)
*/
boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session);
}

View File

@@ -64,7 +64,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo
eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), secondary);
}
return true;
} catch (MaxChangedBlocksException e) {
} catch (MaxChangedBlocksException ignored) {
// one block? eat it
}
return false;
@@ -84,14 +84,19 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo
eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), primary);
}
return true;
} catch (MaxChangedBlocksException e) {
} catch (MaxChangedBlocksException ignored) {
// one block? eat it
}
return true;
return false;
}
public Location getTargetFace(Player player) {
private Location getTargetFace(Player player) {
Location target = player.getBlockTraceFace(getRange(), true);
if (this.range > -1) {
target = player.getBlockTrace(getRange(), true);
} else {
target = player.getBlockTrace(MAX_RANGE, false);
}
if (target == null) {
BBC.NO_BLOCK.send(player);

View File

@@ -0,0 +1,68 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.tool;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.util.Location;
public class NavigationWand implements DoubleActionTraceTool {
@Override
public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
if (!player.hasPermission("worldedit.navigation.jumpto.tool")) {
return false;
}
final int maxDist = config.navigationWandMaxDistance;
if (maxDist <= 0) {
return false;
}
Location pos = player.getSolidBlockTrace(maxDist);
if (pos != null) {
player.findFreePosition(pos);
} else {
player.printError("No block in sight (or too far)!");
}
return true;
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
if (!player.hasPermission("worldedit.navigation.thru.tool")) {
return false;
}
final int maxDist = config.navigationWandMaxDistance;
if (maxDist <= 0) {
return false;
}
if (!player.passThroughForwardWall(Math.max(1, maxDist - 10))) {
player.printError("Nothing to pass through (or too far)!");
}
return true;
}
@Override
public boolean canUse(Actor actor) {
return true; // skip check here - checked separately for primary/secondary
}
}

View File

@@ -22,11 +22,14 @@ package com.sk89q.worldedit.command.tool;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.blocks.MobSpawnerBlock;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
@@ -41,23 +44,30 @@ public class QueryTool implements BlockTool {
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) {
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
World world = (World) clicked.getExtent();
EditSession editSession = session.createEditSession(player);
BlockVector3 blockPoint = clicked.toVector().toBlockPoint();
BaseBlock block = editSession.getFullBlock(blockPoint);
player.print("\u00A79@" + clicked.toVector() + ": " + "\u00A7e"
+ block.getBlockType().getName() + "\u00A77" + " ("
+ block.toString() + ") "
+ "\u00A7f"
+ " (" + world.getBlockLightLevel(blockPoint) + "/" + world.getBlockLightLevel(blockPoint.add(0, 1, 0)) + ")");
if (block instanceof MobSpawnerBlock) {
player.printRaw("\u00A7e" + "Mob Type: "
+ ((MobSpawnerBlock) block).getMobType());
TextComponent.Builder builder = TextComponent.builder();
builder.append(TextComponent.of("@" + clicked.toVector().toBlockPoint() + ": ", TextColor.BLUE));
builder.append(TextComponent.of(block.getBlockType().getName(), TextColor.YELLOW));
builder.append(TextComponent.of(" (" + block + ") ", TextColor.GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Block state"))));
/*
final OptionalInt internalId = BlockStateIdAccess.getBlockStateId(block.toImmutableState());
if (internalId.isPresent()) {
builder.append(TextComponent.of(" (" + internalId.getAsInt() + ") ", TextColor.DARK_GRAY)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Internal ID"))));
}
*/
builder.append(TextComponent.of(" (" + world.getBlockLightLevel(blockPoint) + "/"
+ world.getBlockLightLevel(blockPoint.add(0, 1, 0)) + ")", TextColor.WHITE)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Block Light/Light Above"))));
player.print(builder.build());
return true;
}

View File

@@ -20,22 +20,25 @@
package com.sk89q.worldedit.command.tool;
import com.boydti.fawe.object.mask.IdMask;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
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.block.BlockTypes;
import java.util.Set;
/**
* A pickaxe mode that recursively finds adjacent blocks within range of
* an initial block and of the same type.
@@ -54,34 +57,68 @@ public class RecursivePickaxe implements BlockTool {
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) {
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
World world = (World) clicked.getExtent();
final BlockVector3 pos = clicked.toBlockPoint();
EditSession editSession = session.createEditSession(player);
BlockVector3 origin = clicked.toVector().toBlockPoint();
BlockType initialType = world.getBlock(origin).getBlockType();
BlockStateHolder block = editSession.getBlock(pos);
if (block.getBlockType().getMaterial().isAir()) {
return true;
if (initialType.getMaterial().isAir()) {
return false;
}
if (block.getBlockType() == BlockTypes.BEDROCK && !player.canDestroyBedrock()) {
return true;
if (initialType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) {
return false;
}
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
try (EditSession editSession = session.createEditSession(player)) {
editSession.getSurvivalExtent().setToolUse(config.superPickaxeManyDrop);
final int radius = (int) range;
final BlockReplace replace = new BlockReplace(editSession, (BlockTypes.AIR.getDefaultState()));
editSession.setMask((Mask) null);
RecursiveVisitor visitor = new RecursiveVisitor(new IdMask(editSession), replace, radius, editSession);
visitor.visit(pos);
Operations.completeBlindly(visitor);
final int radius = (int) range;
final BlockReplace replace = new BlockReplace(editSession, (BlockTypes.AIR.getDefaultState()));
editSession.setMask(null);
RecursiveVisitor visitor = new RecursiveVisitor(new IdMask(editSession), replace, radius, editSession);
visitor.visit(pos);
Operations.completeBlindly(visitor);
editSession.flushQueue();
session.remember(editSession);
}
editSession.flushQueue();
session.remember(editSession);
return true;
}
private static void recurse(Platform server, EditSession editSession, World world, BlockVector3 pos,
BlockVector3 origin, double size, BlockType initialType, Set<BlockVector3> visited) throws MaxChangedBlocksException {
final double distanceSq = origin.distanceSq(pos);
if (distanceSq > size*size || visited.contains(pos)) {
return;
}
visited.add(pos);
if (editSession.getBlock(pos).getBlockType() != initialType) {
return;
}
editSession.setBlock(pos, BlockTypes.AIR.getDefaultState());
world.queueBlockBreakEffect(server, pos, initialType, distanceSq);
recurse(server, editSession, world, pos.add(1, 0, 0),
origin, size, initialType, visited);
recurse(server, editSession, world, pos.add(-1, 0, 0),
origin, size, initialType, visited);
recurse(server, editSession, world, pos.add(0, 0, 1),
origin, size, initialType, visited);
recurse(server, editSession, world, pos.add(0, 0, -1),
origin, size, initialType, visited);
recurse(server, editSession, world, pos.add(0, 1, 0),
origin, size, initialType, visited);
recurse(server, editSession, world, pos.add(0, -1, 0),
origin, size, initialType, visited);
}
}

View File

@@ -0,0 +1,59 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.tool;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.util.Location;
public class SelectionWand implements DoubleActionBlockTool {
@Override
public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
RegionSelector selector = session.getRegionSelector(player.getWorld());
BlockVector3 blockPoint = clicked.toVector().toBlockPoint();
if (selector.selectPrimary(blockPoint, ActorSelectorLimits.forActor(player))) {
selector.explainPrimarySelection(player, session, blockPoint);
}
return true;
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
RegionSelector selector = session.getRegionSelector(player.getWorld());
BlockVector3 blockPoint = clicked.toVector().toBlockPoint();
if (selector.selectSecondary(blockPoint, ActorSelectorLimits.forActor(player))) {
selector.explainSecondarySelection(player, session, blockPoint);
}
return true;
}
@Override
public boolean canUse(Actor actor) {
return actor.hasPermission("worldedit.selection.pos");
}
}

View File

@@ -27,6 +27,7 @@ import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
@@ -42,22 +43,23 @@ public class SinglePickaxe implements BlockTool {
}
@Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, com.sk89q.worldedit.util.Location clicked) {
World world = (World) clicked.getExtent();
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session, Location clicked) {
World world = (World) clicked.getExtent();
BlockVector3 blockPoint = clicked.toBlockPoint();
final BlockType blockType = world.getBlock(blockPoint).getBlockType();
if (blockType == BlockTypes.BEDROCK
&& !player.canDestroyBedrock()) {
return true;
if (blockType == BlockTypes.BEDROCK && !player.canDestroyBedrock()) {
return false;
}
try (EditSession editSession = session.createEditSession(player)) {
editSession.getSurvivalExtent().setToolUse(config.superPickaxeDrop);
editSession.setBlock(blockPoint, BlockTypes.AIR.getDefaultState());
session.remember(editSession);
} catch (MaxChangedBlocksException e) {
player.printError("Max blocks change limit reached.");
}
return true;
}
}

View File

@@ -26,5 +26,14 @@ import com.sk89q.worldedit.extension.platform.Platform;
public interface TraceTool extends Tool {
/**
* Perform the primary action of this trace tool.
*
* @param server
* @param config
* @param player
* @param session
* @return true to cancel the original event which triggered this action (if possible)
*/
boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session);
}

View File

@@ -20,6 +20,7 @@
package com.sk89q.worldedit.command.tool;
import com.boydti.fawe.config.BBC;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
@@ -27,6 +28,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator;
@@ -53,8 +55,9 @@ public class TreePlanter implements BlockTool {
try {
boolean successful = false;
final BlockVector3 pos = clicked.toVector().add(0, 1, 0).toBlockPoint();
for (int i = 0; i < 10; i++) {
if (treeType.generate(editSession, clicked.add(0, 1, 0).toBlockPoint())) {
if (treeType.generate(editSession, pos)) {
successful = true;
break;
}

View File

@@ -22,6 +22,7 @@ package com.sk89q.worldedit.command.tool.brush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern;
@@ -31,14 +32,30 @@ import com.sk89q.worldedit.session.ClipboardHolder;
public class ClipboardBrush implements Brush {
private ClipboardHolder holder;
private boolean ignoreAirBlocks;
private boolean usingOrigin;
private final ClipboardHolder holder;
private final boolean ignoreAirBlocks;
private final boolean usingOrigin;
private final boolean pasteEntities;
private final boolean pasteBiomes;
private final Mask sourceMask;
public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin) {
this.holder = holder;
this.ignoreAirBlocks = ignoreAirBlocks;
this.usingOrigin = usingOrigin;
this.pasteBiomes = false;
this.pasteEntities = false;
this.sourceMask = null;
}
public ClipboardBrush(ClipboardHolder holder, boolean ignoreAirBlocks, boolean usingOrigin, boolean pasteEntities,
boolean pasteBiomes, Mask sourceMask) {
this.holder = holder;
this.ignoreAirBlocks = ignoreAirBlocks;
this.usingOrigin = usingOrigin;
this.pasteEntities = pasteEntities;
this.pasteBiomes = pasteBiomes;
this.sourceMask = sourceMask;
}
@Override
@@ -51,6 +68,9 @@ public class ClipboardBrush implements Brush {
.createPaste(editSession)
.to(usingOrigin ? position : position.subtract(centerOffset))
.ignoreAirBlocks(ignoreAirBlocks)
.copyEntities(pasteEntities)
.copyBiomes(pasteBiomes)
.maskSource(sourceMask)
.build();
Operations.completeLegacy(operation);

View File

@@ -21,7 +21,6 @@ package com.sk89q.worldedit.command.tool.brush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockTypes;
@@ -37,7 +36,7 @@ public class CylinderBrush implements Brush {
@Override
public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException {
if (pattern == null) {
pattern = (BlockTypes.COBBLESTONE.getDefaultState());
pattern = BlockTypes.COBBLESTONE.getDefaultState();
}
editSession.makeCylinder(position, pattern, size, size, height, true);
}

View File

@@ -21,16 +21,11 @@ package com.sk89q.worldedit.command.tool.brush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Vector;
public class GravityBrush implements Brush {
private final boolean fullHeight;
@@ -48,8 +43,8 @@ public class GravityBrush implements Brush {
for (int x = position.getBlockX() + size; x > position.getBlockX() - size; --x) {
for (int z = position.getBlockZ() + size; z > position.getBlockZ() - size; --z) {
int freeSpot = startCheckY;
for (int y = startCheckY; y <= endY; y++) {
BlockStateHolder block = editSession.getLazyBlock(x, y, z);
for (int y = startCheckY; y <= endY; ++y) {
final BlockState block = editSession.getLazyBlock(x, y, z);
if (!block.getBlockType().getMaterial().isAir()) {
if (y != freeSpot) {
editSession.setBlock(x, y, z, BlockTypes.AIR.getDefaultState());

View File

@@ -21,7 +21,6 @@ package com.sk89q.worldedit.command.tool.brush;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockTypes;
@@ -31,7 +30,7 @@ public class SphereBrush implements Brush {
@Override
public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException {
if (pattern == null) {
pattern = (BlockTypes.COBBLESTONE.getDefaultState());
pattern = BlockTypes.COBBLESTONE.getDefaultState();
}
editSession.makeSphere(position, pattern, size, size, size, true);
}

View File

@@ -0,0 +1,196 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.command.exception.ExceptionConverter;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.task.FutureForwardingTask;
import com.sk89q.worldedit.util.task.Supervisor;
import org.enginehub.piston.exception.CommandException;
import org.enginehub.piston.exception.CommandExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
public final class AsyncCommandBuilder<T> {
private static final Logger logger = LoggerFactory.getLogger(AsyncCommandBuilder.class);
private final Callable<T> callable;
private final Actor sender;
@Nullable
private Supervisor supervisor;
@Nullable
private String description;
@Nullable
private String delayMessage;
@Nullable
private Component successMessage;
@Nullable
private Consumer<T> consumer;
@Nullable
private Component failureMessage;
@Nullable
private ExceptionConverter exceptionConverter;
private AsyncCommandBuilder(Callable<T> callable, Actor sender) {
checkNotNull(callable);
checkNotNull(sender);
this.callable = callable;
this.sender = sender;
}
public static <T> AsyncCommandBuilder<T> wrap(Callable<T> callable, Actor sender) {
return new AsyncCommandBuilder<>(callable, sender);
}
public AsyncCommandBuilder<T> registerWithSupervisor(Supervisor supervisor, String description) {
this.supervisor = checkNotNull(supervisor);
this.description = checkNotNull(description);
return this;
}
public AsyncCommandBuilder<T> sendMessageAfterDelay(String message) {
this.delayMessage = checkNotNull(message);
return this;
}
public AsyncCommandBuilder<T> onSuccess(@Nullable Component message, @Nullable Consumer<T> consumer) {
checkArgument(message != null || consumer != null, "Can't have null message AND consumer");
this.successMessage = message;
this.consumer = consumer;
return this;
}
public AsyncCommandBuilder<T> onSuccess(@Nullable String message, @Nullable Consumer<T> consumer) {
checkArgument(message != null || consumer != null, "Can't have null message AND consumer");
this.successMessage = message == null ? null : TextComponent.of(message, TextColor.LIGHT_PURPLE);
this.consumer = consumer;
return this;
}
public AsyncCommandBuilder<T> onFailure(@Nullable Component message, @Nullable ExceptionConverter exceptionConverter) {
checkArgument(message != null || exceptionConverter != null, "Can't have null message AND exceptionConverter");
this.failureMessage = message;
this.exceptionConverter = exceptionConverter;
return this;
}
public AsyncCommandBuilder<T> onFailure(@Nullable String message, @Nullable ExceptionConverter exceptionConverter) {
checkArgument(message != null || exceptionConverter != null, "Can't have null message AND exceptionConverter");
this.failureMessage = message == null ? null : ErrorFormat.wrap(message);
this.exceptionConverter = exceptionConverter;
return this;
}
public ListenableFuture<T> buildAndExec(ListeningExecutorService executor) {
final ListenableFuture<T> future = checkNotNull(executor).submit(this::runTask);
if (delayMessage != null) {
FutureProgressListener.addProgressListener(future, sender, delayMessage);
}
if (supervisor != null && description != null) {
supervisor.monitor(FutureForwardingTask.create(future, description, sender));
}
return future;
}
private T runTask() {
T result = null;
try {
result = callable.call();
if (consumer != null) {
consumer.accept(result);
}
if (successMessage != null) {
sender.print(successMessage);
}
} catch (Exception orig) {
Component failure = failureMessage != null ? failureMessage : TextComponent.of("An error occurred");
try {
if (exceptionConverter != null) {
try {
if (orig instanceof com.sk89q.minecraft.util.commands.CommandException) {
throw new CommandExecutionException(orig, ImmutableList.of());
}
exceptionConverter.convert(orig);
throw orig;
} catch (CommandException converted) {
Component message;
// TODO remove this once WG migrates to piston and can use piston exceptions everywhere
message = tryExtractOldCommandException(converted);
if (message == null) {
if (Strings.isNullOrEmpty(converted.getMessage())) {
message = TextComponent.of("Unknown error.");
} else {
message = converted.getRichMessage();
}
}
sender.print(failure.append(TextComponent.of(": ")).append(message));
}
} else {
throw orig;
}
} catch (Throwable unknown) {
sender.print(failure.append(TextComponent.of(": Unknown error. Please see console.")));
logger.error("Uncaught exception occurred in task: " + description, orig);
}
}
return result;
}
// this is needed right now since worldguard is still on the 2011 command framework which throws and converts
// com.sk89q.minecraft.util.commands.CommandException. the ExceptionConverter currently expects converted
// exceptions to be org.enginehub.piston.CommandException, throw it wraps the resulting InvocationTargetException in
// a CommandExecutionException. here, we unwrap those layers to retrieve the original WG error message
private Component tryExtractOldCommandException(CommandException converted) {
Component message = null;
if (converted instanceof CommandExecutionException) {
Throwable parentCause = converted;
while ((parentCause = parentCause.getCause()) != null) {
if (parentCause instanceof com.sk89q.minecraft.util.commands.CommandException) {
final String msg = parentCause.getMessage();
if (!Strings.isNullOrEmpty(msg)) {
message = TextComponent.of(msg);
}
break;
}
}
}
return message;
}
}

View File

@@ -1,141 +0,0 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.command.parametric.ExceptionConverter;
import com.sk89q.worldedit.util.task.FutureForwardingTask;
import com.sk89q.worldedit.util.task.Supervisor;
import com.sk89q.worldedit.world.World;
import javax.annotation.Nullable;
public class AsyncCommandHelper {
private final ListenableFuture<?> future;
private final Supervisor supervisor;
private final Actor sender;
private final ExceptionConverter exceptionConverter;
@Nullable
private Object[] formatArgs;
private AsyncCommandHelper(ListenableFuture<?> future, Supervisor supervisor, Actor sender, ExceptionConverter exceptionConverter) {
checkNotNull(future);
checkNotNull(supervisor);
checkNotNull(sender);
checkNotNull(exceptionConverter);
this.future = future;
this.supervisor = supervisor;
this.sender = sender;
this.exceptionConverter = exceptionConverter;
}
public AsyncCommandHelper formatUsing(Object... args) {
this.formatArgs = args;
return this;
}
private String format(String message) {
if (formatArgs != null) {
return String.format(message, formatArgs);
} else {
return message;
}
}
public AsyncCommandHelper registerWithSupervisor(String description) {
supervisor.monitor(
FutureForwardingTask.create(
future, format(description), sender));
return this;
}
public AsyncCommandHelper sendMessageAfterDelay(String message) {
FutureProgressListener.addProgressListener(future, sender, format(message));
return this;
}
public AsyncCommandHelper thenRespondWith(String success, String failure) {
// Send a response message
Futures.addCallback(
future,
new MessageFutureCallback.Builder(sender)
.exceptionConverter(exceptionConverter)
.onSuccess(format(success))
.onFailure(format(failure))
.build());
return this;
}
public AsyncCommandHelper thenTellErrorsOnly(String failure) {
// Send a response message
Futures.addCallback(
future,
new MessageFutureCallback.Builder(sender)
.exceptionConverter(exceptionConverter)
.onFailure(format(failure))
.build());
return this;
}
public AsyncCommandHelper forRegionDataLoad(World world, boolean silent) {
checkNotNull(world);
formatUsing(world.getName());
registerWithSupervisor("Loading region data for '%s'");
if (silent) {
thenTellErrorsOnly("Failed to load regions '%s'");
} else {
sendMessageAfterDelay("(Please wait... loading the region data for '%s')");
thenRespondWith(
"Loaded region data for '%s'",
"Failed to load regions '%s'");
}
return this;
}
public AsyncCommandHelper forRegionDataSave(World world, boolean silent) {
checkNotNull(world);
formatUsing(world.getName());
registerWithSupervisor("Saving region data for '%s'");
if (silent) {
thenTellErrorsOnly("Failed to save regions '%s'");
} else {
sendMessageAfterDelay("(Please wait... saving the region data for '%s')");
thenRespondWith(
"Saved region data for '%s'",
"Failed to load regions '%s'");
}
return this;
}
public static AsyncCommandHelper wrap(ListenableFuture<?> future, Supervisor supervisor, Actor sender, ExceptionConverter exceptionConverter) {
return new AsyncCommandHelper(future, supervisor, sender, exceptionConverter);
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import org.enginehub.piston.annotation.CommandCondition;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@CommandCondition(CommandPermissionsConditionGenerator.class)
public @interface CommandPermissions {
/**
* A list of permissions. Only one permission has to be met
* for the command to be permitted.
*
* @return a list of permissions strings
*/
String[] value();
}

View File

@@ -0,0 +1,45 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableSet;
import org.enginehub.piston.Command;
import org.enginehub.piston.gen.CommandConditionGenerator;
import org.enginehub.piston.util.NonnullByDefault;
import java.lang.reflect.Method;
import java.util.Set;
@NonnullByDefault
public final class CommandPermissionsConditionGenerator implements CommandConditionGenerator {
public interface Registration {
Registration commandPermissionsConditionGenerator(CommandPermissionsConditionGenerator generator);
}
@Override
public Command.Condition generateCondition(Method commandMethod) {
CommandPermissions annotation = commandMethod.getAnnotation(CommandPermissions.class);
checkNotNull(annotation, "Annotation is missing from commandMethod");
Set<String> permissions = ImmutableSet.copyOf(annotation.value());
return new PermissionCondition(permissions);
}
}

View File

@@ -19,7 +19,6 @@
package com.sk89q.worldedit.command.util;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.worldedit.entity.metadata.EntityProperties;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.EntityFunction;
@@ -29,7 +28,7 @@ import com.sk89q.worldedit.function.EntityFunction;
*/
public class CreatureButcher {
final class Flags {
public final class Flags {
@SuppressWarnings("PointlessBitwiseExpression")
public static final int PETS = 1 << 0;
public static final int NPCS = 1 << 1;
@@ -39,7 +38,6 @@ public class CreatureButcher {
public static final int TAGGED = 1 << 5;
public static final int FRIENDLY = PETS | NPCS | ANIMALS | GOLEMS | AMBIENT | TAGGED;
public static final int ARMOR_STAND = 1 << 6;
public static final int WITH_LIGHTNING = 1 << 20;
private Flags() {
}
@@ -64,19 +62,6 @@ public class CreatureButcher {
}
}
public void fromCommand(CommandContext args) {
or(Flags.FRIENDLY , args.hasFlag('f')); // No permission check here. Flags will instead be filtered by the subsequent calls.
or(Flags.PETS , args.hasFlag('p'), "worldedit.butcher.pets");
or(Flags.NPCS , args.hasFlag('n'), "worldedit.butcher.npcs");
or(Flags.GOLEMS , args.hasFlag('g'), "worldedit.butcher.golems");
or(Flags.ANIMALS , args.hasFlag('a'), "worldedit.butcher.animals");
or(Flags.AMBIENT , args.hasFlag('b'), "worldedit.butcher.ambient");
or(Flags.TAGGED , args.hasFlag('t'), "worldedit.butcher.tagged");
or(Flags.ARMOR_STAND , args.hasFlag('r'), "worldedit.butcher.armorstands");
or(Flags.WITH_LIGHTNING, args.hasFlag('l'), "worldedit.butcher.lightning");
}
public EntityFunction createFunction() {
return entity -> {
boolean killPets = (flags & Flags.PETS) != 0;

View File

@@ -19,16 +19,14 @@
package com.sk89q.worldedit.command.util;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.minecraft.util.commands.CommandException;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.entity.metadata.EntityProperties;
import com.sk89q.worldedit.function.EntityFunction;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import java.util.regex.Pattern;
/**
* The implementation of /remove.
@@ -126,17 +124,21 @@ public class EntityRemover {
}
}
private Type type;
public void fromString(String str) throws CommandException {
public static EntityRemover fromString(String str) {
Type type = Type.findByPattern(str);
if (type != null) {
this.type = type;
return new EntityRemover(type);
} else {
throw new CommandException("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all");
throw new IllegalArgumentException("Acceptable types: projectiles, items, paintings, itemframes, boats, minecarts, tnt, xp, or all");
}
}
private final Type type;
private EntityRemover(Type type) {
this.type = type;
}
public EntityFunction createFunction() {
final Type type = this.type;
checkNotNull(type, "type can't be null");

View File

@@ -0,0 +1,68 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//$Id$
package com.sk89q.worldedit.command.util;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Indicates how the affected blocks should be hinted at in the log.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Logging {
enum LogMode {
/**
* Player position
*/
POSITION,
/**
* Region selection
*/
REGION,
/**
* Player orientation and region selection
*/
ORIENTATION_REGION,
/**
* Either the player position or pos1, depending on the placeAtPos1 flag
*/
PLACEMENT,
/**
* Log all information available
*/
ALL
}
/**
* Log mode.
*
* @return either POSITION, REGION, ORIENTATION_REGION, PLACEMENT or ALL
*/
LogMode value();
}

View File

@@ -1,114 +0,0 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.util.concurrent.FutureCallback;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.command.parametric.ExceptionConverter;
import javax.annotation.Nullable;
public class MessageFutureCallback<V> implements FutureCallback<V> {
private final ExceptionConverter exceptionConverter;
private final Actor sender;
@Nullable
private final String success;
@Nullable
private final String failure;
private MessageFutureCallback(ExceptionConverter exceptionConverter, Actor sender, @Nullable String success, @Nullable String failure) {
this.exceptionConverter = exceptionConverter;
this.sender = sender;
this.success = success;
this.failure = failure;
}
@Override
public void onSuccess(@Nullable V v) {
if (success != null) {
sender.print(success);
}
}
@Override
public void onFailure(@Nullable Throwable throwable) {
try {
exceptionConverter.convert(throwable);
} catch (CommandException e) {
String failure = this.failure != null ? this.failure : "An error occurred";
String message = e.getMessage() != null ? e.getMessage() : "An unknown error occurred. Please see the console!";
sender.printError(failure + ": " + message);
}
}
public static class Builder {
private final Actor sender;
@Nullable
private String success;
@Nullable
private String failure;
private ExceptionConverter exceptionConverter;
public Builder(Actor sender) {
checkNotNull(sender);
this.sender = sender;
}
public Builder exceptionConverter(ExceptionConverter exceptionConverter) {
this.exceptionConverter = exceptionConverter;
return this;
}
public Builder onSuccess(@Nullable String message) {
this.success = message;
return this;
}
public Builder onFailure(@Nullable String message) {
this.failure = message;
return this;
}
public <V> MessageFutureCallback<V> build() {
checkNotNull(exceptionConverter);
return new MessageFutureCallback<>(exceptionConverter, sender, success, failure);
}
}
public static <V> MessageFutureCallback<V> createRegionLoadCallback(ExceptionConverter exceptionConverter, Actor sender) {
return new Builder(sender)
.exceptionConverter(exceptionConverter)
.onSuccess("Successfully load the region data.")
.build();
}
public static <V> MessageFutureCallback<V> createRegionSaveCallback(ExceptionConverter exceptionConverter, Actor sender) {
return new Builder(sender)
.exceptionConverter(exceptionConverter)
.onSuccess("Successfully saved the region data.")
.build();
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import com.sk89q.worldedit.extension.platform.Actor;
import org.enginehub.piston.Command;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import java.util.Set;
public class PermissionCondition implements Command.Condition {
private static final Key<Actor> ACTOR_KEY = Key.of(Actor.class);
private final Set<String> permissions;
public PermissionCondition(Set<String> permissions) {
this.permissions = permissions;
}
public Set<String> getPermissions() {
return permissions;
}
@Override
public boolean satisfied(InjectedValueAccess context) {
return permissions.isEmpty() ||
context.injectedValue(ACTOR_KEY)
.map(actor -> permissions.stream().anyMatch(actor::hasPermission))
.orElse(false);
}
}

View File

@@ -0,0 +1,155 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Actor;
import static com.sk89q.worldedit.internal.command.CommandUtil.byCleanName;
import static com.sk89q.worldedit.internal.command.CommandUtil.getSubCommands;
import com.sk89q.worldedit.util.formatting.component.CommandListBox;
import com.sk89q.worldedit.util.formatting.component.CommandUsageBox;
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException;
import static java.util.stream.Collectors.toList;
import org.enginehub.piston.Command;
import org.enginehub.piston.CommandManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Implementation of the //help command.
*/
// Stored in a separate class to prevent import conflicts, and because it's aliased via /we help.
public class PrintCommandHelp {
private static Command detectCommand(CommandManager manager, String command) {
Optional<Command> mapping;
// First try the command as entered
mapping = manager.getCommand(command);
if (mapping.isPresent()) {
return mapping.get();
}
// If tried with slashes, try dropping a slash
if (command.startsWith("/")) {
mapping = manager.getCommand(command.substring(1));
return mapping.orElse(null);
}
// Otherwise, check /command, since that's common
mapping = manager.getCommand("/" + command);
return mapping.orElse(null);
}
public static void help(List<String> commandPath, int page, boolean listSubCommands, WorldEdit we, Actor actor) throws InvalidComponentException {
CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager();
if (commandPath.isEmpty()) {
printCommands(page, manager.getAllCommands(), actor, ImmutableList.of());
return;
}
List<Command> visited = new ArrayList<>();
Command currentCommand = detectCommand(manager, commandPath.get(0));
if (currentCommand == null) {
actor.printError(String.format("The command '%s' could not be found.", commandPath.get(0)));
return;
}
visited.add(currentCommand);
// Drill down to the command
for (int i = 1; i < commandPath.size(); i++) {
String subCommand = commandPath.get(i);
Map<String, Command> subCommands = getSubCommands(currentCommand);
if (subCommands.isEmpty()) {
actor.printError(String.format("'%s' has no sub-commands. (Maybe '%s' is for a parameter?)",
toCommandString(visited), subCommand));
// full help for single command
CommandUsageBox box = new CommandUsageBox(visited, visited.stream()
.map(Command::getName).collect(Collectors.joining(" ")));
actor.print(box.create());
return;
}
if (subCommands.containsKey(subCommand)) {
currentCommand = subCommands.get(subCommand);
visited.add(currentCommand);
} else {
actor.printError(String.format("The sub-command '%s' under '%s' could not be found.",
subCommand, toCommandString(visited)));
// list subcommands for currentCommand
printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited);
return;
}
}
Map<String, Command> subCommands = getSubCommands(currentCommand);
if (subCommands.isEmpty() || !listSubCommands) {
// Create the message
CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited));
actor.print(box.create());
} else {
printCommands(page, subCommands.values().stream(), actor, visited);
}
}
private static String toCommandString(List<Command> visited) {
return "/" + Joiner.on(" ").join(visited.stream().map(Command::getName).iterator());
}
private static void printCommands(int page, Stream<Command> commandStream, Actor actor,
List<Command> commandList) throws InvalidComponentException {
// Get a list of aliases
List<Command> commands = commandStream
.sorted(byCleanName())
.collect(toList());
String used = commandList.isEmpty() ? null : toCommandString(commandList);
CommandListBox box = new CommandListBox(
(used == null ? "Help" : "Subcommands: " + used),
"//help -s -p %page%" + (used == null ? "" : " " + used));
if (!actor.isPlayer()) {
box.formatForConsole();
}
for (Command mapping : commands) {
String alias = (commandList.isEmpty() ? "/" : "") + mapping.getName();
String command = Stream.concat(commandList.stream(), Stream.of(mapping))
.map(Command::getName)
.collect(Collectors.joining(" ", "/", ""));
box.appendCommand(alias, mapping.getDescription(), command);
}
actor.print(box.create(page));
}
private PrintCommandHelp() {
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import com.google.common.collect.ImmutableSet;
import org.enginehub.piston.Command;
import org.enginehub.piston.inject.InjectedValueAccess;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
public final class SubCommandPermissionCondition extends PermissionCondition {
private final Command.Condition aggregate;
private SubCommandPermissionCondition(Set<String> perms, Command.Condition aggregate) {
super(perms);
this.aggregate = aggregate;
}
@Override
public boolean satisfied(InjectedValueAccess context) {
return aggregate.satisfied(context);
}
public static class Generator {
private final List<Command> subCommands;
public Generator(List<Command> subCommands) {
this.subCommands = subCommands;
}
public Command.Condition build() {
final List<Command.Condition> conditions = subCommands.stream().map(Command::getCondition).collect(Collectors.toList());
final List<Optional<PermissionCondition>> permConds = conditions.stream().map(c -> c.as(PermissionCondition.class)).collect(Collectors.toList());
if (permConds.stream().anyMatch(o -> !o.isPresent())) {
// if any sub-command doesn't require permissions, then this command doesn't require permissions
return new PermissionCondition(ImmutableSet.of());
}
// otherwise, this command requires any one subcommand to be available
final Set<String> perms = permConds.stream().map(Optional::get).flatMap(cond -> cond.getPermissions().stream()).collect(Collectors.toSet());
final Command.Condition aggregate = permConds.stream().map(Optional::get)
.map(c -> (Command.Condition) c)
.reduce(Command.Condition::or).orElse(TRUE);
return new SubCommandPermissionCondition(perms, aggregate);
}
}
}

View File

@@ -0,0 +1,173 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import com.sk89q.worldedit.registry.Keyed;
import com.sk89q.worldedit.registry.NamespacedRegistry;
import com.sk89q.worldedit.registry.Registry;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.block.BlockCategory;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.enginehub.piston.converter.SuggestionHelper.byPrefix;
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
/**
* Internal class for generating common command suggestions.
*/
public final class SuggestionHelper {
private SuggestionHelper() {
}
public static Stream<String> getBlockCategorySuggestions(String tag, boolean allowRandom) {
if (tag.isEmpty() || tag.equals("#")) {
return Stream.of("##", "##*");
}
if (tag.startsWith("#")) {
if (tag.equals("##")) {
return Stream.concat(Stream.of("##*"), getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(2)).map(s -> "##" + s));
} else if (tag.equals("##*") && allowRandom) {
return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(3)).map(s -> "##*" + s);
} else {
boolean wild = tag.startsWith("##*") && allowRandom;
return getNamespacedRegistrySuggestions(BlockCategory.REGISTRY, tag.substring(wild ? 3 : 2)).map(s -> (wild ? "##*" : "##") + s);
}
}
return Stream.empty();
}
public static Stream<String> getBlockPropertySuggestions(String blockType, String props) {
BlockType type = BlockTypes.get(blockType.toLowerCase(Locale.ROOT));
if (type == null) {
return Stream.empty();
}
final Map<String, ? extends Property<?>> propertyMap = type.getPropertyMap();
Set<String> matchedProperties = new HashSet<>();
String[] propParts = props.split(",", -1);
for (int i = 0; i < propParts.length; i++) {
String[] propVal = propParts[i].split("=");
final String matchProp = propVal[0].toLowerCase(Locale.ROOT);
if (i == propParts.length - 1) {
// suggest for next property
String previous = Arrays.stream(propParts, 0, propParts.length - 1).collect(Collectors.joining(","))
+ (propParts.length == 1 ? "" : ",");
String lastValidInput = (blockType + "[" + previous).toLowerCase(Locale.ROOT);
if (propVal.length == 1) {
// only property, no value yet
final List<? extends Property<?>> matchingProps = propertyMap.entrySet().stream()
.filter(p -> !matchedProperties.contains(p.getKey()) && p.getKey().startsWith(matchProp))
.map(Map.Entry::getValue).collect(Collectors.toList());
switch (matchingProps.size()) {
case 0:
return propertyMap.keySet().stream().filter(p -> !matchedProperties.contains(p)).map(prop ->
lastValidInput + prop + "=");
case 1:
return matchingProps.get(0).getValues().stream().map(val ->
lastValidInput + matchingProps.get(0).getName() + "="
+ val.toString().toLowerCase(Locale.ROOT));
default:
return matchingProps.stream().map(p -> lastValidInput + p.getName() + "=");
}
} else {
Property<?> prop = propertyMap.get(matchProp);
if (prop == null) {
return propertyMap.keySet().stream().map(p -> lastValidInput + p);
}
final List<String> values = prop.getValues().stream().map(v -> v.toString().toLowerCase(Locale.ROOT)).collect(Collectors.toList());
String matchVal = propVal[1].toLowerCase(Locale.ROOT);
List<String> matchingVals = values.stream().filter(val -> val.startsWith(matchVal)).collect(Collectors.toList());
if (matchingVals.isEmpty()) {
return values.stream().map(val -> lastValidInput + prop.getName() + "=" + val);
} else {
if (matchingVals.size() == 1 && matchingVals.get(0).equals(matchVal)) {
String currProp = lastValidInput + prop.getName() + "=" + matchVal;
if (matchingVals.size() < values.size()) {
return Stream.of(currProp + "] ", currProp + ",");
}
return Stream.of(currProp + "] ");
}
return matchingVals.stream().map(val -> lastValidInput + prop.getName() + "=" + val);
}
}
} else {
// validate previous properties
if (propVal.length != 2) {
return Stream.empty();
}
Property<?> prop = propertyMap.get(matchProp);
if (prop == null) {
return Stream.empty();
}
try {
prop.getValueFor(propVal[1]);
matchedProperties.add(prop.getName());
} catch (IllegalArgumentException ignored) {
return Stream.empty();
}
}
}
return Stream.empty();
}
public static <V extends Keyed> Stream<String> getRegistrySuggestions(Registry<V> registry, String input) {
if (registry instanceof NamespacedRegistry) {
return getNamespacedRegistrySuggestions(((NamespacedRegistry<V>) registry), input);
}
return limitByPrefix(registry.keySet().stream(), input).stream();
}
public static <V extends Keyed> Stream<String> getNamespacedRegistrySuggestions(NamespacedRegistry<V> registry, String input) {
if (input.isEmpty() || input.equals(":")) {
final Set<String> namespaces = registry.getKnownNamespaces();
if (namespaces.size() == 1) {
return registry.keySet().stream();
} else {
return namespaces.stream().map(s -> s + ":");
}
}
if (input.startsWith(":")) { // special case - search across namespaces
final String term = input.substring(1).toLowerCase(Locale.ROOT);
Predicate<String> search = byPrefix(term);
return registry.keySet().stream().filter(s -> search.test(s.substring(s.indexOf(':') + 1)));
}
// otherwise, we actually have some text to search
if (input.indexOf(':') < 0) {
// don't yet have namespace - search namespaces + default
final String lowerSearch = input.toLowerCase(Locale.ROOT);
String defKey = registry.getDefaultNamespace() + ":" + lowerSearch;
return Stream.concat(registry.keySet().stream().filter(s -> s.startsWith(defKey)),
registry.getKnownNamespaces().stream().filter(n -> n.startsWith(lowerSearch)).map(n -> n + ":"));
}
// have a namespace - search that
Predicate<String> search = byPrefix(input.toLowerCase(Locale.ROOT));
return registry.keySet().stream().filter(search);
}
}

View File

@@ -0,0 +1,46 @@
/*
* 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 Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.util;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.formatting.text.Component;
import javax.annotation.Nullable;
import java.util.concurrent.Callable;
/**
* For internal WorldEdit use only.
*/
public final class WorldEditAsyncCommandBuilder {
private WorldEditAsyncCommandBuilder() {
}
public static void createAndSendMessage(Actor actor, Callable<Component> task, @Nullable String desc) {
final AsyncCommandBuilder<Component> builder = AsyncCommandBuilder.wrap(task, actor);
if (desc != null) {
builder.sendMessageAfterDelay(desc);
}
builder
.onSuccess((String) null, actor::print)
.onFailure((String) null, WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getExceptionConverter())
.buildAndExec(WorldEdit.getInstance().getExecutorService());
}
}

View File

@@ -23,6 +23,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Direction;
@@ -210,6 +211,17 @@ public interface Player extends Entity, Actor {
*/
Location getBlockTrace(int range, boolean useLastBlock);
/**
* Get the point of the block being looked at. May return null.
* Will return the farthest away block before matching the stop mask if useLastBlock is true and no other block is found.
*
* @param range how far to checks for blocks
* @param useLastBlock try to return the last valid block not matching the stop mask found
* @param stopMask the mask used to determine when to stop tracing
* @return point
*/
Location getBlockTrace(int range, boolean useLastBlock, @Nullable Mask stopMask);
/**
* Get the face that the player is looking at.
*
@@ -219,6 +231,16 @@ public interface Player extends Entity, Actor {
*/
Location getBlockTraceFace(int range, boolean useLastBlock);
/**
* Get the face that the player is looking at.
*
* @param range the range
* @param useLastBlock try to return the last valid block not matching the stop mask found
* @param stopMask the mask used to determine when to stop tracing
* @return a face
*/
Location getBlockTraceFace(int range, boolean useLastBlock, @Nullable Mask stopMask);
/**
* Get the point of the block being looked at. May return null.
*

View File

@@ -28,6 +28,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable;
@@ -71,10 +72,10 @@ public class EditSessionEvent extends Event implements Cancellable {
/**
* Create a new event.
*
* @param world the world
* @param actor the actor, or null if there is no actor specified
* @param world the world
* @param actor the actor, or null if there is no actor specified
* @param maxBlocks the maximum number of block changes
* @param stage the stage
* @param stage the stage
*/
public EditSessionEvent(@Nullable World world, Actor actor, int maxBlocks, Stage stage) {
this.world = world;
@@ -96,9 +97,7 @@ public class EditSessionEvent extends Event implements Cancellable {
*
* @return the actor, which may be null if unavailable
*/
public
@Nullable
Actor getActor() {
public @Nullable Actor getActor() {
return actor;
}
@@ -107,9 +106,7 @@ public class EditSessionEvent extends Event implements Cancellable {
*
* @return the world
*/
public
@Nullable
World getWorld() {
public @Nullable World getWorld() {
return world;
}
@@ -173,5 +170,4 @@ public class EditSessionEvent extends Event implements Cancellable {
return clone;
}
}

View File

@@ -21,7 +21,7 @@ package com.sk89q.worldedit.event.platform;
import com.sk89q.worldedit.event.AbstractCancellable;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.CommandManager;
import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -67,6 +67,6 @@ public class CommandEvent extends AbstractCancellable implements Runnable {
@Override
public void run() {
CommandManager.getInstance().handleCommandOnCurrentThread(this);
PlatformCommandManager.getInstance().handleCommandOnCurrentThread(this);
}
}

View File

@@ -20,9 +20,9 @@
package com.sk89q.worldedit.event.platform;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.event.Event;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.util.Substring;
import java.util.Collections;
import java.util.List;
@@ -34,7 +34,7 @@ public class CommandSuggestionEvent extends Event {
private final Actor actor;
private final String arguments;
private List<String> suggestions = Collections.emptyList();
private List<Substring> suggestions = Collections.emptyList();
/**
* Create a new instance.
@@ -71,9 +71,14 @@ public class CommandSuggestionEvent extends Event {
/**
* Get the list of suggestions that are to be presented.
*
* <p>
* Each Substring holds the replacement as the substring,
* and the replacement range as the original substring range.
* </p>
*
* @return the list of suggestions
*/
public List<String> getSuggestions() {
public List<Substring> getSuggestions() {
return suggestions;
}
@@ -82,7 +87,7 @@ public class CommandSuggestionEvent extends Event {
*
* @param suggestions the list of suggestions
*/
public void setSuggestions(List<String> suggestions) {
public void setSuggestions(List<Substring> suggestions) {
checkNotNull(suggestions);
this.suggestions = suggestions;
}

View File

@@ -26,7 +26,6 @@ import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.internal.registry.AbstractFactory;
import com.sk89q.worldedit.world.block.BaseBlock;
import java.util.HashSet;
import java.util.Set;
@@ -45,9 +44,7 @@ public class BlockFactory extends AbstractFactory<BaseBlock> {
* @param worldEdit the WorldEdit instance.
*/
public BlockFactory(WorldEdit worldEdit) {
super(worldEdit);
register(new DefaultBlockParser(worldEdit));
super(worldEdit, new DefaultBlockParser(worldEdit));
}
/**
@@ -61,7 +58,7 @@ public class BlockFactory extends AbstractFactory<BaseBlock> {
public Set<BaseBlock> parseFromListInput(String input, ParserContext context) throws InputParseException {
Set<BaseBlock> blocks = new HashSet<>();
String[] splits = input.split(",");
for (String token : StringUtil.parseListInQuotes(splits, ',', '[', ']')) {
for (String token : StringUtil.parseListInQuotes(splits, ',', '[', ']', true)) {
blocks.add(parseFromInput(token, context));
}
return blocks;

View File

@@ -32,9 +32,7 @@ public class ItemFactory extends AbstractFactory<BaseItem> {
* @param worldEdit the WorldEdit instance.
*/
public ItemFactory(WorldEdit worldEdit) {
super(worldEdit);
register(new DefaultItemParser(worldEdit));
super(worldEdit, new DefaultItemParser(worldEdit));
}
}

View File

@@ -20,12 +20,16 @@
package com.sk89q.worldedit.extension.factory;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.parser.mask.BiomeMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.BlockCategoryMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.DefaultMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.BlockStateMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.BlocksMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.ExistingMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.ExpressionMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.LazyRegionMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.NegateMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.NoiseMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.OffsetMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.RegionMaskParser;
import com.sk89q.worldedit.extension.factory.parser.mask.SolidMaskParser;
import com.sk89q.worldedit.extension.input.InputParseException;
@@ -54,9 +58,20 @@ public final class MaskFactory extends AbstractFactory<Mask> {
* @param worldEdit the WorldEdit instance
*/
public MaskFactory(WorldEdit worldEdit) {
super(worldEdit);
super(worldEdit, new BlocksMaskParser(worldEdit));
register(new ExistingMaskParser(worldEdit));
register(new SolidMaskParser(worldEdit));
register(new LazyRegionMaskParser(worldEdit));
register(new RegionMaskParser(worldEdit));
register(new OffsetMaskParser(worldEdit));
register(new NoiseMaskParser(worldEdit));
register(new BlockStateMaskParser(worldEdit));
register(new NegateMaskParser(worldEdit));
register(new ExpressionMaskParser(worldEdit));
register(new BlockCategoryMaskParser(worldEdit));
register(new DefaultMaskParser(worldEdit));
register(new BiomeMaskParser(worldEdit));
}
@Override

View File

@@ -22,7 +22,6 @@ package com.sk89q.worldedit.extension.factory;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.parser.pattern.BlockCategoryPatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.DefaultPatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.RandomStatePatternParser;
import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser;
@@ -45,9 +44,16 @@ public final class PatternFactory extends AbstractFactory<Pattern> {
* @param worldEdit the WorldEdit instance
*/
public PatternFactory(WorldEdit worldEdit) {
super(worldEdit);
super(worldEdit, new SingleBlockPatternParser(worldEdit));
// split and parse each sub-pattern
register(new RandomPatternParser(worldEdit));
// individual patterns
register(new ClipboardPatternParser(worldEdit));
register(new TypeOrStateApplyingPatternParser(worldEdit));
register(new RandomStatePatternParser(worldEdit));
register(new BlockCategoryPatternParser(worldEdit));
register(new DefaultPatternParser(worldEdit));
}
}

Some files were not shown because too many files have changed in this diff Show More