geforkt von Mirrors/FastAsyncWorldEdit
Move the pasting system over to WorldEdit, and add a /we report command. Currently only reports system status and the config. Need to add a platform reporter system.
Dieser Commit ist enthalten in:
Ursprung
54142c8669
Commit
45f1de6009
@ -14,6 +14,7 @@
|
||||
<allow pkg="gnu.trove"/>
|
||||
<allow pkg="com.google.gson"/>
|
||||
<allow pkg="net.royawesome.jlibnoise"/>
|
||||
<allow pkg="org.json.simple" />
|
||||
|
||||
<subpackage name="util.yaml">
|
||||
<allow pkg="org.yaml.snakeyaml"/>
|
||||
|
@ -21,6 +21,7 @@ package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.sk89q.util.yaml.YAMLProcessor;
|
||||
import com.sk89q.worldedit.util.YAMLConfiguration;
|
||||
import com.sk89q.worldedit.util.report.Unreported;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@ -30,7 +31,7 @@ import java.io.File;
|
||||
public class BukkitConfiguration extends YAMLConfiguration {
|
||||
|
||||
public boolean noOpPermissions = false;
|
||||
private final WorldEditPlugin plugin;
|
||||
@Unreported private final WorldEditPlugin plugin;
|
||||
|
||||
public BukkitConfiguration(YAMLProcessor config, WorldEditPlugin plugin) {
|
||||
super(config, plugin.getLogger());
|
||||
|
@ -12,6 +12,8 @@ dependencies {
|
||||
compile 'com.thoughtworks.paranamer:paranamer:2.6'
|
||||
compile 'com.google.code.gson:gson:2.8.0'
|
||||
compile 'com.sk89q.lib:jlibnoise:1.0.0'
|
||||
compile 'com.googlecode.json-simple:json-simple:1.1.1'
|
||||
//compile 'net.sf.trove4j:trove4j:3.0.3'
|
||||
testCompile 'org.mockito:mockito-core:1.9.0-rc1'
|
||||
|
||||
// Fawe depends
|
||||
|
@ -57,6 +57,8 @@ import com.sk89q.worldedit.util.io.file.FilenameException;
|
||||
import com.sk89q.worldedit.util.io.file.FilenameResolutionException;
|
||||
import com.sk89q.worldedit.util.io.file.InvalidFilenameException;
|
||||
import com.sk89q.worldedit.util.logging.WorldEditPrefixHandler;
|
||||
import com.sk89q.worldedit.util.task.SimpleSupervisor;
|
||||
import com.sk89q.worldedit.util.task.Supervisor;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
||||
@ -101,6 +103,7 @@ public class WorldEdit {
|
||||
private final PlatformManager platformManager = new PlatformManager(this);
|
||||
private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl(eventBus);
|
||||
private final SessionManager sessions = new SessionManager(this);
|
||||
private final Supervisor supervisor = new SimpleSupervisor();
|
||||
|
||||
private final BlockFactory blockFactory = new BlockFactory(this);
|
||||
private final ItemFactory itemFactory = new ItemFactory(this);
|
||||
@ -150,6 +153,16 @@ public class WorldEdit {
|
||||
return eventBus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the supervisor.
|
||||
*
|
||||
* @return the supervisor
|
||||
*/
|
||||
public Supervisor getSupervisor() {
|
||||
return supervisor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the block factory from which new {@link BlockStateHolder}s can be
|
||||
* constructed.
|
||||
|
@ -28,6 +28,7 @@ import com.boydti.fawe.util.HastebinUtility;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.Updater;
|
||||
import com.google.common.io.Files;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
@ -40,6 +41,18 @@ import com.sk89q.worldedit.extension.platform.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
import com.sk89q.worldedit.util.paste.ActorCallbackPaste;
|
||||
import com.sk89q.worldedit.util.report.ConfigReport;
|
||||
import com.sk89q.worldedit.util.report.ReportList;
|
||||
import com.sk89q.worldedit.util.report.SystemInfoReport;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
@ -189,7 +202,8 @@ public class WorldEditCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.debugpaste")
|
||||
public void debugpaste(Actor actor) throws WorldEditException, IOException {
|
||||
BBC.DOWNLOAD_LINK.send(actor, HastebinUtility.debugPaste());
|
||||
// BBC.DOWNLOAD_LINK.send(actor, HastebinUtility.debugPaste());
|
||||
ActorCallbackPaste.pastebin(we.getSupervisor(), actor, null, "FastAsyncWorldEdit report: " + BBC.DOWNLOAD_LINK);
|
||||
}
|
||||
|
||||
@Command(
|
||||
@ -213,6 +227,28 @@ public class WorldEditCommands {
|
||||
}
|
||||
}
|
||||
|
||||
// @Command(aliases = {"report"}, desc = "Writes a report on WorldEdit", flags = "p", max = 0)
|
||||
// @CommandPermissions({"worldedit.report"})
|
||||
// public void report(Actor actor, CommandContext args) throws WorldEditException {
|
||||
// ReportList report = new ReportList("Report");
|
||||
// report.add(new SystemInfoReport());
|
||||
// report.add(new ConfigReport());
|
||||
// String result = report.toString();
|
||||
//
|
||||
// try {
|
||||
// File dest = new File(we.getWorkingDirectoryFile(we.getConfiguration().saveDir), "report.txt");
|
||||
// Files.write(result, dest, Charset.forName("UTF-8"));
|
||||
// actor.print("WorldEdit report written to " + dest.getAbsolutePath());
|
||||
// } catch (IOException e) {
|
||||
// actor.printError("Failed to write report: " + e.getMessage());
|
||||
// }
|
||||
//
|
||||
// if (args.hasFlag('p')) {
|
||||
// actor.checkPermission("worldedit.report.pastebin");
|
||||
// ActorCallbackPaste.pastebin(we.getSupervisor(), actor, result, "WorldEdit report: %s.report");
|
||||
// }
|
||||
// }
|
||||
|
||||
@Command(
|
||||
aliases = {"cui"},
|
||||
usage = "",
|
||||
|
@ -35,7 +35,7 @@ import com.sk89q.worldedit.world.World;
|
||||
|
||||
public class ItemUseParser extends SimpleCommand<Contextual<RegionFunction>> {
|
||||
|
||||
private final ItemParser itemParser = addParameter(new ItemParser("item", "minecraft:dye:15"));
|
||||
private final ItemParser itemParser = addParameter(new ItemParser("item", "minecraft:bone_meal"));
|
||||
|
||||
@Override
|
||||
public Contextual<RegionFunction> call(CommandArgs args, CommandLocals locals) throws CommandException {
|
||||
|
@ -62,7 +62,7 @@ public class NumberParser implements CommandExecutor<Number> {
|
||||
@Override
|
||||
public List<String> getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException {
|
||||
String value = args.next();
|
||||
return value.isEmpty() && defaultSuggestion != null ? Lists.newArrayList(defaultSuggestion) : Collections.<String>emptyList();
|
||||
return value.isEmpty() && defaultSuggestion != null ? Lists.newArrayList(defaultSuggestion) : Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,7 +57,7 @@ public class StringParser implements CommandExecutor<String> {
|
||||
@Override
|
||||
public List<String> getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException {
|
||||
String value = args.next();
|
||||
return value.isEmpty() && defaultSuggestion != null ? Lists.newArrayList(defaultSuggestion) : Collections.<String>emptyList();
|
||||
return value.isEmpty() && defaultSuggestion != null ? Lists.newArrayList(defaultSuggestion) : Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.command.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.util.task.FutureForwardingTask;
|
||||
import com.sk89q.worldedit.util.task.Supervisor;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class AsyncCommandHelper {
|
||||
|
||||
private final ListenableFuture<?> future;
|
||||
private final Supervisor supervisor;
|
||||
private final Actor sender;
|
||||
@Nullable
|
||||
private Object[] formatArgs;
|
||||
|
||||
private AsyncCommandHelper(ListenableFuture<?> future, Supervisor supervisor, Actor sender) {
|
||||
checkNotNull(future);
|
||||
checkNotNull(supervisor);
|
||||
checkNotNull(sender);
|
||||
|
||||
this.future = future;
|
||||
this.supervisor = supervisor;
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public AsyncCommandHelper formatUsing(Object... args) {
|
||||
this.formatArgs = args;
|
||||
return this;
|
||||
}
|
||||
|
||||
private String format(String message) {
|
||||
if (formatArgs != null) {
|
||||
return String.format(message, formatArgs);
|
||||
} else {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
public AsyncCommandHelper registerWithSupervisor(String description) {
|
||||
supervisor.monitor(
|
||||
FutureForwardingTask.create(
|
||||
future, format(description), sender));
|
||||
return this;
|
||||
}
|
||||
|
||||
public AsyncCommandHelper sendMessageAfterDelay(String message) {
|
||||
FutureProgressListener.addProgressListener(future, sender, format(message));
|
||||
return this;
|
||||
}
|
||||
|
||||
public AsyncCommandHelper thenRespondWith(String success, String failure) {
|
||||
// Send a response message
|
||||
Futures.addCallback(
|
||||
future,
|
||||
new MessageFutureCallback.Builder(sender)
|
||||
.onSuccess(format(success))
|
||||
.onFailure(format(failure))
|
||||
.build());
|
||||
return this;
|
||||
}
|
||||
|
||||
public AsyncCommandHelper thenTellErrorsOnly(String failure) {
|
||||
// Send a response message
|
||||
Futures.addCallback(
|
||||
future,
|
||||
new MessageFutureCallback.Builder(sender)
|
||||
.onFailure(format(failure))
|
||||
.build());
|
||||
return this;
|
||||
}
|
||||
|
||||
public AsyncCommandHelper forRegionDataLoad(World world, boolean silent) {
|
||||
checkNotNull(world);
|
||||
|
||||
formatUsing(world.getName());
|
||||
registerWithSupervisor("Loading region data for '%s'");
|
||||
if (silent) {
|
||||
thenTellErrorsOnly("Failed to load regions '%s'");
|
||||
} else {
|
||||
sendMessageAfterDelay("(Please wait... loading the region data for '%s')");
|
||||
thenRespondWith(
|
||||
"Loaded region data for '%s'",
|
||||
"Failed to load regions '%s'");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AsyncCommandHelper forRegionDataSave(World world, boolean silent) {
|
||||
checkNotNull(world);
|
||||
|
||||
formatUsing(world.getName());
|
||||
registerWithSupervisor("Saving region data for '%s'");
|
||||
if (silent) {
|
||||
thenTellErrorsOnly("Failed to save regions '%s'");
|
||||
} else {
|
||||
sendMessageAfterDelay("(Please wait... saving the region data for '%s')");
|
||||
thenRespondWith(
|
||||
"Saved region data for '%s'",
|
||||
"Failed to load regions '%s'");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public static AsyncCommandHelper wrap(ListenableFuture<?> future, Supervisor supervisor, Actor sender) {
|
||||
return new AsyncCommandHelper(future, supervisor, sender);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.command.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
|
||||
import java.util.Timer;
|
||||
|
||||
public class FutureProgressListener implements Runnable {
|
||||
|
||||
private static final Timer timer = new Timer();
|
||||
private static final int MESSAGE_DELAY = 1000;
|
||||
|
||||
private final MessageTimerTask task;
|
||||
|
||||
public FutureProgressListener(Actor sender, String message) {
|
||||
checkNotNull(sender);
|
||||
checkNotNull(message);
|
||||
|
||||
task = new MessageTimerTask(sender, message);
|
||||
timer.schedule(task, MESSAGE_DELAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
public static void addProgressListener(ListenableFuture<?> future, Actor sender, String message) {
|
||||
future.addListener(new FutureProgressListener(sender, message), MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.command.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.util.command.parametric.ExceptionConverter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class MessageFutureCallback<V> implements FutureCallback<V> {
|
||||
|
||||
private final ExceptionConverter exceptionConverter;
|
||||
private final Actor sender;
|
||||
@Nullable
|
||||
private final String success;
|
||||
@Nullable
|
||||
private final String failure;
|
||||
|
||||
private MessageFutureCallback(ExceptionConverter exceptionConverter, Actor sender, @Nullable String success, @Nullable String failure) {
|
||||
this.exceptionConverter = exceptionConverter;
|
||||
this.sender = sender;
|
||||
this.success = success;
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(@Nullable V v) {
|
||||
if (success != null) {
|
||||
sender.print(success);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@Nullable Throwable throwable) {
|
||||
try {
|
||||
exceptionConverter.convert(throwable);
|
||||
} catch (CommandException e) {
|
||||
String failure = this.failure != null ? this.failure : "An error occurred";
|
||||
String message = e.getMessage() != null ? e.getMessage() : "An unknown error occurred. Please see the console!";
|
||||
sender.printError(failure + ": " + message);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final Actor sender;
|
||||
@Nullable
|
||||
private String success;
|
||||
@Nullable
|
||||
private String failure;
|
||||
private ExceptionConverter exceptionConverter;
|
||||
|
||||
public Builder(Actor sender) {
|
||||
checkNotNull(sender);
|
||||
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public Builder exceptionConverter(ExceptionConverter exceptionConverter) {
|
||||
this.exceptionConverter = exceptionConverter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onSuccess(@Nullable String message) {
|
||||
this.success = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder onFailure(@Nullable String message) {
|
||||
this.failure = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <V> MessageFutureCallback<V> build() {
|
||||
checkNotNull(exceptionConverter);
|
||||
return new MessageFutureCallback<>(exceptionConverter, sender, success, failure);
|
||||
}
|
||||
}
|
||||
|
||||
public static <V> MessageFutureCallback<V> createRegionLoadCallback(ExceptionConverter exceptionConverter, Actor sender) {
|
||||
return new Builder(sender)
|
||||
.exceptionConverter(exceptionConverter)
|
||||
.onSuccess("Successfully load the region data.")
|
||||
.build();
|
||||
}
|
||||
|
||||
public static <V> MessageFutureCallback<V> createRegionSaveCallback(ExceptionConverter exceptionConverter, Actor sender) {
|
||||
return new Builder(sender)
|
||||
.exceptionConverter(exceptionConverter)
|
||||
.onSuccess("Successfully saved the region data.")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.command.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class MessageTimerTask extends TimerTask {
|
||||
|
||||
private final Actor sender;
|
||||
private final String message;
|
||||
|
||||
MessageTimerTask(Actor sender, String message) {
|
||||
checkNotNull(sender);
|
||||
checkNotNull(message);
|
||||
|
||||
this.sender = sender;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
sender.printDebug(message);
|
||||
}
|
||||
|
||||
}
|
@ -24,6 +24,7 @@ import com.sk89q.util.yaml.YAMLProcessor;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.session.SessionManager;
|
||||
import com.sk89q.worldedit.util.report.Unreported;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import com.sk89q.worldedit.world.snapshot.SnapshotRepository;
|
||||
@ -40,8 +41,8 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class YAMLConfiguration extends LocalConfiguration {
|
||||
|
||||
protected final YAMLProcessor config;
|
||||
protected final Logger logger;
|
||||
@Unreported protected final YAMLProcessor config;
|
||||
@Unreported protected final Logger logger;
|
||||
|
||||
public YAMLConfiguration(YAMLProcessor config, Logger logger) {
|
||||
this.config = config;
|
||||
|
@ -0,0 +1,490 @@
|
||||
/*
|
||||
* 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.net;
|
||||
|
||||
import com.sk89q.worldedit.util.io.Closer;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class HttpRequest implements Closeable {
|
||||
|
||||
private static final int CONNECT_TIMEOUT = 1000 * 5;
|
||||
private static final int READ_TIMEOUT = 1000 * 5;
|
||||
private static final int READ_BUFFER_SIZE = 1024 * 8;
|
||||
|
||||
private final Map<String, String> headers = new HashMap<>();
|
||||
private final String method;
|
||||
private final URL url;
|
||||
private String contentType;
|
||||
private byte[] body;
|
||||
private HttpURLConnection conn;
|
||||
private InputStream inputStream;
|
||||
|
||||
private long contentLength = -1;
|
||||
private long readBytes = 0;
|
||||
|
||||
/**
|
||||
* Create a new HTTP request.
|
||||
*
|
||||
* @param method the method
|
||||
* @param url the URL
|
||||
*/
|
||||
private HttpRequest(String method, URL url) {
|
||||
this.method = method;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit data.
|
||||
*
|
||||
* @return this object
|
||||
*/
|
||||
public HttpRequest body(String data) {
|
||||
body = data.getBytes();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit form data.
|
||||
*
|
||||
* @param form the form
|
||||
* @return this object
|
||||
*/
|
||||
public HttpRequest bodyForm(Form form) {
|
||||
contentType = "application/x-www-form-urlencoded";
|
||||
body = form.toString().getBytes();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a header.
|
||||
*
|
||||
* @param key the header key
|
||||
* @param value the header value
|
||||
* @return this object
|
||||
*/
|
||||
public HttpRequest header(String key, String value) {
|
||||
if (key.equalsIgnoreCase("Content-Type")) {
|
||||
contentType = value;
|
||||
} else {
|
||||
headers.put(key, value);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the request.
|
||||
* <p/>
|
||||
* After execution, {@link #close()} should be called.
|
||||
*
|
||||
* @return this object
|
||||
* @throws java.io.IOException on I/O error
|
||||
*/
|
||||
public HttpRequest execute() throws IOException {
|
||||
boolean successful = false;
|
||||
|
||||
try {
|
||||
if (conn != null) {
|
||||
throw new IllegalArgumentException("Connection already executed");
|
||||
}
|
||||
|
||||
conn = (HttpURLConnection) reformat(url).openConnection();
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Java)");
|
||||
|
||||
if (body != null) {
|
||||
conn.setRequestProperty("Content-Type", contentType);
|
||||
conn.setRequestProperty("Content-Length", Integer.toString(body.length));
|
||||
conn.setDoInput(true);
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
conn.setRequestProperty(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
conn.setRequestMethod(method);
|
||||
conn.setUseCaches(false);
|
||||
conn.setDoOutput(true);
|
||||
conn.setConnectTimeout(CONNECT_TIMEOUT);
|
||||
conn.setReadTimeout(READ_TIMEOUT);
|
||||
|
||||
conn.connect();
|
||||
|
||||
if (body != null) {
|
||||
DataOutputStream out = new DataOutputStream(conn.getOutputStream());
|
||||
out.write(body);
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
|
||||
inputStream = conn.getResponseCode() == HttpURLConnection.HTTP_OK ?
|
||||
conn.getInputStream() : conn.getErrorStream();
|
||||
|
||||
successful = true;
|
||||
} finally {
|
||||
if (!successful) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that the response code is one of the given response codes.
|
||||
*
|
||||
* @param codes a list of codes
|
||||
* @return this object
|
||||
* @throws java.io.IOException if there is an I/O error or the response code is not expected
|
||||
*/
|
||||
public HttpRequest expectResponseCode(int... codes) throws IOException {
|
||||
int responseCode = getResponseCode();
|
||||
|
||||
for (int code : codes) {
|
||||
if (code == responseCode) {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
close();
|
||||
throw new IOException("Did not get expected response code, got " + responseCode + " for " + url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the response code.
|
||||
*
|
||||
* @return the response code
|
||||
* @throws java.io.IOException on I/O error
|
||||
*/
|
||||
public int getResponseCode() throws IOException {
|
||||
if (conn == null) {
|
||||
throw new IllegalArgumentException("No connection has been made");
|
||||
}
|
||||
|
||||
return conn.getResponseCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the input stream.
|
||||
*
|
||||
* @return the input stream
|
||||
*/
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buffer the returned response.
|
||||
*
|
||||
* @return the buffered response
|
||||
* @throws java.io.IOException on I/O error
|
||||
* @throws InterruptedException on interruption
|
||||
*/
|
||||
public BufferedResponse returnContent() throws IOException, InterruptedException {
|
||||
if (inputStream == null) {
|
||||
throw new IllegalArgumentException("No input stream available");
|
||||
}
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
int b = 0;
|
||||
while ((b = inputStream.read()) != -1) {
|
||||
bos.write(b);
|
||||
}
|
||||
return new BufferedResponse(bos.toByteArray());
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the result to a file.
|
||||
*
|
||||
* @param file the file
|
||||
* @return this object
|
||||
* @throws java.io.IOException on I/O error
|
||||
* @throws InterruptedException on interruption
|
||||
*/
|
||||
public HttpRequest saveContent(File file) throws IOException, InterruptedException {
|
||||
Closer closer = Closer.create();
|
||||
|
||||
try {
|
||||
FileOutputStream fos = closer.register(new FileOutputStream(file));
|
||||
BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
|
||||
|
||||
saveContent(bos);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the result to an output stream.
|
||||
*
|
||||
* @param out the output stream
|
||||
* @return this object
|
||||
* @throws java.io.IOException on I/O error
|
||||
* @throws InterruptedException on interruption
|
||||
*/
|
||||
public HttpRequest saveContent(OutputStream out) throws IOException, InterruptedException {
|
||||
BufferedInputStream bis;
|
||||
|
||||
try {
|
||||
String field = conn.getHeaderField("Content-Length");
|
||||
if (field != null) {
|
||||
long len = Long.parseLong(field);
|
||||
if (len >= 0) { // Let's just not deal with really big numbers
|
||||
contentLength = len;
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
|
||||
try {
|
||||
bis = new BufferedInputStream(inputStream);
|
||||
|
||||
byte[] data = new byte[READ_BUFFER_SIZE];
|
||||
int len = 0;
|
||||
while ((len = bis.read(data, 0, READ_BUFFER_SIZE)) >= 0) {
|
||||
out.write(data, 0, len);
|
||||
readBytes += len;
|
||||
}
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (conn != null) conn.disconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a GET request.
|
||||
*
|
||||
* @param url the URL
|
||||
* @return a new request object
|
||||
*/
|
||||
public static HttpRequest get(URL url) {
|
||||
return request("GET", url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a POST request.
|
||||
*
|
||||
* @param url the URL
|
||||
* @return a new request object
|
||||
*/
|
||||
public static HttpRequest post(URL url) {
|
||||
return request("POST", url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a request.
|
||||
*
|
||||
* @param method the method
|
||||
* @param url the URL
|
||||
* @return a new request object
|
||||
*/
|
||||
public static HttpRequest request(String method, URL url) {
|
||||
return new HttpRequest(method, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link java.net.URL} and throw a {@link RuntimeException} if the URL
|
||||
* is not valid.
|
||||
*
|
||||
* @param url the url
|
||||
* @return a URL object
|
||||
* @throws RuntimeException if the URL is invalid
|
||||
*/
|
||||
public static URL url(String url) {
|
||||
try {
|
||||
return new URL(url);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* URL may contain spaces and other nasties that will cause a failure.
|
||||
*
|
||||
* @param existing the existing URL to transform
|
||||
* @return the new URL, or old one if there was a failure
|
||||
*/
|
||||
private static URL reformat(URL existing) {
|
||||
try {
|
||||
URL url = new URL(existing.toString());
|
||||
URI uri = new URI(
|
||||
url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(),
|
||||
url.getPath(), url.getQuery(), url.getRef());
|
||||
url = uri.toURL();
|
||||
return url;
|
||||
} catch (MalformedURLException e) {
|
||||
return existing;
|
||||
} catch (URISyntaxException e) {
|
||||
return existing;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used with {@link #bodyForm(Form)}.
|
||||
*/
|
||||
public final static class Form {
|
||||
public final List<String> elements = new ArrayList<>();
|
||||
|
||||
private Form() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a key/value to the form.
|
||||
*
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @return this object
|
||||
*/
|
||||
public Form add(String key, String value) {
|
||||
try {
|
||||
elements.add(URLEncoder.encode(key, "UTF-8") +
|
||||
"=" + URLEncoder.encode(value, "UTF-8"));
|
||||
return this;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
boolean first = true;
|
||||
for (String element : elements) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
builder.append("&");
|
||||
}
|
||||
builder.append(element);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new form.
|
||||
*
|
||||
* @return a new form
|
||||
*/
|
||||
public static Form create() {
|
||||
return new Form();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to buffer the response in memory.
|
||||
*/
|
||||
public class BufferedResponse {
|
||||
private final byte[] data;
|
||||
|
||||
private BufferedResponse(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the result as bytes.
|
||||
*
|
||||
* @return the data
|
||||
*/
|
||||
public byte[] asBytes() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the result as a string.
|
||||
*
|
||||
* @param encoding the encoding
|
||||
* @return the string
|
||||
* @throws java.io.IOException on I/O error
|
||||
*/
|
||||
public String asString(String encoding) throws IOException {
|
||||
return new String(data, encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the result to a file.
|
||||
*
|
||||
* @param file the file
|
||||
* @return this object
|
||||
* @throws java.io.IOException on I/O error
|
||||
* @throws InterruptedException on interruption
|
||||
*/
|
||||
public BufferedResponse saveContent(File file) throws IOException, InterruptedException {
|
||||
Closer closer = Closer.create();
|
||||
file.getParentFile().mkdirs();
|
||||
|
||||
try {
|
||||
FileOutputStream fos = closer.register(new FileOutputStream(file));
|
||||
BufferedOutputStream bos = closer.register(new BufferedOutputStream(fos));
|
||||
|
||||
saveContent(bos);
|
||||
} finally {
|
||||
closer.close();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the result to an output stream.
|
||||
*
|
||||
* @param out the output stream
|
||||
* @return this object
|
||||
* @throws java.io.IOException on I/O error
|
||||
* @throws InterruptedException on interruption
|
||||
*/
|
||||
public BufferedResponse saveContent(OutputStream out) throws IOException, InterruptedException {
|
||||
out.write(data);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.paste;
|
||||
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.sk89q.worldedit.command.util.AsyncCommandHelper;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.util.task.Supervisor;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ActorCallbackPaste {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ActorCallbackPaste.class.getSimpleName());
|
||||
|
||||
private ActorCallbackPaste() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit data to a pastebin service and inform the sender of
|
||||
* success or failure.
|
||||
*
|
||||
* @param supervisor The supervisor instance
|
||||
* @param sender The sender
|
||||
* @param content The content
|
||||
* @param successMessage The message, formatted with {@link String#format(String, Object...)} on success
|
||||
*/
|
||||
public static void pastebin(Supervisor supervisor, final Actor sender, String content, final String successMessage) {
|
||||
ListenableFuture<URL> future = new IncendoPaste("fastasyncworldedit").paste(content);
|
||||
|
||||
AsyncCommandHelper.wrap(future, supervisor, sender)
|
||||
.registerWithSupervisor("Submitting content to a pastebin service...")
|
||||
.sendMessageAfterDelay("(Please wait... sending output to pastebin...)");
|
||||
|
||||
Futures.addCallback(future, new FutureCallback<URL>() {
|
||||
@Override
|
||||
public void onSuccess(URL url) {
|
||||
sender.print(String.format(successMessage, url));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable throwable) {
|
||||
LOGGER.log(Level.WARNING, "Failed to submit pastebin", throwable);
|
||||
sender.printError("Failed to submit to a pastebin. Please see console for the error.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.paste;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.sk89q.worldedit.util.net.HttpRequest;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class EngineHubPaste implements Paster {
|
||||
|
||||
private static final Pattern URL_PATTERN = Pattern.compile("https?://.+$");
|
||||
|
||||
@Override
|
||||
public ListenableFuture<URL> paste(String content) {
|
||||
return Pasters.getExecutor().submit(new PasteTask(content));
|
||||
}
|
||||
|
||||
private final class PasteTask implements Callable<URL> {
|
||||
private final String content;
|
||||
|
||||
private PasteTask(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL call() throws IOException, InterruptedException {
|
||||
HttpRequest.Form form = HttpRequest.Form.create();
|
||||
form.add("content", content);
|
||||
form.add("from", "worldguard");
|
||||
|
||||
URL url = HttpRequest.url("http://paste.enginehub.org/paste");
|
||||
String result = HttpRequest.post(url)
|
||||
.bodyForm(form)
|
||||
.execute()
|
||||
.expectResponseCode(200)
|
||||
.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"));
|
||||
Matcher m = URL_PATTERN.matcher(urlString);
|
||||
|
||||
if (m.matches()) {
|
||||
return new URL(urlString);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IOException("Failed to save paste; instead, got: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,280 @@
|
||||
package com.sk89q.worldedit.util.paste;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Single class paster for the Incendo paste service
|
||||
*
|
||||
* @author Sauilitired
|
||||
*/
|
||||
@SuppressWarnings({"unused", "WeakerAccess"})
|
||||
public final class IncendoPaste implements Paster{
|
||||
|
||||
/**
|
||||
* Upload service URL
|
||||
*/
|
||||
public static final String UPLOAD_PATH = "https://incendo.org/paste/upload";
|
||||
/**
|
||||
* Valid paste applications
|
||||
*/
|
||||
public static final Collection<String>
|
||||
VALID_APPLICATIONS = Arrays
|
||||
.asList("plotsquared", "fastasyncworldedit", "incendopermissions", "kvantum");
|
||||
|
||||
private final Collection<PasteFile> files = new ArrayList<>();
|
||||
private final String pasteApplication;
|
||||
|
||||
/**
|
||||
* Construct a new paster
|
||||
*
|
||||
* @param pasteApplication The application that is sending the paste
|
||||
*/
|
||||
public IncendoPaste(final String pasteApplication) {
|
||||
if (pasteApplication == null || pasteApplication.isEmpty()) {
|
||||
throw new IllegalArgumentException("paste application cannot be null, nor empty");
|
||||
}
|
||||
if (!VALID_APPLICATIONS.contains(pasteApplication.toLowerCase(Locale.ENGLISH))) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Unknown application name: %s", pasteApplication));
|
||||
}
|
||||
this.pasteApplication = pasteApplication;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<URL> paste(String content) {
|
||||
return Pasters.getExecutor().submit(new PasteTask(content));
|
||||
}
|
||||
|
||||
private final class PasteTask implements Callable<URL>{
|
||||
|
||||
private PasteTask(String content) {}
|
||||
|
||||
@Override
|
||||
public URL call() throws Exception {
|
||||
return new URL(debugPaste());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an immutable collection containing all the files that have been added to this paster
|
||||
*
|
||||
* @return Unmodifiable collection
|
||||
*/
|
||||
public final Collection<PasteFile> getFiles() {
|
||||
return Collections.unmodifiableCollection(this.files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a file to the paster
|
||||
*
|
||||
* @param file File to paste
|
||||
*/
|
||||
public void addFile(final PasteFile file) {
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("File cannot be null");
|
||||
}
|
||||
// Check to see that no duplicate files are submitted
|
||||
for (final PasteFile pasteFile : this.files) {
|
||||
if (pasteFile.fileName.equalsIgnoreCase(file.getFileName())) {
|
||||
throw new IllegalArgumentException(String.format("Found duplicate file with name %s",
|
||||
file.getFileName()));
|
||||
}
|
||||
}
|
||||
this.files.add(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JSON string from the submitted information
|
||||
*
|
||||
* @return compiled JSON string
|
||||
*/
|
||||
private String toJsonString() {
|
||||
final StringBuilder builder = new StringBuilder("{\n");
|
||||
builder.append("\"paste_application\": \"").append(this.pasteApplication).append("\",\n\"files\": \"");
|
||||
Iterator<PasteFile> fileIterator = this.files.iterator();
|
||||
while (fileIterator.hasNext()) {
|
||||
final PasteFile file = fileIterator.next();
|
||||
builder.append(file.getFileName());
|
||||
if (fileIterator.hasNext()) {
|
||||
builder.append(",");
|
||||
}
|
||||
}
|
||||
builder.append("\",\n");
|
||||
fileIterator = this.files.iterator();
|
||||
while (fileIterator.hasNext()) {
|
||||
final PasteFile file = fileIterator.next();
|
||||
builder.append("\"file-").append(file.getFileName()).append("\": \"")
|
||||
.append(file.getContent().replaceAll("\"", "\\\\\"")).append("\"");
|
||||
if (fileIterator.hasNext()) {
|
||||
builder.append(",\n");
|
||||
}
|
||||
}
|
||||
builder.append("\n}");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the paste and return the status message
|
||||
*
|
||||
* @return Status message
|
||||
* @throws Throwable any and all exceptions
|
||||
*/
|
||||
public final String upload() throws Throwable {
|
||||
final URL url = new URL(UPLOAD_PATH);
|
||||
final URLConnection connection = url.openConnection();
|
||||
final HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
|
||||
httpURLConnection.setRequestMethod("POST");
|
||||
httpURLConnection.setDoOutput(true);
|
||||
final byte[] content = toJsonString().getBytes(Charsets.UTF_8);
|
||||
httpURLConnection.setFixedLengthStreamingMode(content.length);
|
||||
httpURLConnection.setRequestProperty("Content-Type", "application/json");
|
||||
httpURLConnection.setRequestProperty("Accept", "*/*");
|
||||
httpURLConnection.connect();
|
||||
try (final OutputStream stream = httpURLConnection.getOutputStream()) {
|
||||
stream.write(content);
|
||||
}
|
||||
if (!httpURLConnection.getResponseMessage().contains("OK")) {
|
||||
throw new IllegalStateException(String.format("Server returned status: %d %s",
|
||||
httpURLConnection.getResponseCode(), httpURLConnection.getResponseMessage()));
|
||||
}
|
||||
final StringBuilder input = new StringBuilder();
|
||||
try (final BufferedReader inputStream = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()))) {
|
||||
String line;
|
||||
while ((line = inputStream.readLine()) != null) {
|
||||
input.append(line).append("\n");
|
||||
}
|
||||
}
|
||||
return input.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple class that represents a paste file
|
||||
*/
|
||||
public static class PasteFile {
|
||||
|
||||
private final String fileName;
|
||||
private final String content;
|
||||
|
||||
/**
|
||||
* Construct a new paste file
|
||||
*
|
||||
* @param fileName File name, cannot be empty, nor null
|
||||
* @param content File content, cannot be empty, nor null
|
||||
*/
|
||||
public PasteFile(final String fileName, final String content) {
|
||||
if (fileName == null || fileName.isEmpty()) {
|
||||
throw new IllegalArgumentException("file name cannot be null, nor empty");
|
||||
}
|
||||
if (content == null || content.isEmpty()) {
|
||||
throw new IllegalArgumentException("content cannot be null, nor empty");
|
||||
}
|
||||
this.fileName = fileName;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file name
|
||||
*
|
||||
* @return File name
|
||||
*/
|
||||
public String getFileName() {
|
||||
return this.fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file content as a single string
|
||||
*
|
||||
* @return File content
|
||||
*/
|
||||
public String getContent() {
|
||||
return this.content;
|
||||
}
|
||||
}
|
||||
|
||||
public static String debugPaste() throws IOException {
|
||||
final IncendoPaste incendoPaster = new IncendoPaste("fastasyncworldedit");
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(
|
||||
"# Welcome to this paste\n# It is meant to provide us at IntellectualSites with better information about your "
|
||||
+ "problem\n");
|
||||
b.append("\n# Server Information\n");
|
||||
b.append("server.platform: ").append(Fawe.imp().getPlatform()).append('\n');
|
||||
b.append(Fawe.imp().getDebugInfo()).append('\n');
|
||||
b.append("\n\n# YAY! Now, let's see what we can find in your JVM\n");
|
||||
Runtime runtime = Runtime.getRuntime();
|
||||
b.append("memory.free: ").append(runtime.freeMemory()).append('\n');
|
||||
b.append("memory.max: ").append(runtime.maxMemory()).append('\n');
|
||||
b.append("java.specification.version: '").append(System.getProperty("java.specification.version")).append("'\n");
|
||||
b.append("java.vendor: '").append(System.getProperty("java.vendor")).append("'\n");
|
||||
b.append("java.version: '").append(System.getProperty("java.version")).append("'\n");
|
||||
b.append("os.arch: '").append(System.getProperty("os.arch")).append("'\n");
|
||||
b.append("os.name: '").append(System.getProperty("os.name")).append("'\n");
|
||||
b.append("os.version: '").append(System.getProperty("os.version")).append("'\n\n");
|
||||
b.append("# Okay :D Great. You are now ready to create your bug report!");
|
||||
b.append("\n# You can do so at https://github.com/boy0001/FastAsyncWorldedit/issues");
|
||||
b.append("\n# or via our Discord at https://discord.gg/ngZCzbU");
|
||||
incendoPaster.addFile(new IncendoPaste.PasteFile("information", b.toString()));
|
||||
|
||||
try {
|
||||
final File logFile = new File(Fawe.imp().getDirectory(), "../../logs/latest.log");
|
||||
final String file;
|
||||
if (Files.size(logFile.toPath()) > 14_000_000) {
|
||||
file = "too big :(";
|
||||
} else {
|
||||
file = readFile(logFile);
|
||||
}
|
||||
incendoPaster.addFile(new IncendoPaste.PasteFile("latest.log", file));
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
incendoPaster.addFile(new PasteFile("config.yml", readFile(new File(Fawe.imp().getDirectory(), "config.yml"))));
|
||||
incendoPaster.addFile(new PasteFile("message.yml", readFile(new File(Fawe.imp().getDirectory(), "message.yml"))));
|
||||
incendoPaster.addFile(new PasteFile("commands.yml", readFile(new File(Fawe.imp().getDirectory(), "commands.yml"))));
|
||||
|
||||
final String rawResponse;
|
||||
try {
|
||||
rawResponse = incendoPaster.upload();
|
||||
} catch (Throwable throwable) {
|
||||
throw new IOException(String.format("Failed to upload files: %s", throwable.getMessage()), throwable);
|
||||
}
|
||||
final JsonObject jsonObject = new JsonParser().parse(rawResponse).getAsJsonObject();
|
||||
|
||||
if (jsonObject.has("created")) {
|
||||
final String pasteId = jsonObject.get("paste_id").getAsString();
|
||||
return String.format("https://incendo.org/paste/view/%s", pasteId);
|
||||
} else {
|
||||
throw new IOException(String.format("Failed to upload files: %s",
|
||||
jsonObject.get("response").getAsString()));
|
||||
}
|
||||
}
|
||||
|
||||
private static String readFile(final File file) throws IOException {
|
||||
final StringBuilder content = new StringBuilder();
|
||||
final List<String> lines = new ArrayList<>();
|
||||
try (final BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
for (int i = Math.max(0, lines.size() - 1000); i < lines.size(); i++) {
|
||||
content.append(lines.get(i)).append("\n");
|
||||
}
|
||||
return content.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.paste;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.sk89q.worldedit.util.net.HttpRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Pastebin implements Paster {
|
||||
|
||||
private static final Pattern URL_PATTERN = Pattern.compile("https?://pastebin.com/([^/]+)$");
|
||||
|
||||
private boolean mungingLinks = true;
|
||||
|
||||
public boolean isMungingLinks() {
|
||||
return mungingLinks;
|
||||
}
|
||||
|
||||
public void setMungingLinks(boolean mungingLinks) {
|
||||
this.mungingLinks = mungingLinks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<URL> paste(String content) {
|
||||
if (mungingLinks) {
|
||||
content = content.replaceAll("http://", "http_//");
|
||||
}
|
||||
|
||||
return Pasters.getExecutor().submit(new PasteTask(content));
|
||||
}
|
||||
|
||||
private final class PasteTask implements Callable<URL> {
|
||||
private final String content;
|
||||
|
||||
private PasteTask(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL call() throws IOException, InterruptedException {
|
||||
HttpRequest.Form form = HttpRequest.Form.create();
|
||||
form.add("api_option", "paste");
|
||||
form.add("api_dev_key", "4867eae74c6990dbdef07c543cf8f805");
|
||||
form.add("api_paste_code", content);
|
||||
form.add("api_paste_private", "0");
|
||||
form.add("api_paste_name", "");
|
||||
form.add("api_paste_expire_date", "1W");
|
||||
form.add("api_paste_format", "text");
|
||||
form.add("api_user_key", "");
|
||||
|
||||
URL url = HttpRequest.url("http://pastebin.com/api/api_post.php");
|
||||
String result = HttpRequest.post(url)
|
||||
.bodyForm(form)
|
||||
.execute()
|
||||
.expectResponseCode(200)
|
||||
.returnContent()
|
||||
.asString("UTF-8").trim();
|
||||
|
||||
Matcher m = URL_PATTERN.matcher(result);
|
||||
|
||||
if (m.matches()) {
|
||||
return new URL("http://pastebin.com/raw.php?i=" + m.group(1));
|
||||
} else if (result.matches("^https?://.+")) {
|
||||
return new URL(result);
|
||||
} else {
|
||||
throw new IOException("Failed to save paste; instead, got: " + result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.paste;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
public interface Paster {
|
||||
|
||||
ListenableFuture<URL> paste(String content);
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.paste;
|
||||
|
||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
final class Pasters {
|
||||
|
||||
private static final ListeningExecutorService executor =
|
||||
MoreExecutors.listeningDecorator(
|
||||
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
|
||||
2L, TimeUnit.SECONDS,
|
||||
new SynchronousQueue<>()));
|
||||
|
||||
private Pasters() {
|
||||
}
|
||||
|
||||
static ListeningExecutorService getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.report;
|
||||
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
|
||||
public class ConfigReport extends DataReport {
|
||||
|
||||
public ConfigReport() {
|
||||
super("WorldEdit Configuration");
|
||||
|
||||
append("Configuration", new HierarchyObjectReport("Configuration", WorldEdit.getInstance().getConfiguration()));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.report;
|
||||
|
||||
public class HierarchyObjectReport extends ShallowObjectReport {
|
||||
|
||||
public HierarchyObjectReport(String title, Object object) {
|
||||
super(title, object);
|
||||
|
||||
Class<?> type = object.getClass();
|
||||
while ((type = type.getSuperclass()) != null) {
|
||||
scanClass(object, type);
|
||||
}
|
||||
}
|
||||
}
|
@ -34,8 +34,10 @@ public class ShallowObjectReport extends DataReport {
|
||||
super(title);
|
||||
checkNotNull(object, "object");
|
||||
|
||||
Class<?> type = object.getClass();
|
||||
scanClass(object, object.getClass());
|
||||
}
|
||||
|
||||
void scanClass(Object object, Class<?> type) {
|
||||
for (Field field : type.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
continue;
|
||||
@ -54,5 +56,4 @@ public class ShallowObjectReport extends DataReport {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.task;
|
||||
|
||||
import com.google.common.util.concurrent.AbstractFuture;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* An abstract task that stores a name and owner.
|
||||
*
|
||||
* @param <V> the type returned
|
||||
*/
|
||||
public abstract class AbstractTask<V> extends AbstractFuture<V> implements Task<V> {
|
||||
|
||||
private final UUID uniqueId = UUID.randomUUID();
|
||||
private final String name;
|
||||
private final Object owner;
|
||||
private final Date creationDate = new Date();
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param name the name
|
||||
* @param owner the owner
|
||||
*/
|
||||
protected AbstractTask(String name, @Nullable Object owner) {
|
||||
checkNotNull(name);
|
||||
this.name = name;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getCreationDate() {
|
||||
return creationDate;
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.task;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.sk89q.worldedit.util.task.progress.Progress;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* A task that wraps a {@code ListenableFuture}.
|
||||
*
|
||||
* <p>{@link Task.State#SCHEDULED} is never returned because it is not possible
|
||||
* to test whether the future has "started," so {@link Task.State#RUNNING} is
|
||||
* returned in its place.</p>
|
||||
*
|
||||
* <p>Use {@link #create(ListenableFuture, String, Object)} to create a new
|
||||
* instance.</p>
|
||||
*
|
||||
* @param <V> the type returned
|
||||
*/
|
||||
public class FutureForwardingTask<V> extends AbstractTask<V> {
|
||||
|
||||
private final ListenableFuture<V> future;
|
||||
|
||||
private FutureForwardingTask(ListenableFuture<V> future, String name, @Nullable Object owner) {
|
||||
super(name, owner);
|
||||
checkNotNull(future);
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addListener(Runnable listener, Executor executor) {
|
||||
future.addListener(listener, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return future.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return future.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return future.isDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get() throws InterruptedException, ExecutionException {
|
||||
return future.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return future.get(timeout, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public State getState() {
|
||||
if (isCancelled()) {
|
||||
return State.CANCELLED;
|
||||
} else if (isDone()) {
|
||||
try {
|
||||
get();
|
||||
return State.SUCCEEDED;
|
||||
} catch (InterruptedException e) {
|
||||
return State.CANCELLED;
|
||||
} catch (ExecutionException e) {
|
||||
return State.FAILED;
|
||||
}
|
||||
} else {
|
||||
return State.RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Progress getProgress() {
|
||||
return Progress.indeterminate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param future the future
|
||||
* @param name the name of the task
|
||||
* @param owner the owner of the task, or {@code null}
|
||||
* @param <V> the type returned by the future
|
||||
* @return a new instance
|
||||
*/
|
||||
public static <V> FutureForwardingTask<V> create(ListenableFuture<V> future, String name, @Nullable Object owner) {
|
||||
return new FutureForwardingTask<>(future, name, owner);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.task;
|
||||
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* An implementation of a {@code Supervisor}.
|
||||
*/
|
||||
public class SimpleSupervisor implements Supervisor {
|
||||
|
||||
private final List<Task<?>> monitored = new ArrayList<>();
|
||||
private final Object lock = new Object();
|
||||
|
||||
@Override
|
||||
public List<Task<?>> getTasks() {
|
||||
synchronized (lock) {
|
||||
return new ArrayList<>(monitored);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void monitor(final Task<?> task) {
|
||||
checkNotNull(task);
|
||||
|
||||
synchronized (lock) {
|
||||
monitored.add(task);
|
||||
}
|
||||
|
||||
task.addListener(() -> {
|
||||
synchronized (lock) {
|
||||
monitored.remove(task);
|
||||
}
|
||||
}, MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.task;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manages running tasks and informs users of their progress, but does not
|
||||
* execute the task.
|
||||
*/
|
||||
public interface Supervisor {
|
||||
|
||||
/**
|
||||
* Get a list of running or queued tasks.
|
||||
*
|
||||
* @return a list of tasks
|
||||
*/
|
||||
List<Task<?>> getTasks();
|
||||
|
||||
/**
|
||||
* Monitor the given task.
|
||||
*
|
||||
* @param task the task
|
||||
*/
|
||||
void monitor(Task<?> task);
|
||||
|
||||
}
|
97
worldedit-core/src/main/java/com/sk89q/worldedit/util/task/Task.java
Normale Datei
97
worldedit-core/src/main/java/com/sk89q/worldedit/util/task/Task.java
Normale Datei
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.task;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.sk89q.worldedit.util.task.progress.ProgressObservable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A task is a job that can be scheduled, run, or cancelled. Tasks can report
|
||||
* on their own status. Tasks have owners.
|
||||
*/
|
||||
public interface Task<V> extends ListenableFuture<V>, ProgressObservable {
|
||||
|
||||
/**
|
||||
* Get the unique ID of this task.
|
||||
*
|
||||
* @return this task's unique ID
|
||||
*/
|
||||
UUID getUniqueId();
|
||||
|
||||
/**
|
||||
* Get the name of the task so it can be printed to the user.
|
||||
*
|
||||
* @return the name of the task
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Get the owner of the task.
|
||||
*
|
||||
* @return an owner object, if one is known or valid, otherwise {@code null}
|
||||
*/
|
||||
@Nullable
|
||||
Object getOwner();
|
||||
|
||||
/**
|
||||
* Get the state of the task.
|
||||
*
|
||||
* @return the state of the task
|
||||
*/
|
||||
State getState();
|
||||
|
||||
/**
|
||||
* Get the time at which the task was created.
|
||||
*
|
||||
* @return a date
|
||||
*/
|
||||
Date getCreationDate();
|
||||
|
||||
/**
|
||||
* Represents the state of a task.
|
||||
*/
|
||||
enum State {
|
||||
/**
|
||||
* The task has been scheduled to run but is not running yet.
|
||||
*/
|
||||
SCHEDULED,
|
||||
/**
|
||||
* The task has been cancelled and may be stopped or will stop.
|
||||
*/
|
||||
CANCELLED,
|
||||
/**
|
||||
* The task is currently running.
|
||||
*/
|
||||
RUNNING,
|
||||
/**
|
||||
* The task has failed.
|
||||
*/
|
||||
FAILED,
|
||||
/**
|
||||
* The task has succeeded.
|
||||
*/
|
||||
SUCCEEDED
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.task;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Compares task states according to the order of the {@link Task.State}
|
||||
* enumeration.
|
||||
*/
|
||||
public class TaskStateComparator implements Comparator<Task<?>> {
|
||||
|
||||
@Override
|
||||
public int compare(com.sk89q.worldedit.util.task.Task<?> o1, Task<?> o2) {
|
||||
int ordinal1 = o1.getState().ordinal();
|
||||
int ordinal2 = o2.getState().ordinal();
|
||||
if (ordinal1 < ordinal2) {
|
||||
return -1;
|
||||
} else if (ordinal1 > ordinal2) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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.task.progress;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A progress object describes the progress of an operation, specifying
|
||||
* either a percentage of completion or a status of indeterminacy.
|
||||
*
|
||||
* <p>Progress objects are immutable.</p>
|
||||
*
|
||||
* <p>To create a new instance, use one of the static constructors
|
||||
* on this class.</p>
|
||||
*/
|
||||
public abstract class Progress {
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*/
|
||||
private Progress() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the current progress is indeterminate.
|
||||
*
|
||||
* @return true if indeterminate
|
||||
*/
|
||||
public abstract boolean isIndeterminate();
|
||||
|
||||
/**
|
||||
* Get the progress percentage.
|
||||
*
|
||||
* <p>If {@link #isIndeterminate()} returns {@code true}, the behavior
|
||||
* of this method is undefined.</p>
|
||||
*
|
||||
* @return a number in the range [0, 1]
|
||||
*/
|
||||
public abstract double getProgress();
|
||||
|
||||
/**
|
||||
* Get a static progress object that is indeterminate.
|
||||
*
|
||||
* @return a progress object
|
||||
*/
|
||||
public static Progress indeterminate() {
|
||||
return INDETERMINATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a static progress object that is complete.
|
||||
*
|
||||
* @return a progress object
|
||||
*/
|
||||
public static Progress completed() {
|
||||
return COMPLETED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new progress object with the given percentage.
|
||||
*
|
||||
* @param value the percentage, which will be clamped to [0, 1]
|
||||
* @return a progress object
|
||||
*/
|
||||
public static Progress of(double value) {
|
||||
if (value < 0) {
|
||||
value = 0;
|
||||
} else if (value > 1) {
|
||||
value = 1;
|
||||
}
|
||||
|
||||
final double finalValue = value;
|
||||
return new Progress() {
|
||||
@Override
|
||||
public boolean isIndeterminate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProgress() {
|
||||
return finalValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new progress object with progress split equally between the
|
||||
* given progress objects.
|
||||
*
|
||||
* @param objects an array of progress objects
|
||||
* @return a new progress value
|
||||
*/
|
||||
public static Progress split(Progress... objects) {
|
||||
return split(Arrays.asList(objects));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new progress object with progress split equally between the
|
||||
* given progress objects.
|
||||
*
|
||||
* @param progress a collection of progress objects
|
||||
* @return a new progress value
|
||||
*/
|
||||
public static Progress split(Collection<Progress> progress) {
|
||||
int count = 0;
|
||||
double total = 0;
|
||||
|
||||
for (Progress p : progress) {
|
||||
if (p.isIndeterminate()) {
|
||||
return indeterminate();
|
||||
}
|
||||
total += p.getProgress();
|
||||
}
|
||||
|
||||
return of(total / count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new progress object with progress split equally between the
|
||||
* given {@link ProgressObservable}s.
|
||||
*
|
||||
* @param observables an array of observables
|
||||
* @return a new progress value
|
||||
*/
|
||||
public static Progress splitObservables(ProgressObservable... observables) {
|
||||
return splitObservables(Arrays.asList(observables));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new progress object with progress split equally between the
|
||||
* given {@link ProgressObservable}s.
|
||||
*
|
||||
* @param observables a collection of observables
|
||||
* @return a new progress value
|
||||
*/
|
||||
public static Progress splitObservables(Collection<? extends ProgressObservable> observables) {
|
||||
int count = 0;
|
||||
double total = 0;
|
||||
|
||||
for (ProgressObservable observable : observables) {
|
||||
Progress p = observable.getProgress();
|
||||
if (p.isIndeterminate()) {
|
||||
return indeterminate();
|
||||
}
|
||||
total += p.getProgress();
|
||||
}
|
||||
|
||||
return of(total / count);
|
||||
}
|
||||
|
||||
private static final Progress COMPLETED = of(1);
|
||||
|
||||
private static final Progress INDETERMINATE = new Progress() {
|
||||
@Override
|
||||
public boolean isIndeterminate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getProgress() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.task.progress;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* An iterator that keeps track of how many entries have been visited and
|
||||
* calculates a "percent completed" using a provided total count.
|
||||
*
|
||||
* <p>The returned progress percentage will always be between 0 or 1
|
||||
* (inclusive). If the iterator returns more entries than the total count,
|
||||
* then 100% will be returned for the progress.</p>
|
||||
*
|
||||
* @param <V> the type
|
||||
*/
|
||||
public class ProgressIterator<V> implements Iterator<V>, ProgressObservable {
|
||||
|
||||
private final Iterator<V> iterator;
|
||||
private final int count;
|
||||
private int visited = 0;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param iterator the iterator
|
||||
* @param count the count
|
||||
*/
|
||||
private ProgressIterator(Iterator<V> iterator, int count) {
|
||||
checkNotNull(iterator);
|
||||
this.iterator = iterator;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public V next() {
|
||||
V value = iterator.next();
|
||||
visited++;
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Progress getProgress() {
|
||||
return Progress.of(count > 0 ? Math.min(1, Math.max(0, (visited / (double) count))) : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param iterator the iterator
|
||||
* @param count the number of objects
|
||||
* @param <V> the type
|
||||
* @return an instance
|
||||
*/
|
||||
public static <V> ProgressIterator<V> create(Iterator<V> iterator, int count) {
|
||||
return new ProgressIterator<V>(iterator, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance from a list.
|
||||
*
|
||||
* @param list a list
|
||||
* @param <V> the type
|
||||
* @return an instance
|
||||
*/
|
||||
public static <V> ProgressIterator<V> create(List<V> list) {
|
||||
return create(list.iterator(), list.size());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.task.progress;
|
||||
|
||||
/**
|
||||
* An object that is able to report on its progress.
|
||||
*/
|
||||
public interface ProgressObservable {
|
||||
|
||||
/**
|
||||
* Get the current percentage of completion.
|
||||
*
|
||||
* @return a progress object
|
||||
*/
|
||||
Progress getProgress();
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.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 com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Ignore("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 {
|
||||
BlockTypes.register(new BlockType("worldedit:test"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransform() throws Exception {
|
||||
for (BlockType type : BlockType.REGISTRY.values()) {
|
||||
if (ignored.contains(type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockState base = type.getDefaultState();
|
||||
BlockState rotated = base;
|
||||
|
||||
for (int i = 1; i < 4; i++) {
|
||||
rotated = BlockTransformExtent.transform(base, ROTATE_90);
|
||||
}
|
||||
assertEquals(base, rotated);
|
||||
rotated = base;
|
||||
for (int i = 1; i < 4; i++) {
|
||||
rotated = BlockTransformExtent.transform(base, ROTATE_NEG_90);
|
||||
}
|
||||
assertEquals(base, rotated);
|
||||
}
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ import com.google.common.reflect.TypeToken;
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.session.SessionManager;
|
||||
import com.sk89q.worldedit.util.report.Unreported;
|
||||
import com.sk89q.worldedit.world.registry.LegacyMapper;
|
||||
import com.sk89q.worldedit.world.snapshot.SnapshotRepository;
|
||||
import ninja.leaping.configurate.ConfigurationOptions;
|
||||
@ -36,10 +37,10 @@ import java.util.HashSet;
|
||||
|
||||
public class ConfigurateConfiguration extends LocalConfiguration {
|
||||
|
||||
protected final ConfigurationLoader<CommentedConfigurationNode> config;
|
||||
protected final Logger logger;
|
||||
@Unreported protected final ConfigurationLoader<CommentedConfigurationNode> config;
|
||||
@Unreported protected final Logger logger;
|
||||
|
||||
protected CommentedConfigurationNode node;
|
||||
@Unreported protected CommentedConfigurationNode node;
|
||||
|
||||
public ConfigurateConfiguration(ConfigurationLoader<CommentedConfigurationNode> config, Logger logger) {
|
||||
this.config = config;
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren