Merge remote-tracking branch 'upstream/master' into merge

This commit is contained in:
Jesse Boyd 2019-11-19 21:23:47 +00:00
commit 2c9f192baf
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
272 changed files with 16041 additions and 6107 deletions

View File

@ -1,3 +1,5 @@
import java.util.Properties
plugins { plugins {
`kotlin-dsl` `kotlin-dsl`
kotlin("jvm") version embeddedKotlinVersion kotlin("jvm") version embeddedKotlinVersion
@ -6,6 +8,18 @@ plugins {
repositories { repositories {
jcenter() jcenter()
gradlePluginPortal() gradlePluginPortal()
maven {
name = "Forge Maven"
url = uri("https://files.minecraftforge.net/maven")
}
maven {
name = "Fabric"
url = uri("https://maven.fabricmc.net/")
}
maven {
name = "sponge"
url = uri("https://repo.spongepowered.org/maven")
}
} }
configurations.all { configurations.all {
@ -19,10 +33,24 @@ configurations.all {
} }
} }
val properties = Properties().also { props ->
project.projectDir.resolveSibling("gradle.properties").bufferedReader().use {
props.load(it)
}
}
val loomVersion: String = properties.getProperty("loom.version")
val mixinVersion: String = properties.getProperty("mixin.version")
dependencies { dependencies {
implementation(gradleApi()) implementation(gradleApi())
implementation("gradle.plugin.net.minecrell:licenser:0.4.1")
implementation("org.ajoberstar.grgit:grgit-gradle:3.1.1") implementation("org.ajoberstar.grgit:grgit-gradle:3.1.1")
implementation("com.github.jengelman.gradle.plugins:shadow:5.1.0") implementation("com.github.jengelman.gradle.plugins:shadow:5.1.0")
implementation("net.ltgt.apt-eclipse:net.ltgt.apt-eclipse.gradle.plugin:0.21") implementation("net.ltgt.apt-eclipse:net.ltgt.apt-eclipse.gradle.plugin:0.21")
implementation("net.ltgt.apt-idea:net.ltgt.apt-idea.gradle.plugin:0.21") implementation("net.ltgt.apt-idea:net.ltgt.apt-idea.gradle.plugin:0.21")
implementation("org.jfrog.buildinfo:build-info-extractor-gradle:4.9.7")
implementation("gradle.plugin.org.spongepowered:spongegradle:0.9.0")
implementation("net.minecraftforge.gradle:ForgeGradle:3.0.143")
implementation("net.fabricmc:fabric-loom:$loomVersion")
implementation("net.fabricmc:sponge-mixin:$mixinVersion")
} }

View File

@ -0,0 +1,40 @@
import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.named
import org.jfrog.gradle.plugin.artifactory.dsl.ArtifactoryPluginConvention
import org.jfrog.gradle.plugin.artifactory.task.ArtifactoryTask
private const val ARTIFACTORY_CONTEXT_URL = "artifactory_contextUrl"
private const val ARTIFACTORY_USER = "artifactory_user"
private const val ARTIFACTORY_PASSWORD = "artifactory_password"
fun Project.applyRootArtifactoryConfig() {
if (!project.hasProperty(ARTIFACTORY_CONTEXT_URL)) ext[ARTIFACTORY_CONTEXT_URL] = "http://localhost"
if (!project.hasProperty(ARTIFACTORY_USER)) ext[ARTIFACTORY_USER] = "guest"
if (!project.hasProperty(ARTIFACTORY_PASSWORD)) ext[ARTIFACTORY_PASSWORD] = ""
apply(plugin = "com.jfrog.artifactory")
configure<ArtifactoryPluginConvention> {
setContextUrl("${project.property(ARTIFACTORY_CONTEXT_URL)}")
clientConfig.publisher.run {
repoKey = when {
"${project.version}".contains("SNAPSHOT") -> "libs-snapshot-local"
else -> "libs-release-local"
}
username = "${project.property(ARTIFACTORY_USER)}"
password = "${project.property(ARTIFACTORY_PASSWORD)}"
isMaven = true
isIvy = false
}
}
tasks.named<ArtifactoryTask>("artifactoryPublish") {
isSkip = true
}
}
fun Project.applyCommonArtifactoryConfig() {
tasks.named<ArtifactoryTask>("artifactoryPublish") {
publishConfigs("archives")
}
}

View File

@ -1,3 +1,5 @@
import org.gradle.api.Project
object Versions { object Versions {
const val TEXT = "3.0.1" const val TEXT = "3.0.1"
const val TEXT_EXTRAS = "3.0.2" const val TEXT_EXTRAS = "3.0.2"
@ -6,3 +8,12 @@ object Versions {
const val JUNIT = "5.5.0" const val JUNIT = "5.5.0"
const val MOCKITO = "3.0.0" const val MOCKITO = "3.0.0"
} }
// Properties that need a project reference to resolve:
class ProjectVersions(project: Project) {
val loom = project.rootProject.property("loom.version")
val mixin = project.rootProject.property("mixin.version")
}
val Project.versions
get() = ProjectVersions(this)

View File

@ -44,12 +44,21 @@
<allow pkg="com.google.auto"/> <allow pkg="com.google.auto"/>
<allow pkg="it.unimi.dsi.fastutil"/> <allow pkg="it.unimi.dsi.fastutil"/>
<subpackage name="internal.expression">
<allow pkg="org.antlr.v4"/>
</subpackage>
<subpackage name="bukkit"> <subpackage name="bukkit">
<allow pkg="org.bukkit"/> <allow pkg="org.bukkit"/>
<allow pkg="org.bstats.bukkit"/> <allow pkg="org.bstats.bukkit"/>
<allow pkg="io.papermc.lib"/> <allow pkg="io.papermc.lib"/>
</subpackage> </subpackage>
<subpackage name="cli">
<allow pkg="org.apache.logging.log4j"/>
<allow pkg="org.apache.commons.cli" />
</subpackage>
<subpackage name="forge"> <subpackage name="forge">
<allow pkg="cpw"/> <allow pkg="cpw"/>
<allow pkg="net.minecraft"/> <allow pkg="net.minecraft"/>
@ -63,6 +72,18 @@
<allow pkg="com.mojang.datafixers" /> <allow pkg="com.mojang.datafixers" />
</subpackage> </subpackage>
<subpackage name="fabric">
<allow pkg="net.minecraft"/>
<allow pkg="net.fabricmc"/>
<allow pkg="com.mojang.authlib"/>
<allow pkg="org.apache.logging.log4j"/>
<allow pkg="org.lwjgl"/>
<allow pkg="io.netty.buffer"/>
<allow pkg="org.spongepowered" />
<allow pkg="com.mojang.brigadier" />
<allow pkg="com.mojang.datafixers" />
</subpackage>
<subpackage name="sponge"> <subpackage name="sponge">
<allow pkg="net.minecraft"/> <allow pkg="net.minecraft"/>
<allow pkg="com.google.inject" /> <allow pkg="com.google.inject" />

Binary file not shown.

22
gradlew vendored
View File

@ -1,5 +1,21 @@
#!/usr/bin/env sh #!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
############################################################################## ##############################################################################
## ##
## Gradle start up script for UN*X ## Gradle start up script for UN*X
@ -28,7 +44,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS="" DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD="maximum"
@ -109,8 +125,8 @@ if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi fi
# For Cygwin, switch paths to Windows format before running java # For Cygwin or MSYS, switch paths to Windows format before running java
if $cygwin ; then if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"` APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"` JAVACMD=`cygpath --unix "$JAVACMD"`

18
gradlew.bat vendored
View File

@ -1,3 +1,19 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS= set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome

View File

@ -31,6 +31,7 @@ import com.sk89q.worldedit.bukkit.adapter.IBukkitAdapter;
import com.sk89q.worldedit.bukkit.adapter.SimpleBukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.SimpleBukkitAdapter;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.extension.platform.PlayerProxy; import com.sk89q.worldedit.extension.platform.PlayerProxy;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
@ -51,15 +52,431 @@ import com.sk89q.worldedit.world.item.ItemTypes;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.Objects; import java.util.Objects;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Biome; import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import java.util.EnumMap;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/**
* Adapts between Bukkit and WorldEdit equivalent objects.
*/
public class BukkitAdapter {
private BukkitAdapter() {
}
private static final ParserContext TO_BLOCK_CONTEXT = new ParserContext();
static {
TO_BLOCK_CONTEXT.setRestricted(false);
}
/**
* Checks equality between a WorldEdit BlockType and a Bukkit Material
*
* @param blockType The WorldEdit BlockType
* @param type The Bukkit Material
* @return If they are equal
*/
public static boolean equals(BlockType blockType, Material type) {
return Objects.equals(blockType.getId(), type.getKey().toString());
}
/**
* Convert any WorldEdit world into an equivalent wrapped Bukkit world.
*
* <p>If a matching world cannot be found, a {@link RuntimeException}
* will be thrown.</p>
*
* @param world the world
* @return a wrapped Bukkit world
*/
public static BukkitWorld asBukkitWorld(World world) {
if (world instanceof BukkitWorld) {
return (BukkitWorld) world;
} else {
BukkitWorld bukkitWorld = WorldEditPlugin.getInstance().getInternalPlatform().matchWorld(world);
if (bukkitWorld == null) {
throw new RuntimeException("World '" + world.getName() + "' has no matching version in Bukkit");
}
return bukkitWorld;
}
}
/**
* Create a WorldEdit world from a Bukkit world.
*
* @param world the Bukkit world
* @return a WorldEdit world
*/
public static World adapt(org.bukkit.World world) {
checkNotNull(world);
return new BukkitWorld(world);
}
/**
* Create a WorldEdit Player from a Bukkit Player.
*
* @param player The Bukkit player
* @return The WorldEdit player
*/
public static BukkitPlayer adapt(Player player) {
return WorldEditPlugin.getInstance().wrapPlayer(player);
}
/**
* Create a Bukkit Player from a WorldEdit Player.
*
* @param player The WorldEdit player
* @return The Bukkit player
*/
public static Player adapt(com.sk89q.worldedit.entity.Player player) {
return ((BukkitPlayer) player).getPlayer();
}
/**
* Create a Bukkit world from a WorldEdit world.
*
* @param world the WorldEdit world
* @return a Bukkit world
*/
public static org.bukkit.World adapt(World world) {
checkNotNull(world);
if (world instanceof BukkitWorld) {
return ((BukkitWorld) world).getWorld();
} else {
org.bukkit.World match = Bukkit.getServer().getWorld(world.getName());
if (match != null) {
return match;
} else {
throw new IllegalArgumentException("Can't find a Bukkit world for " + world.getName());
}
}
}
/**
* Create a WorldEdit location from a Bukkit location.
*
* @param location the Bukkit location
* @return a WorldEdit location
*/
public static Location adapt(org.bukkit.Location location) {
checkNotNull(location);
Vector3 position = asVector(location);
return new com.sk89q.worldedit.util.Location(
adapt(location.getWorld()),
position,
location.getYaw(),
location.getPitch());
}
/**
* Create a Bukkit location from a WorldEdit location.
*
* @param location the WorldEdit location
* @return a Bukkit location
*/
public static org.bukkit.Location adapt(Location location) {
checkNotNull(location);
Vector3 position = location.toVector();
return new org.bukkit.Location(
adapt((World) location.getExtent()),
position.getX(), position.getY(), position.getZ(),
location.getYaw(),
location.getPitch());
}
/**
* Create a Bukkit location from a WorldEdit position with a Bukkit world.
*
* @param world the Bukkit world
* @param position the WorldEdit position
* @return a Bukkit location
*/
public static org.bukkit.Location adapt(org.bukkit.World world, Vector3 position) {
checkNotNull(world);
checkNotNull(position);
return new org.bukkit.Location(
world,
position.getX(), position.getY(), position.getZ());
}
/**
* Create a Bukkit location from a WorldEdit position with a Bukkit world.
*
* @param world the Bukkit world
* @param position the WorldEdit position
* @return a Bukkit location
*/
public static org.bukkit.Location adapt(org.bukkit.World world, BlockVector3 position) {
checkNotNull(world);
checkNotNull(position);
return new org.bukkit.Location(
world,
position.getX(), position.getY(), position.getZ());
}
/**
* Create a Bukkit location from a WorldEdit location with a Bukkit world.
*
* @param world the Bukkit world
* @param location the WorldEdit location
* @return a Bukkit location
*/
public static org.bukkit.Location adapt(org.bukkit.World world, Location location) {
checkNotNull(world);
checkNotNull(location);
return new org.bukkit.Location(
world,
location.getX(), location.getY(), location.getZ(),
location.getYaw(),
location.getPitch());
}
/**
* Create a WorldEdit Vector from a Bukkit location.
*
* @param location The Bukkit location
* @return a WorldEdit vector
*/
public static Vector3 asVector(org.bukkit.Location location) {
checkNotNull(location);
return Vector3.at(location.getX(), location.getY(), location.getZ());
}
/**
* Create a WorldEdit BlockVector from a Bukkit location.
*
* @param location The Bukkit location
* @return a WorldEdit vector
*/
public static BlockVector3 asBlockVector(org.bukkit.Location location) {
checkNotNull(location);
return BlockVector3.at(location.getX(), location.getY(), location.getZ());
}
/**
* Create a WorldEdit entity from a Bukkit entity.
*
* @param entity the Bukkit entity
* @return a WorldEdit entity
*/
public static Entity adapt(org.bukkit.entity.Entity entity) {
checkNotNull(entity);
return new BukkitEntity(entity);
}
/**
* Create a Bukkit Material form a WorldEdit ItemType
*
* @param itemType The WorldEdit ItemType
* @return The Bukkit Material
*/
public static Material adapt(ItemType itemType) {
checkNotNull(itemType);
if (!itemType.getId().startsWith("minecraft:")) {
throw new IllegalArgumentException("Bukkit only supports Minecraft items");
}
return Material.getMaterial(itemType.getId().substring(10).toUpperCase(Locale.ROOT));
}
/**
* Create a Bukkit Material form a WorldEdit BlockType
*
* @param blockType The WorldEdit BlockType
* @return The Bukkit Material
*/
public static Material adapt(BlockType blockType) {
checkNotNull(blockType);
if (!blockType.getId().startsWith("minecraft:")) {
throw new IllegalArgumentException("Bukkit only supports Minecraft blocks");
}
return Material.getMaterial(blockType.getId().substring(10).toUpperCase(Locale.ROOT));
}
/**
* Create a WorldEdit GameMode from a Bukkit one.
*
* @param gameMode Bukkit GameMode
* @return WorldEdit GameMode
*/
public static GameMode adapt(org.bukkit.GameMode gameMode) {
checkNotNull(gameMode);
return GameModes.get(gameMode.name().toLowerCase(Locale.ROOT));
}
/**
* Create a WorldEdit BiomeType from a Bukkit one.
*
* @param biome Bukkit Biome
* @return WorldEdit BiomeType
*/
public static BiomeType adapt(Biome biome) {
return BiomeTypes.get(biome.name().toLowerCase(Locale.ROOT));
}
public static Biome adapt(BiomeType biomeType) {
if (!biomeType.getId().startsWith("minecraft:")) {
throw new IllegalArgumentException("Bukkit only supports vanilla biomes");
}
try {
return Biome.valueOf(biomeType.getId().substring(10).toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
return null;
}
}
/**
* Create a WorldEdit EntityType from a Bukkit one.
*
* @param entityType Bukkit EntityType
* @return WorldEdit EntityType
*/
public static EntityType adapt(org.bukkit.entity.EntityType entityType) {
final String name = entityType.getName();
if (name == null) {
return null;
}
return EntityTypes.get(name.toLowerCase(Locale.ROOT));
}
public static org.bukkit.entity.EntityType adapt(EntityType entityType) {
if (!entityType.getId().startsWith("minecraft:")) {
throw new IllegalArgumentException("Bukkit only supports vanilla entities");
}
return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10));
}
private static EnumMap<Material, BlockType> materialBlockTypeCache = new EnumMap<>(Material.class);
private static EnumMap<Material, ItemType> materialItemTypeCache = new EnumMap<>(Material.class);
/**
* Converts a Material to a BlockType
*
* @param material The material
* @return The blocktype
*/
@Nullable
public static BlockType asBlockType(Material material) {
checkNotNull(material);
return materialBlockTypeCache.computeIfAbsent(material, input -> BlockTypes.get(material.getKey().toString()));
}
/**
* Converts a Material to a ItemType
*
* @param material The material
* @return The itemtype
*/
@Nullable
public static ItemType asItemType(Material material) {
checkNotNull(material);
return materialItemTypeCache.computeIfAbsent(material, input -> ItemTypes.get(material.getKey().toString()));
}
private static Int2ObjectMap<BlockState> blockStateCache = new Int2ObjectOpenHashMap<>();
private static Map<String, BlockState> blockStateStringCache = new HashMap<>();
/**
* Create a WorldEdit BlockState from a Bukkit BlockData
*
* @param blockData The Bukkit BlockData
* @return The WorldEdit BlockState
*/
public static BlockState adapt(BlockData blockData) {
checkNotNull(blockData);
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() == null) {
return blockStateStringCache.computeIfAbsent(blockData.getAsString(), input -> {
try {
return WorldEdit.getInstance().getBlockFactory().parseFromInput(input, TO_BLOCK_CONTEXT).toImmutableState();
} catch (InputParseException e) {
e.printStackTrace();
return null;
}
});
} else {
return blockStateCache.computeIfAbsent(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(blockData).orElseGet(
() -> blockData.getAsString().hashCode()
), input -> {
try {
return WorldEdit.getInstance().getBlockFactory().parseFromInput(blockData.getAsString(), TO_BLOCK_CONTEXT).toImmutableState();
} catch (InputParseException e) {
e.printStackTrace();
return null;
}
});
}
}
private static Int2ObjectMap<BlockData> blockDataCache = new Int2ObjectOpenHashMap<>();
/**
* Create a Bukkit BlockData from a WorldEdit BlockStateHolder
*
* @param block The WorldEdit BlockStateHolder
* @return The Bukkit BlockData
*/
public static <B extends BlockStateHolder<B>> BlockData adapt(B block) {
checkNotNull(block);
// Should never not have an ID for this BlockState.
int cacheKey = BlockStateIdAccess.getBlockStateId(block.toImmutableState()).orElseGet(block::hashCode);
return blockDataCache.computeIfAbsent(cacheKey, input -> Bukkit.createBlockData(block.getAsString())).clone();
}
/**
* Create a WorldEdit BlockState from a Bukkit ItemStack
*
* @param itemStack The Bukkit ItemStack
* @return The WorldEdit BlockState
*/
public static BlockState asBlockState(ItemStack itemStack) throws WorldEditException {
checkNotNull(itemStack);
if (itemStack.getType().isBlock()) {
return adapt(itemStack.getType().createBlockData());
} else {
throw new NotABlockException();
}
}
/**
* Create a WorldEdit BaseItemStack from a Bukkit ItemStack
*
* @param itemStack The Bukkit ItemStack
* @return The WorldEdit BaseItemStack
*/
public static BaseItemStack adapt(ItemStack itemStack) {
checkNotNull(itemStack);
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) {
return WorldEditPlugin.getInstance().getBukkitImplAdapter().adapt(itemStack);
}
return new BaseItemStack(ItemTypes.get(itemStack.getType().getKey().toString()), itemStack.getAmount());
}
/**
* Create a Bukkit ItemStack from a WorldEdit BaseItemStack
*
* @param item The WorldEdit BaseItemStack
* @return The Bukkit ItemStack
*/
public static ItemStack adapt(BaseItemStack item) {
checkNotNull(item);
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) {
return WorldEditPlugin.getInstance().getBukkitImplAdapter().adapt(item);
}
return new ItemStack(adapt(item.getType()), item.getAmount());
}
}
/** /**
* Adapts between Bukkit and WorldEdit equivalent objects. * Adapts between Bukkit and WorldEdit equivalent objects.
*/ */

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit; package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -44,9 +43,4 @@ public class BukkitBlockCategoryRegistry implements BlockCategoryRegistry {
Tag<Material> tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, new NamespacedKey(namespace, key), Material.class); Tag<Material> tag = Bukkit.getTag(Tag.REGISTRY_BLOCKS, new NamespacedKey(namespace, key), Material.class);
return getFromBukkitTag(tag); return getFromBukkitTag(tag);
} }
@Override
public Set<BlockType> getAll(Category<BlockType> category) {
return getCategorisedByName(category.getId());
}
} }

View File

@ -75,6 +75,13 @@ public class BukkitBlockRegistry extends BundledBlockRegistry {
return super.getMaterial(state); return super.getMaterial(state);
} }
@Override
public OptionalInt getInternalBlockStateId(BlockState state) {
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) {
return WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state);
}
return OptionalInt.empty();
}
@Nullable @Nullable
@Override @Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) { public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
@ -137,9 +144,4 @@ public class BukkitBlockRegistry extends BundledBlockRegistry {
} }
return blocks; return blocks;
} }
@Override
public OptionalInt getInternalBlockStateId(BlockState state) {
return WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state);
}
} }

View File

@ -106,10 +106,6 @@ public class BukkitCommandSender extends AbstractNonPlayerActor {
return true; return true;
} }
@Override public boolean togglePermission(String permission) {
return false;
}
@Override public void setPermission(String permission, boolean value) { @Override public void setPermission(String permission, boolean value) {
} }

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit; package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -44,9 +43,4 @@ public class BukkitItemCategoryRegistry implements ItemCategoryRegistry {
Tag<Material> tag = Bukkit.getTag(Tag.REGISTRY_ITEMS, new NamespacedKey(namespace, key), Material.class); Tag<Material> tag = Bukkit.getTag(Tag.REGISTRY_ITEMS, new NamespacedKey(namespace, key), Material.class);
return getFromBukkitTag(tag); return getFromBukkitTag(tag);
} }
@Override
public Set<ItemType> getAll(Category<ItemType> category) {
return getCategorisedByName(category.getId());
}
} }

View File

@ -44,6 +44,8 @@ import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Locale;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.gamemode.GameModes;
@ -59,7 +61,6 @@ import org.bukkit.inventory.PlayerInventory;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -215,12 +216,12 @@ public class BukkitPlayer extends AbstractPlayerActor {
@Override @Override
public GameMode getGameMode() { public GameMode getGameMode() {
return GameModes.get(getPlayer().getGameMode().name().toLowerCase(Locale.ROOT)); return GameModes.get(player.getGameMode().name().toLowerCase(Locale.ROOT));
} }
@Override @Override
public void setGameMode(GameMode gameMode) { public void setGameMode(GameMode gameMode) {
getPlayer().setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT))); player.setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT)));
} }
@Override @Override
@ -239,6 +240,16 @@ public class BukkitPlayer extends AbstractPlayerActor {
} }
} }
@Override
public boolean isAllowedToFly() {
return player.getAllowFlight();
}
@Override
public void setFlying(boolean flying) {
player.setFlying(flying);
}
@Override @Override
public void setPermission(String permission, boolean value) { public void setPermission(String permission, boolean value) {
/* /*
@ -281,16 +292,6 @@ public class BukkitPlayer extends AbstractPlayerActor {
return player; return player;
} }
@Override
public boolean isAllowedToFly() {
return getPlayer().getAllowFlight();
}
@Override
public void setFlying(boolean flying) {
getPlayer().setFlying(flying);
}
@Override @Override
public BaseEntity getState() { public BaseEntity getState() {
throw new UnsupportedOperationException("Cannot create a state from this object"); throw new UnsupportedOperationException("Cannot create a state from this object");

View File

@ -41,8 +41,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.annotation.Nullable;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import javax.annotation.Nullable;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;

View File

@ -34,6 +34,7 @@ import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
@ -43,6 +44,7 @@ import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
@ -328,19 +330,27 @@ public class BukkitWorld extends AbstractWorld {
@Override @Override
public void checkLoadedChunk(BlockVector3 pt) { public void checkLoadedChunk(BlockVector3 pt) {
World world = getWorld(); World world = getWorld();
int X = pt.getBlockX() >> 4;
int Z = pt.getBlockZ() >> 4; world.getChunkAt(pt.getBlockX() >> 4, pt.getBlockZ() >> 4);
if (Fawe.isMainThread()) {
world.getChunkAt(X, Z); if (!world.isChunkLoaded(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)) {
} else if (!world.isChunkLoaded(X, Z)) { world.loadChunk(pt.getBlockX() >> 4, pt.getBlockZ() >> 4);
if (PaperLib.isPaper()) {
world.getChunkAtAsync(X, Z, true);
} else {
Fawe.get().getQueueHandler().sync(() -> {
world.getChunkAt(X, Z);
});
}
} }
if (!world.isChunkLoaded(pt.getBlockX() >> 4, pt.getBlockZ() >> 4)) {
int X = pt.getBlockX() >> 4;
int Z = pt.getBlockZ() >> 4;
if (Fawe.isMainThread()) {
world.getChunkAt(X, Z);
} else if (!world.isChunkLoaded(X, Z)) {
if (PaperLib.isPaper()) {
world.getChunkAtAsync(X, Z, true);
} else {
Fawe.get().getQueueHandler().sync(() -> {
world.getChunkAt(X, Z);
});
}
}
}
} }
@Override @Override
@ -552,4 +562,14 @@ public class BukkitWorld extends AbstractWorld {
org.bukkit.entity.Player bukkitPlayer = BukkitAdapter.adapt(player); org.bukkit.entity.Player bukkitPlayer = BukkitAdapter.adapt(player);
WorldEditPlugin.getInstance().getBukkitImplAdapter().sendFakeChunk(getWorld(), bukkitPlayer, packet); WorldEditPlugin.getInstance().getBukkitImplAdapter().sendFakeChunk(getWorld(), bukkitPlayer, packet);
} }
@Override
public boolean useItem(BlockVector3 position, BaseItem item, Direction face) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) {
return adapter.simulateItemUse(getWorld(), position, item, face);
}
return false;
}
} }

View File

@ -26,7 +26,6 @@ import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import java.util.Optional;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.event.Event.Result; import org.bukkit.event.Event.Result;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -42,6 +41,8 @@ import org.enginehub.piston.inject.InjectedValueStore;
import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.Key;
import org.enginehub.piston.inject.MapBackedValueStore; import org.enginehub.piston.inject.MapBackedValueStore;
import java.util.Optional;
/** /**
* Handles all events thrown in relation to a Player * Handles all events thrown in relation to a Player
*/ */

View File

@ -184,7 +184,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
ChunkDeleter.runFromFile(delChunks, true); ChunkDeleter.runFromFile(delChunks, true);
} }
fail(() -> PermissionsResolverManager.initialize(INSTANCE), "Failed to initialize permissions resolver"); fail(() -> PermissionsResolverManager.initialize(INSTANCE), "Failed to initialize permissions resolver");
} }
/** /**
@ -341,6 +341,20 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
} }
} }
@Override
public List<String> onTabComplete(CommandSender sender, Command cmd, String commandLabel, String[] args) {
// Add the command to the array because the underlying command handling
// code of WorldEdit expects it
String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length);
split[0] = "/" + commandLabel;
String arguments = Joiner.on(" ").join(split);
CommandSuggestionEvent event = new CommandSuggestionEvent(wrapCommandSender(sender), arguments);
getWorldEdit().getEventBus().post(event);
return CommandUtil.fixSuggestions(arguments, event.getSuggestions());
}
private void fail(Runnable run, String message) { private void fail(Runnable run, String message) {
try { try {
run.run(); run.run();

View File

@ -90,3 +90,4 @@ no-op-permissions: false
debug: false debug: false
show-help-on-first-use: true show-help-on-first-use: true
server-side-cui: true server-side-cui: true
command-block-support: false

View File

@ -0,0 +1,33 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
applyPlatformAndCoreConfiguration()
applyShadowConfiguration()
dependencies {
"compile"(project(":worldedit-core"))
"compile"("org.apache.logging.log4j:log4j-core:2.8.1")
"compile"("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1")
"compile"("commons-cli:commons-cli:1.4")
}
tasks.named<Jar>("jar") {
manifest {
attributes(
"Implementation-Version" to project.version,
"Main-Class" to "com.sk89q.worldedit.cli.CLIWorldEdit"
)
}
}
tasks.named<ShadowJar>("shadowJar") {
dependencies {
include { true }
}
minimize {
exclude(dependency("org.apache.logging.log4j:log4j-core"))
}
}
tasks.named("assemble").configure {
dependsOn("shadowJar")
}

View File

@ -0,0 +1,37 @@
/*
* 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.cli;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
public class CLIBlockCategoryRegistry implements BlockCategoryRegistry {
@Override
public Set<BlockType> getCategorisedByName(String category) {
return CLIWorldEdit.inst.getFileRegistries().getDataFile().blocktags.getOrDefault(category, Collections.emptyList()).stream()
.map(BlockType.REGISTRY::get)
.collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,73 @@
/*
* 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.cli;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.sk89q.worldedit.cli.data.FileRegistries;
import com.sk89q.worldedit.registry.state.BooleanProperty;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.EnumProperty;
import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BundledBlockRegistry;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
public class CLIBlockRegistry extends BundledBlockRegistry {
private Property<?> createProperty(String type, String key, List<String> values) {
switch (type) {
case "int": {
List<Integer> fixedValues = values.stream().map(Integer::parseInt).collect(Collectors.toList());
return new IntegerProperty(key, fixedValues);
}
case "bool": {
List<Boolean> fixedValues = values.stream().map(Boolean::parseBoolean).collect(Collectors.toList());
return new BooleanProperty(key, fixedValues);
}
case "enum": {
return new EnumProperty(key, values);
}
case "direction": {
List<Direction> fixedValues = values.stream().map(String::toUpperCase).map(Direction::valueOf).collect(Collectors.toList());
return new DirectionalProperty(key, fixedValues);
}
default:
throw new RuntimeException("Failed to create property");
}
}
@Nullable
@Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
Map<String, FileRegistries.BlockProperty> properties =
CLIWorldEdit.inst.getFileRegistries().getDataFile().blocks.get(blockType.getId()).properties;
return ImmutableMap.copyOf(Maps.transformEntries(properties,
(Maps.EntryTransformer<String, FileRegistries.BlockProperty, Property<?>>)
(key, value) -> createProperty(value.type, key, value.values)));
}
}

View File

@ -0,0 +1,165 @@
/*
* 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.cli;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.session.SessionKey;
import com.sk89q.worldedit.util.FileDialogUtil;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.util.formatting.WorldEditText;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.serializer.plain.PlainComponentSerializer;
import org.slf4j.Logger;
import java.io.File;
import java.util.UUID;
public class CLICommandSender implements Actor {
/**
* One time generated ID.
*/
private static final UUID DEFAULT_ID = UUID.fromString("a233eb4b-4cab-42cd-9fd9-7e7b9a3f74be");
private final CLIWorldEdit app;
private final Logger sender;
public CLICommandSender(CLIWorldEdit app, Logger sender) {
checkNotNull(app);
checkNotNull(sender);
this.app = app;
this.sender = sender;
}
@Override
public UUID getUniqueId() {
return DEFAULT_ID;
}
@Override
public String getName() {
return "Console";
}
@Override
public void printRaw(String msg) {
for (String part : msg.split("\n")) {
sender.info(part);
}
}
private static final String ANSI_PURPLE = "\u001B[35m";
private static final String ANSI_RED = "\u001B[31m";
private static final String ANSI_GREEN = "\u001B[32m";
private static final String ANSI_RESET = "\u001B[0m";
@Override
public void print(String msg) {
for (String part : msg.split("\n")) {
sender.info(ANSI_PURPLE + part + ANSI_RESET);
}
}
@Override
public void printDebug(String msg) {
for (String part : msg.split("\n")) {
sender.debug(ANSI_GREEN + part + ANSI_RESET);
}
}
@Override
public void printError(String msg) {
for (String part : msg.split("\n")) {
sender.error(ANSI_RED + part + ANSI_RESET);
}
}
@Override
public void print(Component component) {
print(PlainComponentSerializer.INSTANCE.serialize(WorldEditText.format(component)));
}
@Override
public boolean canDestroyBedrock() {
return true;
}
@Override
public String[] getGroups() {
return new String[0];
}
@Override
public boolean hasPermission(String perm) {
return true;
}
@Override
public void checkPermission(String permission) throws AuthorizationException {
}
@Override
public boolean isPlayer() {
return false;
}
@Override
public File openFileOpenDialog(String[] extensions) {
return FileDialogUtil.showOpenDialog(extensions);
}
@Override
public File openFileSaveDialog(String[] extensions) {
return FileDialogUtil.showSaveDialog(extensions);
}
@Override
public void dispatchCUIEvent(CUIEvent event) {
}
@Override
public SessionKey getSessionKey() {
return new SessionKey() {
@Override
public String getName() {
return "Console";
}
@Override
public boolean isActive() {
return true;
}
@Override
public boolean isPersistent() {
return true;
}
@Override
public UUID getUniqueId() {
return DEFAULT_ID;
}
};
}
}

View File

@ -17,28 +17,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.internal.expression.lexer.tokens; package com.sk89q.worldedit.cli;
/** import com.sk89q.worldedit.util.PropertiesConfiguration;
* A unary or binary operator.
*/
public class OperatorToken extends Token {
public final String operator; import java.io.File;
public OperatorToken(int position, String operator) { public class CLIConfiguration extends PropertiesConfiguration {
super(position);
this.operator = operator; public CLIConfiguration(CLIWorldEdit app) {
super(app.getWorkingDir().resolve("worldedit.properties").toFile());
} }
@Override @Override
public char id() { protected void loadExtra() {
return 'o';
} }
@Override @Override
public String toString() { public File getWorkingDirectory() {
return "OperatorToken(" + operator + ")"; return CLIWorldEdit.inst.getWorkingDir().toFile();
} }
} }

View File

@ -17,28 +17,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.internal.expression.lexer.tokens; package com.sk89q.worldedit.cli;
/** import com.sk89q.worldedit.world.item.ItemType;
* A single character that doesn't fit any of the other token categories. import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
*/
public class CharacterToken extends Token {
public final char character; import java.util.Set;
import java.util.stream.Collectors;
public CharacterToken(int position, char character) { public class CLIItemCategoryRegistry implements ItemCategoryRegistry {
super(position);
this.character = character;
}
@Override @Override
public char id() { public Set<ItemType> getCategorisedByName(String category) {
return character; return CLIWorldEdit.inst.getFileRegistries().getDataFile().itemtags.get(category).stream()
.map(ItemType.REGISTRY::get)
.collect(Collectors.toSet());
} }
@Override
public String toString() {
return "CharacterToken(" + character + ")";
}
} }

View File

@ -0,0 +1,159 @@
/*
* 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.cli;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.AbstractPlatform;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.entity.EntityTypes;
import com.sk89q.worldedit.world.registry.Registries;
import org.enginehub.piston.CommandManager;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import javax.annotation.Nullable;
class CLIPlatform extends AbstractPlatform {
private final CLIWorldEdit app;
private int dataVersion = -1;
private final List<World> worlds = new ArrayList<>();
private final Timer timer = new Timer();
private int lastTimerId = 0;
CLIPlatform(CLIWorldEdit app) {
this.app = app;
}
@Override
public Registries getRegistries() {
return CLIRegistries.getInstance();
}
@Override
public int getDataVersion() {
return this.dataVersion;
}
public void setDataVersion(int dataVersion) {
this.dataVersion = dataVersion;
}
@Override
public DataFixer getDataFixer() {
return null;
}
@Override
public boolean isValidMobType(String type) {
return EntityTypes.get(type) != null;
}
@Override
public void reload() {
getConfiguration().load();
}
@Override
public int schedule(long delay, long period, Runnable task) {
this.timer.schedule(new TimerTask() {
@Override
public void run() {
task.run();
if (period >= 0) {
timer.schedule(this, period);
}
}
}, delay);
return this.lastTimerId++;
}
@Override
public List<? extends World> getWorlds() {
return this.worlds;
}
@Nullable
@Override
public Player matchPlayer(Player player) {
return null;
}
@Nullable
@Override
public World matchWorld(World world) {
return this.worlds.stream()
.filter(w -> w.getId().equals(world.getId()))
.findAny()
.orElse(null);
}
@Override
public void registerCommands(CommandManager manager) {
}
@Override
public void registerGameHooks() {
}
@Override
public CLIConfiguration getConfiguration() {
return app.getConfig();
}
@Override
public String getVersion() {
return app.getInternalVersion();
}
@Override
public String getPlatformName() {
return "CLI-Official";
}
@Override
public String getPlatformVersion() {
return app.getInternalVersion();
}
@Override
public Map<Capability, Preference> getCapabilities() {
Map<Capability, Preference> capabilities = new EnumMap<>(Capability.class);
capabilities.put(Capability.CONFIGURATION, Preference.PREFER_OTHERS);
capabilities.put(Capability.GAME_HOOKS, Preference.NORMAL);
capabilities.put(Capability.PERMISSIONS, Preference.NORMAL);
capabilities.put(Capability.USER_COMMANDS, Preference.NORMAL);
capabilities.put(Capability.WORLD_EDITING, Preference.PREFERRED);
return capabilities;
}
public void addWorld(World world) {
worlds.add(world);
}
}

View File

@ -0,0 +1,64 @@
/*
* 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.cli;
import com.sk89q.worldedit.world.registry.BlockCategoryRegistry;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import com.sk89q.worldedit.world.registry.BundledRegistries;
import com.sk89q.worldedit.world.registry.ItemCategoryRegistry;
public class CLIRegistries extends BundledRegistries {
private static final CLIRegistries INSTANCE = new CLIRegistries();
private final BlockRegistry blockRegistry = new CLIBlockRegistry();
private final BlockCategoryRegistry blockCategoryRegistry = new CLIBlockCategoryRegistry();
private final ItemCategoryRegistry itemCategoryRegistry = new CLIItemCategoryRegistry();
/**
* Create a new instance.
*/
private CLIRegistries() {
}
@Override
public BlockRegistry getBlockRegistry() {
return blockRegistry;
}
@Override
public BlockCategoryRegistry getBlockCategoryRegistry() {
return blockCategoryRegistry;
}
@Override
public ItemCategoryRegistry getItemCategoryRegistry() {
return itemCategoryRegistry;
}
/**
* Get a static instance.
*
* @return an instance
*/
public static CLIRegistries getInstance() {
return INSTANCE;
}
}

View File

@ -17,28 +17,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.internal.expression.lexer.tokens; package com.sk89q.worldedit.cli;
/** public interface CLIWorld {
* A keyword.
*/
public class KeywordToken extends Token {
public final String value; /**
* Saves this world back to file if dirty or forced.
*
* @param force Force a save
*/
void save(boolean force);
public KeywordToken(int position, String value) { /**
super(position); * Gets whether the world is dirty.
this.value = value; *
} * @return If it's dirty
*/
@Override boolean isDirty();
public char id() {
return 'k';
}
@Override
public String toString() {
return "KeywordToken(" + value + ")";
}
/**
* Set the world's dirty status
*
* @param dirty if dirty
*/
void setDirty(boolean dirty);
} }

View File

@ -0,0 +1,335 @@
/*
* 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.cli;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.cli.data.FileRegistries;
import com.sk89q.worldedit.cli.schematic.ClipboardWorld;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
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.extension.platform.Platform;
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.registry.state.Property;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockCategory;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.FuzzyBlockState;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemCategory;
import com.sk89q.worldedit.world.item.ItemType;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Map;
import java.util.Scanner;
/**
* The CLI implementation of WorldEdit.
*/
public class CLIWorldEdit {
private static final Logger LOGGER = LoggerFactory.getLogger(CLIWorldEdit.class);
public static CLIWorldEdit inst;
private CLIPlatform platform;
private CLIConfiguration config;
private Path workingDir;
private String version;
private Actor commandSender;
private FileRegistries fileRegistries;
public CLIWorldEdit() {
inst = this;
}
private void setupPlatform() {
this.fileRegistries = new FileRegistries(this);
this.fileRegistries.loadDataFiles();
WorldEdit.getInstance().getPlatformManager().register(platform);
}
public void setupRegistries() {
// Blocks
for (Map.Entry<String, FileRegistries.BlockManifest> manifestEntry : fileRegistries.getDataFile().blocks.entrySet()) {
if (BlockType.REGISTRY.get(manifestEntry.getKey()) == null) {
BlockType.REGISTRY.register(manifestEntry.getKey(), new BlockType(manifestEntry.getKey(), input -> {
ParserContext context = new ParserContext();
context.setPreferringWildcard(true);
context.setTryLegacy(false);
context.setRestricted(false);
try {
FuzzyBlockState state = (FuzzyBlockState) WorldEdit.getInstance().getBlockFactory().parseFromInput(
manifestEntry.getValue().defaultstate,
context
).toImmutableState();
BlockState defaultState = input.getBlockType().getAllStates().get(0);
for (Map.Entry<Property<?>, Object> propertyObjectEntry : state.getStates().entrySet()) {
@SuppressWarnings("unchecked")
Property<Object> prop = (Property<Object>) propertyObjectEntry.getKey();
defaultState = defaultState.with(prop, propertyObjectEntry.getValue());
}
return defaultState;
} catch (InputParseException e) {
LOGGER.warn("Error loading block state for " + manifestEntry.getKey(), e);
return input;
}
}));
}
}
// Items
for (String name : fileRegistries.getDataFile().items) {
if (ItemType.REGISTRY.get(name) == null) {
ItemType.REGISTRY.register(name, new ItemType(name));
}
}
// Entities
for (String name : fileRegistries.getDataFile().entities) {
if (EntityType.REGISTRY.get(name) == null) {
EntityType.REGISTRY.register(name, new EntityType(name));
}
}
// Biomes
for (String name : fileRegistries.getDataFile().biomes) {
if (BiomeType.REGISTRY.get(name) == null) {
BiomeType.REGISTRY.register(name, new BiomeType(name));
}
}
// Tags
for (String name : fileRegistries.getDataFile().blocktags.keySet()) {
if (BlockCategory.REGISTRY.get(name) == null) {
BlockCategory.REGISTRY.register(name, new BlockCategory(name));
}
}
for (String name : fileRegistries.getDataFile().itemtags.keySet()) {
if (ItemCategory.REGISTRY.get(name) == null) {
ItemCategory.REGISTRY.register(name, new ItemCategory(name));
}
}
}
public void onInitialized() {
// Setup working directory
workingDir = Paths.get("worldedit");
if (!Files.exists(workingDir)) {
try {
Files.createDirectory(workingDir);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
this.commandSender = new CLICommandSender(this, LOGGER);
this.platform = new CLIPlatform(this);
LOGGER.info("WorldEdit CLI (version " + getInternalVersion() + ") is loaded");
}
public void onStarted() {
setupPlatform();
setupRegistries();
WorldEdit.getInstance().loadMappings();
config = new CLIConfiguration(this);
config.load();
WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent());
}
public void onStopped() {
WorldEdit worldEdit = WorldEdit.getInstance();
worldEdit.getSessionManager().unload();
worldEdit.getPlatformManager().unregister(platform);
}
public FileRegistries getFileRegistries() {
return this.fileRegistries;
}
/**
* Get the configuration.
*
* @return the CLI configuration
*/
CLIConfiguration getConfig() {
return this.config;
}
/**
* Get the WorldEdit proxy for the platform.
*
* @return the WorldEdit platform
*/
public Platform getPlatform() {
return this.platform;
}
/**
* Get the working directory where WorldEdit's files are stored.
*
* @return the working directory
*/
public Path getWorkingDir() {
return this.workingDir;
}
/**
* Get the version of the WorldEdit-CLI implementation.
*
* @return a version string
*/
String getInternalVersion() {
if (version == null) {
version = getClass().getPackage().getImplementationVersion();
}
return version;
}
public void saveAllWorlds(boolean force) {
platform.getWorlds().stream()
.filter(world -> world instanceof CLIWorld)
.forEach(world -> ((CLIWorld) world).save(force));
}
public void run(InputStream inputStream) {
try (Scanner scanner = new Scanner(inputStream)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if (line.equals("stop")) {
commandSender.print("Stopping!");
break;
}
CommandEvent event = new CommandEvent(commandSender, line);
WorldEdit.getInstance().getEventBus().post(event);
if (!event.isCancelled()) {
commandSender.printError("Unknown command!");
} else {
saveAllWorlds(false);
}
}
} finally {
saveAllWorlds(false);
}
}
public static void main(String[] args) {
Options options = new Options();
options.addOption("f", "file", true, "The file to load in. Either a schematic, or a level.dat in a world folder.");
options.addOption("s", "script", true, "A file containing a list of commands to run. Newline separated.");
int exitCode = 0;
CLIWorldEdit app = new CLIWorldEdit();
app.onInitialized();
InputStream inputStream = System.in;
try {
CommandLine cmd = new DefaultParser().parse(options, args);
String fileArg = cmd.getOptionValue('f');
File file;
if (fileArg == null) {
String[] formats = Arrays.copyOf(ClipboardFormats.getFileExtensionArray(), ClipboardFormats.getFileExtensionArray().length + 1);
formats[formats.length - 1] = "dat";
file = app.commandSender.openFileOpenDialog(formats);
} else {
file = new File(fileArg);
}
if (file == null) {
throw new IllegalArgumentException("A file must be provided!");
}
if (file.getName().endsWith("level.dat")) {
throw new IllegalArgumentException("level.dat file support is unfinished.");
} else {
ClipboardFormat format = ClipboardFormats.findByFile(file);
if (format != null) {
ClipboardReader dataVersionReader = format
.getReader(Files.newInputStream(file.toPath(), StandardOpenOption.READ));
int dataVersion = dataVersionReader.getDataVersion()
.orElseThrow(() -> new IllegalArgumentException("Failed to obtain data version from schematic."));
dataVersionReader.close();
app.platform.setDataVersion(dataVersion);
app.onStarted();
try (ClipboardReader clipboardReader = format.getReader(Files.newInputStream(file.toPath(), StandardOpenOption.READ))) {
ClipboardWorld world = new ClipboardWorld(
file,
clipboardReader.read(),
file.getName()
);
app.platform.addWorld(world);
WorldEdit.getInstance().getSessionManager().get(app.commandSender).setWorldOverride(world);
}
} else {
throw new IllegalArgumentException("Unknown file provided!");
}
}
String scriptFile = cmd.getOptionValue('s');
if (scriptFile != null) {
File scriptFileHandle = new File(scriptFile);
if (!scriptFileHandle.exists()) {
throw new IllegalArgumentException("Could not find given script file.");
}
InputStream scriptStream = Files.newInputStream(scriptFileHandle.toPath(), StandardOpenOption.READ);
InputStream newLineStream = new ByteArrayInputStream("\n".getBytes(StandardCharsets.UTF_8));
// Cleaner to do this than make an Enumeration :(
inputStream = new SequenceInputStream(new SequenceInputStream(scriptStream, newLineStream), inputStream);
}
app.run(inputStream);
} catch (Exception e) {
e.printStackTrace();
exitCode = 1;
} finally {
app.onStopped();
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.exit(exitCode);
}
}

View File

@ -0,0 +1,77 @@
/*
* 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.cli.data;
import com.google.common.io.Resources;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.sk89q.worldedit.cli.CLIWorldEdit;
import com.sk89q.worldedit.util.io.ResourceLoader;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
public class FileRegistries {
private CLIWorldEdit app;
private Gson gson = new GsonBuilder().create();
private DataFile dataFile;
public FileRegistries(CLIWorldEdit app) {
this.app = app;
}
public void loadDataFiles() {
try {
URL url = ResourceLoader.getResource(FileRegistries.class, app.getPlatform().getDataVersion() + ".json");
this.dataFile = gson.fromJson(Resources.toString(url, StandardCharsets.UTF_8), DataFile.class);
} catch (IOException e) {
throw new RuntimeException("The provided file is not compatible with this version of WorldEdit-CLI. Please update or report this.");
}
}
public DataFile getDataFile() {
return this.dataFile;
}
public static class BlockManifest {
public String defaultstate;
public Map<String, BlockProperty> properties;
}
public static class BlockProperty {
public List<String> values;
public String type;
}
public static class DataFile {
public Map<String, List<String>> itemtags;
public Map<String, List<String>> blocktags;
public Map<String, List<String>> entitytags;
public List<String> items;
public List<String> entities;
public List<String> biomes;
public Map<String, BlockManifest> blocks;
}
}

View File

@ -0,0 +1,217 @@
/*
* 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.cli.schematic;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.cli.CLIWorld;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import javax.annotation.Nullable;
public class ClipboardWorld extends AbstractWorld implements Clipboard, CLIWorld {
private final File file;
private final Clipboard clipboard;
private final String name;
private boolean dirty = false;
public ClipboardWorld(File file, Clipboard clipboard, String name) {
this.file = file;
this.clipboard = clipboard;
this.name = name;
}
@Override
public String getName() {
return this.name;
}
@Override
public String getId() {
return getName().replace(" ", "_").toLowerCase(Locale.ROOT);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight)
throws WorldEditException {
dirty = true;
return clipboard.setBlock(position, block);
}
@Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
return false;
}
@Override
public int getBlockLightLevel(BlockVector3 position) {
return 0;
}
@Override
public boolean clearContainerBlockContents(BlockVector3 position) {
return false;
}
@Override
public void dropItem(Vector3 position, BaseItemStack item) {
}
@Override
public void simulateBlockMine(BlockVector3 position) {
}
@Override
public boolean regenerate(Region region, EditSession editSession) {
return false;
}
@Override
public List<? extends Entity> getEntities(Region region) {
return clipboard.getEntities(region);
}
@Override
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position)
throws MaxChangedBlocksException {
return false;
}
@Override
public List<? extends Entity> getEntities() {
return clipboard.getEntities();
}
@Override
public BlockVector3 getSpawnPosition() {
return clipboard.getOrigin();
}
@Nullable
@Override
public Entity createEntity(Location location, BaseEntity entity) {
dirty = true;
return clipboard.createEntity(location, entity);
}
@Override
public BlockState getBlock(BlockVector3 position) {
return clipboard.getBlock(position);
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
return clipboard.getFullBlock(position);
}
@Override
public BiomeType getBiome(BlockVector2 position) {
return clipboard.getBiome(position);
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
dirty = true;
return clipboard.setBiome(position, biome);
}
@Override
public Region getRegion() {
return clipboard.getRegion();
}
@Override
public BlockVector3 getDimensions() {
return clipboard.getDimensions();
}
@Override
public BlockVector3 getOrigin() {
return clipboard.getOrigin();
}
@Override
public void setOrigin(BlockVector3 origin) {
clipboard.setOrigin(origin);
dirty = true;
}
@Override
public boolean hasBiomes() {
return clipboard.hasBiomes();
}
@Override
public BlockVector3 getMaximumPoint() {
return clipboard.getMaximumPoint();
}
@Override
public BlockVector3 getMinimumPoint() {
return clipboard.getMinimumPoint();
}
@Override
public void save(boolean force) {
if (dirty || force) {
try (ClipboardWriter writer = ClipboardFormats.findByFile(file).getWriter(new FileOutputStream(file))) {
writer.write(this);
dirty = false;
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public boolean isDirty() {
return this.dirty;
}
@Override
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,33 @@
#Don't put comments; they get removed
default-max-polygon-points=-1
schematic-save-dir=schematics
super-pickaxe-many-drop-items=true
register-help=true
nav-wand-item=minecraft:compass
profile=false
trace-unflushed-sessions=false
super-pickaxe-drop-items=true
disallowed-blocks=minecraft:oak_sapling,minecraft:jungle_sapling,minecraft:dark_oak_sapling,minecraft:spruce_sapling,minecraft:birch_sapling,minecraft:acacia_sapling,minecraft:black_bed,minecraft:blue_bed,minecraft:brown_bed,minecraft:cyan_bed,minecraft:gray_bed,minecraft:green_bed,minecraft:light_blue_bed,minecraft:light_gray_bed,minecraft:lime_bed,minecraft:magenta_bed,minecraft:orange_bed,minecraft:pink_bed,minecraft:purple_bed,minecraft:red_bed,minecraft:white_bed,minecraft:yellow_bed,minecraft:powered_rail,minecraft:detector_rail,minecraft:grass,minecraft:dead_bush,minecraft:moving_piston,minecraft:piston_head,minecraft:sunflower,minecraft:rose_bush,minecraft:dandelion,minecraft:poppy,minecraft:brown_mushroom,minecraft:red_mushroom,minecraft:tnt,minecraft:torch,minecraft:fire,minecraft:redstone_wire,minecraft:wheat,minecraft:potatoes,minecraft:carrots,minecraft:melon_stem,minecraft:pumpkin_stem,minecraft:beetroots,minecraft:rail,minecraft:lever,minecraft:redstone_torch,minecraft:redstone_wall_torch,minecraft:repeater,minecraft:comparator,minecraft:stone_button,minecraft:birch_button,minecraft:acacia_button,minecraft:dark_oak_button,minecraft:jungle_button,minecraft:oak_button,minecraft:spruce_button,minecraft:cactus,minecraft:sugar_cane,minecraft:bedrock
max-super-pickaxe-size=5
max-brush-radius=10
craftscript-dir=craftscripts
no-double-slash=false
wand-item=minecraft:wooden_axe
shell-save-type=
scripting-timeout=3000
snapshots-dir=
use-inventory-creative-override=false
log-file=worldedit.log
log-format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s]: %5$s%6$s%n
max-changed-blocks=-1
nav-wand-distance=50
butcher-default-radius=-1
default-max-changed-blocks=-1
history-size=15
use-inventory=false
allow-symbolic-links=false
use-inventory-override=false
log-commands=false
butcher-max-radius=-1
max-polygon-points=20
max-radius=-1

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="com.sk89q,org.enginehub">
<Appenders>
<Console name="SysOut" target="SYSTEM_OUT">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
</Console>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy />
<OnStartupTriggeringPolicy />
</Policies>
</RollingRandomAccessFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="SysOut"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>

View File

@ -21,14 +21,14 @@ configurations.all {
dependencies { dependencies {
"compile"(project(":worldedit-libs:core")) "compile"(project(":worldedit-libs:core"))
"compile"("de.schlichtherle:truezip:6.8.3") "compile"("de.schlichtherle:truezip:6.8.3")
"compile"("rhino:js:1.7R2") "compile"("rhino:js:1.7.11")
"compile"("org.yaml:snakeyaml:1.23") "compile"("org.yaml:snakeyaml:1.23")
"compile"("com.google.guava:guava:21.0") "compile"("com.google.guava:guava:21.0")
"compile"("com.google.code.findbugs:jsr305:3.0.2") "compile"("com.google.code.findbugs:jsr305:3.0.2")
"compile"("com.google.code.gson:gson:2.8.0") "compile"("com.google.code.gson:gson:2.8.0")
"compile"("org.slf4j:slf4j-api:1.7.26") "compile"("org.slf4j:slf4j-api:1.7.26")
"compile"("it.unimi.dsi:fastutil:8.2.1") "compile"("it.unimi.dsi:fastutil:8.2.1")
"compile"("com.googlecode.json-simple:json-simple:1.1.1") { isTransitive = false } "compile"("com.googlecode.json-simple:json-simple:1.3.9") { isTransitive = false }
"compileOnly"(project(":worldedit-libs:core:ap")) "compileOnly"(project(":worldedit-libs:core:ap"))
"annotationProcessor"(project(":worldedit-libs:core:ap")) "annotationProcessor"(project(":worldedit-libs:core:ap"))
// ensure this is on the classpath for the AP // ensure this is on the classpath for the AP
@ -48,6 +48,26 @@ tasks.withType<JavaCompile>().configureEach {
options.compilerArgs.add("-Aarg.name.key.prefix=") options.compilerArgs.add("-Aarg.name.key.prefix=")
} }
tasks.named<AntlrTask>("generateGrammarSource").configure {
val pkg = "com.sk89q.worldedit.antlr"
outputDirectory = file("build/generated-src/antlr/main/${pkg.replace('.', '/')}")
arguments = listOf(
"-visitor", "-package", pkg,
"-Xexact-output-dir"
)
}
// Give intellij info about where ANTLR code comes from
plugins.withId("idea") {
configure<IdeaModel> {
afterEvaluate {
module.sourceDirs.add(file("src/main/antlr"))
module.sourceDirs.add(file("build/generated-src/antlr/main"))
module.generatedSourceDirs.add(file("build/generated-src/antlr/main"))
}
}
}
sourceSets { sourceSets {
main { main {
java { java {

View File

@ -0,0 +1,24 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.3.41"
application
}
applyCommonConfiguration()
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
application.mainClassName = "com.sk89q.worldedit.internal.util.DocumentationPrinter"
tasks.named<JavaExec>("run") {
workingDir = rootProject.projectDir
}
dependencies {
"implementation"(project(":worldedit-libs:core:ap"))
"implementation"(project(":worldedit-core"))
"implementation"(kotlin("stdlib-jdk8"))
"implementation"(kotlin("reflect"))
}

View File

@ -0,0 +1,354 @@
/*
* 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.internal.util
import com.google.common.base.Strings
import com.sk89q.worldedit.WorldEdit
import com.sk89q.worldedit.command.BiomeCommands
import com.sk89q.worldedit.command.ChunkCommands
import com.sk89q.worldedit.command.ClipboardCommands
import com.sk89q.worldedit.command.GeneralCommands
import com.sk89q.worldedit.command.GenerationCommands
import com.sk89q.worldedit.command.HistoryCommands
import com.sk89q.worldedit.command.NavigationCommands
import com.sk89q.worldedit.command.RegionCommands
import com.sk89q.worldedit.command.ScriptingCommands
import com.sk89q.worldedit.command.SelectionCommands
import com.sk89q.worldedit.command.SnapshotUtilCommands
import com.sk89q.worldedit.command.ToolCommands
import com.sk89q.worldedit.command.ToolUtilCommands
import com.sk89q.worldedit.command.UtilityCommands
import com.sk89q.worldedit.command.util.PermissionCondition
import com.sk89q.worldedit.internal.command.CommandUtil
import com.sk89q.worldedit.util.formatting.text.TextComponent
import org.enginehub.piston.Command
import org.enginehub.piston.config.TextConfig
import org.enginehub.piston.part.SubCommandPart
import org.enginehub.piston.util.HelpGenerator
import java.nio.file.Files
import java.nio.file.Paths
import java.util.stream.Stream
import kotlin.streams.toList
class DocumentationPrinter private constructor() {
private val nameRegex = Regex("name = \"(.+?)\"")
private val commands = WorldEdit.getInstance().platformManager.platformCommandManager.commandManager.allCommands
.map { it.name to it }.toList().toMap()
private val cmdOutput = StringBuilder()
private val permsOutput = StringBuilder()
private val matchedCommands = mutableSetOf<String>()
private suspend inline fun <reified T> SequenceScope<String>.yieldAllCommandsIn() {
val sourceFile = Paths.get("worldedit-core/src/main/java/" + T::class.qualifiedName!!.replace('.', '/') + ".java")
require(Files.exists(sourceFile)) {
"Source not found for ${T::class.qualifiedName}, looked at ${sourceFile.toAbsolutePath()}"
}
Files.newBufferedReader(sourceFile).useLines { lines ->
var inCommand = false
for (line in lines) {
if (inCommand) {
when (val match = nameRegex.find(line)) {
null -> if (line.trim() == ")") inCommand = false
else -> yield(match.groupValues[1])
}
} else if (line.contains("@Command(")) {
inCommand = true
}
}
}
}
private fun writeAllCommands() {
writeHeader()
dumpSection("General Commands") {
yield("worldedit")
yieldAllCommandsIn<HistoryCommands>()
yieldAllCommandsIn<GeneralCommands>()
}
dumpSection("Navigation Commands") {
yieldAllCommandsIn<NavigationCommands>()
}
dumpSection("Selection Commands") {
yieldAllCommandsIn<SelectionCommands>()
yield("/expand")
}
dumpSection("Region Commands") {
yieldAllCommandsIn<RegionCommands>()
}
dumpSection("Generation Commands") {
yieldAllCommandsIn<GenerationCommands>()
}
dumpSection("Schematic and Clipboard Commands") {
yield("schematic")
yieldAllCommandsIn<ClipboardCommands>()
}
dumpSection("Tool Commands") {
yield("tool")
yieldAllCommandsIn<ToolCommands>()
yieldAllCommandsIn<ToolUtilCommands>()
}
dumpSection("Super Pickaxe Commands") {
yield("superpickaxe")
}
dumpSection("Brush Commands") {
yield("brush")
}
dumpSection("Biome Commands") {
yieldAllCommandsIn<BiomeCommands>()
}
dumpSection("Chunk Commands") {
yieldAllCommandsIn<ChunkCommands>()
}
dumpSection("Snapshot Commands") {
yieldAllCommandsIn<SnapshotUtilCommands>()
yield("snapshot")
}
dumpSection("Scripting Commands") {
yieldAllCommandsIn<ScriptingCommands>()
}
dumpSection("Utility Commands") {
yieldAllCommandsIn<UtilityCommands>()
}
writeFooter()
val missingCommands = commands.keys.filterNot { it in matchedCommands }
require(missingCommands.isEmpty()) { "Missing commands: $missingCommands" }
}
private fun writeHeader() {
cmdOutput.appendln("""
========
Commands
========
.. contents::
:local:
.. note::
Arguments enclosed in ``[ ]`` are optional, those enclosed in ``< >`` are required.
.. tip::
You can access a command listing in-game via the ``//help`` command.
""".trim())
permsOutput.appendln("""
===========
Permissions
===========
By default, no one can use WorldEdit. In order for yourself, moderators, and players to use WorldEdit, you must provide the proper permissions. One way is to provide op to moderators and administrators (unless disabled in the :doc:`configuration <config>`), but providing the permission nodes on this page (through a permissions plugin) is the more flexible.
You can give the ``worldedit.*`` permission to give yourself and other administrators full access to WorldEdit.
Commands
=========
See the :doc:`commands` page for an explanation of some of these commands.
.. csv-table::
:header: Command, Permission
:widths: 15, 25
""".trim())
permsOutput.appendln()
}
private fun writeFooter() {
permsOutput.appendln()
permsOutput.append("""
Other Permissions
==================
.. csv-table::
:header: Permission, Explanation
:widths: 15, 25
``worldedit.navigation.jumpto.tool``,"Allows usage of the navigation wand's ``/jumpto`` shortcut (left click)."
``worldedit.navigation.thru.tool``,"Allows usage of the navigation wand's ``/thru`` shortcut (right click)."
``worldedit.anyblock``,"Allows usage of blocks in the :doc:`disallowed-blocks <config>` config option."
``worldedit.limit.unrestricted``,"Allows setting the limit via the ``//limit`` :doc:`command <commands>` higher than the maximum in the :doc:`configuration <config>`, as well as other limit bypasses."
``worldedit.timeout.unrestricted``,"Allows setting the calculation timeout via the ``//timeout`` :doc:`command <commands>` higher than the maximum in the :doc:`configuration <config>`."
``worldedit.inventory.unrestricted``,"Override the ``use-inventory`` option if enabled in the :doc:`configuration <config>`."
``worldedit.override.bedrock``,"Allows breaking of bedrock with the super-pickaxe tool."
``worldedit.override.data-cycler``,"Allows cycling non-whitelisted blocks with the data cycler tool."
``worldedit.setnbt``,"Allows setting `extra data <https://minecraft.gamepedia.com/Block_entity>`_ on blocks (such as signs, chests, etc)."
``worldedit.report.pastebin``,"Allows uploading report files to pastebin automatically for the ``/worldedit report`` :doc:`command <commands>`."
``worldedit.scripting.execute.<filename>``,"Allows using the CraftScript with the given filename."
""".trim())
}
private fun dumpSection(title: String, addCommandNames: suspend SequenceScope<String>.() -> Unit) {
cmdOutput.append("\n").append(title).append("\n").append(Strings.repeat("~", title.length)).append("\n")
val prefix = reduceToRst(TextConfig.commandPrefixValue())
val commands = sequence(addCommandNames).map { this.commands.getValue(it) }.toList()
matchedCommands.addAll(commands.map { it.name })
cmdsToPerms(commands, prefix)
for (command in commands) {
writeCommandBlock(command, prefix, Stream.empty())
command.parts.stream().filter { p -> p is SubCommandPart }
.flatMap { p -> (p as SubCommandPart).commands.stream() }
.forEach { sc ->
writeCommandBlock(sc, prefix + command.name + " ", Stream.of(command))
}
}
}
private fun cmdsToPerms(cmds: List<Command>, prefix: String) {
cmds.forEach { c ->
permsOutput.append(" ").append(cmdToPerm(prefix, c)).append("\n")
c.parts.filterIsInstance<SubCommandPart>()
.forEach { scp ->
cmdsToPerms(scp.commands.sortedBy { it.name }, prefix + c.name + " ")
}
}
}
private fun cmdToPerm(prefix: String, c: Command): String {
val cond = c.condition
val permissions = when {
cond is PermissionCondition && cond.permissions.isNotEmpty() ->
cond.permissions.joinToString(", ") { "``$it``" }
else -> ""
}
return "``$prefix${c.name}``,\"$permissions\""
}
private fun writeCommandBlock(command: Command, prefix: String, parents: Stream<Command>) {
val name = prefix + command.name
val entries = commandTableEntries(command, parents)
cmdOutput.appendln(".. raw:: html")
cmdOutput.appendln()
cmdOutput.appendln(""" <span id="command-${linkSafe(name)}"></span>""")
cmdOutput.appendln()
cmdOutput.append(".. topic:: ``$name``")
if (!command.aliases.isEmpty()) {
command.aliases.joinTo(cmdOutput, ", ",
prefix = " (or ",
postfix = ")",
transform = { "``$prefix$it``" })
}
cmdOutput.appendln()
cmdOutput.appendln(" :class: command-topic").appendln()
CommandUtil.deprecationWarning(command).ifPresent { warning ->
cmdOutput.appendln("""
| .. WARNING::
| ${reduceToRst(warning).makeRstSafe("\n\n")}
""".trimMargin())
}
cmdOutput.appendln("""
| .. csv-table::
| :widths: 8, 15
""".trimMargin())
cmdOutput.appendln()
for ((k, v) in entries) {
val rstSafe = v.makeRstSafe("\n")
cmdOutput.append(" ".repeat(2))
.append(k)
.append(",")
.append('"')
.append(rstSafe)
.append('"').appendln()
}
cmdOutput.appendln()
}
private fun String.makeRstSafe(lineJoiner: String) = trim()
.replace("\"", "\\\"").replace("\n", "\n" + " ".repeat(2))
.lineSequence()
.map { line -> line.ifBlank { "" } }
.joinToString(separator = lineJoiner)
private fun linkSafe(text: String) = text.replace(" ", "-")
private fun commandTableEntries(command: Command, parents: Stream<Command>): Map<String, String> {
return sequence {
val desc = command.description.run {
val footer = CommandUtil.footerWithoutDeprecation(command)
when {
footer.isPresent -> append(
TextComponent.builder("\n\n").append(footer.get())
)
else -> this
}
}
yield("**Description**" to reduceToRst(desc))
val cond = command.condition
if (cond is PermissionCondition && cond.permissions.isNotEmpty()) {
val perms = cond.permissions.joinToString(", ") { "``$it``" }
yield("**Permissions**" to perms)
}
val usage = reduceToRst(HelpGenerator.create(Stream.concat(parents, Stream.of(command)).toList()).usage)
yield("**Usage**" to "``$usage``")
// Part descriptions
command.parts.filterNot { it is SubCommandPart }
.forEach {
val title = "\u2001\u2001``" + reduceToRst(it.textRepresentation) + "``"
yield(title to reduceToRst(it.description))
}
}.toMap()
}
companion object {
/**
* Generates documentation.
*/
@JvmStatic
fun main(args: Array<String>) {
try {
val printer = DocumentationPrinter()
printer.writeAllCommands()
writeOutput("commands.rst", printer.cmdOutput.toString())
writeOutput("permissions.rst", printer.permsOutput.toString())
} finally {
WorldEdit.getInstance().sessionManager.unload()
}
}
private fun writeOutput(file: String, output: String) {
Files.newBufferedWriter(Paths.get(file)).use {
it.write(output)
}
}
}
}

View File

@ -121,7 +121,6 @@ public class MobSpawnerBlock extends BaseBlock {
@Override @Override
public CompoundTag getNbtData() { public CompoundTag getNbtData() {
Map<String, Tag> values = new HashMap<>(); Map<String, Tag> values = new HashMap<>();
values.put("EntityId", new StringTag(mobType));
values.put("Delay", new ShortTag(delay)); values.put("Delay", new ShortTag(delay));
values.put("SpawnCount", new ShortTag(spawnCount)); values.put("SpawnCount", new ShortTag(spawnCount));
values.put("SpawnRange", new ShortTag(spawnRange)); values.put("SpawnRange", new ShortTag(spawnRange));
@ -180,7 +179,6 @@ public class MobSpawnerBlock extends BaseBlock {
this.delay = -1; this.delay = -1;
} }
ShortTag spawnCountTag = null; ShortTag spawnCountTag = null;
ShortTag spawnRangeTag = null; ShortTag spawnRangeTag = null;
ShortTag minSpawnDelayTag = null; ShortTag minSpawnDelayTag = null;

View File

@ -0,0 +1,236 @@
grammar Expression;
// Lexer tokens:
PLUS : '+' ;
MINUS : '-' ;
TIMES : '*' ;
DIVIDE : '/' ;
MODULO : '%' ;
POWER : '^' | '**' ;
LEFT_SHIFT : '<<' ;
RIGHT_SHIFT : '>>' ;
ASSIGN : '=' ;
COMPLEMENT : '~' ;
PLUS_ASSIGN : '+=' ;
MINUS_ASSIGN : '-=' ;
TIMES_ASSIGN : '*=' ;
DIVIDE_ASSIGN : '/=' ;
MODULO_ASSIGN : '%=' ;
POWER_ASSIGN : '^=' ;
EQUAL : '==' ;
NOT_EQUAL : '!=' ;
NEAR : '~=' ;
LESS_THAN : '<' ;
LESS_THAN_OR_EQUAL : '<=' ;
GREATER_THAN : '>' ;
GREATER_THAN_OR_EQUAL : '>=' ;
// SC = "Short Circuit"
// Non-SC variants not currently implemented.
AND_SC : '&&' ;
OR_SC : '||' ;
INCREMENT : '++' ;
DECREMENT : '--' ;
COMMA : ',' ;
OPEN_PAREN : '(' ;
CLOSE_PAREN : ')' ;
OPEN_BRACKET : '{' ;
CLOSE_BRACKET : '}' ;
SEMI_COLON : ';' ;
QUESTION_MARK : '?' ;
COLON : ':' ;
EXCLAMATION_MARK : '!' ;
IF : 'if' ;
ELSE : 'else' ;
WHILE : 'while' ;
DO : 'do' ;
FOR : 'for' ;
BREAK : 'break' ;
CONTINUE : 'continue' ;
RETURN : 'return' ;
SWITCH : 'switch' ;
CASE : 'case' ;
DEFAULT : 'default' ;
fragment DIGIT : [0-9] ;
fragment SIGN : [+-] ;
fragment EXP_CHAR : [eE] ;
fragment DECIMAL : '.' DIGIT+ ( EXP_CHAR SIGN? DIGIT+ )? ;
// All numbers are treated the same. No int/dec divide.
NUMBER : ( DIGIT+ DECIMAL? | DECIMAL ) ;
ID : [A-Za-z] [0-9A-Za-z_]* ;
WS : [ \t\r\n\u000C]+ -> skip ;
// Parser rules:
/**
* All statements parseable from the input. Forces consumption of EOF token.
*/
allStatements : statements EOF ;
statements : statement+ ;
statement
: ( block
| ifStatement
| whileStatement
| doStatement
| forStatement
| simpleForStatement
| breakStatement
| continueStatement
| returnStatement
| switchStatement
| expressionStatement
| emptyStatement
) SEMI_COLON?
;
block : '{' statements '}' ;
ifStatement : IF '(' condition=expression ')' trueBranch=statement ( ELSE falseBranch=statement )? ;
whileStatement : WHILE '(' condition=expression ')' body=statement ;
doStatement : DO body=statement WHILE '(' condition=expression ')' ;
// C-Style for loop
forStatement
: FOR '(' init=expression ';' condition=expression ';' update=expression ')' body=statement ;
// Range for loop
simpleForStatement
: FOR '(' counter=ID ASSIGN first=expression ',' last=expression ')' body=statement ;
breakStatement : BREAK ;
continueStatement : CONTINUE ;
returnStatement : RETURN value=expression? ;
switchStatement : SWITCH '(' target=expression ')' '{' (labels+=switchLabel ':' bodies+=statements )+ '}' ;
switchLabel
: CASE constant=constantExpression # Case
| DEFAULT # Default
;
expressionStatement : expression ;
emptyStatement: SEMI_COLON ;
expression : assignmentExpression ;
assignmentExpression
: conditionalExpression
| assignment
;
assignment
: target=ID assignmentOperator source=expression
;
assignmentOperator
: ASSIGN
| POWER_ASSIGN
| TIMES_ASSIGN
| DIVIDE_ASSIGN
| MODULO_ASSIGN
| PLUS_ASSIGN
| MINUS_ASSIGN
;
conditionalExpression
: conditionalOrExpression # CEFallthrough
| condition=conditionalOrExpression QUESTION_MARK
trueBranch=expression COLON falseBranch=conditionalExpression # TernaryExpr
;
conditionalOrExpression
: conditionalAndExpression # COFallthrough
| left=conditionalOrExpression OR_SC right=conditionalAndExpression # ConditionalOrExpr
;
conditionalAndExpression
: equalityExpression # CAFallthrough
| left=conditionalAndExpression AND_SC right=equalityExpression # ConditionalAndExpr
;
equalityExpression
: relationalExpression # EqFallthrough
| left=equalityExpression
op=
( EQUAL
| NOT_EQUAL
| NEAR
) right=relationalExpression # EqualityExpr
;
relationalExpression
: shiftExpression # ReFallthrough
| left=relationalExpression
op=
( LESS_THAN
| GREATER_THAN
| LESS_THAN_OR_EQUAL
| GREATER_THAN_OR_EQUAL
) right=shiftExpression # RelationalExpr
;
shiftExpression
: additiveExpression # ShFallthrough
| left=shiftExpression op=( LEFT_SHIFT | RIGHT_SHIFT ) right=additiveExpression # ShiftExpr
;
additiveExpression
: multiplicativeExpression # AdFallthrough
| left=additiveExpression op=( PLUS | MINUS ) right=multiplicativeExpression # AddExpr
;
multiplicativeExpression
: powerExpression # MuFallthrough
| left=multiplicativeExpression
op=
( TIMES
| DIVIDE
| MODULO
) right=powerExpression # MultiplicativeExpr
;
powerExpression
: unaryExpression # PwFallthrough
| left=powerExpression POWER right=unaryExpression # PowerExpr
;
unaryExpression
: op=( INCREMENT | DECREMENT ) target=ID # PreCrementExpr
| op=( PLUS | MINUS ) expr=unaryExpression # PlusMinusExpr
| postfixExpression # UaFallthrough
| COMPLEMENT expr=unaryExpression # ComplementExpr
| EXCLAMATION_MARK expr=unaryExpression # NotExpr
;
postfixExpression
: unprioritizedExpression # PoFallthrough
| target=ID op=( INCREMENT | DECREMENT) # PostCrementExpr
| expr=postfixExpression op=EXCLAMATION_MARK # PostfixExpr
;
unprioritizedExpression
: functionCall # FunctionCallExpr
| constantExpression # ConstantExpr
| source=ID # IdExpr
| '(' expression ')' # WrappedExpr
;
constantExpression : NUMBER ;
functionCall : name=ID '(' (args+=expression ( ',' args+=expression )*)? ')' ;

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>tar.gz</format>
<format>tar.bz2</format>
<format>zip</format>
</formats>
<files>
<file>
<source>${project.build.directory}/${artifactId}-${project.version}.jar</source>
<destName>WorldEdit.jar</destName>
<outputDirectory>/</outputDirectory>
<filtered>false</filtered>
</file>
<file>
<source>README.html</source>
<outputDirectory>/</outputDirectory>
<filtered>true</filtered>
</file>
</files>
<fileSets>
<fileSet>
<includes>
<include>LICENSE.txt</include>
<include>CHANGELOG.txt</include>
<include>contrib/craftscripts/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@ -23,6 +23,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Locale; import java.util.Locale;
import java.util.Locale;
/** /**
* The {@code TAG_Int_Array} tag. * The {@code TAG_Int_Array} tag.
*/ */

View File

@ -23,6 +23,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Locale; import java.util.Locale;
import java.util.Locale;
/** /**
* The {@code TAG_Long_Array} tag. * The {@code TAG_Long_Array} tag.
*/ */

View File

@ -43,6 +43,8 @@ import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Watchdog;
import com.sk89q.worldedit.extent.ChangeSetExtent; import com.sk89q.worldedit.extent.ChangeSetExtent;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.MaskingExtent; import com.sk89q.worldedit.extent.MaskingExtent;
@ -60,6 +62,7 @@ import com.sk89q.worldedit.extent.world.FastModeExtent;
import com.sk89q.worldedit.extent.world.SurvivalModeExtent; import com.sk89q.worldedit.extent.world.SurvivalModeExtent;
import com.sk89q.worldedit.extent.world.WatchdogTickingExtent; import com.sk89q.worldedit.extent.world.WatchdogTickingExtent;
import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.GroundFunction;
import com.sk89q.worldedit.function.biome.BiomeReplace;
import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.function.block.Naturalizer; import com.sk89q.worldedit.function.block.Naturalizer;
@ -94,11 +97,11 @@ import com.sk89q.worldedit.history.changeset.ChangeSet;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException; import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException;
import com.sk89q.worldedit.internal.expression.runtime.RValue;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.MathUtils; import com.sk89q.worldedit.math.MathUtils;
import com.sk89q.worldedit.internal.expression.ExpressionTimeoutException;
import com.sk89q.worldedit.internal.expression.LocalSlot.Variable;
import com.sk89q.worldedit.math.MutableBlockVector2; import com.sk89q.worldedit.math.MutableBlockVector2;
import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.MutableBlockVector3;
import com.sk89q.worldedit.math.Vector2; import com.sk89q.worldedit.math.Vector2;
@ -319,6 +322,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
public Extent getBypassHistory() { public Extent getBypassHistory() {
return bypassHistory; return bypassHistory;
} }
private final List<WatchdogTickingExtent> watchdogExtents = new ArrayList<>(2);
public void setExtent(AbstractDelegateExtent extent) { public void setExtent(AbstractDelegateExtent extent) {
new ExtentTraverser<>(getExtent()).setNext(extent); new ExtentTraverser<>(getExtent()).setNext(extent);
@ -1164,6 +1168,18 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
return this.changes = visitor.getAffected(); return this.changes = visitor.getAffected();
} }
/**
* Count the number of blocks of a list of types in a region.
*
* @param region the region
* @param searchBlocks the list of blocks to search
* @return the number of blocks that matched the block
*/
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
BlockMask mask = new BlockMask(this, searchBlocks);
return countBlocks(region, mask);
}
/** /**
* Remove a cuboid above the given position with a given apothem and a given height. * Remove a cuboid above the given position with a given apothem and a given height.
* *
@ -1182,8 +1198,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
getWorld(), // Causes clamping of Y range getWorld(), // Causes clamping of Y range
position.add(-apothem + 1, 0, -apothem + 1), position.add(-apothem + 1, 0, -apothem + 1),
position.add(apothem - 1, height - 1, apothem - 1)); position.add(apothem - 1, height - 1, apothem - 1));
Pattern pattern = BlockTypes.AIR.getDefaultState(); return setBlocks(region, BlockTypes.AIR.getDefaultState());
return setBlocks(region, pattern);
} }
/** /**
@ -1231,16 +1246,15 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* Remove blocks of a certain type nearby a given position. * Remove blocks of a certain type nearby a given position.
* *
* @param position center position of cuboid * @param position center position of cuboid
* @param blockType the block type to match * @param mask the mask to match
* @param apothem an apothem of the cuboid, where the minimum is 1 * @param apothem an apothem of the cuboid, where the minimum is 1
* @return number of blocks affected * @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed * @throws MaxChangedBlocksException thrown if too many blocks are changed
*/ */
public int removeNear(BlockVector3 position, BlockType blockType, int apothem) throws MaxChangedBlocksException { public int removeNear(BlockVector3 position, Mask mask, int apothem) throws MaxChangedBlocksException {
checkNotNull(position); checkNotNull(position);
checkArgument(apothem >= 1, "apothem >= 1"); checkArgument(apothem >= 1, "apothem >= 1");
Mask mask = new SingleBlockTypeMask(this, blockType);
BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1); BlockVector3 adjustment = BlockVector3.ONE.multiply(apothem - 1);
Region region = new CuboidRegion( Region region = new CuboidRegion(
getWorld(), // Causes clamping of Y range getWorld(), // Causes clamping of Y range
@ -1450,7 +1464,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @param region the region to stack * @param region the region to stack
* @param dir the direction to stack * @param dir the direction to stack
* @param count the number of times to stack * @param count the number of times to stack
* @param copyAir true to also copy air blocks * @param copyEntities true to copy entities
* @param copyBiomes true to copy biomes
* @param mask source mask for the operation (only matching blocks are copied)
* @return number of blocks affected * @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed * @throws MaxChangedBlocksException thrown if too many blocks are changed
*/ */
@ -1485,10 +1501,13 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @param region the region to move * @param region the region to move
* @param dir the direction * @param dir the direction
* @param distance the distance to move * @param distance the distance to move
* @param copyAir true to copy air blocks * @param moveEntities true to move entities
* @param copyBiomes true to copy biomes (source biome is unchanged)
* @param mask source mask for the operation (only matching blocks are moved)
* @param replacement the replacement pattern to fill in after moving, or null to use air * @param replacement the replacement pattern to fill in after moving, or null to use air
* @return number of blocks moved * @return number of blocks moved
* @throws MaxChangedBlocksException thrown if too many blocks are changed * @throws MaxChangedBlocksException thrown if too many blocks are changed
* @throws IllegalArgumentException thrown if the region is not a flat region, but copyBiomes is true
*/ */
public int moveRegion(Region region, BlockVector3 dir, int distance, boolean copyAir, public int moveRegion(Region region, BlockVector3 dir, int distance, boolean copyAir,
boolean moveEntities, boolean copyBiomes, Pattern replacement) throws MaxChangedBlocksException { boolean moveEntities, boolean copyBiomes, Pattern replacement) throws MaxChangedBlocksException {
@ -1563,7 +1582,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
/** /**
* Drain nearby pools of water or lava, optionally removed waterlogged states from blocks. * Drain nearby pools of water or lava, optionally removed waterlogged states from blocks.
* *
* @param origin the origin to drain from, which will search a 3×3 area * @param origin the origin to drain from, which will search a 3x3 area
* @param radius the radius of the removal, where a value should be 0 or greater * @param radius the radius of the removal, where a value should be 0 or greater
* @param waterlogged true to make waterlogged blocks non-waterlogged as well * @param waterlogged true to make waterlogged blocks non-waterlogged as well
* @return number of blocks affected * @return number of blocks affected
@ -1592,14 +1611,14 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
} }
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1)); RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1));
// Around the origin in a 3×3 block // Around the origin in a 3x3 block
for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) { for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) {
if (mask.test(position)) { if (mask.test(position)) {
visitor.visit(position); visitor.visit(position);
} }
} }
Operations.completeBlindly(visitor); Operations.completeLegacy(visitor);
return this.changes = visitor.getAffected(); return this.changes = visitor.getAffected();
} }
@ -1680,6 +1699,21 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
return makeCylinder(pos, block, radiusX, radiusZ, height, thickness, false); return makeCylinder(pos, block, radiusX, radiusZ, height, thickness, false);
} }
/**
* Stack a cuboid region. For compatibility, entities are copied by biomes are not.
* Use {@link #stackCuboidRegion(Region, BlockVector3, int, boolean, boolean, Mask)} to fine tune.
*
* @param region the region to stack
* @param dir the direction to stack
* @param count the number of times to stack
* @param copyAir true to also copy air blocks
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int stackCuboidRegion(Region region, BlockVector3 dir, int count, boolean copyAir) throws MaxChangedBlocksException {
return stackCuboidRegion(region, dir, count, true, false, copyAir ? null : new ExistingBlockMask(this));
}
private int makeCylinder(BlockVector3 pos, Pattern block, double radiusX, double radiusZ, int height, double thickness, boolean filled) throws MaxChangedBlocksException { private int makeCylinder(BlockVector3 pos, Pattern block, double radiusX, double radiusZ, int height, double thickness, boolean filled) throws MaxChangedBlocksException {
int affected = 0; int affected = 0;
@ -1790,6 +1824,21 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
return this.changes; return this.changes;
} }
/**
* Move the blocks in a region a certain direction.
*
* @param region the region to move
* @param dir the direction
* @param distance the distance to move
* @param copyAir true to copy air blocks
* @param replacement the replacement pattern to fill in after moving, or null to use air
* @return number of blocks moved
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int moveRegion(Region region, BlockVector3 dir, int distance, boolean copyAir, Pattern replacement) throws MaxChangedBlocksException {
return moveRegion(region, dir, distance, true, false, copyAir ? new ExistingBlockMask(this) : null, replacement);
}
public int makeCircle(BlockVector3 pos, final Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled, Vector3 normal) throws MaxChangedBlocksException { public int makeCircle(BlockVector3 pos, final Pattern block, double radiusX, double radiusY, double radiusZ, boolean filled, Vector3 normal) throws MaxChangedBlocksException {
radiusX += 0.5; radiusX += 0.5;
radiusY += 0.5; radiusY += 0.5;
@ -2322,8 +2371,10 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data"); final Expression expression = Expression.compile(expressionString, "x", "y", "z", "type", "data");
expression.optimize(); expression.optimize();
final RValue typeVariable = expression.getVariable("type", false); final Variable typeVariable = expression.getSlots().getVariable("type")
final RValue dataVariable = expression.getVariable("data", false); .orElseThrow(IllegalStateException::new);
final Variable dataVariable = expression.getSlots().getVariable("data")
.orElseThrow(IllegalStateException::new);
final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero); final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero);
expression.setEnvironment(environment); expression.setEnvironment(environment);
@ -2371,9 +2422,12 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final Expression expression = Expression.compile(expressionString, "x", "y", "z"); final Expression expression = Expression.compile(expressionString, "x", "y", "z");
expression.optimize(); expression.optimize();
final RValue x = expression.getVariable("x", false).optimize(); final Variable x = expression.getSlots().getVariable("x")
final RValue y = expression.getVariable("y", false).optimize(); .orElseThrow(IllegalStateException::new);
final RValue z = expression.getVariable("z", false).optimize(); final Variable y = expression.getSlots().getVariable("y")
.orElseThrow(IllegalStateException::new);
final Variable z = expression.getSlots().getVariable("z")
.orElseThrow(IllegalStateException::new);
final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero); final WorldEditExpressionEnvironment environment = new WorldEditExpressionEnvironment(this, unit, zero);
expression.setEnvironment(environment); expression.setEnvironment(environment);

View File

@ -20,8 +20,6 @@
package com.sk89q.worldedit; package com.sk89q.worldedit;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.EditSessionEvent; import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBag;

View File

@ -78,7 +78,6 @@ import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.snapshot.Snapshot; import com.sk89q.worldedit.world.snapshot.Snapshot;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.io.File; import java.io.File;
@ -148,6 +147,7 @@ public class LocalSession implements TextureHolder {
private transient ResettableExtent transform = null; private transient ResettableExtent transform = null;
private transient ZoneId timezone = ZoneId.systemDefault(); private transient ZoneId timezone = ZoneId.systemDefault();
private transient World currentWorld; private transient World currentWorld;
private transient boolean tickingWatchdog = false;
private transient UUID uuid; private transient UUID uuid;
private transient volatile long historySize = 0; private transient volatile long historySize = 0;
@ -157,8 +157,6 @@ public class LocalSession implements TextureHolder {
private transient World worldOverride; private transient World worldOverride;
private transient boolean tickingWatchdog = false; private transient boolean tickingWatchdog = false;
private transient boolean loadDefaults = true;
// Saved properties // Saved properties
private String lastScript; private String lastScript;
private RegionSelectorType defaultSelector; private RegionSelectorType defaultSelector;
@ -1104,6 +1102,14 @@ public class LocalSession implements TextureHolder {
} }
} }
public void setPlaceAtPos1(boolean placeAtPos1) {
this.placeAtPos1 = placeAtPos1;
}
public boolean isPlaceAtPos1() {
return placeAtPos1;
}
public void setTool(BaseItem item, @Nullable Tool tool, Player player) throws InvalidToolBindException { public void setTool(BaseItem item, @Nullable Tool tool, Player player) throws InvalidToolBindException {
ItemType type = item.getType(); ItemType type = item.getType();
if (type.hasBlockType() && type.getBlockType().getMaterial().isAir()) { if (type.hasBlockType() && type.getBlockType().getMaterial().isAir()) {
@ -1603,4 +1609,13 @@ public class LocalSession implements TextureHolder {
} }
} }
} }
private void prepareEditingExtents(EditSession editSession, Actor actor) {
editSession.setFastMode(fastMode);
editSession.setReorderMode(reorderMode);
if (editSession.getSurvivalExtent() != null) {
editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt"));
}
editSession.setTickingWatchdog(tickingWatchdog);
}
} }

View File

@ -1,66 +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.blocks.metadata;
/**
* Represents the possible types of mobs.
*/
public enum MobType {
BAT("Bat"),
BLAZE("Blaze"),
CAVE_SPIDER("CaveSpider"),
CHICKEN("Chicken"),
COW("Cow"),
CREEPER("Creeper"),
ENDERDRAGON("EnderDragon"),
ENDERMAN("Enderman"),
GHAST("Ghast"),
GIANT("Giant"),
VILLAGER_GOLEM("VillagerGolem"),
HORSE("EntityHorse"),
MAGMA_CUBE("LavaSlime"),
MOOSHROOM("MushroomCow"),
OCELOT("Ozelot"),
PIG("Pig"),
PIG_ZOMBIE("PigZombie"),
SHEEP("Sheep"),
SILVERFISH("Silverfish"),
SKELETON("Skeleton"),
SLIME("Slime"),
SNOWMAN("SnowMan"),
SPIDER("Spider"),
SQUID("Squid"),
VILLAGER("Villager"),
WITCH("Witch"),
WITHER("WitherBoss"),
WOLF("Wolf"),
ZOMBIE("Zombie");
private final String name;
MobType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@ -27,6 +27,7 @@ import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
@ -81,6 +82,7 @@ public class BiomeCommands {
public void biomeList(Actor actor, public void biomeList(Actor actor,
@ArgFlag(name = 'p', desc = "Page number.", def = "1") @ArgFlag(name = 'p', desc = "Page number.", def = "1")
int page) { int page) {
WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> {
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager() BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry(); .queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
@ -97,7 +99,8 @@ public class BiomeCommands {
} }
}) })
.collect(Collectors.toList())); .collect(Collectors.toList()));
actor.print(paginationBox.create(page)); return paginationBox.create(page);
}, null);
} }
@Command( @Command(
@ -180,7 +183,8 @@ public class BiomeCommands {
Mask2D mask2d = mask != null ? mask.toMask2D() : null; Mask2D mask2d = mask != null ? mask.toMask2D() : null;
if (atPosition) { if (atPosition) {
region = new CuboidRegion(player.getLocation().toVector().toBlockPoint(), player.getLocation().toVector().toBlockPoint()); final BlockVector3 pos = player.getLocation().toVector().toBlockPoint();
region = new CuboidRegion(pos, pos);
} else { } else {
region = session.getSelection(world); region = session.getSelection(world);
} }

View File

@ -19,8 +19,6 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
@ -67,6 +65,7 @@ import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.factory.ReplaceFactory;
import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.command.argument.Arguments; import com.sk89q.worldedit.command.argument.Arguments;
import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; import com.sk89q.worldedit.command.factory.TreeGeneratorFactory;
@ -127,6 +126,7 @@ import java.nio.file.FileSystems;
import java.util.List; import java.util.List;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.Command;
import com.sk89q.worldedit.function.factory.Apply;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.ArgFlag;
@ -134,6 +134,8 @@ import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.Key;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Commands to set brush shape. * Commands to set brush shape.
*/ */
@ -152,6 +154,15 @@ public class BrushCommands {
this.worldEdit = worldEdit; this.worldEdit = worldEdit;
} }
@Command(
name = "none",
aliases = "unbind",
desc = "Unbind a bound brush from your current item"
)
void none(Player player, LocalSession session) throws WorldEditException {
ToolCommands.setToolNone(player, session, "Brush");
}
@Command( @Command(
name = "blendball", name = "blendball",
aliases = {"bb", "blend"}, aliases = {"bb", "blend"},
@ -644,18 +655,18 @@ public class BrushCommands {
) )
@Deprecated @Deprecated
@CommandPermissions("worldedit.brush.clipboard") @CommandPermissions("worldedit.brush.clipboard")
public void clipboardBrush(LocalSession session, InjectedValueAccess context, public void clipboardBrush(Player player, LocalSession session,
@Switch(name = 'a', desc = "Don't paste air from the clipboard") @Switch(name = 'a', desc = "Don't paste air from the clipboard")
boolean ignoreAir, boolean ignoreAir,
@Switch(name = 'o', desc = "Paste starting at the target location, instead of centering on it") @Switch(name = 'o', desc = "Paste starting at the target location, instead of centering on it")
boolean usingOrigin, boolean usingOrigin,
@Switch(name = 'e', desc = "Skip paste entities if available") @Switch(name = 'e', desc = "Paste entities if available")
boolean skipEntities, boolean pasteEntities,
@Switch(name = 'b', desc = "Paste biomes if available") @Switch(name = 'b', desc = "Paste biomes if available")
boolean pasteBiomes, boolean pasteBiomes,
@ArgFlag(name = 'm', desc = "Skip blocks matching this mask in the clipboard", def = "") @ArgFlag(name = 'm', desc = "Skip blocks matching this mask in the clipboard", def = "")
@ClipboardMask @ClipboardMask
Mask sourceMask) throws WorldEditException { Mask sourceMask) throws WorldEditException {
ClipboardHolder holder = session.getClipboard(); ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard(); Clipboard clipboard = holder.getClipboard();
@ -678,13 +689,13 @@ public class BrushCommands {
descFooter = "Example: '/brush smooth 2 4 grass_block,dirt,stone'" descFooter = "Example: '/brush smooth 2 4 grass_block,dirt,stone'"
) )
@CommandPermissions("worldedit.brush.smooth") @CommandPermissions("worldedit.brush.smooth")
public void smoothBrush(Player player, InjectedValueAccess context, EditSession editSession, public void smoothBrush(Player player, LocalSession session,
@Arg(desc = "The radius to sample for softening", def = "2") @Arg(desc = "The radius to sample for softening", def = "2")
Expression radius, Expression radius,
@Arg(desc = "The number of iterations to perform", def = "4") @Arg(desc = "The number of iterations to perform", def = "4")
int iterations, int iterations,
@Arg(desc = "The mask of blocks to use for the heightmap", def = "") @Arg(desc = "The mask of blocks to use for the heightmap", def = "")
Mask maskOpt) throws WorldEditException { Mask maskOpt) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius); worldEdit.checkMaxBrushRadius(radius);
FaweLimit limit = Settings.IMP.getLimit(player); FaweLimit limit = Settings.IMP.getLimit(player);
@ -1089,4 +1100,106 @@ public class BrushCommands {
player.print("Set brush to " + factory); player.print("Set brush to " + factory);
} }
@Command(
name = "deform",
desc = "Deform brush, applies an expression to an area"
)
@CommandPermissions("worldedit.brush.deform")
public void deform(Player player, LocalSession localSession,
@Arg(desc = "The shape of the region")
RegionFactory shape,
@Arg(desc = "The size of the brush", def = "5")
double radius,
@Arg(desc = "Expression to apply", def = "y-=0.2")
String expression,
@Switch(name = 'r', desc = "Use the game's coordinate origin")
boolean useRawCoords,
@Switch(name = 'o', desc = "Use the placement position as the origin")
boolean usePlacement) throws WorldEditException {
Deform deform = new Deform(expression);
if (useRawCoords) {
deform.setMode(Deform.Mode.RAW_COORD);
} else if (usePlacement) {
deform.setMode(Deform.Mode.OFFSET);
deform.setOffset(localSession.getPlacementPosition(player).toVector3());
}
setOperationBasedBrush(player, localSession, radius,
deform, shape, "worldedit.brush.deform");
}
@Command(
name = "set",
desc = "Set brush, sets all blocks in the area"
)
@CommandPermissions("worldedit.brush.set")
public void set(Player player, LocalSession localSession,
@Arg(desc = "The shape of the region")
RegionFactory shape,
@Arg(desc = "The size of the brush", def = "5")
double radius,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern) throws WorldEditException {
setOperationBasedBrush(player, localSession, radius,
new Apply(new ReplaceFactory(pattern)), shape, "worldedit.brush.set");
}
@Command(
name = "forest",
desc = "Forest brush, creates a forest in the area"
)
@CommandPermissions("worldedit.brush.forest")
public void forest(Player player, LocalSession localSession,
@Arg(desc = "The shape of the region")
RegionFactory shape,
@Arg(desc = "The size of the brush", def = "5")
double radius,
@Arg(desc = "The density of the brush", def = "20")
double density,
@Arg(desc = "The type of tree to use")
TreeGenerator.TreeType type) throws WorldEditException {
setOperationBasedBrush(player, localSession, radius,
new Paint(new TreeGeneratorFactory(type), density / 100), shape, "worldedit.brush.forest");
}
@Command(
name = "raise",
desc = "Raise brush, raise all blocks by one"
)
@CommandPermissions("worldedit.brush.raise")
public void raise(Player player, LocalSession localSession,
@Arg(desc = "The shape of the region")
RegionFactory shape,
@Arg(desc = "The size of the brush", def = "5")
double radius) throws WorldEditException {
setOperationBasedBrush(player, localSession, radius,
new Deform("y-=1"), shape, "worldedit.brush.raise");
}
@Command(
name = "lower",
desc = "Lower brush, lower all blocks by one"
)
@CommandPermissions("worldedit.brush.lower")
public void lower(Player player, LocalSession localSession,
@Arg(desc = "The shape of the region")
RegionFactory shape,
@Arg(desc = "The size of the brush", def = "5")
double radius) throws WorldEditException {
setOperationBasedBrush(player, localSession, radius,
new Deform("y+=1"), shape, "worldedit.brush.lower");
}
static void setOperationBasedBrush(Player player, LocalSession session, double radius,
Contextual<? extends Operation> factory,
RegionFactory shape,
String permission) throws WorldEditException {
WorldEdit.getInstance().checkMaxBrushRadius(radius);
BrushTool tool = session.getBrushTool(player.getItemInHand(HandSide.MAIN_HAND).getType());
tool.setSize(radius);
tool.setFill(null);
tool.setBrush(new OperationFactoryBrush(factory, shape, session), permission);
player.print("Set brush to " + factory);
}
} }

View File

@ -18,8 +18,6 @@
*/ */
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME; import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
@ -39,6 +37,7 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.PaginationBox; import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
@ -46,9 +45,10 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.storage.LegacyChunkStore; import com.sk89q.worldedit.world.storage.LegacyChunkStore;
import com.sk89q.worldedit.world.storage.McRegionChunkStore; import com.sk89q.worldedit.world.storage.McRegionChunkStore;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.ArrayList; import java.util.ArrayList;
@ -59,6 +59,8 @@ import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.exception.StopExecutionException; import org.enginehub.piston.exception.StopExecutionException;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Commands for working with chunks. * Commands for working with chunks.
*/ */

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import com.google.common.collect.Lists;
import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
@ -37,12 +39,10 @@ import com.boydti.fawe.util.MaskTraverser;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.PasteEvent; import com.sk89q.worldedit.event.extent.PasteEvent;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
@ -53,6 +53,8 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.block.BlockReplace;
import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
@ -91,11 +93,10 @@ import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.PLACEMENT;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import java.util.List;
/** /**
* Clipboard commands. * Clipboard commands.
@ -103,18 +104,6 @@ import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ClipboardCommands { public class ClipboardCommands {
private WorldEdit worldEdit;
/**
* Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/
public ClipboardCommands(WorldEdit worldEdit) {
checkNotNull(worldEdit);
this.worldEdit = worldEdit;
}
@Command( @Command(
name = "/copy", name = "/copy",
@ -442,6 +431,8 @@ public class ClipboardCommands {
boolean atOrigin, boolean atOrigin,
@Switch(name = 's', desc = "Select the region after pasting") @Switch(name = 's', desc = "Select the region after pasting")
boolean selectPasted, boolean selectPasted,
@Switch(name = 'n', desc = "No paste, select only. (Implies -s)")
boolean onlySelect,
@Switch(name = 'e', desc = "Paste entities if available") @Switch(name = 'e', desc = "Paste entities if available")
boolean pasteEntities, boolean pasteEntities,
@Switch(name = 'b', desc = "Paste biomes if available") @Switch(name = 'b', desc = "Paste biomes if available")
@ -457,6 +448,7 @@ public class ClipboardCommands {
} }
Clipboard clipboard = holder.getClipboard(); Clipboard clipboard = holder.getClipboard();
Region region = clipboard.getRegion(); Region region = clipboard.getRegion();
List<String> messages = Lists.newArrayList();
BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(actor); BlockVector3 to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(actor);
checkPaste(actor, editSession, to, holder, clipboard); checkPaste(actor, editSession, to, holder, clipboard);
@ -471,7 +463,7 @@ public class ClipboardCommands {
.build(); .build();
Operations.completeLegacy(operation); Operations.completeLegacy(operation);
if (selectPasted) { if (selectPasted || onlySelect) {
BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin()); BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
Vector3 realTo = to.toVector3().add(holder.getTransform().apply(clipboardOffset.toVector3())); Vector3 realTo = to.toVector3().add(holder.getTransform().apply(clipboardOffset.toVector3()));
Vector3 max = realTo.add(holder.getTransform().apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3())); Vector3 max = realTo.add(holder.getTransform().apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3()));
@ -578,7 +570,7 @@ public class ClipboardCommands {
AffineTransform transform = new AffineTransform(); AffineTransform transform = new AffineTransform();
transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3()); transform = transform.scale(direction.abs().multiply(-2).add(1, 1, 1).toVector3());
holder.setTransform(holder.getTransform().combine(transform)); holder.setTransform(holder.getTransform().combine(transform));
actor.print(BBC.COMMAND_FLIPPED.s()); actor.print("The clipboard copy has been flipped.");
} }
@Command( @Command(
@ -588,6 +580,6 @@ public class ClipboardCommands {
@CommandPermissions("worldedit.clipboard.clear") @CommandPermissions("worldedit.clipboard.clear")
public void clearClipboard(Actor actor, LocalSession session) throws WorldEditException { public void clearClipboard(Actor actor, LocalSession session) throws WorldEditException {
session.setClipboard(null); session.setClipboard(null);
actor.print(BBC.CLIPBOARD_CLEARED.s()); actor.print("Clipboard cleared.");
} }
} }

View File

@ -19,9 +19,6 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
import static com.sk89q.worldedit.internal.command.CommandUtil.requireIV;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
@ -39,7 +36,6 @@ import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import java.util.List;
import org.enginehub.piston.Command; import org.enginehub.piston.Command;
import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManager;
import org.enginehub.piston.CommandManagerService; import org.enginehub.piston.CommandManagerService;
@ -48,6 +44,11 @@ import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.Key;
import org.enginehub.piston.part.SubCommandPart; 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}. * Extracted from {@link SelectionCommands} to allow importing of {@link Command}.
*/ */

View File

@ -19,8 +19,6 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.extent.ResettableExtent; import com.boydti.fawe.object.extent.ResettableExtent;
@ -44,6 +42,8 @@ import com.sk89q.worldedit.extension.input.DisallowedUsageException;
import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import java.util.ArrayList;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
@ -52,7 +52,6 @@ import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -64,6 +63,8 @@ import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* General WorldEdit commands. * General WorldEdit commands.
*/ */
@ -132,8 +133,8 @@ public class GeneralCommands {
} }
@Command( @Command(
name = "/fast", name = "/fast",
desc = "Toggle fast mode" desc = "Toggle fast mode"
) )
@CommandPermissions("worldedit.fast") @CommandPermissions("worldedit.fast")
public void fast(Actor actor, LocalSession session, public void fast(Actor actor, LocalSession session,
@ -144,12 +145,13 @@ public class GeneralCommands {
actor.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + "."); actor.printError("Fast mode already " + (fastMode ? "enabled" : "disabled") + ".");
return; return;
} }
if (hasFastMode) { if (hasFastMode) {
session.setFastMode(false); session.setFastMode(false);
actor.print(BBC.FAST_DISABLED.s()); actor.print("Fast mode disabled.");
} else { } else {
session.setFastMode(true); session.setFastMode(true);
actor.print(BBC.FAST_ENABLED.s()); actor.print("Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.");
} }
} }
@ -196,20 +198,20 @@ public class GeneralCommands {
} }
} }
// @Command( @Command(
// name = "/world", name = "/world",
// desc = "Sets the world override" desc = "Sets the world override"
// ) )
// @CommandPermissions("worldedit.world") @CommandPermissions("worldedit.world")
// public void worldOverride(Actor actor, LocalSession session, public void world(Actor actor, LocalSession session,
// @Arg(desc = "The world override", def = "") World world) { @Arg(desc = "The world override", def = "") World world) {
// session.setWorldOverride(world); session.setWorldOverride(world);
// if (world == null) { if (world == null) {
// actor.print("Removed world override."); actor.print("Removed world override.");
// } else { } else {
// actor.print("Set the world override to " + world.getId() + ". (Use //world to go back to default)"); actor.print("Set the world override to " + world.getId() + ". (Use //world to go back to default)");
// } }
// } }
@Command( @Command(
name = "/watchdog", name = "/watchdog",
@ -237,16 +239,18 @@ public class GeneralCommands {
@Command( @Command(
name = "gmask", name = "gmask",
aliases = {"/gmask"}, aliases = {"/gmask"},
descFooter = "The global destination mask applies to all edits you do and masks based on the destination blocks (i.e., the blocks in the world).",
desc = "Set the global mask" desc = "Set the global mask"
) )
@CommandPermissions({"worldedit.global-mask", "worldedit.mask.global"}) @CommandPermissions("worldedit.global-mask")
public void gmask(Actor actor, LocalSession session, @Arg(desc = "The mask to set", def = "") Mask mask) { public void gmask(Actor actor, LocalSession session,
session.setMask(mask); @Arg(desc = "The mask to set", def = "")
Mask mask) {
if (mask == null) { if (mask == null) {
actor.print(BBC.MASK_DISABLED.s()); session.setMask(null);
actor.print("Global mask disabled.");
} else { } else {
actor.print(BBC.MASK.s()); session.setMask(mask);
actor.print("Global mask set.");
} }
} }
@ -291,7 +295,7 @@ public class GeneralCommands {
actor.print(new ItemSearcher(search, blocksOnly, itemsOnly, page).call()); actor.print(new ItemSearcher(search, blocksOnly, itemsOnly, page).call());
} }
public static class ItemSearcher implements Callable<Component> { private static class ItemSearcher implements Callable<Component> {
private final boolean blocksOnly; private final boolean blocksOnly;
private final boolean itemsOnly; private final boolean itemsOnly;
private final String search; private final String search;

View File

@ -18,8 +18,6 @@
*/ */
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.MethodCommands.getArguments; import static com.sk89q.worldedit.command.MethodCommands.getArguments;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; 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.PLACEMENT;
@ -42,10 +40,13 @@ import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.generator.CavesGen; import com.sk89q.worldedit.function.generator.CavesGen;
import java.util.List;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.internal.annotation.Radii;
import com.sk89q.worldedit.internal.annotation.Range; import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.internal.annotation.Selection; import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
@ -61,11 +62,12 @@ import java.awt.RenderingHints;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.List;
import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import static com.google.common.base.Preconditions.checkNotNull;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
/** /**
@ -184,20 +186,15 @@ public class GenerationCommands {
) )
@CommandPermissions("worldedit.generation.cylinder") @CommandPermissions("worldedit.generation.cylinder")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void hcyl(Actor actor, LocalSession session, EditSession editSession, public int hcyl(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate") @Arg(desc = "The pattern of blocks to generate")
Pattern pattern, Pattern pattern,
@Arg(desc = "The radii of the cylinder. Order is N/S, E/W") BlockVector2 radius, @Arg(desc = "The radii of the cylinder. 1st is N/S, 2nd is E/W")
@Radii(2)
List<Double> radii,
@Arg(desc = "The height of the cylinder", def = "1") @Arg(desc = "The height of the cylinder", def = "1")
int height, int height) throws WorldEditException {
@Range(min = 1) @Arg(desc = "double", def = "1") double thickness, InjectedValueAccess context) throws WorldEditException { return cyl(actor, session, editSession, pattern, radii, height, true);
double max = MathMan.max(radius.getBlockX(), radius.getBlockZ());
worldEdit.checkMaxRadius(max);
BlockVector3 pos = session.getPlacementPosition(actor);
actor.checkConfirmationRadius(() -> {
int affected = editSession.makeHollowCylinder(pos, pattern, radius.getX(), radius.getZ(), Math.min(256, height), thickness - 1);
BBC.VISITOR_BLOCK.send(actor, affected);
}, "/hcyl", (int) max, context);
} }
@Command( @Command(
@ -278,9 +275,10 @@ public class GenerationCommands {
int size, int size,
@Arg(desc = "The type of forest", def = "tree") @Arg(desc = "The type of forest", def = "tree")
TreeType type, TreeType type,
@Range(min = 0, max = 100) @Arg(desc = "The density of the forest, between 0 and 100", def = "5") @Arg(desc = "The density of the forest, between 0 and 100", def = "5")
double density) throws WorldEditException { double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100"); checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100");
worldEdit.checkMaxRadius(size);
density /= 100; density /= 100;
int affected = editSession.makeForest(session.getPlacementPosition(actor), size, density, type); int affected = editSession.makeForest(session.getPlacementPosition(actor), size, density, type);
actor.print(affected + " trees created."); actor.print(affected + " trees created.");
@ -295,14 +293,10 @@ public class GenerationCommands {
@Logging(POSITION) @Logging(POSITION)
public int pumpkins(Actor actor, LocalSession session, EditSession editSession, public int pumpkins(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The size of the patch", def = "10") @Arg(desc = "The size of the patch", def = "10")
int size, int size) throws WorldEditException {
@Arg(desc = "//TODO", def = "10") worldEdit.checkMaxRadius(size);
int apothem, int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), size);
@Arg(desc = "//TODO ", def = "0.02") actor.print(affected + " pumpkin patches created.");
double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100");
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), apothem, density);
BBC.COMMAND_PUMPKIN.send(actor, affected);
return affected; return affected;
} }

View File

@ -19,8 +19,6 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
@ -57,6 +55,8 @@ import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Commands to undo, redo, and clear history. * Commands to undo, redo, and clear history.
*/ */
@ -223,6 +223,16 @@ public class HistoryCommands {
aliases = { "/un", "/ud", "undo" }, aliases = { "/un", "/ud", "undo" },
desc = "Undoes the last action (from history)" desc = "Undoes the last action (from history)"
) )
} else {
undoSession = session;
}
int finalTimes = times;
player.checkConfirmation(() -> {
EditSession undone = null;
int i = 0;
for (; i < finalTimes; ++i) {
undone = undoSession.undo(undoSession.getBlockBag(player), player);
if (undone == null) break;
@CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"}) @CommandPermissions({"worldedit.history.undo", "worldedit.history.undo.self"})
public void undo(Player player, LocalSession session, public void undo(Player player, LocalSession session,
@Range(min = 1) @Arg(desc = "Number of undoes to perform", def = "1") @Range(min = 1) @Arg(desc = "Number of undoes to perform", def = "1")
@ -243,16 +253,6 @@ public class HistoryCommands {
BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, playerName); BBC.COMMAND_HISTORY_OTHER_ERROR.send(player, playerName);
return; return;
} }
} else {
undoSession = session;
}
int finalTimes = times;
player.checkConfirmation(() -> {
EditSession undone = null;
int i = 0;
for (; i < finalTimes; ++i) {
undone = undoSession.undo(undoSession.getBlockBag(player), player);
if (undone == null) break;
worldEdit.flushBlockBag(player, undone); worldEdit.flushBlockBag(player, undone);
} }
if (undone == null) i--; if (undone == null) i--;
@ -311,7 +311,7 @@ public class HistoryCommands {
@CommandPermissions("worldedit.history.clear") @CommandPermissions("worldedit.history.clear")
public void clearHistory(Actor actor, LocalSession session) { public void clearHistory(Actor actor, LocalSession session) {
session.clearHistory(); session.clearHistory();
actor.print(BBC.COMMAND_HISTORY_CLEAR.s()); actor.print("History cleared.");
} }
} }

View File

@ -18,8 +18,6 @@
*/ */
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
@ -36,6 +34,8 @@ import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Commands for moving the player around. * Commands for moving the player around.
*/ */
@ -62,7 +62,7 @@ public class NavigationCommands {
@CommandPermissions("worldedit.navigation.unstuck") @CommandPermissions("worldedit.navigation.unstuck")
public void unstuck(Player player) throws WorldEditException { public void unstuck(Player player) throws WorldEditException {
player.findFreePosition(); player.findFreePosition();
player.print(BBC.UNSTUCK.s()); player.print("There you go!");
} }
@Command( @Command(
@ -84,11 +84,7 @@ public class NavigationCommands {
if (ascentLevels == 0) { if (ascentLevels == 0) {
player.printError(BBC.ASCEND_FAIL.s()); player.printError(BBC.ASCEND_FAIL.s());
} else { } else {
if (ascentLevels == 1) { player.print((ascentLevels != 1) ? "Ascended " + ascentLevels + " levels." : "Ascended a level.");
player.print(BBC.ASCENDED_SINGULAR.s());
} else {
BBC.ASCENDED_PLURAL.send(player, ascentLevels);
}
} }
} }
@ -113,7 +109,7 @@ public class NavigationCommands {
} else if (descentLevels == 1) { } else if (descentLevels == 1) {
player.print(BBC.DESCEND_SINGULAR.s()); player.print(BBC.DESCEND_SINGULAR.s());
} else { } else {
BBC.DESCEND_PLURAL.send(player, descentLevels); player.print((descentLevels != 1) ? "Descended " + descentLevels + " levels." : "Descended a level.");
} }
} }

View File

@ -19,19 +19,23 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import com.google.common.base.Joiner;
import com.boydti.fawe.FaweAPI; import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.implementation.processors.ChunkSendProcessor; import com.boydti.fawe.beta.implementation.processors.ChunkSendProcessor;
import com.boydti.fawe.beta.implementation.processors.NullProcessor; import com.boydti.fawe.beta.implementation.processors.NullProcessor;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FaweLimit;
import com.google.common.collect.Lists;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.block.BlockReplace;
import com.sk89q.worldedit.command.util.Logging; import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
@ -39,9 +43,11 @@ import com.sk89q.worldedit.function.FlatRegionFunction;
import com.sk89q.worldedit.function.GroundFunction; import com.sk89q.worldedit.function.GroundFunction;
import com.sk89q.worldedit.function.biome.BiomeReplace; import com.sk89q.worldedit.function.biome.BiomeReplace;
import com.sk89q.worldedit.function.generator.FloraGenerator; import com.sk89q.worldedit.function.generator.FloraGenerator;
import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.NoiseFilter2D; import com.sk89q.worldedit.function.mask.NoiseFilter2D;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
@ -63,6 +69,8 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.regions.Regions; import com.sk89q.worldedit.regions.Regions;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
@ -81,10 +89,7 @@ import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.MethodCommands.getArguments; import static com.sk89q.worldedit.command.MethodCommands.getArguments;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ORIENTATION_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.command.util.Logging.LogMode.REGION;
import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument; import static com.sk89q.worldedit.internal.command.CommandUtil.checkCommandArgument;
@ -98,16 +103,35 @@ import static com.sk89q.worldedit.regions.Regions.minimumBlockY;
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class RegionCommands { public class RegionCommands {
private final WorldEdit worldEdit;
/** /**
* Create a new instance. * Create a new instance.
*
* @param worldEdit reference to WorldEdit
*/ */
public RegionCommands(WorldEdit worldEdit) { public RegionCommands() {
checkNotNull(worldEdit); }
this.worldEdit = worldEdit;
@Command(
name = "/set",
desc = "Sets all the blocks in the region"
)
@CommandPermissions("worldedit.region.set")
@Logging(REGION)
public int set(Actor actor, EditSession editSession,
@Selection Region region,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern) {
RegionFunction set = new BlockReplace(editSession, pattern);
RegionVisitor visitor = new RegionVisitor(region, set);
Operations.completeBlindly(visitor);
List<String> messages = Lists.newArrayList();
visitor.addStatusMessages(messages);
if (messages.isEmpty()) {
actor.print("Operation completed.");
} else {
actor.print("Operation completed (" + Joiner.on(", ").join(messages) + ").");
}
return visitor.getAffected();
} }
@Command( @Command(
@ -254,7 +278,7 @@ public class RegionCommands {
@Selection Region region, @Selection Region region,
@Arg(desc = "The pattern of blocks to place") @Arg(desc = "The pattern of blocks to place")
Pattern pattern, Pattern pattern,
@Range(min = 1) @Arg(desc = "The thickness of the line", def = "0") @Arg(desc = "The thickness of the line", def = "0")
int thickness, int thickness,
@Switch(name = 'h', desc = "Generate only a shell") @Switch(name = 'h', desc = "Generate only a shell")
boolean shell) throws WorldEditException { boolean shell) throws WorldEditException {
@ -269,7 +293,7 @@ public class RegionCommands {
BlockVector3 pos2 = cuboidregion.getPos2(); BlockVector3 pos2 = cuboidregion.getPos2();
int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell); int blocksChanged = editSession.drawLine(pattern, pos1, pos2, thickness, !shell);
BBC.VISITOR_BLOCK.send(actor, blocksChanged); actor.print(blocksChanged + " block(s) have been changed.");
return blocksChanged; return blocksChanged;
} }
@ -290,7 +314,7 @@ public class RegionCommands {
boolean shell, InjectedValueAccess context) throws WorldEditException { boolean shell, InjectedValueAccess context) throws WorldEditException {
if (!(region instanceof ConvexPolyhedralRegion)) { if (!(region instanceof ConvexPolyhedralRegion)) {
actor.printError("//curve only works with convex polyhedral selections"); actor.printError("//curve only works with convex polyhedral selections");
return; return 0;
} }
checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); checkCommandArgument(thickness >= 0, "Thickness must be >= 0");
@ -300,7 +324,7 @@ public class RegionCommands {
int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell); int blocksChanged = editSession.drawSpline(pattern, vectors, 0, 0, 0, 10, thickness, !shell);
BBC.VISITOR_BLOCK.send(actor, blocksChanged); actor.print(blocksChanged + " block(s) have been changed.");
}, getArguments(context), region, context); }, getArguments(context), region, context);
} }
@ -321,14 +345,8 @@ public class RegionCommands {
} }
Mask finalFrom = from; Mask finalFrom = from;
actor.checkConfirmationRegion(() -> { actor.checkConfirmationRegion(() -> {
int affected = editSession.replaceBlocks(region, finalFrom, to); int affected = editSession.replaceBlocks(region, finalFrom, to);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been replaced.");
if (!actor.hasPermission("fawe.tips")) {
BBC.TIP_REPLACE_ID
.or(BBC.TIP_REPLACE_LIGHT, BBC.TIP_REPLACE_MARKER, BBC.TIP_TAB_COMPLETE,
BBC.TIP_REPLACE_REGEX, BBC.TIP_REPLACE_REGEX_2, BBC.TIP_REPLACE_REGEX_3,
BBC.TIP_REPLACE_REGEX_4, BBC.TIP_REPLACE_REGEX_5).send(actor);
}
}, getArguments(context), region, context); }, getArguments(context), region, context);
} }
@ -342,8 +360,8 @@ public class RegionCommands {
@Arg(desc = "The pattern of blocks to overlay") @Arg(desc = "The pattern of blocks to overlay")
Pattern pattern, InjectedValueAccess context) throws WorldEditException { Pattern pattern, InjectedValueAccess context) throws WorldEditException {
actor.checkConfirmationRegion(() -> { actor.checkConfirmationRegion(() -> {
int affected = editSession.overlayCuboidBlocks(region, pattern); int affected = editSession.overlayCuboidBlocks(region, pattern);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been overlaid.");
}, getArguments(context), region, context); }, getArguments(context), region, context);
} }
@ -380,11 +398,12 @@ public class RegionCommands {
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.region.center") @CommandPermissions("worldedit.region.center")
public void center(Actor actor, EditSession editSession, @Selection Region region, public int center(Actor actor, EditSession editSession, @Selection Region region,
@Arg(desc = "The pattern of blocks to set") @Arg(desc = "The pattern of blocks to set")
Pattern pattern) throws WorldEditException { Pattern pattern) throws WorldEditException {
int affected = editSession.center(region, pattern); int affected = editSession.center(region, pattern);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print("Center set (" + affected + " block(s) changed)");
return affected;
} }
@Command( @Command(
@ -396,7 +415,7 @@ public class RegionCommands {
public void naturalize(Actor actor, EditSession editSession, @Selection Region region, InjectedValueAccess context) throws WorldEditException { public void naturalize(Actor actor, EditSession editSession, @Selection Region region, InjectedValueAccess context) throws WorldEditException {
actor.checkConfirmationRegion(() -> { actor.checkConfirmationRegion(() -> {
int affected = editSession.naturalizeCuboidBlocks(region); int affected = editSession.naturalizeCuboidBlocks(region);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been made to look more natural.");
}, getArguments(context), region, context); }, getArguments(context), region, context);
} }
@ -411,7 +430,7 @@ public class RegionCommands {
Pattern pattern, InjectedValueAccess context) throws WorldEditException { Pattern pattern, InjectedValueAccess context) throws WorldEditException {
actor.checkConfirmationRegion(() -> { actor.checkConfirmationRegion(() -> {
int affected = editSession.makeWalls(region, pattern); int affected = editSession.makeWalls(region, pattern);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been changed.");
}, getArguments(context), region, context); }, getArguments(context), region, context);
} }
@ -427,7 +446,7 @@ public class RegionCommands {
Pattern pattern, InjectedValueAccess context) throws WorldEditException { Pattern pattern, InjectedValueAccess context) throws WorldEditException {
actor.checkConfirmationRegion(() -> { actor.checkConfirmationRegion(() -> {
int affected = editSession.makeCuboidFaces(region, pattern); int affected = editSession.makeCuboidFaces(region, pattern);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been changed.");
}, getArguments(context), region, context); }, getArguments(context), region, context);
} }
@ -456,7 +475,7 @@ public class RegionCommands {
HeightMap heightMap = new HeightMap(editSession, region, mask, snow); HeightMap heightMap = new HeightMap(editSession, region, mask, snow);
HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0));
int affected = heightMap.applyFilter(filter, iterations); int affected = heightMap.applyFilter(filter, iterations);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print("Terrain's height map smoothed. " + affected + " block(s) changed.");
} catch (Throwable e) { } catch (Throwable e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -522,8 +541,20 @@ public class RegionCommands {
boolean copyBiomes, boolean copyBiomes,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
checkCommandArgument(count >= 1, "Count must be >= 1"); checkCommandArgument(count >= 1, "Count must be >= 1");
Mask combinedMask;
if (ignoreAirBlocks) {
if (mask == null) {
combinedMask = new ExistingBlockMask(editSession);
} else {
combinedMask = new MaskIntersection(mask, new ExistingBlockMask(editSession));
}
} else {
combinedMask = mask;
}
actor.checkConfirmationRegion(() -> { actor.checkConfirmationRegion(() -> {
int affected = editSession.moveRegion(region, direction, count, !ignoreAirBlocks, !skipEntities, copyBiomes, replace); int affected = editSession.moveRegion(region, direction, count, !ignoreAirBlocks, !skipEntities, copyBiomes, combinedMask, replace);
if (moveSelection) { if (moveSelection) {
try { try {
@ -583,17 +614,29 @@ public class RegionCommands {
@ArgFlag(name = 'm', desc = "Source mask", def="") @ArgFlag(name = 'm', desc = "Source mask", def="")
Mask sourceMask, Mask sourceMask,
InjectedValueAccess context) throws WorldEditException { InjectedValueAccess context) throws WorldEditException {
Mask combinedMask;
if (ignoreAirBlocks) {
if (mask == null) {
combinedMask = new ExistingBlockMask(editSession);
} else {
combinedMask = new MaskIntersection(mask, new ExistingBlockMask(editSession));
}
} else {
combinedMask = mask;
}
actor.checkConfirmationStack(() -> { actor.checkConfirmationStack(() -> {
if (sourceMask != null) { if (sourceMask != null) {
editSession.addSourceMask(sourceMask); editSession.addSourceMask(sourceMask);
} }
int affected = editSession.stackCuboidRegion(region, direction, count, !ignoreAirBlocks, !skipEntities, copyBiomes); int affected = editSession.stackCuboidRegion(region, direction, count, !skipEntities, copyBiomes, combinedMask);
if (moveSelection) { if (moveSelection) {
try { try {
final BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()); final BlockVector3 size = region.getMaximumPoint().subtract(region.getMinimumPoint()).add(1, 1, 1);
final BlockVector3 shiftVector = direction.toVector3().multiply(count * (Math.abs(direction.dot(size)) + 1)).toBlockPoint(); final BlockVector3 shiftVector = direction.multiply(size).multiply(count);
region.shift(shiftVector); region.shift(shiftVector);
session.getRegionSelector(world).learnChanges(); session.getRegionSelector(world).learnChanges();
@ -652,7 +695,7 @@ public class RegionCommands {
if (actor instanceof Player) { if (actor instanceof Player) {
((Player) actor).findFreePosition(); ((Player) actor).findFreePosition();
} }
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been deformed.");
} catch (ExpressionException e) { } catch (ExpressionException e) {
actor.printError(e.getMessage()); actor.printError(e.getMessage());
} }
@ -718,7 +761,7 @@ public class RegionCommands {
Mask finalMask = mask == null ? new SolidBlockMask(editSession) : mask; Mask finalMask = mask == null ? new SolidBlockMask(editSession) : mask;
actor.checkConfirmationRegion(() -> { actor.checkConfirmationRegion(() -> {
int affected = editSession.hollowOutRegion(region, thickness, pattern, finalMask); int affected = editSession.hollowOutRegion(region, thickness, pattern, finalMask);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been changed.");
}, getArguments(context), region, context); }, getArguments(context), region, context);
} }
@ -735,7 +778,7 @@ public class RegionCommands {
double density) throws WorldEditException { double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]");
int affected = editSession.makeForest(region, density / 100, type); int affected = editSession.makeForest(region, density / 100, type);
BBC.COMMAND_TREE.send(actor, affected); actor.print(affected + " trees created.");
return affected; return affected;
} }
@ -756,7 +799,7 @@ public class RegionCommands {
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density / 100)); visitor.setMask(new NoiseFilter2D(new RandomNoise(), density / 100));
Operations.completeLegacy(visitor); Operations.completeLegacy(visitor);
BBC.COMMAND_FLORA.send(actor, ground.getAffected()); actor.print(affected + " flora created.");
}, "/flora", region, context); }, "/flora", region, context);
} }

View File

@ -20,7 +20,6 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.boydti.fawe.util.ReflectionUtils.as; import static com.boydti.fawe.util.ReflectionUtils.as;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
@ -41,6 +40,7 @@ import com.sk89q.worldedit.command.argument.Arguments;
import com.sk89q.worldedit.command.util.AsyncCommandBuilder; import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import com.sk89q.worldedit.command.util.CommandPermissions; import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator; import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.ActorSaveClipboardEvent; import com.sk89q.worldedit.event.extent.ActorSaveClipboardEvent;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
@ -60,6 +60,7 @@ import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent; import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.component.CodeFormat;
import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.io.Closer; import com.sk89q.worldedit.util.io.Closer;
import com.sk89q.worldedit.util.io.file.FilenameException; import com.sk89q.worldedit.util.io.file.FilenameException;
@ -70,6 +71,8 @@ import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import static com.google.common.base.Preconditions.checkArgument;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
@ -843,6 +846,24 @@ public class SchematicCommands {
return fileList; return fileList;
} }
@Command(
name = "delete",
aliases = {"d"},
desc = "Delete a saved schematic"
)
@CommandPermissions("worldedit.schematic.delete")
public void delete(Actor actor,
@Arg(desc = "File name.")
String filename) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
File f = worldEdit.getSafeOpenFile(actor instanceof Player ? ((Player) actor) : null,
dir, filename, "schematic", ClipboardFormats.getFileExtensionArray());
if (!f.exists()) {
actor.printError("Schematic " + filename + " does not exist!");
return;
private boolean delete(File file) { private boolean delete(File file) {
if (file.delete()) { if (file.delete()) {
new File(file.getParentFile(), "." + file.getName() + ".cached").delete(); new File(file.getParentFile(), "." + file.getName() + ".cached").delete();

View File

@ -18,8 +18,6 @@
*/ */
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
@ -39,6 +37,8 @@ import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Commands related to scripting. * Commands related to scripting.
@ -68,8 +68,8 @@ public class ScriptingCommands {
} }
@Command( @Command(
name = "cs", name = "cs",
desc = "Execute a CraftScript" desc = "Execute a CraftScript"
) )
@CommandPermissions("worldedit.scripting.execute") @CommandPermissions("worldedit.scripting.execute")
@Logging(ALL) @Logging(ALL)
@ -77,9 +77,9 @@ public class ScriptingCommands {
@Arg(desc = "Filename of the CraftScript to load") @Arg(desc = "Filename of the CraftScript to load")
String filename, String filename,
@Arg(desc = "Arguments to the CraftScript", def = "", variable = true) @Arg(desc = "Arguments to the CraftScript", def = "", variable = true)
List<String> commandStr) throws WorldEditException { List<String> args) throws WorldEditException {
if (!player.hasPermission("worldedit.scripting.execute." + filename)) { if (!player.hasPermission("worldedit.scripting.execute." + filename)) {
player.printError(BBC.SCRIPTING_NO_PERM.s()); player.printError("You don't have permission to use that script.");
return; return;
} }
@ -88,19 +88,19 @@ public class ScriptingCommands {
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir); File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
File f = worldEdit.getSafeOpenFile(player, dir, filename, "js", "js"); File f = worldEdit.getSafeOpenFile(player, dir, filename, "js", "js");
worldEdit.runScript(player, f, Stream.concat(Stream.of(filename), commandStr.stream()) worldEdit.runScript(player, f, Stream.concat(Stream.of(filename), args.stream())
.toArray(String[]::new)); .toArray(String[]::new));
} }
@Command( @Command(
name = ".s", name = ".s",
desc = "Execute last CraftScript" desc = "Execute last CraftScript"
) )
@CommandPermissions("worldedit.scripting.execute") @CommandPermissions("worldedit.scripting.execute")
@Logging(ALL) @Logging(ALL)
public void executeLast(Player player, LocalSession session, public void executeLast(Player player, LocalSession session,
@Arg(desc = "Arguments to the CraftScript", def = "", variable = true) @Arg(desc = "Arguments to the CraftScript", def = "", variable = true)
List<String> commandStr) throws WorldEditException { List<String> args) throws WorldEditException {
String lastScript = session.getLastScript(); String lastScript = session.getLastScript();
@ -117,7 +117,7 @@ public class ScriptingCommands {
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir); File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js"); File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js");
worldEdit.runScript(player, f, Stream.concat(Stream.of(lastScript), commandStr.stream()) worldEdit.runScript(player, f, Stream.concat(Stream.of(lastScript), args.stream())
.toArray(String[]::new)); .toArray(String[]::new));
} }
} }

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import com.google.common.base.Strings;
import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION; import static com.sk89q.worldedit.command.util.Logging.LogMode.POSITION;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION; import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
@ -44,6 +46,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extension.platform.Locatable;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Direction;
@ -77,12 +80,19 @@ import com.sk89q.worldedit.world.storage.ChunkStore;
import java.io.File; import java.io.File;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException;
import com.sk89q.worldedit.util.formatting.text.Component;
import java.util.Optional; import java.util.Optional;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import com.sk89q.worldedit.world.block.BlockType;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.exception.StopExecutionException;
/** /**
* Selection commands. * Selection commands.
@ -98,7 +108,6 @@ public class SelectionCommands {
@Command( @Command(
name = "/pos1", name = "/pos1",
aliases = "/1",
desc = "Set position 1" desc = "Set position 1"
) )
@Logging(POSITION) @Logging(POSITION)
@ -116,18 +125,17 @@ public class SelectionCommands {
return; return;
} }
if (!session.getRegionSelector(world).selectPrimary(pos.toBlockPoint(), ActorSelectorLimits.forActor(actor))) { if (!session.getRegionSelector(world).selectPrimary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) {
actor.printError(BBC.SELECTOR_ALREADY_SET.s()); actor.printError("Position already set.");
return; return;
} }
session.getRegionSelector(world) session.getRegionSelector(world)
.explainPrimarySelection(actor, session, pos.toBlockPoint()); .explainPrimarySelection(actor, session, pos.toVector().toBlockPoint());
} }
@Command( @Command(
name = "/pos2", name = "/pos2",
aliases = "/2",
desc = "Set position 2" desc = "Set position 2"
) )
@Logging(POSITION) @Logging(POSITION)
@ -145,13 +153,13 @@ public class SelectionCommands {
return; return;
} }
if (!session.getRegionSelector(world).selectSecondary(pos.toBlockPoint(), ActorSelectorLimits.forActor(actor))) { if (!session.getRegionSelector(world).selectSecondary(pos.toVector().toBlockPoint(), ActorSelectorLimits.forActor(actor))) {
actor.printError(BBC.SELECTOR_ALREADY_SET.s()); actor.printError("Position already set.");
return; return;
} }
session.getRegionSelector(world) session.getRegionSelector(world)
.explainSecondarySelection(actor, session, pos.toBlockPoint()); .explainSecondarySelection(actor, session, pos.toVector().toBlockPoint());
} }
@Command( @Command(
@ -204,7 +212,7 @@ public class SelectionCommands {
) )
@Logging(POSITION) @Logging(POSITION)
@CommandPermissions("worldedit.selection.chunk") @CommandPermissions("worldedit.selection.chunk")
public void chunk(Player player, LocalSession session, public void chunk(Actor actor, World world, LocalSession session,
@Arg(desc = "The chunk to select", def = "") @Arg(desc = "The chunk to select", def = "")
BlockVector2 coordinates, BlockVector2 coordinates,
@Switch(name = 's', desc = "Expand your selection to encompass all chunks that are part of it") @Switch(name = 's', desc = "Expand your selection to encompass all chunks that are part of it")
@ -213,7 +221,6 @@ public class SelectionCommands {
boolean useChunkCoordinates) throws WorldEditException { boolean useChunkCoordinates) throws WorldEditException {
final BlockVector3 min; final BlockVector3 min;
final BlockVector3 max; final BlockVector3 max;
final World world = player.getWorld();
if (expandSelection) { if (expandSelection) {
Region region = session.getSelection(world); Region region = session.getSelection(world);
@ -223,7 +230,9 @@ public class SelectionCommands {
min = BlockVector3.at(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); min = BlockVector3.at(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16);
max = BlockVector3.at(max2D.getBlockX() * 16 + 15, world.getMaxY(), max2D.getBlockZ() * 16 + 15); max = BlockVector3.at(max2D.getBlockX() * 16 + 15, world.getMaxY(), max2D.getBlockZ() * 16 + 15);
BBC.SELECTION_CHUNKS.send(player, min2D.getBlockX() + ", " + min2D.getBlockZ(), max2D.getBlockX() + ", " + max2D.getBlockZ()); actor.print("Chunks selected: ("
+ min2D.getBlockX() + ", " + min2D.getBlockZ() + ") - ("
+ max2D.getBlockX() + ", " + max2D.getBlockZ() + ")");
} else { } else {
final BlockVector2 min2D; final BlockVector2 min2D;
if (coordinates != null) { if (coordinates != null) {
@ -233,13 +242,18 @@ public class SelectionCommands {
: ChunkStore.toChunk(coordinates.toBlockVector3()); : ChunkStore.toChunk(coordinates.toBlockVector3());
} else { } else {
// use player loc // use player loc
min2D = ChunkStore.toChunk(player.getBlockLocation().toBlockPoint()); if (actor instanceof Locatable) {
min2D = ChunkStore.toChunk(((Locatable) actor).getBlockLocation().toVector().toBlockPoint());
} else {
throw new StopExecutionException(TextComponent.of("A player or coordinates are required."));
}
} }
min = BlockVector3.at(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); min = BlockVector3.at(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16);
max = min.add(15, world.getMaxY(), 15); max = min.add(15, world.getMaxY(), 15);
BBC.SELECTION_CHUNK.send(player, min2D.getBlockX() + ", " + min2D.getBlockZ()); actor.print("Chunk selected: "
+ min2D.getBlockX() + ", " + min2D.getBlockZ());
} }
final CuboidRegionSelector selector; final CuboidRegionSelector selector;
@ -248,11 +262,11 @@ public class SelectionCommands {
} else { } else {
selector = new CuboidRegionSelector(world); selector = new CuboidRegionSelector(world);
} }
selector.selectPrimary(min, ActorSelectorLimits.forActor(player)); selector.selectPrimary(min, ActorSelectorLimits.forActor(actor));
selector.selectSecondary(max, ActorSelectorLimits.forActor(player)); selector.selectSecondary(max, ActorSelectorLimits.forActor(actor));
session.setRegionSelector(world, selector); session.setRegionSelector(world, selector);
session.dispatchCUISelection(player); session.dispatchCUISelection(actor);
} }
@ -333,8 +347,7 @@ public class SelectionCommands {
session.getRegionSelector(world).explainRegionAdjust(actor, session); session.getRegionSelector(world).explainRegionAdjust(actor, session);
actor.print("Region contracted " + (oldSize - newSize) + " blocks.");
BBC.SELECTION_CONTRACT.send(actor, (oldSize - newSize));
} catch (RegionOperationException e) { } catch (RegionOperationException e) {
actor.printError(e.getMessage()); actor.printError(e.getMessage());
} }
@ -363,7 +376,7 @@ public class SelectionCommands {
session.getRegionSelector(world).explainRegionAdjust(actor, session); session.getRegionSelector(world).explainRegionAdjust(actor, session);
actor.print(BBC.SELECTION_SHIFT.s()); actor.print("Region shifted.");
} catch (RegionOperationException e) { } catch (RegionOperationException e) {
actor.printError(e.getMessage()); actor.printError(e.getMessage());
} }
@ -386,7 +399,7 @@ public class SelectionCommands {
region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical)); region.expand(getChangesForEachDir(amount, onlyHorizontal, onlyVertical));
session.getRegionSelector(world).learnChanges(); session.getRegionSelector(world).learnChanges();
session.getRegionSelector(world).explainRegionAdjust(actor, session); session.getRegionSelector(world).explainRegionAdjust(actor, session);
actor.print(BBC.SELECTION_OUTSET.s()); actor.print("Region outset.");
} }
@Command( @Command(
@ -496,11 +509,11 @@ public class SelectionCommands {
desc = "Counts the number of blocks matching a mask" desc = "Counts the number of blocks matching a mask"
) )
@CommandPermissions("worldedit.analysis.count") @CommandPermissions("worldedit.analysis.count")
public void count(Player player, LocalSession session, EditSession editSession, public void count(Actor actor, World world, LocalSession session, EditSession editSession,
@Arg(desc = "The mask of blocks to match") @Arg(desc = "The mask of blocks to match")
Mask mask) throws WorldEditException { Mask mask) throws WorldEditException {
int count = editSession.countBlocks(session.getSelection(player.getWorld()), mask); int count = editSession.countBlocks(session.getSelection(world), mask);
BBC.SELECTION_COUNT.send(player, count); actor.print("Counted: " + count);
} }
@Command( @Command(
@ -531,7 +544,7 @@ public class SelectionCommands {
if (distribution.isEmpty()) { // *Should* always be false if (distribution.isEmpty()) { // *Should* always be false
player.printError("No blocks counted."); actor.printError("No blocks counted.");
return; return;
} }
@ -549,6 +562,65 @@ public class SelectionCommands {
} }
} }
private static class BlockDistributionResult extends PaginationBox {
private final List<Countable<BlockState>> distribution;
private final int totalBlocks;
private final boolean separateStates;
BlockDistributionResult(List<Countable<BlockState>> distribution, boolean separateStates) {
super("Block Distribution", "//distr -p %page%" + (separateStates ? " -d" : ""));
this.distribution = distribution;
// note: doing things like region.getArea is inaccurate for non-cuboids.
this.totalBlocks = distribution.stream().mapToInt(Countable::getAmount).sum();
this.separateStates = separateStates;
setComponentsPerPage(7);
}
@Override
public Component getComponent(int number) {
Countable<BlockState> c = distribution.get(number);
TextComponent.Builder line = TextComponent.builder();
final int count = c.getAmount();
final double perc = count / (double) totalBlocks * 100;
final int maxDigits = (int) (Math.log10(totalBlocks) + 1);
final int curDigits = (int) (Math.log10(count) + 1);
line.append(String.format("%s%.3f%% ", perc < 10 ? " " : "", perc), TextColor.GOLD);
final int space = maxDigits - curDigits;
String pad = Strings.repeat(" ", space == 0 ? 2 : 2 * space + 1);
line.append(String.format("%s%s", count, pad), TextColor.YELLOW);
final BlockState state = c.getID();
final BlockType blockType = state.getBlockType();
TextComponent blockName = TextComponent.of(blockType.getName(), TextColor.LIGHT_PURPLE);
TextComponent toolTip;
if (separateStates && state != blockType.getDefaultState()) {
toolTip = TextComponent.of(state.getAsString(), TextColor.GRAY);
blockName = blockName.append(TextComponent.of("*", TextColor.LIGHT_PURPLE));
} else {
toolTip = TextComponent.of(blockType.getId(), TextColor.GRAY);
}
blockName = blockName.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, toolTip));
line.append(blockName);
return line.build();
}
@Override
public int getComponentsSize() {
return distribution.size();
}
@Override
public Component create(int page) throws InvalidComponentException {
super.getContents().append(TextComponent.of("Total Block Count: " + totalBlocks, TextColor.GRAY))
.append(TextComponent.newline());
return super.create(page);
}
}
@Command( @Command(
name = "/sel", name = "/sel",
aliases = { ";", "/desel", "/deselect" }, aliases = { ";", "/desel", "/deselect" },

View File

@ -76,7 +76,7 @@ public class SnapshotCommands {
LocalConfiguration config = we.getConfiguration(); LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) { if (config.snapshotRepo == null) {
actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); actor.printError("Snapshot/backup restore is not configured.");
return; return;
} }
@ -86,7 +86,7 @@ public class SnapshotCommands {
if (!snapshots.isEmpty()) { if (!snapshots.isEmpty()) {
actor.print(new SnapshotListBox(world.getName(), snapshots).create(page)); actor.print(new SnapshotListBox(world.getName(), snapshots).create(page));
} else { } else {
actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); actor.printError("No snapshots are available. See console for details.");
// Okay, let's toss some debugging information! // Okay, let's toss some debugging information!
File dir = config.snapshotRepo.getDirectory(); File dir = config.snapshotRepo.getDirectory();
@ -101,7 +101,7 @@ public class SnapshotCommands {
} }
} }
} catch (MissingWorldException ex) { } catch (MissingWorldException ex) {
actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); actor.printError("No snapshots were found for this world.");
} }
} }
@ -117,7 +117,7 @@ public class SnapshotCommands {
LocalConfiguration config = we.getConfiguration(); LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) { if (config.snapshotRepo == null) {
actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); actor.printError("Snapshot/backup restore is not configured.");
return; return;
} }
@ -128,19 +128,19 @@ public class SnapshotCommands {
if (snapshot != null) { if (snapshot != null) {
session.setSnapshot(null); session.setSnapshot(null);
actor.print(BBC.SNAPSHOT_NEWEST.s()); actor.print("Now using newest snapshot.");
} else { } else {
actor.printError(BBC.SNAPSHOT_NOT_FOUND.s()); actor.printError("No snapshots were found.");
} }
} catch (MissingWorldException ex) { } catch (MissingWorldException ex) {
actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); actor.printError("No snapshots were found for this world.");
} }
} else { } else {
try { try {
session.setSnapshot(config.snapshotRepo.getSnapshot(name)); session.setSnapshot(config.snapshotRepo.getSnapshot(name));
BBC.SNAPSHOT_SET.send(actor, name); actor.print("Snapshot set to: " + name);
} catch (InvalidSnapshotException e) { } catch (InvalidSnapshotException e) {
actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); actor.printError("That snapshot does not exist or is not available.");
} }
} }
} }
@ -156,12 +156,12 @@ public class SnapshotCommands {
LocalConfiguration config = we.getConfiguration(); LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) { if (config.snapshotRepo == null) {
actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); actor.printError("Snapshot/backup restore is not configured.");
return; return;
} }
if (index < 1) { if (index < 1) {
actor.printError(BBC.SNAPSHOT_INVALID_INDEX.s()); actor.printError("Invalid index, must be equal or higher then 1.");
return; return;
} }
@ -173,13 +173,13 @@ public class SnapshotCommands {
} }
Snapshot snapshot = snapshots.get(index - 1); Snapshot snapshot = snapshots.get(index - 1);
if (snapshot == null) { if (snapshot == null) {
actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); actor.printError("That snapshot does not exist or is not available.");
return; return;
} }
session.setSnapshot(snapshot); session.setSnapshot(snapshot);
BBC.SNAPSHOT_SET.send(actor, snapshot.getName()); actor.print("Snapshot set to: " + snapshot.getName());
} catch (MissingWorldException e) { } catch (MissingWorldException e) {
actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); actor.printError("No snapshots were found for this world.");
} }
} }
@ -195,7 +195,7 @@ public class SnapshotCommands {
LocalConfiguration config = we.getConfiguration(); LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) { if (config.snapshotRepo == null) {
actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); actor.printError("Snapshot/backup restore is not configured.");
return; return;
} }
@ -207,10 +207,10 @@ public class SnapshotCommands {
+ dateFormat.withZone(session.getTimeZone()).format(date) + "."); + dateFormat.withZone(session.getTimeZone()).format(date) + ".");
} else { } else {
session.setSnapshot(snapshot); session.setSnapshot(snapshot);
BBC.SNAPSHOT_SET.send(actor, snapshot.getName()); actor.print("Snapshot set to: " + snapshot.getName());
} }
} catch (MissingWorldException ex) { } catch (MissingWorldException ex) {
actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); actor.printError("No snapshots were found for this world.");
} }
} }
@ -226,7 +226,7 @@ public class SnapshotCommands {
LocalConfiguration config = we.getConfiguration(); LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) { if (config.snapshotRepo == null) {
actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); actor.printError("Snapshot/backup restore is not configured.");
return; return;
} }
@ -240,7 +240,7 @@ public class SnapshotCommands {
actor.print("Snapshot set to: " + snapshot.getName()); actor.print("Snapshot set to: " + snapshot.getName());
} }
} catch (MissingWorldException ex) { } catch (MissingWorldException ex) {
actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); actor.printError("No snapshots were found for this world.");
} }
} }

View File

@ -68,7 +68,7 @@ public class SnapshotUtilCommands {
LocalConfiguration config = we.getConfiguration(); LocalConfiguration config = we.getConfiguration();
if (config.snapshotRepo == null) { if (config.snapshotRepo == null) {
actor.printError(BBC.SNAPSHOT_NOT_CONFIGURED.s()); actor.printError("Snapshot/backup restore is not configured.");
return; return;
} }
@ -79,7 +79,7 @@ public class SnapshotUtilCommands {
try { try {
snapshot = config.snapshotRepo.getSnapshot(snapshotName); snapshot = config.snapshotRepo.getSnapshot(snapshotName);
} catch (InvalidSnapshotException e) { } catch (InvalidSnapshotException e) {
actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); actor.printError("That snapshot does not exist or is not available.");
return; return;
} }
} else { } else {
@ -92,7 +92,7 @@ public class SnapshotUtilCommands {
snapshot = config.snapshotRepo.getDefaultSnapshot(world.getName()); snapshot = config.snapshotRepo.getDefaultSnapshot(world.getName());
if (snapshot == null) { if (snapshot == null) {
actor.printError(BBC.SNAPSHOT_NOT_AVAILABLE.s()); actor.printError("No snapshots were found. See console for details.");
// Okay, let's toss some debugging information! // Okay, let's toss some debugging information!
File dir = config.snapshotRepo.getDirectory(); File dir = config.snapshotRepo.getDirectory();
@ -109,15 +109,21 @@ public class SnapshotUtilCommands {
return; return;
} }
} catch (MissingWorldException ex) { } catch (MissingWorldException ex) {
actor.printError(BBC.SNAPSHOT_NOT_FOUND_WORLD.s()); actor.printError("No snapshots were found for this world.");
return; return;
} }
} }
ChunkStore chunkStore;
// Load chunk store // Load chunk store
try (ChunkStore chunkStore = snapshot.getChunkStore()) { try {
BBC.SNAPSHOT_LOADED.send(actor, snapshot.getName()); chunkStore = snapshot.getChunkStore();
actor.print("Snapshot '" + snapshot.getName() + "' loaded; now restoring...");
} catch (DataException | IOException e) {
actor.printError("Failed to load snapshot: " + e.getMessage());
return;
}
// Restore snapshot // Restore snapshot
SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region); SnapshotRestore restore = new SnapshotRestore(chunkStore, editSession, region);
@ -128,12 +134,12 @@ public class SnapshotUtilCommands {
if (restore.hadTotalFailure()) { if (restore.hadTotalFailure()) {
String error = restore.getLastErrorMessage(); String error = restore.getLastErrorMessage();
if (!restore.getMissingChunks().isEmpty()) { if (!restore.getMissingChunks().isEmpty()) {
actor.printError(BBC.SNAPSHOT_ERROR_RESTORE.s()); actor.printError("Chunks were not present in snapshot.");
} else if (error != null) { } else if (error != null) {
actor.printError("Errors prevented any blocks from being restored."); actor.printError("Errors prevented any blocks from being restored.");
actor.printError("Last error: " + error); actor.printError("Last error: " + error);
} else { } else {
actor.printError(BBC.SNAPSHOT_ERROR_RESTORE_CHUNKS.s()); actor.printError("No chunks could be loaded. (Bad archive?)");
} }
} else { } else {
actor.print(String.format("Restored; %d " actor.print(String.format("Restored; %d "
@ -143,6 +149,6 @@ public class SnapshotUtilCommands {
} }
} catch (DataException | IOException e) { } catch (DataException | IOException e) {
actor.printError("Failed to load snapshot: " + e.getMessage()); actor.printError("Failed to load snapshot: " + e.getMessage());
}
} }
}
} }

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.command; package com.sk89q.worldedit.command;
import com.google.common.collect.Collections2;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.brush.InspectBrush; import com.boydti.fawe.object.brush.InspectBrush;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
@ -28,6 +30,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.command.tool.BlockDataCyler; import com.sk89q.worldedit.command.tool.BlockDataCyler;
import com.sk89q.worldedit.command.tool.BlockReplacer; import com.sk89q.worldedit.command.tool.BlockReplacer;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
import com.sk89q.worldedit.command.tool.DistanceWand; import com.sk89q.worldedit.command.tool.DistanceWand;
import com.sk89q.worldedit.command.tool.FloatingTreeRemover; import com.sk89q.worldedit.command.tool.FloatingTreeRemover;
import com.sk89q.worldedit.command.tool.FloodFillTool; import com.sk89q.worldedit.command.tool.FloodFillTool;
@ -44,27 +47,95 @@ import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.Command;
import com.sk89q.worldedit.internal.command.CommandRegistrationHandler;
import com.sk89q.worldedit.internal.command.CommandUtil;
import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg; import org.enginehub.piston.annotation.param.Arg;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.CommandManagerService;
import org.enginehub.piston.CommandMetadata;
import org.enginehub.piston.CommandParameters;
import org.enginehub.piston.part.SubCommandPart;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class) @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class ToolCommands { public class ToolCommands {
public static void register(CommandRegistrationHandler registration,
CommandManager commandManager,
CommandManagerService commandManagerService,
WorldEdit worldEdit) {
// Collect the tool commands
CommandManager collect = commandManagerService.newCommandManager();
registration.register(
collect,
ToolCommandsRegistration.builder(),
new ToolCommands(worldEdit)
);
// Register deprecated global commands
Set<org.enginehub.piston.Command> commands = collect.getAllCommands()
.collect(Collectors.toSet());
for (org.enginehub.piston.Command command : commands) {
if (command.getAliases().contains("unbind")) {
// Don't register new /tool unbind alias
command = command.toBuilder().aliases(
Collections2.filter(command.getAliases(), alias -> !"unbind".equals(alias))
).build();
}
commandManager.register(CommandUtil.deprecate(
command, "Global tool names cause conflicts " +
"and will be removed in WorldEdit 8", ToolCommands::asNonGlobal
));
}
// Remove aliases with / in them, since it doesn't make sense for sub-commands.
Set<org.enginehub.piston.Command> nonGlobalCommands = commands.stream()
.map(command ->
command.toBuilder().aliases(
Collections2.filter(command.getAliases(), alias -> !alias.startsWith("/"))
).build()
)
.collect(Collectors.toSet());
commandManager.register("tool", command -> {
command.addPart(SubCommandPart.builder(
TranslatableComponent.of("tool"),
TextComponent.of("The tool to bind")
)
.withCommands(nonGlobalCommands)
.required()
.build());
command.description(TextComponent.of("Binds a tool to the item in your hand"));
});
}
private static String asNonGlobal(org.enginehub.piston.Command oldCommand,
CommandParameters oldParameters) {
String name = Optional.ofNullable(oldParameters.getMetadata())
.map(CommandMetadata::getCalledName)
.filter(n -> !n.startsWith("/"))
.orElseGet(oldCommand::getName);
return "/tool " + name;
}
static void setToolNone(Player player, LocalSession session, String type)
throws InvalidToolBindException {
session.setTool(player.getItemInHand(HandSide.MAIN_HAND).getType(), null);
player.print(type + " unbound from your current item.");
}
private final WorldEdit we; private final WorldEdit we;
public ToolCommands(WorldEdit we) { public ToolCommands(WorldEdit we) {
this.we = we; this.we = we;
} }
// @Command(
// 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( @Command(
name = "selwand", name = "selwand",
aliases = "/selwand", aliases = "/selwand",
@ -74,7 +145,7 @@ public class ToolCommands {
public void selwand(Player player, LocalSession session) throws WorldEditException { public void selwand(Player player, LocalSession session) throws WorldEditException {
final ItemType itemType = player.getItemInHand(HandSide.MAIN_HAND).getType(); final ItemType itemType = player.getItemInHand(HandSide.MAIN_HAND).getType();
session.setTool(player, SelectionWand.INSTANCE); session.setTool(itemType, new SelectionWand());
player.print("Selection wand bound to " + itemType.getName() + "."); player.print("Selection wand bound to " + itemType.getName() + ".");
} }
@ -215,8 +286,17 @@ public class ToolCommands {
Pattern secondary) throws WorldEditException { Pattern secondary) throws WorldEditException {
BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND); BaseItemStack itemStack = player.getItemInHand(HandSide.MAIN_HAND);
session.setTool(player, new LongRangeBuildTool(primary, secondary)); session.setTool(itemStack.getType(), new LongRangeBuildTool(primary, secondary));
BBC.TOOL_LRBUILD_BOUND.send(player, itemStack.getType().getName()); player.print("Long-range building tool bound to " + itemStack.getType().getName() + ".");
BBC.TOOL_LRBUILD_INFO.send(player, secondary, primary); String primaryName = "pattern";
String secondaryName = "pattern";
if (primary instanceof BlockStateHolder) {
primaryName = ((BlockStateHolder<?>) primary).getBlockType().getName();
}
if (secondary instanceof BlockStateHolder) {
secondaryName = ((BlockStateHolder<?>) secondary).getBlockType().getName();
}
player.print("Left-click set to " + primaryName + "; right-click set to "
+ secondaryName + ".");
} }
} }

View File

@ -82,16 +82,16 @@ public class ToolUtilCommands {
return; return;
} }
if (maskOpt == null) { if (maskOpt == null) {
player.print(BBC.BRUSH_MASK_DISABLED.s()); player.print("Brush mask disabled.");
tool.setMask(null); tool.setMask(null);
return; return;
} }
BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext(); BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext();
String lastArg = Iterables.getLast(CommandArgParser.spaceSplit(arguments.get())).getSubstring(); String lastArg = Iterables.getLast(CommandArgParser.spaceSplit(arguments.get())).getSubstring();
settings.addSetting(BrushSettings.SettingType.MASK, lastArg); settings.addSetting(BrushSettings.SettingType.MASK, lastArg);
settings.setMask(maskOpt); settings.setMask(maskOpt);
tool.update(); tool.update();
player.print(BBC.BRUSH_MASK.s()); player.print("Brush mask set.");
} }
@Command( @Command(
@ -110,7 +110,7 @@ public class ToolUtilCommands {
if (tool == null) { if (tool == null) {
player.print(BBC.BRUSH_NONE.s()); player.print(BBC.BRUSH_NONE.s());
return; return;
} }
if (pattern == null) { if (pattern == null) {
player.print(BBC.BRUSH_MATERIAL.s()); player.print(BBC.BRUSH_MATERIAL.s());
tool.setFill(null); tool.setFill(null);
@ -125,61 +125,29 @@ public class ToolUtilCommands {
} }
@Command( @Command(
name = "range", name = "range",
desc = "Set the brush range" desc = "Set the brush range"
) )
@CommandPermissions("worldedit.brush.options.range") @CommandPermissions("worldedit.brush.options.range")
public void range(Player player, LocalSession session, public void range(Player player, LocalSession session,
@Arg(desc = "The range of the brush") @Arg(desc = "The range of the brush")
int range) throws WorldEditException { int range) throws WorldEditException {
range = Math.max(0, Math.min(256, range)); session.getBrushTool(player, false).setRange(range);
BrushTool tool = session.getBrushTool(player, false); player.print("Brush range set.");
if (tool == null) {
player.print(BBC.BRUSH_NONE.s());
return;
}
tool.setRange(range);
player.print(BBC.BRUSH_RANGE.s());
} }
@Command( @Command(
name = "size", name = "size",
desc = "Set the brush size" desc = "Set the brush size"
) )
@CommandPermissions("worldedit.brush.options.size") @CommandPermissions("worldedit.brush.options.size")
public void size(Player player, LocalSession session, public void size(Player player, LocalSession session,
@Arg(desc = "The size of the brush", def = "5") @Arg(desc = "The size of the brush")
int size, int size) throws WorldEditException {
@Switch(name = 'h', desc = "TODO")
boolean offHand) throws WorldEditException {
we.checkMaxBrushRadius(size); we.checkMaxBrushRadius(size);
BrushTool tool = session.getBrushTool(player, false);
if (tool == null) {
player.print(BBC.BRUSH_NONE.s());
return;
}
BrushSettings settings = offHand ? tool.getOffHand() : tool.getContext();
settings.setSize(size);
tool.update();
player.print(BBC.BRUSH_SIZE.s());
}
@Command( session.getBrushTool(player, false).setSize(size);
name = "tracemask", player.print("Brush size set.");
aliases = {"tarmask", "tm", "targetmask"},
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 maskOpt) throws WorldEditException {
BrushTool tool = session.getBrushTool(player, false);
if (tool == null) {
player.print(BBC.BRUSH_NONE.s());
return;
}
tool.setTraceMask(maskOpt);
BBC.BRUSH_TARGET_MASK_SET.send(player, maskOpt.toString());
} }
//todo none should be moved to the same class where it is in upstream //todo none should be moved to the same class where it is in upstream
@ -194,28 +162,42 @@ public class ToolUtilCommands {
} }
@Command( @Command(
name = "/superpickaxe", name = "tracemask",
aliases = {",", "/sp", "/pickaxe"}, aliases = {"tarmask", "tm", "targetmask"},
desc = "Toggle the super pickaxe function" 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 maskOpt) throws WorldEditException {
session.getBrushTool(player, false).setTraceMask(maskOpt);
if (maskOpt == null) {
player.print("Trace mask disabled.");
} else {
player.print("Trace mask set.");
}
}
@Command(
name = "/",
aliases = { "," },
desc = "Toggle the super pickaxe function"
) )
@CommandPermissions("worldedit.superpickaxe") @CommandPermissions("worldedit.superpickaxe")
public void togglePickaxe(Player player, LocalSession session, public void togglePickaxe(Player player, LocalSession session,
@Arg(desc = "state", def = "on") String state) throws WorldEditException { @Arg(desc = "The new super pickaxe state", def = "")
if (session.hasSuperPickAxe()) { Boolean superPickaxe) {
if ("on".equals(state)) { boolean hasSuperPickAxe = session.hasSuperPickAxe();
player.print(BBC.SUPERPICKAXE_ENABLED.s()); if (superPickaxe != null && superPickaxe == hasSuperPickAxe) {
player.printError("Super pickaxe already " + (superPickaxe ? "enabled" : "disabled") + ".");
return; return;
} }
if (hasSuperPickAxe) {
session.disableSuperPickAxe(); session.disableSuperPickAxe();
player.print(BBC.SUPERPICKAXE_DISABLED.s()); player.print("Super pickaxe disabled.");
} else { } else {
if ("off".equals(state)) {
player.print(BBC.SUPERPICKAXE_DISABLED.s());
return;
}
session.enableSuperPickAxe(); session.enableSuperPickAxe();
player.print(BBC.SUPERPICKAXE_ENABLED.s()); player.print("Super pickaxe enabled.");
} }
} }

View File

@ -30,7 +30,6 @@ import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.image.ImageUtil; import com.boydti.fawe.util.image.ImageUtil;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
@ -46,21 +45,23 @@ import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.PrintCommandHelp; import com.sk89q.worldedit.command.util.PrintCommandHelp;
import com.sk89q.worldedit.command.util.SkipQueue; import com.sk89q.worldedit.command.util.SkipQueue;
import com.sk89q.worldedit.entity.Entity; import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.function.EntityFunction; import com.sk89q.worldedit.function.EntityFunction;
import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.mask.BlockTypeMask;
import com.sk89q.worldedit.function.visitor.EntityVisitor; import com.sk89q.worldedit.function.visitor.EntityVisitor;
import com.sk89q.worldedit.internal.annotation.Direction; import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.Range; import com.sk89q.worldedit.internal.annotation.Range;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException; import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import java.text.DecimalFormat;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.CylinderRegion; import com.sk89q.worldedit.regions.CylinderRegion;
@ -77,7 +78,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.nio.file.Files; import java.nio.file.Files;
import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.ArrayList; import java.util.ArrayList;
@ -99,7 +99,8 @@ import org.enginehub.piston.annotation.param.Switch;
/** /**
* Utility commands. * Utility commands.
*/ */
@CommandContainer(superTypes = { @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class UtilityCommands {
// CommandQueuedConditionGenerator.Registration.class, // CommandQueuedConditionGenerator.Registration.class,
CommandPermissionsConditionGenerator.Registration.class // TODO NOT IMPLEMENTED - Piston doesn't seem to work with multiple conditions??? CommandPermissionsConditionGenerator.Registration.class // TODO NOT IMPLEMENTED - Piston doesn't seem to work with multiple conditions???
}) })
@ -193,6 +194,7 @@ public class UtilityCommands {
@Command( @Command(
name = "/fill", name = "/fill",
desc = "Fill a hole" desc = "Fill a hole"
) )
@CommandPermissions("worldedit.fill") @CommandPermissions("worldedit.fill")
@Logging(PLACEMENT) @Logging(PLACEMENT)
@ -218,6 +220,8 @@ public class UtilityCommands {
/* /*
@Command( @Command(
name = "/fillr",
desc = "Fill a hole recursively"
name = "patterns", name = "patterns",
desc = "View help about patterns", desc = "View help about patterns",
descFooter = "Patterns determine what blocks are placed\n" + descFooter = "Patterns determine what blocks are placed\n" +
@ -296,10 +300,10 @@ public class UtilityCommands {
public int fillr(Actor actor, LocalSession session, EditSession editSession, public int fillr(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The blocks to fill with") @Arg(desc = "The blocks to fill with")
Pattern pattern, Pattern pattern,
@Range(min=1) @Arg(desc = "The radius to fill in") @Arg(desc = "The radius to fill in")
Expression radiusExp, Expression radiusExp,
@Arg(desc = "The depth to fill", def = "") @Arg(desc = "The depth to fill", def = "")
Integer depth) throws WorldEditException, EvaluationException { Integer depth) throws WorldEditException {
double radius = radiusExp.evaluate(); double radius = radiusExp.evaluate();
radius = Math.max(1, radius); radius = Math.max(1, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
@ -319,10 +323,10 @@ public class UtilityCommands {
@CommandPermissions("worldedit.drain") @CommandPermissions("worldedit.drain")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int drain(Actor actor, LocalSession session, EditSession editSession, public int drain(Actor actor, LocalSession session, EditSession editSession,
@Range(min=0) @Arg(desc = "The radius to drain") @Arg(desc = "The radius to drain")
Expression radiusExp, Expression radiusExp,
@Switch(name = 'w', desc = "Also un-waterlog blocks") @Switch(name = 'w', desc = "Also un-waterlog blocks")
boolean waterlogged) throws WorldEditException, EvaluationException { boolean waterlogged) throws WorldEditException {
double radius = radiusExp.evaluate(); double radius = radiusExp.evaluate();
radius = Math.max(0, radius); radius = Math.max(0, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
@ -340,9 +344,8 @@ public class UtilityCommands {
@CommandPermissions("worldedit.fixlava") @CommandPermissions("worldedit.fixlava")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int fixLava(Actor actor, LocalSession session, EditSession editSession, public int fixLava(Actor actor, LocalSession session, EditSession editSession,
@Range(min=0) @Arg(desc = "The radius to fix in") @Arg(desc = "The radius to fix in")
Expression radiusExp) throws WorldEditException, EvaluationException { double radius) throws WorldEditException {
double radius = radiusExp.evaluate();
radius = Math.max(0, radius); radius = Math.max(0, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA); int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA);
@ -358,13 +361,12 @@ public class UtilityCommands {
@CommandPermissions("worldedit.fixwater") @CommandPermissions("worldedit.fixwater")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int fixWater(Actor actor, LocalSession session, EditSession editSession, public int fixWater(Actor actor, LocalSession session, EditSession editSession,
@Range(min=0) @Arg(desc = "The radius to fix in") @Arg(desc = "The radius to fix in")
Expression radiusExp) throws WorldEditException, EvaluationException { double radius) throws WorldEditException {
double radius = radiusExp.evaluate();
radius = Math.max(0, radius); radius = Math.max(0, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER); int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been changed.");
return affected; return affected;
} }
@ -376,15 +378,16 @@ public class UtilityCommands {
@CommandPermissions("worldedit.removeabove") @CommandPermissions("worldedit.removeabove")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int removeAbove(Actor actor, World world, LocalSession session, EditSession editSession, public int removeAbove(Actor actor, World world, LocalSession session, EditSession editSession,
@Range(min=1) @Arg(name = "size", desc = "The apothem of the square to remove from", def = "1") @Arg(desc = "The apothem of the square to remove from", def = "1")
int size, int size,
@Arg(desc = "The maximum height above you to remove from", def = "") @Arg(desc = "The maximum height above you to remove from", def = "")
Integer height) throws WorldEditException { Integer height) throws WorldEditException {
size = Math.max(1, size); size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1); height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1);
int affected = editSession.removeAbove(session.getPlacementPosition(actor), size, height); int affected = editSession.removeAbove(session.getPlacementPosition(actor), size, height);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been removed.");
return affected; return affected;
} }
@ -396,7 +399,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.removebelow") @CommandPermissions("worldedit.removebelow")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int removeBelow(Actor actor, World world, LocalSession session, EditSession editSession, public int removeBelow(Actor actor, World world, LocalSession session, EditSession editSession,
@Arg(name = "size", desc = "The apothem of the square to remove from", def = "1") @Arg(desc = "The apothem of the square to remove from", def = "1")
int size, int size,
@Arg(desc = "The maximum height below you to remove from", def = "") @Arg(desc = "The maximum height below you to remove from", def = "")
Integer height) throws WorldEditException { Integer height) throws WorldEditException {
@ -405,7 +408,7 @@ public class UtilityCommands {
height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1); height = height != null ? Math.min((world.getMaxY() + 1), height + 1) : (world.getMaxY() + 1);
int affected = editSession.removeBelow(session.getPlacementPosition(actor), size, height); int affected = editSession.removeBelow(session.getPlacementPosition(actor), size, height);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been removed.");
return affected; return affected;
} }
@ -419,25 +422,25 @@ public class UtilityCommands {
public int removeNear(Actor actor, LocalSession session, EditSession editSession, public int removeNear(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The mask of blocks to remove") @Arg(desc = "The mask of blocks to remove")
Mask mask, Mask mask,
@Range(min=1) @Arg(desc = "The radius of the square to remove from", def = "50") @Arg(desc = "The radius of the square to remove from", def = "50")
int radius) throws WorldEditException { int radius) throws WorldEditException {
radius = Math.max(1, radius); radius = Math.max(1, radius);
we.checkMaxRadius(radius); we.checkMaxRadius(radius);
int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, radius); int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, radius);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been removed.");
return affected; return affected;
} }
@Command( @Command(
name = "replacenear", name = "replacenear",
aliases = { "/replacenear", "/rn" }, aliases = { "/replacenear" },
desc = "Replace nearby blocks" desc = "Replace nearby blocks"
) )
@CommandPermissions("worldedit.replacenear") @CommandPermissions("worldedit.replacenear")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int replaceNear(Actor actor, World world, LocalSession session, EditSession editSession, public int replaceNear(Actor actor, World world, LocalSession session, EditSession editSession,
@Range(min=1) @Arg(desc = "The radius of the square to remove in") @Arg(desc = "The radius of the square to remove in")
int radius, int radius,
@Arg(desc = "The mask matching blocks to remove", def = "") @Arg(desc = "The mask matching blocks to remove", def = "")
Mask from, Mask from,
@ -456,7 +459,7 @@ public class UtilityCommands {
} }
int affected = editSession.replaceBlocks(region, from, to); int affected = editSession.replaceBlocks(region, from, to);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been replaced.");
return affected; return affected;
} }
@ -468,7 +471,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.snow") @CommandPermissions("worldedit.snow")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int snow(Actor actor, LocalSession session, EditSession editSession, public int snow(Actor actor, LocalSession session, EditSession editSession,
@Range(min=1) @Arg(desc = "The radius of the circle to snow in", def = "10") @Arg(desc = "The radius of the circle to snow in", def = "10")
double size) throws WorldEditException { double size) throws WorldEditException {
size = Math.max(1, size); size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
@ -486,7 +489,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.thaw") @CommandPermissions("worldedit.thaw")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int thaw(Actor actor, LocalSession session, EditSession editSession, public int thaw(Actor actor, LocalSession session, EditSession editSession,
@Range(min=1) @Arg(desc = "The radius of the circle to thaw in", def = "10") @Arg(desc = "The radius of the circle to thaw in", def = "10")
double size) throws WorldEditException { double size) throws WorldEditException {
size = Math.max(1, size); size = Math.max(1, size);
we.checkMaxRadius(size); we.checkMaxRadius(size);
@ -504,7 +507,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.green") @CommandPermissions("worldedit.green")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public int green(Actor actor, LocalSession session, EditSession editSession, public int green(Actor actor, LocalSession session, EditSession editSession,
@Range(min=1) @Arg(desc = "The radius of the circle to convert in", def = "10") @Arg(desc = "The radius of the circle to convert in", def = "10")
double size, double size,
@Switch(name = 'f', desc = "Also convert coarse dirt") @Switch(name = 'f', desc = "Also convert coarse dirt")
boolean convertCoarse) throws WorldEditException { boolean convertCoarse) throws WorldEditException {
@ -513,10 +516,37 @@ public class UtilityCommands {
final boolean onlyNormalDirt = !convertCoarse; final boolean onlyNormalDirt = !convertCoarse;
final int affected = editSession.green(session.getPlacementPosition(actor), size, onlyNormalDirt); final int affected = editSession.green(session.getPlacementPosition(actor), size, onlyNormalDirt);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " surface(s) greened.");
return affected; return affected;
} }
private int killMatchingEntities(Integer radius, Actor actor, Supplier<EntityFunction> func) throws IncompleteRegionException,
MaxChangedBlocksException {
List<EntityVisitor> visitors = new ArrayList<>();
LocalSession session = we.getSessionManager().get(actor);
BlockVector3 center = session.getPlacementPosition(actor);
EditSession editSession = session.createEditSession(actor);
List<? extends Entity> entities;
if (radius >= 0) {
CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius);
entities = editSession.getEntities(region);
} else {
entities = editSession.getEntities();
}
visitors.add(new EntityVisitor(entities.iterator(), func.get()));
int killed = 0;
for (EntityVisitor visitor : visitors) {
Operations.completeLegacy(visitor);
killed += visitor.getAffected();
}
session.remember(editSession);
editSession.flushSession();
return killed;
}
@Command( @Command(
name = "extinguish", name = "extinguish",
aliases = { "/ex", "/ext", "/extinguish", "ex", "ext" }, aliases = { "/ex", "/ext", "/extinguish", "ex", "ext" },
@ -525,7 +555,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.extinguish") @CommandPermissions("worldedit.extinguish")
@Logging(PLACEMENT) @Logging(PLACEMENT)
public void extinguish(Actor actor, LocalSession session, EditSession editSession, public void extinguish(Actor actor, LocalSession session, EditSession editSession,
@Range(min=1) @Arg(desc = "The radius of the square to remove in", def = "") @Arg(desc = "The radius of the square to remove in", def = "")
Integer radius) throws WorldEditException { Integer radius) throws WorldEditException {
LocalConfiguration config = we.getConfiguration(); LocalConfiguration config = we.getConfiguration();
@ -534,9 +564,9 @@ public class UtilityCommands {
int size = radius != null ? Math.max(1, radius) : defaultRadius; int size = radius != null ? Math.max(1, radius) : defaultRadius;
we.checkMaxRadius(size); we.checkMaxRadius(size);
Mask mask = BlockTypes.FIRE.toMask(); Mask mask = new BlockTypeMask(editSession, BlockTypes.FIRE);
int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, size); int affected = editSession.removeNear(session.getPlacementPosition(actor), mask, size);
BBC.VISITOR_BLOCK.send(actor, affected); actor.print(affected + " block(s) have been removed.");
} }
@Command( @Command(
@ -597,6 +627,22 @@ public class UtilityCommands {
return killed; return killed;
} }
@Command(
name = "/help",
desc = "Displays help for WorldEdit commands"
)
@CommandPermissions("worldedit.help")
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.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help");
}
@Command( @Command(
name = "remove", name = "remove",
aliases = { "rem", "rement" }, aliases = { "rem", "rement" },
@ -607,9 +653,8 @@ public class UtilityCommands {
public int remove(Actor actor, public int remove(Actor actor,
@Arg(desc = "The type of entity to remove") @Arg(desc = "The type of entity to remove")
EntityRemover remover, EntityRemover remover,
@Range(min=-1) @Arg(desc = "The radius of the cuboid to remove from") @Arg(desc = "The radius of the cuboid to remove from")
int radius) throws WorldEditException { int radius) throws WorldEditException {
if (radius < -1) { if (radius < -1) {
actor.printError("Use -1 to remove all entities in loaded chunks"); actor.printError("Use -1 to remove all entities in loaded chunks");
return 0; return 0;
@ -621,34 +666,6 @@ public class UtilityCommands {
return removed; return removed;
} }
private int killMatchingEntities(Integer radius, Actor actor, Supplier<EntityFunction> func) throws IncompleteRegionException, MaxChangedBlocksException {
List<EntityVisitor> visitors = new ArrayList<>();
LocalSession session = we.getSessionManager().get(actor);
BlockVector3 center = session.getPlacementPosition(actor);
EditSession editSession = session.createEditSession(actor);
List<? extends Entity> entities;
if (radius >= 0) {
CylinderRegion region = CylinderRegion.createRadius(editSession, center, radius);
entities = editSession.getEntities(region);
} else {
entities = editSession.getEntities();
}
visitors.add(new EntityVisitor(entities.iterator(), func.get()));
int killed = 0;
for (EntityVisitor visitor : visitors) {
Operations.completeLegacy(visitor);
killed += visitor.getAffected();
}
BBC.KILL_SUCCESS.send(actor, killed, radius);
session.remember(editSession);
editSession.flushSession();
return killed;
}
// get the formatter with the system locale. in the future, if we can get a local from a player, we can use that // get the formatter with the system locale. in the future, if we can get a local from a player, we can use that
private static final DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.getDefault()); private static final DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(Locale.getDefault());
static { static {
@ -663,7 +680,7 @@ public class UtilityCommands {
@CommandPermissions("worldedit.calc") @CommandPermissions("worldedit.calc")
public void calc(Actor actor, public void calc(Actor actor,
@Arg(desc = "Expression to evaluate", variable = true) @Arg(desc = "Expression to evaluate", variable = true)
List<String> input) throws EvaluationException { List<String> input) {
Expression expression; Expression expression;
try { try {
expression = Expression.compile(String.join(" ", input)); expression = Expression.compile(String.join(" ", input));
@ -672,11 +689,12 @@ public class UtilityCommands {
"'%s' could not be parsed as a valid expression", input)); "'%s' could not be parsed as a valid expression", input));
return; return;
} }
double result = expression.evaluate( WorldEditAsyncCommandBuilder.createAndSendMessage(actor, () -> {
new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout()); double result = expression.evaluate(
String formatted = Double.isNaN(result) ? "NaN" : formatter.format(result); new double[]{}, WorldEdit.getInstance().getSessionManager().get(actor).getTimeout());
TextComponent msg = SubtleFormat.wrap(input + " = ").append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE)); String formatted = Double.isNaN(result) ? "NaN" : formatter.format(result);
actor.print(msg); return SubtleFormat.wrap(input + " = ").append(TextComponent.of(formatted, TextColor.LIGHT_PURPLE));
}, null);
} }
@Command( @Command(
@ -690,22 +708,6 @@ public class UtilityCommands {
} }
} }
@Command(
name = "/help",
desc = "Displays help for WorldEdit commands"
)
@CommandPermissions("worldedit.help")
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> commandStr) throws WorldEditException {
PrintCommandHelp.help(commandStr, page, listSubCommands,
we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help");
}
public static List<Map.Entry<URI, String>> filesToEntry(final File root, final List<File> files, final UUID uuid) { public static List<Map.Entry<URI, String>> filesToEntry(final File root, final List<File> files, final UUID uuid) {
return Lists.transform(files, input -> { // Keep this functional, as transform is evaluated lazily return Lists.transform(files, input -> { // Keep this functional, as transform is evaluated lazily
URI uri = input.toURI(); URI uri = input.toURI();

View File

@ -56,11 +56,9 @@ import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag; import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch; import org.enginehub.piston.annotation.param.Switch;
@CommandContainer(superTypes = {CommandPermissionsConditionGenerator.Registration.class, CommandQueuedConditionGenerator.Registration.class}) @CommandContainer(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class WorldEditCommands { public class WorldEditCommands {
private static final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("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; private final WorldEdit we;
@ -174,11 +172,10 @@ public class WorldEditCommands {
try { try {
ZoneId tz = ZoneId.of(timezone); ZoneId tz = ZoneId.of(timezone);
session.setTimezone(tz); session.setTimezone(tz);
BBC.TIMEZONE_SET.send(actor, tz.getDisplayName( actor.print("Timezone set for this session to: " + tz.getDisplayName(
TextStyle.FULL, Locale.ENGLISH TextStyle.FULL, Locale.ENGLISH
)); ));
BBC.TIMEZONE_DISPLAY actor.print("The current time in that timezone is: " + dateFormat.format(ZonedDateTime.now(tz)));
.send(actor, dateFormat.format(ZonedDateTime.now(tz)));
} catch (ZoneRulesException e) { } catch (ZoneRulesException e) {
actor.printError("Invalid timezone"); actor.printError("Invalid timezone");
} }
@ -186,7 +183,7 @@ public class WorldEditCommands {
@Command( @Command(
name = "help", name = "help",
desc = "Displays help for FAWE commands" desc = "Displays help for WorldEdit commands"
) )
@SkipQueue @SkipQueue
@CommandPermissions("worldedit.help") @CommandPermissions("worldedit.help")
@ -196,8 +193,8 @@ public class WorldEditCommands {
@ArgFlag(name = 'p', desc = "The page to retrieve", def = "1") @ArgFlag(name = 'p', desc = "The page to retrieve", def = "1")
int page, int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true) @Arg(desc = "The command to retrieve help for", def = "", variable = true)
List<String> commandStr) throws WorldEditException { List<String> command) throws WorldEditException {
PrintCommandHelp.help(commandStr, page, listSubCommands, PrintCommandHelp.help(command, page, listSubCommands,
we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help"); we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help");
} }
} }

View File

@ -19,20 +19,21 @@
package com.sk89q.worldedit.command.argument; 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.base.Splitter;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.util.formatting.text.TextComponent;
import java.util.List;
import org.enginehub.piston.converter.ArgumentConverter; import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult; import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.SuccessfulConversion; import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.sk89q.worldedit.util.formatting.text.TextComponent.space;
public class CommaSeparatedValuesConverter<T> implements ArgumentConverter<T> { public class CommaSeparatedValuesConverter<T> implements ArgumentConverter<T> {
public static <T> CommaSeparatedValuesConverter<T> wrap(ArgumentConverter<T> delegate) { public static <T> CommaSeparatedValuesConverter<T> wrap(ArgumentConverter<T> delegate) {

View File

@ -28,12 +28,13 @@ import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult; import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion; import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion; 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.InjectedValueAccess;
import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.Key;
import java.util.List; import java.util.List;
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
public class EntityRemoverConverter implements ArgumentConverter<EntityRemover> { public class EntityRemoverConverter implements ArgumentConverter<EntityRemover> {
public static void register(CommandManager commandManager) { public static void register(CommandManager commandManager) {

View File

@ -66,8 +66,8 @@ public class AreaPickaxe implements BlockTool {
try { try {
for (int x = ox - range; x <= ox + range; ++x) { for (int x = ox - range; x <= ox + range; ++x) {
for (int z = oz - range; z <= oz + range; ++z) { for (int y = oy - range; y <= oy + range; ++y) {
for (int y = oy + range; y >= oy - range; --y) { for (int z = oz - range; z <= oz + range; ++z) {
if (initialType.equals(editSession.getBlock(x, y, z))) { if (initialType.equals(editSession.getBlock(x, y, z))) {
continue; continue;
} }

View File

@ -70,7 +70,6 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.expression.Expression; import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockType;
@ -437,7 +436,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
@Override @Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
return act(BrushAction.PRIMARY, player, session); return act(BrushAction.PRIMARY, player, session);
} }
public BlockVector3 getPosition(EditSession editSession, Player player) { public BlockVector3 getPosition(EditSession editSession, Player player) {
Location loc = player.getLocation(); Location loc = player.getLocation();

View File

@ -23,7 +23,6 @@ import com.boydti.fawe.config.BBC;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.entity.Player; 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.Platform;
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits; import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
@ -40,11 +39,6 @@ public class DistanceWand extends BrushTool implements DoubleActionTraceTool {
super("worldedit.selection.pos"); super("worldedit.selection.pos");
} }
@Override
public boolean canUse(Actor player) {
return player.hasPermission("worldedit.wand");
}
@Override @Override
public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
Location target = getTarget(player); Location target = getTarget(player);
@ -74,8 +68,7 @@ public class DistanceWand extends BrushTool implements DoubleActionTraceTool {
private Location getTarget(Player player) { private Location getTarget(Player player) {
Location target; Location target;
Mask mask = getTraceMask(); Mask mask = getTraceMask();
int range = getRange(); if (this.range > -1) {
if (range < MAX_RANGE) {
target = player.getBlockTrace(getRange(), true, mask); target = player.getBlockTrace(getRange(), true, mask);
} else { } else {
target = player.getBlockTrace(MAX_RANGE, false, mask); target = player.getBlockTrace(MAX_RANGE, false, mask);

View File

@ -118,7 +118,7 @@ public class FloatingTreeRemover implements BlockTool {
* @param origin any point contained in the floating tree * @param origin any point contained in the floating tree
* @return a set containing all blocks in the tree/shroom or null if this is not a floating tree/shroom. * @return a set containing all blocks in the tree/shroom or null if this is not a floating tree/shroom.
*/ */
private Set<BlockVector3> bfs(World world, BlockVector3 origin) throws MaxChangedBlocksException { private Set<BlockVector3> bfs(World world, BlockVector3 origin) {
final LocalBlockVectorSet visited = new LocalBlockVectorSet(); final LocalBlockVectorSet visited = new LocalBlockVectorSet();
final LocalBlockVectorSet queue = new LocalBlockVectorSet(); final LocalBlockVectorSet queue = new LocalBlockVectorSet();

View File

@ -27,6 +27,7 @@ import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
@ -56,39 +57,56 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo
public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) { public boolean actSecondary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
Location pos = getTargetFace(player); Location pos = getTargetFace(player);
if (pos == null) return false; if (pos == null) return false;
try (EditSession eS = session.createEditSession(player)) { BlockBag bag = session.getBlockBag(player);
try (EditSession editSession = session.createEditSession(player)) {
try {
editSession.disableBuffering();
BlockVector3 blockPoint = pos.toVector().toBlockPoint(); BlockVector3 blockPoint = pos.toVector().toBlockPoint();
BaseBlock applied = secondary.apply(blockPoint); BaseBlock applied = secondary.apply(blockPoint);
if (applied.getBlockType().getMaterial().isAir()) { if (applied.getBlockType().getMaterial().isAir()) {
eS.setBlock(blockPoint, secondary); editSession.setBlock(blockPoint, secondary);
} else { } else {
eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), secondary); editSession.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), secondary);
}
} catch (MaxChangedBlocksException ignored) {
} finally {
session.remember(editSession);
} }
return true; } finally {
} catch (MaxChangedBlocksException ignored) { if (bag != null) {
// one block? eat it bag.flushChanges();
} }
return false; }
return true;
} }
@Override @Override
public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) { public boolean actPrimary(Platform server, LocalConfiguration config, Player player, LocalSession session) {
Location pos = getTargetFace(player); Location pos = getTargetFace(player);
if (pos == null) return false; if (pos == null) return false;
try (EditSession eS = session.createEditSession(player)) { BlockBag bag = session.getBlockBag(player);
try (EditSession editSession = session.createEditSession(player)) {
try {
editSession.disableBuffering();
BlockVector3 blockPoint = pos.toVector().toBlockPoint(); BlockVector3 blockPoint = pos.toVector().toBlockPoint();
BaseBlock applied = primary.apply(blockPoint); BaseBlock applied = primary.apply(blockPoint);
if (applied.getBlockType().getMaterial().isAir()) { if (applied.getBlockType().getMaterial().isAir()) {
eS.setBlock(blockPoint, primary); editSession.setBlock(blockPoint, primary);
} else { } else {
eS.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), primary); editSession.setBlock(pos.toVector().subtract(pos.getDirection()).toBlockPoint(), primary);
}
} catch (MaxChangedBlocksException ignored) {
} finally {
session.remember(editSession);
} }
return true; } finally {
} catch (MaxChangedBlocksException ignored) { if (bag != null) {
// one block? eat it bag.flushChanges();
} }
return false; }
return true;
} }
private Location getTargetFace(Player player) { private Location getTargetFace(Player player) {
@ -99,6 +117,7 @@ public class LongRangeBuildTool extends BrushTool implements DoubleActionTraceTo
} else { } else {
target = player.getBlockTrace(MAX_RANGE, false, mask); target = player.getBlockTrace(MAX_RANGE, false, mask);
} }
if (target == null) { if (target == null) {
player.printError(BBC.NO_BLOCK.s()); player.printError(BBC.NO_BLOCK.s());
return null; return null;

View File

@ -24,6 +24,7 @@ import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
@ -33,6 +34,8 @@ import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
import java.util.OptionalInt;
/** /**
* Looks up information about a block. * Looks up information about a block.
*/ */

View File

@ -84,4 +84,36 @@ public class RecursivePickaxe implements BlockTool {
return true; 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

@ -44,7 +44,7 @@ public class ClipboardBrush implements Brush {
this.ignoreAirBlocks = ignoreAirBlocks; this.ignoreAirBlocks = ignoreAirBlocks;
this.usingOrigin = usingOrigin; this.usingOrigin = usingOrigin;
this.pasteBiomes = false; this.pasteBiomes = false;
this.pasteEntities = true; this.pasteEntities = false;
this.sourceMask = null; this.sourceMask = null;
} }

View File

@ -23,7 +23,12 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.util.LocatedBlock;
import java.util.LinkedHashSet;
import java.util.Set;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.util.collection.LocatedBlockList;
import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.BlockTypes;
public class GravityBrush implements Brush { public class GravityBrush implements Brush {
@ -48,12 +53,15 @@ public class GravityBrush implements Brush {
if (y != freeSpot) { if (y != freeSpot) {
editSession.setBlock((int)x, (int)y, (int)z, BlockTypes.AIR.getDefaultState()); editSession.setBlock((int)x, (int)y, (int)z, BlockTypes.AIR.getDefaultState());
editSession.setBlock((int)x, (int)freeSpot, (int)z, block); editSession.setBlock((int)x, (int)freeSpot, (int)z, block);
} }
freeSpot = y + 1; freeSpot = y + 1;
}
} }
} }
column.clear();
removedBlocks.clear();
} }
} }
}
} }

View File

@ -19,8 +19,6 @@
package com.sk89q.worldedit.command.util; 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.base.Strings;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@ -42,6 +40,9 @@ import javax.annotation.Nullable;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.function.Consumer; import java.util.function.Consumer;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
public final class AsyncCommandBuilder<T> { public final class AsyncCommandBuilder<T> {
private static final Logger logger = LoggerFactory.getLogger(AsyncCommandBuilder.class); private static final Logger logger = LoggerFactory.getLogger(AsyncCommandBuilder.class);

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.command.util; package com.sk89q.worldedit.command.util;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import org.enginehub.piston.Command; import org.enginehub.piston.Command;
import org.enginehub.piston.gen.CommandConditionGenerator; import org.enginehub.piston.gen.CommandConditionGenerator;
@ -28,6 +27,8 @@ import org.enginehub.piston.util.NonnullByDefault;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Set; import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
@NonnullByDefault @NonnullByDefault
public final class CommandPermissionsConditionGenerator implements CommandConditionGenerator { public final class CommandPermissionsConditionGenerator implements CommandConditionGenerator {

View File

@ -20,12 +20,12 @@
package com.sk89q.worldedit.command.util; package com.sk89q.worldedit.command.util;
import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TaskManager;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.entity.metadata.EntityProperties; import com.sk89q.worldedit.entity.metadata.EntityProperties;
import com.sk89q.worldedit.function.EntityFunction; import com.sk89q.worldedit.function.EntityFunction;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**

View File

@ -24,8 +24,6 @@ import org.enginehub.piston.Command;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key; import org.enginehub.piston.inject.Key;
import java.lang.annotation.Annotation;
import java.util.Optional;
import java.util.Set; import java.util.Set;
public class PermissionCondition implements Command.Condition { public class PermissionCondition implements Command.Condition {

View File

@ -303,14 +303,6 @@ public interface Player extends Entity, Actor {
*/ */
void setPosition(Vector3 pos, float pitch, float yaw); void setPosition(Vector3 pos, float pitch, float yaw);
/**
* Move the player.
*
* @param pos where to move them
*/
@Override
void setPosition(Vector3 pos);
/** /**
* Sends a fake block to the client. * Sends a fake block to the client.
* *

View File

@ -18,8 +18,6 @@
*/ */
package com.sk89q.worldedit.event.platform; package com.sk89q.worldedit.event.platform;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.event.Event; import com.sk89q.worldedit.event.Event;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.internal.util.Substring; import com.sk89q.worldedit.internal.util.Substring;
@ -27,6 +25,8 @@ import com.sk89q.worldedit.internal.util.Substring;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Posted when suggestions for auto-completion are requested for command input. * Posted when suggestions for auto-completion are requested for command input.
*/ */

View File

@ -32,6 +32,7 @@ import com.sk89q.worldedit.internal.registry.InputParser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* A registry of known {@link Mask}s. Provides methods to instantiate * A registry of known {@link Mask}s. Provides methods to instantiate
@ -48,19 +49,36 @@ public final class MaskFactory extends AbstractFactory<Mask> {
* @param worldEdit the WorldEdit instance * @param worldEdit the WorldEdit instance
*/ */
public MaskFactory(WorldEdit worldEdit) { public MaskFactory(WorldEdit worldEdit) {
super(worldEdit, new DefaultMaskParser(worldEdit)); super(worldEdit, new DefaultMaskParser(worldEdit));
/*
super(worldEdit, new BlocksMaskParser(worldEdit));
// register(new ExistingMaskParser(worldEdit)); register(new ExistingMaskParser(worldEdit));
// register(new SolidMaskParser(worldEdit)); register(new SolidMaskParser(worldEdit));
// register(new LazyRegionMaskParser(worldEdit)); register(new LazyRegionMaskParser(worldEdit));
// register(new RegionMaskParser(worldEdit)); register(new RegionMaskParser(worldEdit));
// register(new OffsetMaskParser(worldEdit)); register(new OffsetMaskParser(worldEdit));
// register(new NoiseMaskParser(worldEdit)); register(new NoiseMaskParser(worldEdit));
// register(new BlockStateMaskParser(worldEdit)); register(new BlockStateMaskParser(worldEdit));
// register(new NegateMaskParser(worldEdit)); register(new NegateMaskParser(worldEdit));
// register(new ExpressionMaskParser(worldEdit)); register(new ExpressionMaskParser(worldEdit));
register(new BlockCategoryMaskParser(worldEdit)); // TODO implement in DefaultMaskParser */
// register(new BiomeMaskParser(worldEdit)); register(new BlockCategoryMaskParser(worldEdit));
/*
register(new BiomeMaskParser(worldEdit));
*/
}
@Override
public List<String> getSuggestions(String input) {
final String[] split = input.split(" ");
if (split.length > 1) {
String prev = input.substring(0, input.lastIndexOf(" ")) + " ";
return super.getSuggestions(split[split.length -1]).stream().map(s -> prev + s).collect(Collectors.toList());
}
return super.getSuggestions(input);
} }
@Override @Override

View File

@ -40,16 +40,19 @@ public final class PatternFactory extends AbstractFactory<Pattern> {
* @param worldEdit the WorldEdit instance * @param worldEdit the WorldEdit instance
*/ */
public PatternFactory(WorldEdit worldEdit) { public PatternFactory(WorldEdit worldEdit) {
super(worldEdit, new DefaultPatternParser(worldEdit)); super(worldEdit, new DefaultPatternParser(worldEdit));
/*
super(worldEdit, new SingleBlockPatternParser(worldEdit));
// split and parse each sub-pattern // split and parse each sub-pattern
// register(new RandomPatternParser(worldEdit)); register(new RandomPatternParser(worldEdit));
// individual patterns // individual patterns
// register(new ClipboardPatternParser(worldEdit)); register(new ClipboardPatternParser(worldEdit));
// register(new TypeOrStateApplyingPatternParser(worldEdit)); register(new TypeOrStateApplyingPatternParser(worldEdit));
// register(new RandomStatePatternParser(worldEdit)); register(new RandomStatePatternParser(worldEdit));
register(new BlockCategoryPatternParser(worldEdit)); // TODO implement in pattern parser */
register(new BlockCategoryPatternParser(worldEdit));
} }
} }

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.extension.factory.parser; package com.sk89q.worldedit.extension.factory.parser;
import com.google.common.collect.Maps;
import com.boydti.fawe.command.SuggestInputParseException; import com.boydti.fawe.command.SuggestInputParseException;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.jnbt.JSON2NBT; import com.boydti.fawe.jnbt.JSON2NBT;
@ -35,7 +37,7 @@ import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.MobSpawnerBlock; import com.sk89q.worldedit.blocks.MobSpawnerBlock;
import com.sk89q.worldedit.blocks.SignBlock; import com.sk89q.worldedit.blocks.SignBlock;
import com.sk89q.worldedit.blocks.SkullBlock; import com.sk89q.worldedit.blocks.SkullBlock;
import com.sk89q.worldedit.blocks.metadata.MobType; import com.sk89q.worldedit.command.util.SuggestionHelper;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.DisallowedUsageException; import com.sk89q.worldedit.extension.input.DisallowedUsageException;
import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.InputParseException;
@ -61,6 +63,8 @@ import com.sk89q.worldedit.world.registry.LegacyMapper;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -111,6 +115,8 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
} }
} }
private static String[] EMPTY_STRING_ARRAY = {};
/** /**
* Backwards compatibility for wool colours in block syntax. * Backwards compatibility for wool colours in block syntax.
* *
@ -162,6 +168,71 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
} }
} }
private static Map<Property<?>, Object> parseProperties(BlockType type, String[] stateProperties, ParserContext context) throws NoMatchException {
Map<Property<?>, Object> blockStates = new HashMap<>();
if (stateProperties.length > 0) { // Block data not yet detected
// Parse the block data (optional)
for (String parseableData : stateProperties) {
try {
String[] parts = parseableData.split("=");
if (parts.length != 2) {
throw new NoMatchException("Bad state format in " + parseableData);
}
@SuppressWarnings("unchecked")
Property<Object> propertyKey = (Property<Object>) type.getPropertyMap().get(parts[0]);
if (propertyKey == null) {
if (context.getActor() != null) {
throw new NoMatchException("Unknown property " + parts[0] + " for block " + type.getId());
} else {
WorldEdit.logger.warn("Unknown property " + parts[0] + " for block " + type.getId());
}
return Maps.newHashMap();
}
if (blockStates.containsKey(propertyKey)) {
throw new NoMatchException("Duplicate property " + parts[0]);
}
Object value;
try {
value = propertyKey.getValueFor(parts[1]);
} catch (IllegalArgumentException e) {
throw new NoMatchException("Unknown value " + parts[1] + " for state " + parts[0]);
}
blockStates.put(propertyKey, value);
} catch (NoMatchException e) {
throw e; // Pass-through
} catch (Exception e) {
WorldEdit.logger.warn("Unknown state '" + parseableData + "'", e);
throw new NoMatchException("Unknown state '" + parseableData + "'");
}
}
}
return blockStates;
}
@Override
public Stream<String> getSuggestions(String input) {
final int idx = input.lastIndexOf('[');
if (idx < 0) {
return SuggestionHelper.getNamespacedRegistrySuggestions(BlockType.REGISTRY, input);
}
String blockType = input.substring(0, idx);
BlockType type = BlockTypes.get(blockType.toLowerCase(Locale.ROOT));
if (type == null) {
return Stream.empty();
}
String props = input.substring(idx + 1);
if (props.isEmpty()) {
return type.getProperties().stream().map(p -> input + p.getName() + "=");
}
return SuggestionHelper.getBlockPropertySuggestions(blockType, props);
}
private BaseBlock parseLogic(String input, ParserContext context) throws InputParseException { private BaseBlock parseLogic(String input, ParserContext context) throws InputParseException {
String[] blockAndExtraData = input.trim().split("\\|", 2); String[] blockAndExtraData = input.trim().split("\\|", 2);
blockAndExtraData[0] = woolMapper(blockAndExtraData[0]); blockAndExtraData[0] = woolMapper(blockAndExtraData[0]);
@ -193,7 +264,7 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
state = LegacyMapper.getInstance().getBlockFromLegacy(type.getLegacyCombinedId() >> 4, data); state = LegacyMapper.getInstance().getBlockFromLegacy(type.getLegacyCombinedId() >> 4, data);
} }
} }
} catch (NumberFormatException e) { } catch (NumberFormatException ignored) {
} }
} }
@ -206,6 +277,13 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
typeString = blockAndExtraData[0]; typeString = blockAndExtraData[0];
} else { } else {
typeString = blockAndExtraData[0].substring(0, stateStart); typeString = blockAndExtraData[0].substring(0, stateStart);
if (stateStart + 1 >= blockAndExtraData[0].length()) {
throw new InputParseException("Invalid format. Hanging bracket @ " + stateStart + ".");
}
int stateEnd = blockAndExtraData[0].lastIndexOf(']');
if (stateEnd < 0) {
throw new InputParseException("Invalid format. Unclosed property.");
}
stateString = blockAndExtraData[0].substring(stateStart + 1, blockAndExtraData[0].length() - 1); stateString = blockAndExtraData[0].substring(stateStart + 1, blockAndExtraData[0].length() - 1);
} }
if (typeString.isEmpty()) { if (typeString.isEmpty()) {
@ -288,6 +366,10 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
} }
} }
} }
// this should be impossible but IntelliJ isn't that smart
if (blockType == null) {
throw new NoMatchException("Does not match a valid block type: '" + input + "'");
}
if (blockAndExtraData.length > 1 && blockAndExtraData[1].startsWith("{")) { if (blockAndExtraData.length > 1 && blockAndExtraData[1].startsWith("{")) {
String joined = StringMan.join(Arrays.copyOfRange(blockAndExtraData, 1, blockAndExtraData.length), "|"); String joined = StringMan.join(Arrays.copyOfRange(blockAndExtraData, 1, blockAndExtraData.length), "|");
@ -322,6 +404,7 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
break; break;
} }
} }
mobName = ent.getId();
if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) { if (!worldEdit.getPlatformManager().queryCapability(Capability.USER_COMMANDS).isValidMobType(mobName)) {
String finalMobName = mobName.toLowerCase(Locale.ROOT); String finalMobName = mobName.toLowerCase(Locale.ROOT);
throw new SuggestInputParseException("Unknown mob type '" + mobName + "'", mobName, () -> Stream.of(MobType.values()) throw new SuggestInputParseException("Unknown mob type '" + mobName + "'", mobName, () -> Stream.of(MobType.values())

View File

@ -28,7 +28,6 @@ import com.sk89q.worldedit.function.mask.BiomeMask2D;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.session.request.RequestExtent;
import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.biome.BiomeType;
import java.util.Arrays; import java.util.Arrays;

View File

@ -26,7 +26,8 @@ import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.function.mask.BlockStateMask; import com.sk89q.worldedit.function.mask.BlockStateMask;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.session.request.RequestExtent;
import java.util.stream.Stream;
import java.util.stream.Stream; import java.util.stream.Stream;

View File

@ -25,7 +25,6 @@ import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.internal.registry.SimpleInputParser; import com.sk89q.worldedit.internal.registry.SimpleInputParser;
import com.sk89q.worldedit.session.request.RequestExtent;
import java.util.List; import java.util.List;

View File

@ -29,7 +29,8 @@ import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.OffsetMask; import com.sk89q.worldedit.function.mask.OffsetMask;
import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.session.request.RequestExtent;
import java.util.stream.Stream;
import java.util.stream.Stream; import java.util.stream.Stream;

View File

@ -25,7 +25,6 @@ import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.SolidBlockMask; import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.internal.registry.SimpleInputParser; import com.sk89q.worldedit.internal.registry.SimpleInputParser;
import com.sk89q.worldedit.session.request.RequestExtent;
import java.util.List; import java.util.List;

View File

@ -30,6 +30,7 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.pattern.StateApplyingPattern; import com.sk89q.worldedit.function.pattern.StateApplyingPattern;
import com.sk89q.worldedit.function.pattern.TypeApplyingPattern; import com.sk89q.worldedit.function.pattern.TypeApplyingPattern;
import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.internal.registry.InputParser;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream; import java.util.stream.Stream;

View File

@ -19,45 +19,12 @@
package com.sk89q.worldedit.extension.platform; package com.sk89q.worldedit.extension.platform;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.internal.cui.CUIEvent; import com.sk89q.worldedit.internal.cui.CUIEvent;
import java.io.File; import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class AbstractNonPlayerActor implements Actor { public abstract class AbstractNonPlayerActor implements Actor {
private final ConcurrentHashMap<String, Object> meta = new ConcurrentHashMap<>();
@Override
public Map<String, Object> getRawMeta() {
return meta;
}
// Queue for async tasks
private AtomicInteger runningCount = new AtomicInteger();
private SimpleAsyncNotifyQueue asyncNotifyQueue = new SimpleAsyncNotifyQueue(
(thread, throwable) -> {
while (throwable.getCause() != null) {
throwable = throwable.getCause();
}
if (throwable instanceof WorldEditException) {
printError(throwable.getLocalizedMessage());
} else {
FaweException fe = FaweException.get(throwable);
if (fe != null) {
printError(fe.getMessage());
} else {
throwable.printStackTrace();
}
}
});
@Override @Override
public boolean canDestroyBedrock() { public boolean canDestroyBedrock() {
return true; return true;
@ -81,35 +48,4 @@ public abstract class AbstractNonPlayerActor implements Actor {
@Override @Override
public void dispatchCUIEvent(CUIEvent event) { public void dispatchCUIEvent(CUIEvent event) {
} }
/**
* Run a task either async, or on the current thread
*
* @param ifFree
* @param checkFree Whether to first check if a task is running
* @param async
* @return false if the task was ran or queued
*/
@Override
public boolean runAction(Runnable ifFree, boolean checkFree, boolean async) {
if (checkFree) {
if (runningCount.get() != 0) {
return false;
}
}
Runnable wrapped = () -> {
try {
runningCount.addAndGet(1);
ifFree.run();
} finally {
runningCount.decrementAndGet();
}
};
if (async) {
asyncNotifyQueue.queue(wrapped);
} else {
TaskManager.IMP.taskNow(wrapped, false);
}
return true;
}
} }

View File

@ -19,13 +19,14 @@
package com.sk89q.worldedit.extension.platform; package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.EditSession;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue; import com.boydti.fawe.object.task.SimpleAsyncNotifyQueue;
import com.boydti.fawe.regions.FaweMaskManager; import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.WEManager; import com.boydti.fawe.util.WEManager;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
@ -45,6 +46,8 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.ConvexPolyhedralRegionSelector; import com.sk89q.worldedit.regions.selector.ConvexPolyhedralRegionSelector;
import javax.annotation.Nullable;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector; import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.regions.selector.CylinderRegionSelector; import com.sk89q.worldedit.regions.selector.CylinderRegionSelector;
import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector; import com.sk89q.worldedit.regions.selector.Polygonal2DRegionSelector;
@ -70,7 +73,6 @@ import java.text.NumberFormat;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;
import org.enginehub.piston.inject.InjectedValueAccess; import org.enginehub.piston.inject.InjectedValueAccess;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -249,7 +251,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
if (!lastState) { if (!lastState) {
lastState = BlockTypeUtil.centralBottomLimit(state) != 1; lastState = BlockTypeUtil.centralBottomLimit(state) != 1;
continue; continue;
} }
if (freeStart == -1) { if (freeStart == -1) {
freeStart = level + BlockTypeUtil.centralTopLimit(state); freeStart = level + BlockTypeUtil.centralTopLimit(state);
} else { } else {
@ -257,13 +259,13 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
double space = level + bottomLimit - freeStart; double space = level + bottomLimit - freeStart;
if (space >= height) { if (space >= height) {
setPosition(Vector3.at(x + 0.5, freeStart, z + 0.5)); setPosition(Vector3.at(x + 0.5, freeStart, z + 0.5));
return true; return true;
} }
// Not enough room, reset the free position // Not enough room, reset the free position
if (bottomLimit != 1) { if (bottomLimit != 1) {
freeStart = -1; freeStart = -1;
} }
} }
} else { } else {
freeStart = -1; freeStart = -1;
lastState = true; lastState = true;
@ -414,7 +416,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
session.setBlock(spot, BlockTypes.GLASS.getDefaultState()); session.setBlock(spot, BlockTypes.GLASS.getDefaultState());
} catch (MaxChangedBlocksException ignored) { } catch (MaxChangedBlocksException ignored) {
} }
} }
} else { } else {
setFlying(true); setFlying(true);
} }
@ -477,6 +479,23 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
return getBlockTrace(range, false); return getBlockTrace(range, false);
} }
/**
* Advances the block target block until the current block is a free
* @return true if a free spot is found
*/
private boolean advanceToFree(TargetBlock hitBlox) {
Location curBlock;
while ((curBlock = hitBlox.getCurrentBlock()) != null) {
if (canPassThroughBlock(curBlock)) {
return true;
}
hitBlox.getNextBlock();
}
return false;
}
@Override @Override
public Location getSolidBlockTrace(int range) { public Location getSolidBlockTrace(int range) {
TargetBlock tb = new TargetBlock(this, range, 0.2); TargetBlock tb = new TargetBlock(this, range, 0.2);
@ -541,33 +560,17 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
return false; return false;
} }
/**
* Advances the block target block until the current block is a free
* @return true if a free spot is found
*/
private boolean advanceToFree(TargetBlock hitBlox) {
Location curBlock;
while ((curBlock = hitBlox.getCurrentBlock()) != null) {
if (canPassThroughBlock(curBlock)) {
return true;
}
hitBlox.getNextBlock();
}
return false;
}
@Override @Override
public boolean passThroughForwardWall(int range) { public boolean passThroughForwardWall(int range) {
TargetBlock hitBlox = new TargetBlock(this, range, 0.2); TargetBlock hitBlox = new TargetBlock(this, range, 0.2);
if (!advanceToWall(hitBlox)) { if (!advanceToWall(hitBlox)) {
return false; return false;
} }
if (!advanceToFree(hitBlox)) { if (!advanceToFree(hitBlox)) {
return false; return false;
} }
Location foundBlock = hitBlox.getCurrentBlock(); Location foundBlock = hitBlox.getCurrentBlock();
@ -576,7 +579,6 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
return true; return true;
} }
return false; return false;
} }

View File

@ -19,6 +19,11 @@
package com.sk89q.worldedit.extension.platform; package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockRegistry;
/** /**
* A collection of capabilities that a {@link Platform} may support. * A collection of capabilities that a {@link Platform} may support.
*/ */
@ -73,7 +78,22 @@ public enum Capability {
/** /**
* The capability of a platform to perform modifications to a world. * The capability of a platform to perform modifications to a world.
*/ */
WORLD_EDITING; WORLD_EDITING {
@Override
void initialize(PlatformManager platformManager, Platform platform) {
BlockRegistry blockRegistry = platform.getRegistries().getBlockRegistry();
for (BlockType type : BlockType.REGISTRY) {
for (BlockState state : type.getAllStates()) {
BlockStateIdAccess.register(state, blockRegistry.getInternalBlockStateId(state));
}
}
}
@Override
void unload(PlatformManager platformManager, Platform platform) {
BlockStateIdAccess.clear();
}
};
void initialize(PlatformManager platformManager, Platform platform) { void initialize(PlatformManager platformManager, Platform platform) {

View File

@ -321,45 +321,45 @@ public class PlatformManager {
if (!(actor instanceof Player)) { if (!(actor instanceof Player)) {
return; return;
} }
Player player = (Player) actor; Player player = (Player) actor;
LocalSession session = worldEdit.getSessionManager().get(actor); LocalSession session = worldEdit.getSessionManager().get(actor);
Request.reset(); Request.reset();
Request.request().setSession(session); Request.request().setSession(session);
Request.request().setWorld(player.getWorld()); Request.request().setWorld(player.getWorld());
try { try {
Vector3 vector = location.toVector(); Vector3 vector = location.toVector();
VirtualWorld virtual = session.getVirtualWorld(); VirtualWorld virtual = session.getVirtualWorld();
if (virtual != null) { if (virtual != null) {
virtual.handleBlockInteract(player, vector.toBlockPoint(), event); virtual.handleBlockInteract(player, vector.toBlockPoint(), event);
if (event.isCancelled()) return; if (event.isCancelled()) return;
} }
if (event.getType() == Interaction.HIT) { if (event.getType() == Interaction.HIT) {
// superpickaxe is special because its primary interaction is a left click, not a right click // superpickaxe is special because its primary interaction is a left click, not a right click
// in addition, it is implicitly bound to all pickaxe items, not just a single tool item // in addition, it is implicitly bound to all pickaxe items, not just a single tool item
if (session.hasSuperPickAxe() && player.isHoldingPickAxe()) { if (session.hasSuperPickAxe() && player.isHoldingPickAxe()) {
final BlockTool superPickaxe = session.getSuperPickaxe(); final BlockTool superPickaxe = session.getSuperPickaxe();
if (superPickaxe != null && superPickaxe.canUse(player)) { if (superPickaxe != null && superPickaxe.canUse(player)) {
player.runAction(() -> reset(superPickaxe) player.runAction(() -> reset(superPickaxe)
.actPrimary(queryCapability(Capability.WORLD_EDITING), .actPrimary(queryCapability(Capability.WORLD_EDITING),
getConfiguration(), player, session, location), false, true); getConfiguration(), player, session, location), false, true);
event.setCancelled(true); event.setCancelled(true);
return; return;
}
} }
}
Tool tool = session.getTool(player); Tool tool = session.getTool(player);
if (tool instanceof DoubleActionBlockTool && tool.canUse(player)) { if (tool instanceof DoubleActionBlockTool && tool.canUse(player)) {
player.runAction(() -> reset(((DoubleActionBlockTool) tool)) player.runAction(() -> reset(((DoubleActionBlockTool) tool))
.actSecondary(queryCapability(Capability.WORLD_EDITING), .actSecondary(queryCapability(Capability.WORLD_EDITING),
getConfiguration(), player, session, location), false, true); getConfiguration(), player, session, location), false, true);
event.setCancelled(true); event.setCancelled(true);
} }
} else if (event.getType() == Interaction.OPEN) { } else if (event.getType() == Interaction.OPEN) {
Tool tool = session.getTool(player); Tool tool = session.getTool(player);
if (tool instanceof BlockTool && tool.canUse(player)) { if (tool instanceof BlockTool && tool.canUse(player)) {
if (player.checkAction()) { if (player.checkAction()) {
@ -367,20 +367,20 @@ public class PlatformManager {
BlockTool blockTool = (BlockTool) tool; BlockTool blockTool = (BlockTool) tool;
if (!(tool instanceof BrushTool)) { if (!(tool instanceof BrushTool)) {
blockTool = reset(blockTool); blockTool = reset(blockTool);
} }
blockTool.actPrimary(queryCapability(Capability.WORLD_EDITING), blockTool.actPrimary(queryCapability(Capability.WORLD_EDITING),
getConfiguration(), player, session, location); getConfiguration(), player, session, location);
}, false, true); }, false, true);
event.setCancelled(true); event.setCancelled(true);
} }
} }
} }
} catch (Throwable e) { } catch (Throwable e) {
handleThrowable(e, actor); handleThrowable(e, actor);
} finally { } finally {
Request.reset(); Request.reset();
}
} }
}
public void handleThrowable(Throwable e, Actor actor) { public void handleThrowable(Throwable e, Actor actor) {
FaweException faweException = FaweException.get(e); FaweException faweException = FaweException.get(e);
@ -409,53 +409,29 @@ public class PlatformManager {
try { try {
switch (event.getInputType()) { switch (event.getInputType()) {
case PRIMARY: { case PRIMARY: {
if (getConfiguration().navigationWandMaxDistance > 0 && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) {
if (!player.hasPermission("worldedit.navigation.jumpto.tool")) {
return;
}
Location pos = player.getSolidBlockTrace(getConfiguration().navigationWandMaxDistance);
if (pos != null) {
player.findFreePosition(pos);
} else {
player.printError(BBC.NO_BLOCK.s());
}
event.setCancelled(true);
return;
}
Tool tool = session.getTool(player); Tool tool = session.getTool(player);
if (tool instanceof DoubleActionTraceTool && tool.canUse(player)) { if (tool instanceof DoubleActionTraceTool && tool.canUse(player)) {
player.runAsyncIfFree(() -> reset((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING), player.runAsyncIfFree(() -> reset((DoubleActionTraceTool) tool).actSecondary(queryCapability(Capability.WORLD_EDITING),
getConfiguration(), player, session)); getConfiguration(), player, session));
event.setCancelled(true); event.setCancelled(true);
return; }
} return;
}
break; break;
} }
case SECONDARY: { case SECONDARY: {
if (getConfiguration().navigationWandMaxDistance > 0 && player.getItemInHand(HandSide.MAIN_HAND).getType().getId().equals(getConfiguration().navigationWand)) {
if (!player.hasPermission("worldedit.navigation.thru.tool")) {
return;
}
if (!player.passThroughForwardWall(40)) {
player.printError(BBC.NAVIGATION_WAND_ERROR.s());
}
event.setCancelled(true);
return;
}
Tool tool = session.getTool(player); Tool tool = session.getTool(player);
if (tool instanceof TraceTool && tool.canUse(player)) { if (tool instanceof TraceTool && tool.canUse(player)) {
//todo this needs to be fixed so the event is canceled after actPrimary is used and returns true //todo this needs to be fixed so the event is canceled after actPrimary is used and returns true
player.runAction(() -> reset((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), player.runAction(() -> reset((TraceTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING),
getConfiguration(), player, session), false, true); getConfiguration(), player, session), false, true);
event.setCancelled(true); event.setCancelled(true);
return; }
} return;
}
break; break;
} }

View File

@ -221,4 +221,9 @@ public class PlayerProxy extends AbstractPlayerActor {
public Player getBasePlayer() { public Player getBasePlayer() {
return basePlayer; return basePlayer;
} }
@Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
basePlayer.floatAt(x, y, z, alwaysGlass);
}
} }

View File

@ -572,7 +572,7 @@ public interface Extent extends InputExtent, OutputExtent {
* @throws MaxChangedBlocksException thrown if too many blocks are changed * @throws MaxChangedBlocksException thrown if too many blocks are changed
*/ */
default <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException { default <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException {
return replaceBlocks(region, filter, new BlockPattern(replacement)); return replaceBlocks(region, filter, (Pattern) replacement);
} }
/** /**

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