mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 01:37:37 +00:00
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.
This commit is contained in:
parent
54142c8669
commit
45f1de6009
@ -14,6 +14,7 @@
|
|||||||
<allow pkg="gnu.trove"/>
|
<allow pkg="gnu.trove"/>
|
||||||
<allow pkg="com.google.gson"/>
|
<allow pkg="com.google.gson"/>
|
||||||
<allow pkg="net.royawesome.jlibnoise"/>
|
<allow pkg="net.royawesome.jlibnoise"/>
|
||||||
|
<allow pkg="org.json.simple" />
|
||||||
|
|
||||||
<subpackage name="util.yaml">
|
<subpackage name="util.yaml">
|
||||||
<allow pkg="org.yaml.snakeyaml"/>
|
<allow pkg="org.yaml.snakeyaml"/>
|
||||||
|
@ -21,6 +21,7 @@ package com.sk89q.worldedit.bukkit;
|
|||||||
|
|
||||||
import com.sk89q.util.yaml.YAMLProcessor;
|
import com.sk89q.util.yaml.YAMLProcessor;
|
||||||
import com.sk89q.worldedit.util.YAMLConfiguration;
|
import com.sk89q.worldedit.util.YAMLConfiguration;
|
||||||
|
import com.sk89q.worldedit.util.report.Unreported;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ import java.io.File;
|
|||||||
public class BukkitConfiguration extends YAMLConfiguration {
|
public class BukkitConfiguration extends YAMLConfiguration {
|
||||||
|
|
||||||
public boolean noOpPermissions = false;
|
public boolean noOpPermissions = false;
|
||||||
private final WorldEditPlugin plugin;
|
@Unreported private final WorldEditPlugin plugin;
|
||||||
|
|
||||||
public BukkitConfiguration(YAMLProcessor config, WorldEditPlugin plugin) {
|
public BukkitConfiguration(YAMLProcessor config, WorldEditPlugin plugin) {
|
||||||
super(config, plugin.getLogger());
|
super(config, plugin.getLogger());
|
||||||
|
@ -12,6 +12,8 @@ dependencies {
|
|||||||
compile 'com.thoughtworks.paranamer:paranamer:2.6'
|
compile 'com.thoughtworks.paranamer:paranamer:2.6'
|
||||||
compile 'com.google.code.gson:gson:2.8.0'
|
compile 'com.google.code.gson:gson:2.8.0'
|
||||||
compile 'com.sk89q.lib:jlibnoise:1.0.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'
|
testCompile 'org.mockito:mockito-core:1.9.0-rc1'
|
||||||
|
|
||||||
// Fawe depends
|
// 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.FilenameResolutionException;
|
||||||
import com.sk89q.worldedit.util.io.file.InvalidFilenameException;
|
import com.sk89q.worldedit.util.io.file.InvalidFilenameException;
|
||||||
import com.sk89q.worldedit.util.logging.WorldEditPrefixHandler;
|
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.BlockStateHolder;
|
||||||
import com.sk89q.worldedit.world.block.BlockType;
|
import com.sk89q.worldedit.world.block.BlockType;
|
||||||
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
||||||
@ -101,6 +103,7 @@ public class WorldEdit {
|
|||||||
private final PlatformManager platformManager = new PlatformManager(this);
|
private final PlatformManager platformManager = new PlatformManager(this);
|
||||||
private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl(eventBus);
|
private final EditSessionFactory editSessionFactory = new EditSessionFactory.EditSessionFactoryImpl(eventBus);
|
||||||
private final SessionManager sessions = new SessionManager(this);
|
private final SessionManager sessions = new SessionManager(this);
|
||||||
|
private final Supervisor supervisor = new SimpleSupervisor();
|
||||||
|
|
||||||
private final BlockFactory blockFactory = new BlockFactory(this);
|
private final BlockFactory blockFactory = new BlockFactory(this);
|
||||||
private final ItemFactory itemFactory = new ItemFactory(this);
|
private final ItemFactory itemFactory = new ItemFactory(this);
|
||||||
@ -150,6 +153,16 @@ public class WorldEdit {
|
|||||||
return eventBus;
|
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
|
* Get the block factory from which new {@link BlockStateHolder}s can be
|
||||||
* constructed.
|
* constructed.
|
||||||
|
@ -28,6 +28,7 @@ import com.boydti.fawe.util.HastebinUtility;
|
|||||||
import com.boydti.fawe.util.StringMan;
|
import com.boydti.fawe.util.StringMan;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
import com.boydti.fawe.util.Updater;
|
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.Command;
|
||||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||||
@ -40,6 +41,18 @@ import com.sk89q.worldedit.extension.platform.*;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
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.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -189,7 +202,8 @@ public class WorldEditCommands {
|
|||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.debugpaste")
|
@CommandPermissions("worldedit.debugpaste")
|
||||||
public void debugpaste(Actor actor) throws WorldEditException, IOException {
|
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(
|
@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(
|
@Command(
|
||||||
aliases = {"cui"},
|
aliases = {"cui"},
|
||||||
usage = "",
|
usage = "",
|
||||||
|
@ -35,7 +35,7 @@ import com.sk89q.worldedit.world.World;
|
|||||||
|
|
||||||
public class ItemUseParser extends SimpleCommand<Contextual<RegionFunction>> {
|
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
|
@Override
|
||||||
public Contextual<RegionFunction> call(CommandArgs args, CommandLocals locals) throws CommandException {
|
public Contextual<RegionFunction> call(CommandArgs args, CommandLocals locals) throws CommandException {
|
||||||
|
@ -62,7 +62,7 @@ public class NumberParser implements CommandExecutor<Number> {
|
|||||||
@Override
|
@Override
|
||||||
public List<String> getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException {
|
public List<String> getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException {
|
||||||
String value = args.next();
|
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
|
@Override
|
||||||
|
@ -57,7 +57,7 @@ public class StringParser implements CommandExecutor<String> {
|
|||||||
@Override
|
@Override
|
||||||
public List<String> getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException {
|
public List<String> getSuggestions(CommandArgs args, CommandLocals locals) throws MissingArgumentException {
|
||||||
String value = args.next();
|
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
|
@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.LocalConfiguration;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.session.SessionManager;
|
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.block.BlockTypes;
|
||||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||||
import com.sk89q.worldedit.world.snapshot.SnapshotRepository;
|
import com.sk89q.worldedit.world.snapshot.SnapshotRepository;
|
||||||
@ -40,8 +41,8 @@ import java.util.stream.Collectors;
|
|||||||
*/
|
*/
|
||||||
public class YAMLConfiguration extends LocalConfiguration {
|
public class YAMLConfiguration extends LocalConfiguration {
|
||||||
|
|
||||||
protected final YAMLProcessor config;
|
@Unreported protected final YAMLProcessor config;
|
||||||
protected final Logger logger;
|
@Unreported protected final Logger logger;
|
||||||
|
|
||||||
public YAMLConfiguration(YAMLProcessor config, Logger logger) {
|
public YAMLConfiguration(YAMLProcessor config, Logger logger) {
|
||||||
this.config = config;
|
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);
|
super(title);
|
||||||
checkNotNull(object, "object");
|
checkNotNull(object, "object");
|
||||||
|
|
||||||
Class<?> type = object.getClass();
|
scanClass(object, object.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
void scanClass(Object object, Class<?> type) {
|
||||||
for (Field field : type.getDeclaredFields()) {
|
for (Field field : type.getDeclaredFields()) {
|
||||||
if (Modifier.isStatic(field.getModifiers())) {
|
if (Modifier.isStatic(field.getModifiers())) {
|
||||||
continue;
|
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);
|
||||||
|
|
||||||
|
}
|
@ -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.LocalConfiguration;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.session.SessionManager;
|
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.registry.LegacyMapper;
|
||||||
import com.sk89q.worldedit.world.snapshot.SnapshotRepository;
|
import com.sk89q.worldedit.world.snapshot.SnapshotRepository;
|
||||||
import ninja.leaping.configurate.ConfigurationOptions;
|
import ninja.leaping.configurate.ConfigurationOptions;
|
||||||
@ -36,10 +37,10 @@ import java.util.HashSet;
|
|||||||
|
|
||||||
public class ConfigurateConfiguration extends LocalConfiguration {
|
public class ConfigurateConfiguration extends LocalConfiguration {
|
||||||
|
|
||||||
protected final ConfigurationLoader<CommentedConfigurationNode> config;
|
@Unreported protected final ConfigurationLoader<CommentedConfigurationNode> config;
|
||||||
protected final Logger logger;
|
@Unreported protected final Logger logger;
|
||||||
|
|
||||||
protected CommentedConfigurationNode node;
|
@Unreported protected CommentedConfigurationNode node;
|
||||||
|
|
||||||
public ConfigurateConfiguration(ConfigurationLoader<CommentedConfigurationNode> config, Logger logger) {
|
public ConfigurateConfiguration(ConfigurationLoader<CommentedConfigurationNode> config, Logger logger) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
Loading…
Reference in New Issue
Block a user