Merge branch 'master' into fix/quoted

This commit is contained in:
Kenzie Togami
2019-07-27 17:41:44 -07:00
92 changed files with 1767 additions and 1637 deletions

View File

@ -1,52 +0,0 @@
plugins {
id("net.ltgt.apt") version "0.21"
}
apply plugin: 'java-library'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'net.ltgt.apt-eclipse'
apply plugin: 'net.ltgt.apt-idea'
configurations.all { Configuration it ->
it.resolutionStrategy { ResolutionStrategy rs ->
rs.force("com.google.guava:guava:21.0")
}
}
dependencies {
compile project(':worldedit-libs:core')
compile 'de.schlichtherle:truezip:6.8.3'
compile 'rhino:js:1.7R2'
compile 'org.yaml:snakeyaml:1.9'
compile 'com.google.guava:guava:21.0'
compile 'com.google.code.findbugs:jsr305:1.3.9'
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.googlecode.json-simple:json-simple:1.1.1'
compile 'org.slf4j:slf4j-api:1.7.26'
compileOnly project(':worldedit-libs:core:ap')
annotationProcessor project(':worldedit-libs:core:ap')
annotationProcessor "com.google.guava:guava:21.0"
def avVersion = "1.6.5"
compileOnly "com.google.auto.value:auto-value-annotations:$avVersion"
annotationProcessor "com.google.auto.value:auto-value:$avVersion"
//compile 'net.sf.trove4j:trove4j:3.0.3'
testCompile 'org.mockito:mockito-core:1.9.0-rc1'
}
tasks.withType(JavaCompile).configureEach {
it.options.compilerArgs.add("-Aarg.name.key.prefix=")
}
sourceSets {
main {
java {
srcDir 'src/main/java'
srcDir 'src/legacy/java'
}
resources {
srcDir 'src/main/resources'
}
}
}

View File

@ -0,0 +1,49 @@
plugins {
id("java-library")
id("net.ltgt.apt-eclipse")
id("net.ltgt.apt-idea")
}
applyPlatformAndCoreConfiguration()
configurations.all {
resolutionStrategy {
force("com.google.guava:guava:21.0")
}
}
dependencies {
"compile"(project(":worldedit-libs:core"))
"compile"("de.schlichtherle:truezip:6.8.3")
"compile"("org.mozilla:rhino:1.7.11")
"compile"("org.yaml:snakeyaml:1.9")
"compile"("com.google.guava:guava:21.0")
"compile"("com.google.code.findbugs:jsr305:1.3.9")
"compile"("com.google.code.gson:gson:2.8.0")
"compile"("org.slf4j:slf4j-api:1.7.26")
"compileOnly"(project(":worldedit-libs:core:ap"))
"annotationProcessor"(project(":worldedit-libs:core:ap"))
// ensure this is on the classpath for the AP
"annotationProcessor"("com.google.guava:guava:21.0")
"compileOnly"("com.google.auto.value:auto-value-annotations:${Versions.AUTO_VALUE}")
"annotationProcessor"("com.google.auto.value:auto-value:${Versions.AUTO_VALUE}")
"testCompile"("org.mockito:mockito-core:1.9.0-rc1")
}
tasks.withType<JavaCompile>().configureEach {
dependsOn(":worldedit-libs:build")
options.compilerArgs.add("-Aarg.name.key.prefix=")
}
sourceSets {
main {
java {
srcDir("src/main/java")
srcDir("src/legacy/java")
}
resources {
srcDir("src/main/resources")
}
}
}

View File

@ -1,17 +1,15 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.3.31"
kotlin("jvm") version "1.3.41"
}
applyCommonConfiguration()
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
repositories {
jcenter()
}
dependencies {
"implementation"(project(":worldedit-libs:core:ap"))
"implementation"(project(":worldedit-core"))

View File

@ -180,7 +180,8 @@ public class BiomeCommands {
Mask2D mask2d = mask != null ? mask.toMask2D() : null;
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 {
region = session.getSelection(world);
}

View File

@ -26,6 +26,7 @@ import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.internal.anvil.ChunkDeleter;
import com.sk89q.worldedit.internal.anvil.ChunkDeletionInfo;
@ -34,6 +35,7 @@ import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
@ -50,8 +52,8 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.command.util.Logging.LogMode.REGION;
@ -93,11 +95,11 @@ public class ChunkCommands {
@CommandPermissions("worldedit.listchunks")
public void listChunks(Player player, LocalSession session,
@ArgFlag(name = 'p', desc = "Page number.", def = "1") int page) throws WorldEditException {
Set<BlockVector2> chunks = session.getSelection(player.getWorld()).getChunks();
final Region region = session.getSelection(player.getWorld());
PaginationBox paginationBox = PaginationBox.fromStrings("Selected Chunks", "/listchunks -p %page%",
chunks.stream().map(BlockVector2::toString).collect(Collectors.toList()));
player.print(paginationBox.create(page));
WorldEditAsyncCommandBuilder.createAndSendMessage(player,
() -> new ChunkListPaginationBox(region).create(page),
"Listing chunks for " + player.getName());
}
@Command(
@ -134,8 +136,8 @@ public class ChunkCommands {
newBatch.backup = true;
final Region selection = session.getSelection(player.getWorld());
if (selection instanceof CuboidRegion) {
newBatch.minChunk = BlockVector2.at(selection.getMinimumPoint().getBlockX() >> 4, selection.getMinimumPoint().getBlockZ() >> 4);
newBatch.maxChunk = BlockVector2.at(selection.getMaximumPoint().getBlockX() >> 4, selection.getMaximumPoint().getBlockZ() >> 4);
newBatch.minChunk = selection.getMinimumPoint().shr(4).toBlockVector2();
newBatch.maxChunk = selection.getMaximumPoint().shr(4).toBlockVector2();
} else {
// this has a possibility to OOM for very large selections still
Set<BlockVector2> chunks = selection.getChunks();
@ -168,4 +170,27 @@ public class ChunkCommands {
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop"))));
}
private static class ChunkListPaginationBox extends PaginationBox {
//private final Region region;
private final List<BlockVector2> chunks;
ChunkListPaginationBox(Region region) {
super("Selected Chunks", "/listchunks -p %page%");
// TODO make efficient/streamable/calculable implementations of this
// for most region types, so we can just store the region and random-access get one page of chunks
// (this is non-trivial for some types of selections...)
//this.region = region.clone();
this.chunks = new ArrayList<>(region.getChunks());
}
@Override
public Component getComponent(int number) {
return TextComponent.of(chunks.get(number).toString());
}
@Override
public int getComponentsSize() {
return chunks.size();
}
}
}

View File

@ -162,13 +162,13 @@ public class GenerationCommands {
final double radiusX, radiusY, radiusZ;
switch (radii.size()) {
case 1:
radiusX = radiusY = radiusZ = Math.max(1, radii.get(0));
radiusX = radiusY = radiusZ = Math.max(0, radii.get(0));
break;
case 3:
radiusX = Math.max(1, radii.get(0));
radiusY = Math.max(1, radii.get(1));
radiusZ = Math.max(1, radii.get(2));
radiusX = Math.max(0, radii.get(0));
radiusY = Math.max(0, radii.get(1));
radiusZ = Math.max(0, radii.get(2));
break;
default:
@ -205,7 +205,7 @@ public class GenerationCommands {
@Arg(desc = "The density of the forest, between 0 and 100", def = "5")
double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100");
density = density / 100;
density /= 100;
int affected = editSession.makeForest(session.getPlacementPosition(player), size, density, type);
player.print(affected + " trees created.");
return affected;

View File

@ -19,6 +19,8 @@
package com.sk89q.worldedit.command;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
@ -42,10 +44,10 @@ import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.formatting.component.CodeFormat;
import com.sk89q.worldedit.util.formatting.component.ErrorFormat;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SchematicPaginationBox;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.io.Closer;
import com.sk89q.worldedit.util.io.file.FilenameException;
@ -68,7 +70,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
@ -404,4 +408,44 @@ public class SchematicCommands {
}
return fileList;
}
private static class SchematicPaginationBox extends PaginationBox {
private final String prefix;
private final File[] files;
SchematicPaginationBox(String rootDir, File[] files, String pageCommand) {
super("Available schematics", pageCommand);
this.prefix = rootDir == null ? "" : rootDir;
this.files = files;
}
@Override
public Component getComponent(int number) {
checkArgument(number < files.length && number >= 0);
File file = files[number];
Multimap<String, ClipboardFormat> exts = ClipboardFormats.getFileExtensionMap();
String format = exts.get(Files.getFileExtension(file.getName()))
.stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown");
boolean inRoot = file.getParentFile().getName().equals(prefix);
String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1];
return TextComponent.builder()
.content("")
.append(TextComponent.of("[L]")
.color(TextColor.GOLD)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load"))))
.append(TextComponent.space())
.append(TextComponent.of(path)
.color(TextColor.DARK_GREEN)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format))))
.build();
}
@Override
public int getComponentsSize() {
return files.length;
}
}
}

View File

@ -19,6 +19,7 @@
package com.sk89q.worldedit.command;
import com.google.common.base.Strings;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
@ -56,16 +57,19 @@ import com.sk89q.worldedit.regions.selector.SphereRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.component.BlockDistributionResult;
import com.sk89q.worldedit.util.formatting.component.CommandListBox;
import com.sk89q.worldedit.util.formatting.component.InvalidComponentException;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SubtleFormat;
import com.sk89q.worldedit.util.formatting.component.TextComponentProducer;
import com.sk89q.worldedit.util.formatting.text.Component;
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.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.storage.ChunkStore;
@ -570,7 +574,7 @@ public class SelectionCommands {
}
case LIST:
default:
CommandListBox box = new CommandListBox("Selection modes", null);
CommandListBox box = new CommandListBox("Selection modes", null, null);
box.setHidingHelp(true);
TextComponentProducer contents = box.getContents();
contents.append(SubtleFormat.wrap("Select one of the modes below:")).newline();
@ -608,4 +612,62 @@ public class SelectionCommands {
session.dispatchCUISelection(player);
}
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);
}
}
}

View File

@ -523,7 +523,8 @@ public class UtilityCommands {
int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true)
List<String> command) throws WorldEditException {
PrintCommandHelp.help(command, page, listSubCommands, we, actor);
PrintCommandHelp.help(command, page, listSubCommands,
we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "//help");
}
}

View File

@ -164,6 +164,7 @@ public class WorldEditCommands {
int page,
@Arg(desc = "The command to retrieve help for", def = "", variable = true)
List<String> command) throws WorldEditException {
PrintCommandHelp.help(command, page, listSubCommands, we, actor);
PrintCommandHelp.help(command, page, listSubCommands,
we.getPlatformManager().getPlatformCommandManager().getCommandManager(), actor, "/worldedit help");
}
}

View File

@ -92,7 +92,7 @@ public class BrushTool implements TraceTool {
* @return the mask used to stop block traces
*/
public @Nullable Mask getTraceMask() {
return mask;
return this.traceMask;
}
/**

View File

@ -23,44 +23,78 @@ import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.util.LocatedBlock;
import com.sk89q.worldedit.util.collection.LocatedBlockList;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.LinkedHashSet;
import java.util.Set;
public class GravityBrush implements Brush {
private final boolean fullHeight;
public GravityBrush(boolean fullHeight) {
this.fullHeight = fullHeight;
}
@Override
public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException {
final double startY = fullHeight ? editSession.getWorld().getMaxY() : position.getBlockY() + size;
for (double x = position.getBlockX() + size; x > position.getBlockX() - size; --x) {
for (double z = position.getBlockZ() + size; z > position.getBlockZ() - size; --z) {
double y = startY;
final List<BlockState> blockTypes = new ArrayList<>();
for (; y > position.getBlockY() - size; --y) {
final BlockVector3 pt = BlockVector3.at(x, y, z);
final BlockState block = editSession.getBlock(pt);
if (!block.getBlockType().getMaterial().isAir()) {
blockTypes.add(block);
editSession.setBlock(pt, BlockTypes.AIR.getDefaultState());
double yMax = fullHeight ? editSession.getWorld().getMaxY() : position.getY() + size;
double yMin = Math.max(position.getY() - size, 0);
LocatedBlockList column = new LocatedBlockList();
Set<BlockVector3> removedBlocks = new LinkedHashSet<>();
for (double x = position.getX() - size; x <= position.getX() + size; x++) {
for (double z = position.getZ() - size; z <= position.getZ() + size; z++) {
/*
* Algorithm:
* 1. Find lowest air block in the selection -> $lowestAir = position
* 2. Move the first non-air block above it down to $lowestAir
* 3. Add 1 to $lowestAir's y-coord.
* 4. If more blocks above current position, repeat from 2
*/
BlockVector3 lowestAir = null;
for (double y = yMin; y <= yMax; y++) {
BlockVector3 pt = BlockVector3.at(x, y, z);
BaseBlock block = editSession.getFullBlock(pt);
if (block.getBlockType().getMaterial().isAir()) {
if (lowestAir == null) {
// we found the lowest air block
lowestAir = pt;
}
continue;
}
}
BlockVector3 pt = BlockVector3.at(x, y, z);
Collections.reverse(blockTypes);
for (int i = 0; i < blockTypes.size();) {
if (editSession.getBlock(pt).getBlockType().getMaterial().isAir()) {
editSession.setBlock(pt, blockTypes.get(i++));
if (lowestAir == null) {
// no place to move the block to
continue;
}
pt = pt.add(0, 1, 0);
BlockVector3 newPos = lowestAir;
// we know the block above must be air,
// since either this block is being moved into it,
// or there has been more air before this block
lowestAir = lowestAir.add(0, 1, 0);
removedBlocks.remove(newPos);
column.add(newPos, block);
removedBlocks.add(pt);
}
for (LocatedBlock block : column) {
editSession.setBlock(block.getLocation(), block.getBlock());
}
for (BlockVector3 removedBlock : removedBlocks) {
editSession.setBlock(removedBlock, BlockTypes.AIR.getDefaultState());
}
column.clear();
removedBlocks.clear();
}
}
}

View File

@ -67,11 +67,11 @@ public class PrintCommandHelp {
return mapping.orElse(null);
}
public static void help(List<String> commandPath, int page, boolean listSubCommands, WorldEdit we, Actor actor) throws InvalidComponentException {
CommandManager manager = we.getPlatformManager().getPlatformCommandManager().getCommandManager();
public static void help(List<String> commandPath, int page, boolean listSubCommands,
CommandManager manager, Actor actor, String helpRootCommand) throws InvalidComponentException {
if (commandPath.isEmpty()) {
printCommands(page, manager.getAllCommands(), actor, ImmutableList.of());
printCommands(page, manager.getAllCommands(), actor, ImmutableList.of(), helpRootCommand);
return;
}
@ -93,7 +93,7 @@ public class PrintCommandHelp {
toCommandString(visited), subCommand));
// full help for single command
CommandUsageBox box = new CommandUsageBox(visited, visited.stream()
.map(Command::getName).collect(Collectors.joining(" ")));
.map(Command::getName).collect(Collectors.joining(" ")), helpRootCommand);
actor.print(box.create());
return;
}
@ -105,7 +105,7 @@ public class PrintCommandHelp {
actor.printError(String.format("The sub-command '%s' under '%s' could not be found.",
subCommand, toCommandString(visited)));
// list subcommands for currentCommand
printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited);
printCommands(page, getSubCommands(Iterables.getLast(visited)).values().stream(), actor, visited, helpRootCommand);
return;
}
}
@ -114,10 +114,10 @@ public class PrintCommandHelp {
if (subCommands.isEmpty() || !listSubCommands) {
// Create the message
CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited));
CommandUsageBox box = new CommandUsageBox(visited, toCommandString(visited), helpRootCommand);
actor.print(box.create());
} else {
printCommands(page, subCommands.values().stream(), actor, visited);
printCommands(page, subCommands.values().stream(), actor, visited, helpRootCommand);
}
}
@ -126,7 +126,7 @@ public class PrintCommandHelp {
}
private static void printCommands(int page, Stream<Command> commandStream, Actor actor,
List<Command> commandList) throws InvalidComponentException {
List<Command> commandList, String helpRootCommand) throws InvalidComponentException {
// Get a list of aliases
List<Command> commands = commandStream
.sorted(byCleanName())
@ -135,7 +135,8 @@ public class PrintCommandHelp {
String used = commandList.isEmpty() ? null : toCommandString(commandList);
CommandListBox box = new CommandListBox(
(used == null ? "Help" : "Subcommands: " + used),
"//help -s -p %page%" + (used == null ? "" : " " + used));
helpRootCommand + " -s -p %page%" + (used == null ? "" : " " + used),
helpRootCommand);
if (!actor.isPlayer()) {
box.formatForConsole();
}

View File

@ -19,7 +19,10 @@
package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.NotABlockException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
@ -32,6 +35,7 @@ import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TargetBlock;
import com.sk89q.worldedit.util.auth.AuthorizationException;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -173,7 +177,7 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
if (spots == 2) {
final BlockVector3 platform = BlockVector3.at(x, y - 2, z);
final BlockState block = world.getBlock(platform);
final com.sk89q.worldedit.world.block.BlockType type = block.getBlockType();
final BlockType type = block.getBlockType();
// Don't get put in lava!
if (type == BlockTypes.LAVA) {
@ -259,6 +263,13 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
// Found a ceiling!
if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) {
int platformY = Math.max(initialY, y - 3 - clearance);
if (platformY < initialY) { // if ==, they already have the given clearance, if <, clearance is too large
printError("Not enough space above you!");
return false;
} else if (platformY == initialY) {
printError("You're already at the ceiling.");
return false;
}
floatAt(x, platformY + 1, z, alwaysGlass);
return true;
}
@ -302,25 +313,49 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
try {
if (alwaysGlass || !isAllowedToFly()) {
BlockVector3 spot = BlockVector3.at(x, y - 1, z);
if (!getLocation().getExtent().getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) {
getLocation().getExtent().setBlock(spot, BlockTypes.GLASS.getDefaultState());
final World world = getWorld();
if (!world.getBlock(spot).getBlockType().getMaterial().isMovementBlocker()) {
try (EditSession session = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, 1, this)) {
session.setBlock(spot, BlockTypes.GLASS.getDefaultState());
} catch (MaxChangedBlocksException ignored) {
}
}
} catch (WorldEditException e) {
e.printStackTrace();
} else {
setFlying(true);
}
setPosition(Vector3.at(x + 0.5, y, z + 0.5));
}
/**
* Check whether the player is allowed to fly.
*
* @return true if allowed flight
*/
protected boolean isAllowedToFly() {
return false;
}
/**
* Set whether the player is currently flying.
*
* @param flying true to fly
*/
protected void setFlying(boolean flying) {
}
@Override
public Location getBlockIn() {
return getLocation().setPosition(getLocation().toVector().floor());
final Location location = getLocation();
return location.setPosition(location.toVector().floor());
}
@Override
public Location getBlockOn() {
return getLocation().setPosition(getLocation().setY(getLocation().getY() - 1).toVector().floor());
final Location location = getLocation();
return location.setPosition(location.setY(location.getY() - 1).toVector().floor());
}
@Override
@ -369,15 +404,16 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public Direction getCardinalDirection(int yawOffset) {
if (getLocation().getPitch() > 67.5) {
final Location location = getLocation();
if (location.getPitch() > 67.5) {
return Direction.DOWN;
}
if (getLocation().getPitch() < -67.5) {
if (location.getPitch() < -67.5) {
return Direction.UP;
}
// From hey0's code
double rot = (getLocation().getYaw() + yawOffset) % 360; //let's use real yaw now
double rot = (location.getYaw() + yawOffset) % 360; //let's use real yaw now
if (rot < 0) {
rot += 360.0;
}
@ -394,51 +430,62 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
}
}
private boolean canPassThroughBlock(Location curBlock) {
BlockVector3 blockPos = curBlock.toVector().toBlockPoint();
BlockState block = curBlock.getExtent().getBlock(blockPos);
return !block.getBlockType().getMaterial().isMovementBlocker();
}
/**
* Get the player's view yaw.
*
* @return yaw
* Advances the block target block until the current block is a wall
* @return true if a wall is found
*/
@Override
public boolean passThroughForwardWall(int range) {
int searchDist = 0;
TargetBlock hitBlox = new TargetBlock(this, range, 0.2);
Extent world = getLocation().getExtent();
Location block;
boolean firstBlock = true;
int freeToFind = 2;
boolean inFree = false;
while ((block = hitBlox.getNextBlock()) != null) {
boolean free = !world.getBlock(block.toVector().toBlockPoint()).getBlockType().getMaterial().isMovementBlocker();
if (firstBlock) {
firstBlock = false;
if (!free) {
--freeToFind;
continue;
}
}
++searchDist;
if (searchDist > 20) {
return false;
}
if (inFree != free) {
if (free) {
--freeToFind;
}
}
if (freeToFind == 0) {
setOnGround(block);
private boolean advanceToWall(TargetBlock hitBlox) {
Location curBlock;
while ((curBlock = hitBlox.getCurrentBlock()) != null) {
if (!canPassThroughBlock(curBlock)) {
return true;
}
inFree = free;
hitBlox.getNextBlock();
}
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
public boolean passThroughForwardWall(int range) {
TargetBlock hitBlox = new TargetBlock(this, range, 0.2);
if (!advanceToWall(hitBlox)) {
return false;
}
if (!advanceToFree(hitBlox)) {
return false;
}
Location foundBlock = hitBlox.getCurrentBlock();
if (foundBlock != null) {
setOnGround(foundBlock);
return true;
}
return false;
@ -446,7 +493,8 @@ public abstract class AbstractPlayerActor implements Actor, Player, Cloneable {
@Override
public void setPosition(Vector3 pos) {
setPosition(pos, getLocation().getPitch(), getLocation().getYaw());
final Location location = getLocation();
setPosition(pos, location.getPitch(), location.getYaw());
}
@Override

View File

@ -178,4 +178,9 @@ class PlayerProxy extends AbstractPlayerActor {
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
basePlayer.sendFakeBlock(pos, block);
}
@Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
basePlayer.floatAt(x, y, z, alwaysGlass);
}
}

View File

@ -0,0 +1,67 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.extent;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Optional;
/**
* Base extent class for buffering changes between {@link #setBlock(BlockVector3, BlockStateHolder)}
* and the delegate extent. This class ensures that {@link #getBlock(BlockVector3)} is properly
* handled, by returning buffered blocks.
*/
public abstract class AbstractBufferingExtent extends AbstractDelegateExtent {
/**
* Create a new instance.
*
* @param extent the extent
*/
protected AbstractBufferingExtent(Extent extent) {
super(extent);
}
@Override
public abstract <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 location, T block) throws WorldEditException;
protected final <T extends BlockStateHolder<T>> boolean setDelegateBlock(BlockVector3 location, T block) throws WorldEditException {
return super.setBlock(location, block);
}
@Override
public BlockState getBlock(BlockVector3 position) {
return getBufferedBlock(position)
.map(BaseBlock::toImmutableState)
.orElseGet(() -> super.getBlock(position));
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
return getBufferedBlock(position)
.orElseGet(() -> super.getFullBlock(position));
}
protected abstract Optional<BaseBlock> getBufferedBlock(BlockVector3 position);
}

View File

@ -21,16 +21,16 @@ package com.sk89q.worldedit.extent.buffer;
import com.google.common.collect.Maps;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Map;
import java.util.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
@ -38,7 +38,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
* Buffers changes to an {@link Extent} and allows retrieval of the changed blocks,
* without modifying the underlying extent.
*/
public class ExtentBuffer extends AbstractDelegateExtent {
public class ExtentBuffer extends AbstractBufferingExtent {
private final Map<BlockVector3, BaseBlock> buffer = Maps.newHashMap();
private final Mask mask;
@ -67,23 +67,11 @@ public class ExtentBuffer extends AbstractDelegateExtent {
}
@Override
public BlockState getBlock(BlockVector3 position) {
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
if (mask.test(position)) {
return getOrDefault(position).toImmutableState();
return Optional.of(buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos))));
}
return super.getBlock(position);
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
if (mask.test(position)) {
return getOrDefault(position);
}
return super.getFullBlock(position);
}
private BaseBlock getOrDefault(BlockVector3 position) {
return buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos)));
return Optional.empty();
}
@Override

View File

@ -206,6 +206,8 @@ public class MCEditSchematicReader extends NBTSchematicReader {
}
if (values.isEmpty()) {
t = null;
} else {
t = new CompoundTag(values);
}
if (fixer != null && t != null) {
@ -378,6 +380,24 @@ public class MCEditSchematicReader extends NBTSchematicReader {
return "note_block";
case "Structure":
return "structure_block";
case "Chest":
return "chest";
case "Sign":
return "sign";
case "Banner":
return "banner";
case "Beacon":
return "beacon";
case "Comparator":
return "comparator";
case "Dropper":
return "dropper";
case "Furnace":
return "furnace";
case "Hopper":
return "hopper";
case "Skull":
return "skull";
default:
return id;
}

View File

@ -111,7 +111,7 @@ public class SpongeSchematicReader extends NBTSchematicReader {
} else if (dataVersion < liveDataVersion) {
fixer = platform.getDataFixer();
if (fixer != null) {
log.info("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.",
log.debug("Schematic was made in an older Minecraft version ({} < {}), will attempt DFU.",
dataVersion, liveDataVersion);
} else {
log.info("Schematic was made in an older Minecraft version ({} < {}), but DFU is not available. Data may be incompatible.",

View File

@ -260,8 +260,9 @@ public class SpongeSchematicWriter implements ClipboardWriter {
}
values.remove("id");
values.put("Id", new StringTag(state.getType().getId()));
values.put("Pos", writeVector(e.getLocation().toVector()));
values.put("Rotation", writeRotation(e.getLocation()));
final Location location = e.getLocation();
values.put("Pos", writeVector(location.toVector()));
values.put("Rotation", writeRotation(location));
return new CompoundTag(values);
}).filter(Objects::nonNull).collect(Collectors.toList());

View File

@ -19,22 +19,25 @@
package com.sk89q.worldedit.extent.reorder;
import com.google.common.collect.Table;
import com.google.common.collect.TreeBasedTable;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.RunContext;
import com.sk89q.worldedit.function.operation.SetLocatedBlocks;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.collection.LocatedBlockList;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
/**
* A special extent that batches changes into Minecraft chunks. This helps
@ -42,17 +45,19 @@ import java.util.TreeMap;
* loaded repeatedly, however it does take more memory due to caching the
* blocks.
*/
public class ChunkBatchingExtent extends AbstractDelegateExtent {
public class ChunkBatchingExtent extends AbstractBufferingExtent {
/**
* Comparator optimized for sorting chunks by the region file they reside
* in. This allows for file caches to be used while loading the chunk.
*/
private static final Comparator<BlockVector2> REGION_OPTIMIZED_SORT =
Comparator.comparing((BlockVector2 vec) -> vec.divide(32), BlockVector2.COMPARING_GRID_ARRANGEMENT)
Comparator.comparing((BlockVector2 vec) -> vec.shr(5), BlockVector2.COMPARING_GRID_ARRANGEMENT)
.thenComparing(BlockVector2.COMPARING_GRID_ARRANGEMENT);
private final SortedMap<BlockVector2, LocatedBlockList> batches = new TreeMap<>(REGION_OPTIMIZED_SORT);
private final Table<BlockVector2, BlockVector3, BaseBlock> batches =
TreeBasedTable.create(REGION_OPTIMIZED_SORT, BlockVector3.sortByCoordsYzx());
private final Set<BlockVector3> containedBlocks = new HashSet<>();
private boolean enabled;
public ChunkBatchingExtent(Extent extent) {
@ -76,16 +81,34 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
return enabled;
}
private BlockVector2 getChunkPos(BlockVector3 location) {
return location.shr(4).toBlockVector2();
}
private BlockVector3 getInChunkPos(BlockVector3 location) {
return BlockVector3.at(location.getX() & 15, location.getY(), location.getZ() & 15);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
if (!enabled) {
return getExtent().setBlock(location, block);
return setDelegateBlock(location, block);
}
BlockVector2 chunkPos = BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4);
batches.computeIfAbsent(chunkPos, k -> new LocatedBlockList()).add(location, block);
BlockVector2 chunkPos = getChunkPos(location);
BlockVector3 inChunkPos = getInChunkPos(location);
batches.put(chunkPos, inChunkPos, block.toBaseBlock());
containedBlocks.add(location);
return true;
}
@Override
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
if (!containedBlocks.contains(position)) {
return Optional.empty();
}
return Optional.of(batches.get(getChunkPos(position), getInChunkPos(position)));
}
@Override
protected Operation commitBefore() {
if (!commitRequired()) {
@ -94,17 +117,22 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
return new Operation() {
// we get modified between create/resume -- only create this on resume to prevent CME
private Iterator<LocatedBlockList> batchIterator;
private Iterator<Map.Entry<BlockVector2, Map<BlockVector3, BaseBlock>>> batchIterator;
@Override
public Operation resume(RunContext run) throws WorldEditException {
if (batchIterator == null) {
batchIterator = batches.values().iterator();
batchIterator = batches.rowMap().entrySet().iterator();
}
if (!batchIterator.hasNext()) {
return null;
}
new SetLocatedBlocks(getExtent(), batchIterator.next()).resume(run);
Map.Entry<BlockVector2, Map<BlockVector3, BaseBlock>> next = batchIterator.next();
BlockVector3 chunkOffset = next.getKey().toBlockVector3().shl(4);
for (Map.Entry<BlockVector3, BaseBlock> block : next.getValue().entrySet()) {
getExtent().setBlock(block.getKey().add(chunkOffset), block.getValue());
containedBlocks.remove(block.getKey());
}
batchIterator.remove();
return this;
}

View File

@ -20,7 +20,7 @@
package com.sk89q.worldedit.extent.reorder;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.OperationQueue;
@ -36,13 +36,17 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
/**
* Re-orders blocks into several stages.
*/
public class MultiStageReorder extends AbstractDelegateExtent implements ReorderingExtent {
public class MultiStageReorder extends AbstractBufferingExtent implements ReorderingExtent {
private static final Map<BlockType, PlacementPriority> priorityMap = new HashMap<>();
@ -139,6 +143,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL);
}
private final Set<BlockVector3> containedBlocks = new HashSet<>();
private Map<PlacementPriority, LocatedBlockList> stages = new HashMap<>();
private boolean enabled;
@ -212,7 +217,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
if (!enabled) {
return super.setBlock(location, block);
return setDelegateBlock(location, block);
}
BlockState existing = getBlock(location);
@ -240,9 +245,21 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
}
stages.get(priority).add(location, block);
containedBlocks.add(location);
return !existing.equalsFuzzy(block);
}
@Override
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
if (!containedBlocks.contains(position)) {
return Optional.empty();
}
return stages.values().stream()
.map(blocks -> blocks.get(position))
.filter(Objects::nonNull)
.findAny();
}
@Override
public Operation commitBefore() {
if (!commitRequired()) {

View File

@ -55,7 +55,9 @@ public class BlockOptimizedHistory extends ArrayListHistory {
if (change instanceof BlockChange) {
BlockChange blockChange = (BlockChange) change;
BlockVector3 position = blockChange.getPosition();
previous.add(position, blockChange.getPrevious());
if (!previous.containsLocation(position)) {
previous.add(position, blockChange.getPrevious());
}
current.add(position, blockChange.getCurrent());
} else {
super.add(change);

View File

@ -32,6 +32,7 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
@ -114,11 +115,12 @@ public class ServerCUIHandler {
}
// Borrowed this math from FAWE
double rotX = player.getLocation().getYaw();
double rotY = player.getLocation().getPitch();
final Location location = player.getLocation();
double rotX = location.getYaw();
double rotY = location.getPitch();
double xz = Math.cos(Math.toRadians(rotY));
int x = (int) (player.getLocation().getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12);
int z = (int) (player.getLocation().getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12);
int x = (int) (location.getX() - (-xz * Math.sin(Math.toRadians(rotX))) * 12);
int z = (int) (location.getZ() - (xz * Math.cos(Math.toRadians(rotX))) * 12);
int y = Math.max(0, Math.min(Math.min(255, posY + 32), posY + 3));
Map<String, Tag> structureTag = new HashMap<>();

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.math;
import com.google.common.collect.ComparisonChain;
import com.sk89q.worldedit.math.transform.AffineTransform;
import java.util.Comparator;
@ -28,7 +27,7 @@ import java.util.Comparator;
* An immutable 2-dimensional vector.
*/
public final class BlockVector2 {
public static final BlockVector2 ZERO = new BlockVector2(0, 0);
public static final BlockVector2 UNIT_X = new BlockVector2(1, 0);
public static final BlockVector2 UNIT_Z = new BlockVector2(0, 1);
@ -48,12 +47,8 @@ public final class BlockVector2 {
* cdef
* </pre>
*/
public static final Comparator<BlockVector2> COMPARING_GRID_ARRANGEMENT = (a, b) -> {
return ComparisonChain.start()
.compare(a.getBlockZ(), b.getBlockZ())
.compare(a.getBlockX(), b.getBlockX())
.result();
};
public static final Comparator<BlockVector2> COMPARING_GRID_ARRANGEMENT =
Comparator.comparingInt(BlockVector2::getZ).thenComparingInt(BlockVector2::getX);
public static BlockVector2 at(double x, double z) {
return at((int) Math.floor(x), (int) Math.floor(z));
@ -303,6 +298,27 @@ public final class BlockVector2 {
return divide(n, n);
}
/**
* Shift all components right.
*
* @param x the value to shift x by
* @param z the value to shift z by
* @return a new vector
*/
public BlockVector2 shr(int x, int z) {
return at(this.x >> x, this.z >> z);
}
/**
* Shift all components right by {@code n}.
*
* @param n the value to shift by
* @return a new vector
*/
public BlockVector2 shr(int n) {
return shr(n, n);
}
/**
* Get the length of the vector.
*
@ -532,5 +548,4 @@ public final class BlockVector2 {
public String toString() {
return "(" + x + ", " + z + ")";
}
}

View File

@ -19,13 +19,12 @@
package com.sk89q.worldedit.math;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.collect.ComparisonChain;
import com.sk89q.worldedit.math.transform.AffineTransform;
import java.util.Comparator;
import static com.google.common.base.Preconditions.checkArgument;
/**
* An immutable 3-dimensional vector.
*/
@ -64,18 +63,15 @@ public final class BlockVector3 {
// thread-safe initialization idiom
private static final class YzxOrderComparator {
private static final Comparator<BlockVector3> YZX_ORDER = (a, b) -> {
return ComparisonChain.start()
.compare(a.y, b.y)
.compare(a.z, b.z)
.compare(a.x, b.x)
.result();
};
private static final Comparator<BlockVector3> YZX_ORDER =
Comparator.comparingInt(BlockVector3::getY)
.thenComparingInt(BlockVector3::getZ)
.thenComparingInt(BlockVector3::getX);
}
/**
* Returns a comparator that sorts vectors first by Y, then Z, then X.
*
*
* <p>
* Useful for sorting by chunk block storage order.
*/
@ -348,6 +344,50 @@ public final class BlockVector3 {
return divide(n, n, n);
}
/**
* Shift all components right.
*
* @param x the value to shift x by
* @param y the value to shift y by
* @param z the value to shift z by
* @return a new vector
*/
public BlockVector3 shr(int x, int y, int z) {
return at(this.x >> x, this.y >> y, this.z >> z);
}
/**
* Shift all components right by {@code n}.
*
* @param n the value to shift by
* @return a new vector
*/
public BlockVector3 shr(int n) {
return shr(n, n, n);
}
/**
* Shift all components left.
*
* @param x the value to shift x by
* @param y the value to shift y by
* @param z the value to shift z by
* @return a new vector
*/
public BlockVector3 shl(int x, int y, int z) {
return at(this.x << x, this.y << y, this.z << z);
}
/**
* Shift all components left by {@code n}.
*
* @param n the value to shift by
* @return a new vector
*/
public BlockVector3 shl(int n) {
return shl(n, n, n);
}
/**
* Get the length of the vector.
*

View File

@ -0,0 +1,41 @@
/*
* 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.scripting;
import org.mozilla.javascript.ClassShutter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Hides Minecraft's obfuscated & de-obfuscated names from scripts.
*/
class MinecraftHidingClassShutter implements ClassShutter {
private static final Logger LOGGER = LoggerFactory.getLogger(MinecraftHidingClassShutter.class);
@Override
public boolean visibleToScripts(String fullClassName) {
if (!fullClassName.contains(".")) {
// Default package -- probably Minecraft
return false;
}
return !fullClassName.startsWith("net.minecraft");
}
}

View File

@ -50,6 +50,7 @@ public class RhinoCraftScriptEngine implements CraftScriptEngine {
throws ScriptException, Throwable {
RhinoContextFactory factory = new RhinoContextFactory(timeLimit);
Context cx = factory.enterContext();
cx.setClassShutter(new MinecraftHidingClassShutter());
ScriptableObject scriptable = new ImporterTopLevel(cx);
Scriptable scope = cx.initStandardObjects(scriptable);

View File

@ -1,134 +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.scripting.java;
import com.sk89q.worldedit.scripting.RhinoContextFactory;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import java.io.IOException;
import java.io.Reader;
import javax.script.AbstractScriptEngine;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
public class RhinoScriptEngine extends AbstractScriptEngine {
private ScriptEngineFactory factory;
private Context cx;
public RhinoScriptEngine() {
RhinoContextFactory factory = new RhinoContextFactory(3000);
factory.enterContext();
}
@Override
public Bindings createBindings() {
return new SimpleBindings();
}
@Override
public Object eval(String script, ScriptContext context)
throws ScriptException {
Scriptable scope = setupScope(cx, context);
String filename = (filename = (String) get(ScriptEngine.FILENAME)) == null
? "<unknown>" : filename;
try {
return cx.evaluateString(scope, script, filename, 1, null);
} catch (RhinoException e) {
String msg;
int line = (line = e.lineNumber()) == 0 ? -1 : line;
if (e instanceof JavaScriptException) {
msg = String.valueOf(((JavaScriptException) e).getValue());
} else {
msg = e.getMessage();
}
ScriptException scriptException =
new ScriptException(msg, e.sourceName(), line);
scriptException.initCause(e);
throw scriptException;
} finally {
Context.exit();
}
}
@Override
public Object eval(Reader reader, ScriptContext context)
throws ScriptException {
Scriptable scope = setupScope(cx, context);
String filename = (filename = (String) get(ScriptEngine.FILENAME)) == null
? "<unknown>" : filename;
try {
return cx.evaluateReader(scope, reader, filename, 1, null);
} catch (RhinoException e) {
String msg;
int line = (line = e.lineNumber()) == 0 ? -1 : line;
if (e instanceof JavaScriptException) {
msg = String.valueOf(((JavaScriptException) e).getValue());
} else {
msg = e.getMessage();
}
ScriptException scriptException =
new ScriptException(msg, e.sourceName(), line);
scriptException.initCause(e);
throw scriptException;
} catch (IOException e) {
throw new ScriptException(e);
} finally {
Context.exit();
}
}
@Override
public ScriptEngineFactory getFactory() {
if (factory != null) {
return factory;
} else {
return new RhinoScriptEngineFactory();
}
}
private Scriptable setupScope(Context cx, ScriptContext context) {
ScriptableObject scriptable = new ImporterTopLevel(cx);
Scriptable scope = cx.initStandardObjects(scriptable);
//ScriptableObject.putProperty(scope, "argv", Context.javaToJS(args, scope));
return scope;
}
}

View File

@ -1,153 +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.scripting.java;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
public class RhinoScriptEngineFactory implements ScriptEngineFactory {
private static List<String> names;
private static List<String> mimeTypes;
private static List<String> extensions;
static {
names = new ArrayList<>(5);
names.add("ECMAScript");
names.add("ecmascript");
names.add("JavaScript");
names.add("javascript");
names.add("js");
names = Collections.unmodifiableList(names);
mimeTypes = new ArrayList<>(4);
mimeTypes.add("application/ecmascript");
mimeTypes.add("text/ecmascript");
mimeTypes.add("application/javascript");
mimeTypes.add("text/javascript");
mimeTypes = Collections.unmodifiableList(mimeTypes);
extensions = new ArrayList<>(2);
extensions.add("emcascript");
extensions.add("js");
extensions = Collections.unmodifiableList(extensions);
}
@Override
public String getEngineName() {
return "Rhino JavaScript Engine (SK)";
}
@Override
public String getEngineVersion() {
return "unknown";
}
@Override
public List<String> getExtensions() {
return extensions;
}
@Override
public String getLanguageName() {
return "EMCAScript";
}
@Override
public String getLanguageVersion() {
return "1.8";
}
@Override
public String getMethodCallSyntax(String obj, String m, String... args) {
StringBuilder s = new StringBuilder();
s.append(obj);
s.append(".");
s.append(m);
s.append("(");
for (int i = 0; i < args.length; ++i) {
s.append(args[i]);
if (i < args.length - 1) {
s.append(",");
}
}
s.append(")");
return s.toString();
}
@Override
public List<String> getMimeTypes() {
return mimeTypes;
}
@Override
public List<String> getNames() {
return names;
}
@Override
public String getOutputStatement(String str) {
return "print(" + str.replace("\\", "\\\\")
.replace("\"", "\\\\\"")
.replace(";", "\\\\;") + ")";
}
@Override
public Object getParameter(String key) {
switch (key) {
case ScriptEngine.ENGINE:
return getEngineName();
case ScriptEngine.ENGINE_VERSION:
return getEngineVersion();
case ScriptEngine.NAME:
return getEngineName();
case ScriptEngine.LANGUAGE:
return getLanguageName();
case ScriptEngine.LANGUAGE_VERSION:
return getLanguageVersion();
case "THREADING":
return "MULTITHREADED";
default:
throw new IllegalArgumentException("Invalid key");
}
}
@Override
public String getProgram(String... statements) {
StringBuilder s = new StringBuilder();
for (String stmt : statements) {
s.append(stmt);
s.append(";");
}
return s.toString();
}
@Override
public ScriptEngine getScriptEngine() {
return new RhinoScriptEngine();
}
}

View File

@ -21,68 +21,72 @@ package com.sk89q.worldedit.util.collection;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.LocatedBlock;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
/**
* Wrapper around a list of blocks located in the world.
*/
public class LocatedBlockList implements Iterable<LocatedBlock> {
private final List<LocatedBlock> list;
private final Map<BlockVector3, LocatedBlock> map = new LinkedHashMap<>();
public LocatedBlockList() {
list = new ArrayList<>();
}
public LocatedBlockList(Collection<? extends LocatedBlock> collection) {
list = new ArrayList<>(collection);
for (LocatedBlock locatedBlock : collection) {
map.put(locatedBlock.getLocation(), locatedBlock);
}
}
public void add(LocatedBlock setBlockCall) {
checkNotNull(setBlockCall);
list.add(setBlockCall);
map.put(setBlockCall.getLocation(), setBlockCall);
}
public <B extends BlockStateHolder<B>> void add(BlockVector3 location, B block) {
add(new LocatedBlock(location, block.toBaseBlock()));
}
public boolean containsLocation(BlockVector3 location) {
return map.containsKey(location);
}
public @Nullable BaseBlock get(BlockVector3 location) {
return map.get(location).getBlock();
}
public int size() {
return list.size();
return map.size();
}
public void clear() {
list.clear();
map.clear();
}
@Override
public Iterator<LocatedBlock> iterator() {
return list.iterator();
return map.values().iterator();
}
public Iterator<LocatedBlock> reverseIterator() {
return new Iterator<LocatedBlock>() {
private final ListIterator<LocatedBlock> backingIterator = list.listIterator(list.size());
@Override
public boolean hasNext() {
return backingIterator.hasPrevious();
}
@Override
public LocatedBlock next() {
return backingIterator.previous();
}
};
List<LocatedBlock> data = new ArrayList<>(map.values());
Collections.reverse(data);
return data.iterator();
}
}

View File

@ -1,90 +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.util.formatting.component;
import com.google.common.base.Strings;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import java.util.List;
public class BlockDistributionResult extends PaginationBox {
private final List<Countable<BlockState>> distribution;
private final int totalBlocks;
private final boolean separateStates;
public 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);
}
}

View File

@ -32,14 +32,16 @@ public class CommandListBox extends PaginationBox {
private List<CommandEntry> commands = Lists.newArrayList();
private boolean hideHelp;
private String helpCommand;
/**
* Create a new box.
*
* @param title the title
*/
public CommandListBox(String title, String pageCommand) {
public CommandListBox(String title, String pageCommand, String helpCommand) {
super(title, pageCommand);
this.helpCommand = helpCommand;
}
@Override
@ -72,7 +74,7 @@ public class CommandListBox extends PaginationBox {
this.hideHelp = hideHelp;
}
private static class CommandEntry {
private class CommandEntry {
private final String alias;
private final Component description;
private final String insertion;
@ -87,7 +89,7 @@ public class CommandListBox extends PaginationBox {
TextComponentProducer line = new TextComponentProducer();
if (!hideHelp) {
line.append(SubtleFormat.wrap("? ")
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "//help " + insertion))
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, CommandListBox.this.helpCommand + " " + insertion))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Additional Help"))));
}
TextComponent command = TextComponent.of(alias, TextColor.GOLD);

View File

@ -45,9 +45,10 @@ public class CommandUsageBox extends TextComponentProducer {
*
* @param commands the commands to describe
* @param commandString the commands that were used, such as "/we" or "/brush sphere"
* @param helpRootCommand the command used to get subcommand help
*/
public CommandUsageBox(List<Command> commands, String commandString) throws InvalidComponentException {
this(commands, commandString, null);
public CommandUsageBox(List<Command> commands, String commandString, String helpRootCommand) throws InvalidComponentException {
this(commands, commandString, helpRootCommand, null);
}
/**
@ -55,15 +56,18 @@ public class CommandUsageBox extends TextComponentProducer {
*
* @param commands the commands to describe
* @param commandString the commands that were used, such as "/we" or "/brush sphere"
* @param helpRootCommand the command used to get subcommand help
* @param parameters list of parameters to use
*/
public CommandUsageBox(List<Command> commands, String commandString, @Nullable CommandParameters parameters) throws InvalidComponentException {
public CommandUsageBox(List<Command> commands, String commandString, String helpRootCommand,
@Nullable CommandParameters parameters) throws InvalidComponentException {
checkNotNull(commands);
checkNotNull(commandString);
attachCommandUsage(commands, commandString);
checkNotNull(helpRootCommand);
attachCommandUsage(commands, commandString, helpRootCommand);
}
private void attachCommandUsage(List<Command> commands, String commandString) {
private void attachCommandUsage(List<Command> commands, String commandString, String helpRootCommand) {
TextComponentProducer boxContent = new TextComponentProducer()
.append(HelpGenerator.create(commands).getFullHelp());
if (getSubCommands(Iterables.getLast(commands)).size() > 0) {
@ -73,7 +77,7 @@ public class CommandUsageBox extends TextComponentProducer {
.append(TextComponent.builder("List Subcommands")
.color(ColorConfig.getMainText())
.decoration(TextDecoration.ITALIC, true)
.clickEvent(ClickEvent.runCommand("//help -s " + commandString))
.clickEvent(ClickEvent.runCommand(helpRootCommand + " -s " + commandString))
.hoverEvent(HoverEvent.showText(TextComponent.of("List all subcommands of this command")))
.build())
.build());

View File

@ -1,75 +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.util.formatting.component;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.util.formatting.text.Component;
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.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import java.io.File;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
public class SchematicPaginationBox extends PaginationBox {
private final String prefix;
private final File[] files;
public SchematicPaginationBox(String rootDir, File[] files, String pageCommand) {
super("Available schematics", pageCommand);
this.prefix = rootDir == null ? "" : rootDir;
this.files = files;
}
@Override
public Component getComponent(int number) {
checkArgument(number < files.length && number >= 0);
File file = files[number];
Multimap<String, ClipboardFormat> exts = ClipboardFormats.getFileExtensionMap();
String format = exts.get(Files.getFileExtension(file.getName()))
.stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown");
boolean inRoot = file.getParentFile().getName().equals(prefix);
String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1];
return TextComponent.builder()
.content("")
.append(TextComponent.of("[L]")
.color(TextColor.GOLD)
.clickEvent(ClickEvent.of(ClickEvent.Action.RUN_COMMAND, "/schem load " + path))
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to load"))))
.append(TextComponent.space())
.append(TextComponent.of(path)
.color(TextColor.DARK_GREEN)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TextComponent.of(format))))
.build();
}
@Override
public int getComponentsSize() {
return files.length;
}
}

View File

@ -19,8 +19,9 @@
package com.sk89q.worldedit.util.paste;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.sk89q.worldedit.util.net.HttpRequest;
import org.json.simple.JSONValue;
import java.io.IOException;
import java.net.URL;
@ -33,6 +34,8 @@ public class EngineHubPaste implements Paster {
private static final Pattern URL_PATTERN = Pattern.compile("https?://.+$");
private static final Gson GSON = new Gson();
@Override
public Callable<URL> paste(String content) {
return new PasteTask(content);
@ -59,10 +62,10 @@ public class EngineHubPaste implements Paster {
.returnContent()
.asString("UTF-8").trim();
Object object = JSONValue.parse(result);
if (object instanceof Map) {
@SuppressWarnings("unchecked")
String urlString = String.valueOf(((Map<Object, Object>) object).get("url"));
Map<Object, Object> object = GSON.fromJson(result, new TypeToken<Map<Object, Object>>() {
}.getType());
if (object != null) {
String urlString = String.valueOf(object.get("url"));
Matcher m = URL_PATTERN.matcher(urlString);
if (m.matches()) {

View File

@ -19,19 +19,20 @@
package com.sk89q.minecraft.util.commands;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.HashSet;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class CommandContextTest {
@ -39,7 +40,7 @@ public class CommandContextTest {
private static final String firstCmdString = "herpderp -opw testers \"mani world\" 'another thing' because something";
CommandContext firstCommand;
@Before
@BeforeEach
public void setUpTest() {
try {
firstCommand = new CommandContext(firstCmdString, new HashSet<>(Arrays.asList('o', 'w')));
@ -49,10 +50,12 @@ public class CommandContextTest {
}
}
@Test(expected = CommandException.class)
public void testInvalidFlags() throws CommandException {
@Test
public void testInvalidFlags() {
final String failingCommand = "herpderp -opw testers";
new CommandContext(failingCommand, new HashSet<>(Arrays.asList('o', 'w')));
assertThrows(CommandException.class, () -> {
new CommandContext(failingCommand, new HashSet<>(Arrays.asList('o', 'w')));
});
}
@Test

View File

@ -19,33 +19,33 @@
package com.sk89q.worldedit.extent.transform;
import static org.junit.Assert.assertEquals;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.Set;
@Ignore("A platform is currently required to get properties, preventing this test.")
import static org.junit.jupiter.api.Assertions.assertEquals;
@Disabled("A platform is currently required to get properties, preventing this test.")
public class BlockTransformExtentTest {
private static final Transform ROTATE_90 = new AffineTransform().rotateY(-90);
private static final Transform ROTATE_NEG_90 = new AffineTransform().rotateY(90);
private final Set<BlockType> ignored = new HashSet<>();
@Before
public void setUp() throws Exception {
@BeforeEach
public void setUp() {
BlockType.REGISTRY.register("worldedit:test", new BlockType("worldedit:test"));
}
@Test
public void testTransform() throws Exception {
public void testTransform() {
for (BlockType type : BlockType.REGISTRY.values()) {
if (ignored.contains(type)) {
continue;

View File

@ -21,10 +21,10 @@ package com.sk89q.worldedit.internal.command;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.internal.util.Substring;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static com.sk89q.worldedit.internal.command.CommandArgParser.spaceSplit;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CommandArgParserTest {
@Test

View File

@ -19,16 +19,6 @@
package com.sk89q.worldedit.internal.expression;
import static java.lang.Math.atan2;
import static java.lang.Math.sin;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Platform;
@ -36,9 +26,20 @@ import com.sk89q.worldedit.internal.expression.lexer.LexerException;
import com.sk89q.worldedit.internal.expression.parser.ParserException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static java.lang.Math.atan2;
import static java.lang.Math.sin;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ExpressionTest {
@Before
@BeforeEach
public void setup() {
Platform mockPlat = Mockito.mock(Platform.class);
Mockito.when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() {
@ -51,7 +52,7 @@ public class ExpressionTest {
@Test
public void testEvaluate() throws ExpressionException {
// check
// check
assertEquals(1 - 2 + 3, simpleEval("1 - 2 + 3"), 0);
// check unary ops
@ -68,56 +69,46 @@ public class ExpressionTest {
}
@Test
public void testErrors() throws ExpressionException {
// test lexer errors
try {
compile("#");
fail("Error expected");
} catch (LexerException e) {
assertEquals("Error position", 0, e.getPosition());
}
// test parser errors
try {
compile("x");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
}
try {
compile("x()");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
}
try {
compile("(");
fail("Error expected");
} catch (ParserException ignored) {}
try {
compile("x(");
fail("Error expected");
} catch (ParserException ignored) {}
// test overloader errors
try {
compile("atan2(1)");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
}
try {
compile("atan2(1, 2, 3)");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
}
try {
compile("rotate(1, 2, 3)");
fail("Error expected");
} catch (ParserException e) {
assertEquals("Error position", 0, e.getPosition());
}
public void testErrors() {
assertAll(
// test lexer errors
() -> {
LexerException e = assertThrows(LexerException.class,
() -> compile("#"));
assertEquals(0, e.getPosition(), "Error position");
},
// test parser errors
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("x"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("x()"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> assertThrows(ParserException.class,
() -> compile("(")),
() -> assertThrows(ParserException.class,
() -> compile("x(")),
// test overloader errors
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("atan2(1)"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("atan2(1, 2, 3)"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("rotate(1, 2, 3)"));
assertEquals(0, e.getPosition(), "Error position");
}
);
}
@Test
@ -181,13 +172,11 @@ public class ExpressionTest {
}
@Test
public void testTimeout() throws Exception {
try {
simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}");
fail("Loop was not stopped.");
} catch (EvaluationException e) {
assertTrue(e.getMessage().contains("Calculations exceeded time limit"));
}
public void testTimeout() {
ExpressionTimeoutException e = assertThrows(ExpressionTimeoutException.class,
() -> simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"),
"Loop was not stopped.");
assertTrue(e.getMessage().contains("Calculations exceeded time limit"));
}
private double simpleEval(String expressionString) throws ExpressionException {

View File

@ -19,12 +19,12 @@
package com.sk89q.worldedit.util;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.world.World;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
/**
* Tests {@link Location}.

View File

@ -19,14 +19,14 @@
package com.sk89q.worldedit.util.eventbus;
import org.junit.Test;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class EventBusTest {