mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-24 19:46:34 +01:00
Various
per player limits - max blocks - max checks - max fails - max entities - max blockstates Also add command limit Fix negative coord compression issue
This commit is contained in:
parent
ba04eb9fc8
commit
fb4ed9362d
@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
@ -157,9 +158,9 @@ public class WEListener implements Listener {
|
||||
final String cmd = message.toLowerCase();
|
||||
final boolean single = true;
|
||||
final String[] split = cmd.split(" ");
|
||||
|
||||
final long maxVolume = Settings.WE_MAX_VOLUME;
|
||||
final long maxIterations = Settings.WE_MAX_ITERATIONS;
|
||||
FaweLimit limit = player.getLimit();
|
||||
final long maxVolume = limit.MAX_FAILS + limit.MAX_CHANGES;
|
||||
final long maxIterations = limit.MAX_ITERATIONS;
|
||||
// if (player.hasPermission("fawe.bypass")) {
|
||||
// return true;
|
||||
// }
|
||||
|
@ -2,8 +2,10 @@ package com.boydti.fawe.bukkit.v0;
|
||||
|
||||
import com.boydti.fawe.bukkit.logging.BlocksHubHook;
|
||||
import com.boydti.fawe.object.EditSessionWrapper;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
@ -20,13 +22,12 @@ public class BukkitEditSessionWrapper_0 extends EditSessionWrapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent getHistoryExtent(final Extent parent, final FaweChangeSet set, final FawePlayer<?> player) {
|
||||
public Extent getHistoryExtent(String world, FaweLimit limit, Extent parent, FaweChangeSet set, FaweQueue queue, FawePlayer<?> player) {
|
||||
if (this.hook != null) {
|
||||
// If we are doing logging, return a custom logging extent
|
||||
return this.hook.getLoggingExtent(parent, set, player);
|
||||
}
|
||||
// Otherwise return the normal history extent
|
||||
return super.getHistoryExtent(parent, set, player);
|
||||
return super.getHistoryExtent(world, limit, parent, set, queue, player);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -266,6 +266,9 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 {
|
||||
}
|
||||
lcx = cx;
|
||||
lcz = cz;
|
||||
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
|
||||
return 0;
|
||||
}
|
||||
lc = methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call();
|
||||
} else if (cy == lcy) {
|
||||
return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0;
|
||||
|
@ -242,6 +242,9 @@ public class BukkitQueue_1_9 extends BukkitQueue_0 {
|
||||
}
|
||||
lcx = cx;
|
||||
lcz = cz;
|
||||
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
|
||||
return 0;
|
||||
}
|
||||
lc = methodGetType.of(methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call());
|
||||
}
|
||||
int combined = (int) methodGetCombinedId.call(lc.call(x & 15, y, z & 15));
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.boydti.fawe;
|
||||
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
|
||||
public class FaweCache {
|
||||
public final static short[][][] CACHE_I = new short[256][16][16];
|
||||
@ -13,6 +14,8 @@ public class FaweCache {
|
||||
public final static short[] CACHE_ID = new short[65535];
|
||||
public final static byte[] CACHE_DATA = new byte[65535];
|
||||
|
||||
public final static BaseBlock[] CACHE_BLOCK = new BaseBlock[Short.MAX_VALUE];
|
||||
|
||||
// Faster than java random (since the game just needs to look random)
|
||||
public final static PseudoRandom RANDOM = new PseudoRandom();
|
||||
|
||||
@ -36,6 +39,12 @@ public class FaweCache {
|
||||
CACHE_ID[i] = (short) j;
|
||||
CACHE_DATA[i] = (byte) k;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Short.MAX_VALUE; i++) {
|
||||
int id = i >> 4;
|
||||
int data = i & 0xf;
|
||||
CACHE_BLOCK[i] = new BaseBlock(id, data);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasData(int id) {
|
||||
|
@ -3,6 +3,7 @@ package com.boydti.fawe.command;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
|
||||
public class Reload extends FaweCommand {
|
||||
|
||||
@ -13,7 +14,7 @@ public class Reload extends FaweCommand {
|
||||
@Override
|
||||
public boolean execute(final FawePlayer player, final String... args) {
|
||||
Fawe.get().setupConfigs();
|
||||
player.sendMessage("&d[FAWE] Reloaded configuration");
|
||||
MainUtil.sendMessage(player, "&d[FAWE] Reloaded configuration");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
16
core/src/main/java/com/boydti/fawe/command/Undolist.java
Normal file
16
core/src/main/java/com/boydti/fawe/command/Undolist.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.boydti.fawe.command;
|
||||
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
|
||||
public class Undolist extends FaweCommand {
|
||||
|
||||
public Undolist() {
|
||||
super("fawe.undolist");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(final FawePlayer player, final String... args) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ public enum BBC {
|
||||
FIX_LIGHTING_SELECTION("&7Lighting has been fixed in %s0 chunks. Relog to see the affect.", "Info"),
|
||||
NO_REGION("&cYou have no current WorldEdit region", "Error"),
|
||||
SET_REGION("&7Selection set to your current WorldEdit region", "Info"),
|
||||
WORLDEDIT_COMMAND_LIMIT("&7Please wait until your current action completes", "Info"),
|
||||
WORLDEDIT_DELAYED("&7Please wait while we process your WorldEdit action...", "Info"),
|
||||
WORLDEDIT_RUN("&7Apologies for the delay. Now executing: %s", "Info"),
|
||||
WORLDEDIT_COMPLETE("&7WorldEdit action completed.", "Info"),
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.boydti.fawe.config;
|
||||
|
||||
import com.boydti.fawe.configuration.file.YamlConfiguration;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -12,10 +14,6 @@ import java.util.Map.Entry;
|
||||
|
||||
public class Settings {
|
||||
|
||||
public static int MAX_BLOCKSTATES = 1337;
|
||||
public static int MAX_ENTITIES = 1337;
|
||||
public static long WE_MAX_ITERATIONS = 1000;
|
||||
public static long WE_MAX_VOLUME = 50000000;
|
||||
public static boolean REQUIRE_SELECTION = false;
|
||||
public static boolean FIX_ALL_LIGHTING = true;
|
||||
public static boolean COMMAND_PROCESSOR = false;
|
||||
@ -27,6 +25,25 @@ public class Settings {
|
||||
public static int BUFFER_SIZE = 531441;
|
||||
public static boolean METRICS = true;
|
||||
|
||||
public static HashMap<String, FaweLimit> limits;
|
||||
|
||||
public static FaweLimit getLimit(FawePlayer player) {
|
||||
FaweLimit limit = new FaweLimit();
|
||||
for (Entry<String, FaweLimit> entry : limits.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key.equals("default") || player.hasPermission("fawe.limit." + key)) {
|
||||
FaweLimit newLimit = entry.getValue();
|
||||
limit.MAX_CHANGES = Math.max(limit.MAX_CHANGES, newLimit.MAX_CHANGES != -1 ? newLimit.MAX_CHANGES : Integer.MAX_VALUE);
|
||||
limit.MAX_BLOCKSTATES = Math.max(limit.MAX_BLOCKSTATES, newLimit.MAX_BLOCKSTATES != -1 ? newLimit.MAX_BLOCKSTATES : Integer.MAX_VALUE);
|
||||
limit.MAX_CHECKS = Math.max(limit.MAX_CHECKS, newLimit.MAX_CHECKS != -1 ? newLimit.MAX_CHECKS : Integer.MAX_VALUE);
|
||||
limit.MAX_ENTITIES = Math.max(limit.MAX_ENTITIES, newLimit.MAX_ENTITIES != -1 ? newLimit.MAX_ENTITIES : Integer.MAX_VALUE);
|
||||
limit.MAX_FAILS = Math.max(limit.MAX_FAILS, newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE);
|
||||
limit.MAX_ITERATIONS = Math.max(limit.MAX_ITERATIONS, newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
return limit;
|
||||
}
|
||||
|
||||
public static void setup(final File file) {
|
||||
if (!file.exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
@ -38,11 +55,9 @@ public class Settings {
|
||||
}
|
||||
final YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
|
||||
|
||||
limits = new HashMap<>();
|
||||
|
||||
final Map<String, Object> options = new HashMap<>();
|
||||
options.put("max-blockstates", MAX_BLOCKSTATES);
|
||||
options.put("max-entities", MAX_ENTITIES);
|
||||
options.put("max-iterations", WE_MAX_ITERATIONS);
|
||||
options.put("max-volume", WE_MAX_VOLUME);
|
||||
options.put("require-selection-in-mask", REQUIRE_SELECTION);
|
||||
options.put("command-blacklist", WE_BLACKLIST);
|
||||
options.put("command-processor", COMMAND_PROCESSOR);
|
||||
@ -53,6 +68,18 @@ public class Settings {
|
||||
options.put("history.compress", false);
|
||||
options.put("metrics", METRICS);
|
||||
|
||||
// Default limit
|
||||
FaweLimit defaultLimit = new FaweLimit();
|
||||
if (!config.contains("limits.default")) {
|
||||
config.createSection("limits.default");
|
||||
}
|
||||
defaultLimit.load(config.getConfigurationSection("limits.default"), null, true);
|
||||
for (String key : config.getConfigurationSection("limits").getKeys(false)) {
|
||||
FaweLimit limit = new FaweLimit();
|
||||
limit.load(config.getConfigurationSection("limits." + key), defaultLimit, false);
|
||||
}
|
||||
|
||||
|
||||
for (final Entry<String, Object> node : options.entrySet()) {
|
||||
if (!config.contains(node.getKey())) {
|
||||
config.set(node.getKey(), node.getValue());
|
||||
@ -60,10 +87,6 @@ public class Settings {
|
||||
}
|
||||
FIX_ALL_LIGHTING = config.getBoolean("fix-all-lighting");
|
||||
COMMAND_PROCESSOR = config.getBoolean("command-processor");
|
||||
MAX_BLOCKSTATES = config.getInt("max-blockstates");
|
||||
MAX_ENTITIES = config.getInt("max-entities");
|
||||
WE_MAX_ITERATIONS = config.getInt("max-iterations");
|
||||
WE_MAX_VOLUME = config.getInt("max-volume");
|
||||
MEM_FREE = config.getInt("max-memory-percent");
|
||||
REQUIRE_SELECTION = config.getBoolean("require-selection-in-mask");
|
||||
WE_BLACKLIST = config.getStringList("command-blacklist");
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BlockType;
|
||||
@ -26,7 +27,7 @@ public class EditSessionWrapper {
|
||||
return minY;
|
||||
}
|
||||
|
||||
public Extent getHistoryExtent(final Extent parent, FaweChangeSet set, final FawePlayer<?> player) {
|
||||
return new HistoryExtent(player.getLocation().world, parent, set);
|
||||
public Extent getHistoryExtent(String world, FaweLimit limit, Extent parent, FaweChangeSet set, FaweQueue queue, FawePlayer<?> player) {
|
||||
return new HistoryExtent(world, limit, parent, set, queue);
|
||||
}
|
||||
}
|
||||
|
54
core/src/main/java/com/boydti/fawe/object/FaweLimit.java
Normal file
54
core/src/main/java/com/boydti/fawe/object/FaweLimit.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.boydti.fawe.object;
|
||||
|
||||
import com.boydti.fawe.configuration.ConfigurationSection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Jesse on 4/5/2016.
|
||||
*/
|
||||
public class FaweLimit {
|
||||
public int MAX_CHANGES = 50000000;
|
||||
public int MAX_FAILS = 50000000;
|
||||
public int MAX_CHECKS = 50000000;
|
||||
public int MAX_ITERATIONS = 1000;
|
||||
public int MAX_BLOCKSTATES = 1337;
|
||||
public int MAX_ENTITIES = 1337;
|
||||
|
||||
public static FaweLimit MAX;
|
||||
static {
|
||||
MAX = new FaweLimit();
|
||||
MAX.MAX_CHANGES = Integer.MAX_VALUE;
|
||||
MAX.MAX_FAILS = Integer.MAX_VALUE;
|
||||
MAX.MAX_CHECKS = Integer.MAX_VALUE;
|
||||
MAX.MAX_ITERATIONS = Integer.MAX_VALUE;
|
||||
MAX.MAX_BLOCKSTATES = Integer.MAX_VALUE;
|
||||
MAX.MAX_ENTITIES = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public boolean load(ConfigurationSection section, FaweLimit defaultLimit, boolean save) {
|
||||
this.MAX_CHANGES = section.getInt("max-changes", defaultLimit == null ? MAX_CHANGES : defaultLimit.MAX_CHANGES);
|
||||
this.MAX_FAILS = section.getInt("max-fails", defaultLimit == null ? MAX_FAILS : defaultLimit.MAX_FAILS);
|
||||
this.MAX_CHECKS = section.getInt("max-checks", defaultLimit == null ? MAX_CHECKS : defaultLimit.MAX_CHECKS);
|
||||
this.MAX_ITERATIONS = section.getInt("max-iterations", defaultLimit == null ? MAX_ITERATIONS : defaultLimit.MAX_ITERATIONS);
|
||||
this.MAX_BLOCKSTATES = section.getInt("max-blockstates", defaultLimit == null ? MAX_BLOCKSTATES : defaultLimit.MAX_BLOCKSTATES);
|
||||
this.MAX_ENTITIES = section.getInt("max-entities", defaultLimit == null ? MAX_ENTITIES : defaultLimit.MAX_ENTITIES);
|
||||
boolean changed = false;
|
||||
if (save) {
|
||||
HashMap<String, Object> options = new HashMap<>();
|
||||
options.put("max-changes", MAX_CHANGES);
|
||||
options.put("max-fails", MAX_FAILS);
|
||||
options.put("max-checks", MAX_CHECKS);
|
||||
options.put("max-iterations", MAX_ITERATIONS);
|
||||
options.put("max-blockstates", MAX_BLOCKSTATES);
|
||||
options.put("max-entities", MAX_ENTITIES);
|
||||
for (Map.Entry<String, Object> entry : options.entrySet()) {
|
||||
if (!section.contains(entry.getKey())) {
|
||||
section.set(entry.getKey(), entry.getValue());
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ public abstract class FawePlayer<T> {
|
||||
/**
|
||||
* The metadata map.
|
||||
*/
|
||||
private ConcurrentHashMap<String, Object> meta;
|
||||
private volatile ConcurrentHashMap<String, Object> meta;
|
||||
|
||||
public static <T> FawePlayer<T> wrap(final Object obj) {
|
||||
return Fawe.imp().wrap(obj);
|
||||
@ -67,6 +67,10 @@ public abstract class FawePlayer<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public FaweLimit getLimit() {
|
||||
return Settings.getLimit(this);
|
||||
}
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public abstract UUID getUUID();
|
||||
|
@ -3,7 +3,6 @@ package com.boydti.fawe.object;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
@ -30,6 +29,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
|
||||
|
||||
private final com.boydti.fawe.object.changeset.FaweChangeSet changeSet;
|
||||
private final FaweQueue queue;
|
||||
private final FaweLimit limit;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
@ -37,9 +37,10 @@ public class HistoryExtent extends AbstractDelegateExtent {
|
||||
* @param extent the extent
|
||||
* @param changeSet the change set
|
||||
*/
|
||||
public HistoryExtent(final String world, final Extent extent, final FaweChangeSet changeSet) {
|
||||
public HistoryExtent(final String world, FaweLimit limit, final Extent extent, final FaweChangeSet changeSet, FaweQueue queue) {
|
||||
super(extent);
|
||||
this.queue = SetQueue.IMP.getQueue(world);
|
||||
this.limit = limit;
|
||||
this.queue = queue;
|
||||
checkNotNull(changeSet);
|
||||
this.changeSet = changeSet;
|
||||
}
|
||||
|
@ -175,11 +175,13 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
||||
try {
|
||||
OutputStream stream = getBAOS(x, y, z);
|
||||
//x
|
||||
stream.write((x - ox) & 0xff);
|
||||
stream.write(((x - ox) >> 8) & 0xff);
|
||||
x-=ox;
|
||||
stream.write((x) & 0xff);
|
||||
stream.write(((x) >> 8) & 0xff);
|
||||
//z
|
||||
stream.write((z - oz) & 0xff);
|
||||
stream.write(((z - oz) >> 8) & 0xff);
|
||||
z-=oz;
|
||||
stream.write((z) & 0xff);
|
||||
stream.write(((z) >> 8) & 0xff);
|
||||
//y
|
||||
stream.write((byte) y);
|
||||
//from
|
||||
@ -375,8 +377,8 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
|
||||
|
||||
public Change read() {
|
||||
try {
|
||||
int x = gis.read() + (gis.read() << 8) + ox;
|
||||
int z = gis.read() + (gis.read() << 8) + oz;
|
||||
int x = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + ox;
|
||||
int z = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + oz;
|
||||
int y = gis.read() & 0xff;
|
||||
int from1 = gis.read();
|
||||
int from2 = gis.read();
|
||||
|
@ -64,11 +64,13 @@ public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
|
||||
try {
|
||||
OutputStream stream = getBAOS(x, y, z);
|
||||
//x
|
||||
stream.write((x - ox) & 0xff);
|
||||
stream.write(((x - ox) >> 8) & 0xff);
|
||||
x -= ox;
|
||||
z -= oz;
|
||||
stream.write((x & 0xff));
|
||||
stream.write(((x >> 8) & 0xff));
|
||||
//z
|
||||
stream.write((z - oz) & 0xff);
|
||||
stream.write(((z - oz) >> 8) & 0xff);
|
||||
stream.write((z & 0xff));
|
||||
stream.write( ((z >> 8) & 0xff));
|
||||
//y
|
||||
stream.write((byte) y);
|
||||
//from
|
||||
@ -150,8 +152,6 @@ public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
|
||||
idsStream = new ByteArrayOutputStream(Settings.BUFFER_SIZE);
|
||||
idsStreamZip = new LZ4OutputStream(idsStream, Settings.BUFFER_SIZE, factory.fastCompressor());
|
||||
if (Settings.COMPRESSION_LEVEL > 0) {
|
||||
// Deflater deflater = new Deflater(Math.min(9, Settings.COMPRESSION_LEVEL), true);
|
||||
// idsStreamZip = new DeflaterOutputStream(idsStreamZip, deflater, true);
|
||||
idsStreamZip = new LZ4OutputStream(idsStreamZip, Settings.BUFFER_SIZE, factory.highCompressor());
|
||||
}
|
||||
ox = x;
|
||||
@ -198,8 +198,8 @@ public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
|
||||
|
||||
public Change read() {
|
||||
try {
|
||||
int x = gis.read() + (gis.read() << 8) + ox;
|
||||
int z = gis.read() + (gis.read() << 8) + oz;
|
||||
int x = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + ox;
|
||||
int z = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + oz;
|
||||
int y = gis.read() & 0xff;
|
||||
int from1 = gis.read();
|
||||
int from2 = gis.read();
|
||||
|
@ -2,7 +2,6 @@ package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
@ -21,13 +20,11 @@ import java.util.List;
|
||||
|
||||
public class FastWorldEditExtent extends AbstractDelegateExtent {
|
||||
|
||||
private final Thread thread;
|
||||
private final FaweQueue queue;
|
||||
|
||||
public FastWorldEditExtent(final World world, final Thread thread) {
|
||||
public FastWorldEditExtent(final World world, FaweQueue queue) {
|
||||
super(world);
|
||||
this.thread = thread;
|
||||
this.queue = SetQueue.IMP.getQueue(world.getName());
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -46,9 +43,7 @@ public class FastWorldEditExtent extends AbstractDelegateExtent {
|
||||
if (!queue.isChunkLoaded(position.getBlockX() >> 4, position.getBlockZ() >> 4)) {
|
||||
return EditSession.nullBiome;
|
||||
}
|
||||
synchronized (this.thread) {
|
||||
return super.getBiome(position);
|
||||
}
|
||||
return super.getBiome(position);
|
||||
}
|
||||
|
||||
private BaseBlock lastBlock;
|
||||
@ -67,24 +62,18 @@ public class FastWorldEditExtent extends AbstractDelegateExtent {
|
||||
return EditSession.nullBlock;
|
||||
}
|
||||
}
|
||||
synchronized (this.thread) {
|
||||
this.lastVector = position.toBlockVector();
|
||||
return this.lastBlock = super.getBlock(position);
|
||||
}
|
||||
this.lastVector = position.toBlockVector();
|
||||
return this.lastBlock = super.getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
synchronized (this.thread) {
|
||||
return super.getEntities();
|
||||
}
|
||||
return super.getEntities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities(final Region region) {
|
||||
synchronized (this.thread) {
|
||||
return super.getEntities(region);
|
||||
}
|
||||
return super.getEntities(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,13 +1,10 @@
|
||||
package com.boydti.fawe.object.extent;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.sk89q.worldedit.BlockVector;
|
||||
@ -29,30 +26,18 @@ import java.util.List;
|
||||
|
||||
public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
private final FaweQueue queue;
|
||||
private final FaweLimit limit;
|
||||
private Extent parent;
|
||||
|
||||
private boolean BSblocked = false;
|
||||
private boolean Eblocked = false;
|
||||
private int BScount = 0;
|
||||
private int Ecount = 0;
|
||||
private int count = 0;
|
||||
|
||||
private int max;
|
||||
private final FawePlayer<?> user;
|
||||
private final HashSet<RegionWrapper> mask;
|
||||
private final Thread thread;
|
||||
|
||||
public ProcessedWEExtent(final World world, final Thread thread, final FawePlayer<?> player, final HashSet<RegionWrapper> mask, final int max) {
|
||||
public ProcessedWEExtent(final World world, final FawePlayer<?> player, final HashSet<RegionWrapper> mask, FaweLimit limit, FaweQueue queue) {
|
||||
super(world);
|
||||
this.user = player;
|
||||
this.queue = SetQueue.IMP.getQueue(world.getName());
|
||||
this.max = max != -1 ? max : Integer.MAX_VALUE;
|
||||
this.queue = queue;
|
||||
this.mask = mask;
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
public void setMax(final int max) {
|
||||
this.max = max != -1 ? max : Integer.MAX_VALUE;
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public void setParent(final Extent parent) {
|
||||
@ -61,14 +46,9 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
|
||||
@Override
|
||||
public Entity createEntity(final Location location, final BaseEntity entity) {
|
||||
if (this.Eblocked) {
|
||||
if (limit.MAX_ENTITIES-- < 0) {
|
||||
return null;
|
||||
}
|
||||
this.Ecount++;
|
||||
if (this.Ecount > Settings.MAX_ENTITIES) {
|
||||
this.Eblocked = true;
|
||||
MainUtil.sendAdmin(BBC.WORLDEDIT_DANGEROUS_WORLDEDIT.format(queue.world + ": " + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ(), this.user));
|
||||
}
|
||||
if (WEManager.IMP.maskContains(this.mask, location.getBlockX(), location.getBlockZ())) {
|
||||
TaskManager.IMP.task(new Runnable() {
|
||||
@Override
|
||||
@ -85,9 +65,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
if (!queue.isChunkLoaded(position.getBlockX() >> 4, position.getBlockZ() >> 4)) {
|
||||
return EditSession.nullBiome;
|
||||
}
|
||||
synchronized (this.thread) {
|
||||
return super.getBiome(position);
|
||||
}
|
||||
return super.getBiome(position);
|
||||
}
|
||||
|
||||
private BaseBlock lastBlock;
|
||||
@ -95,6 +73,9 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(final Vector position) {
|
||||
// TODO get fast!
|
||||
// TODO caches base blocks
|
||||
|
||||
if ((this.lastBlock != null) && this.lastVector.equals(position.toBlockVector())) {
|
||||
return this.lastBlock;
|
||||
}
|
||||
@ -106,24 +87,18 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
return EditSession.nullBlock;
|
||||
}
|
||||
}
|
||||
synchronized (this.thread) {
|
||||
this.lastVector = position.toBlockVector();
|
||||
return this.lastBlock = super.getLazyBlock(position);
|
||||
}
|
||||
this.lastVector = position.toBlockVector();
|
||||
return super.getLazyBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
synchronized (this.thread) {
|
||||
return super.getEntities();
|
||||
}
|
||||
return super.getEntities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities(final Region region) {
|
||||
synchronized (this.thread) {
|
||||
return super.getEntities(region);
|
||||
}
|
||||
return super.getEntities(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -171,18 +146,13 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
case 33:
|
||||
case 151:
|
||||
case 178: {
|
||||
if (this.BSblocked) {
|
||||
if (limit.MAX_BLOCKSTATES-- < 0) {
|
||||
return false;
|
||||
}
|
||||
this.BScount++;
|
||||
if (this.BScount > Settings.MAX_BLOCKSTATES) {
|
||||
this.BSblocked = true;
|
||||
MainUtil.sendAdmin(BBC.WORLDEDIT_DANGEROUS_WORLDEDIT.format(queue.world + ": " + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ(), this.user));
|
||||
}
|
||||
final int x = location.getBlockX();
|
||||
final int z = location.getBlockZ();
|
||||
if (WEManager.IMP.maskContains(this.mask, x, z)) {
|
||||
if (this.count++ > this.max) {
|
||||
if (limit.MAX_CHANGES-- < 0) {
|
||||
if (this.parent != null) {
|
||||
WEManager.IMP.cancelEdit(this.parent);
|
||||
this.parent = null;
|
||||
@ -204,6 +174,11 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
}
|
||||
queue.setBlock(x, location.getBlockY(), z, id, FaweCache.hasData(id) ? (byte) block.getData() : 0);
|
||||
return true;
|
||||
} else if (limit.MAX_FAILS-- < 0) {
|
||||
if (this.parent != null) {
|
||||
WEManager.IMP.cancelEdit(this.parent);
|
||||
this.parent = null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -212,7 +187,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
final int y = location.getBlockY();
|
||||
final int z = location.getBlockZ();
|
||||
if (WEManager.IMP.maskContains(this.mask, location.getBlockX(), location.getBlockZ())) {
|
||||
if (this.count++ > this.max) {
|
||||
if (limit.MAX_CHANGES--<0) {
|
||||
WEManager.IMP.cancelEdit(this.parent);
|
||||
this.parent = null;
|
||||
return false;
|
||||
@ -306,6 +281,11 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (limit.MAX_FAILS-- < 0) {
|
||||
if (this.parent != null) {
|
||||
WEManager.IMP.cancelEdit(this.parent);
|
||||
this.parent = null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -40,11 +40,7 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
final PlotId id = plot.getId();
|
||||
boolean hasPerm = false;
|
||||
if (plot.owner != null) {
|
||||
if (plot.owner.equals(pp.getUUID())) {
|
||||
hasPerm = true;
|
||||
} else if (plot.isAdded(pp.getUUID()) && pp.hasPermission("fawe.plotsquared.member")) {
|
||||
hasPerm = true;
|
||||
}
|
||||
hasPerm = plot.isOwner(pp.getUUID()) || plot.getTrusted().contains(pp.getUUID()) || (plot.getMembers().contains(pp.getUUID()) && pp.hasPermission("fawe.plotsquared.member"));
|
||||
if (hasPerm) {
|
||||
RegionWrapper region = plot.getLargestRegion();
|
||||
HashSet<RegionWrapper> regions = plot.getRegions();
|
||||
|
@ -26,7 +26,6 @@ public class WEManager {
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
parent = null;
|
||||
}
|
||||
|
||||
public boolean maskContains(final HashSet<RegionWrapper> mask, final int x, final int z) {
|
||||
|
@ -24,6 +24,7 @@ import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.EditSessionWrapper;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.NullChangeSet;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
@ -35,8 +36,10 @@ import com.boydti.fawe.object.extent.NullExtent;
|
||||
import com.boydti.fawe.object.extent.ProcessedWEExtent;
|
||||
import com.boydti.fawe.object.extent.SafeExtentWrapper;
|
||||
import com.boydti.fawe.util.ExtentWrapper;
|
||||
import com.boydti.fawe.util.FaweQueue;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.Perm;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
@ -153,14 +156,14 @@ public class EditSession implements Extent {
|
||||
protected final World world;
|
||||
private FaweChangeSet changeSet;
|
||||
private final EditSessionWrapper wrapper;
|
||||
private @Nullable Extent changeSetExtent;
|
||||
private MaskingExtent maskingExtent;
|
||||
private @Nullable ProcessedWEExtent processed;
|
||||
private final Extent bypassReorderHistory;
|
||||
private final Extent bypassHistory;
|
||||
private final Extent bypassNone;
|
||||
private boolean fastmode;
|
||||
private Mask oldMask;
|
||||
private FaweLimit limit = FaweLimit.MAX;
|
||||
private FaweQueue queue;
|
||||
|
||||
public static BaseBiome nullBiome = new BaseBiome(0);
|
||||
public static BaseBlock nullBlock = new BaseBlock(0);
|
||||
@ -190,8 +193,6 @@ public class EditSession implements Extent {
|
||||
this(WorldEdit.getInstance().getEventBus(), world, maxBlocks, blockBag, new EditSessionEvent(world, null, maxBlocks, null));
|
||||
}
|
||||
|
||||
private final Thread thread;
|
||||
|
||||
private int changes = 0;
|
||||
private int maxBlocks;
|
||||
private BlockBag blockBag;
|
||||
@ -212,7 +213,6 @@ public class EditSession implements Extent {
|
||||
|
||||
this.blockBag = blockBag;
|
||||
this.maxBlocks = maxBlocks;
|
||||
this.thread = Fawe.get().getMainThread();
|
||||
this.world = world;
|
||||
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
|
||||
// this.changeSet = new BlockOptimizedHistory();
|
||||
@ -227,10 +227,10 @@ public class EditSession implements Extent {
|
||||
return;
|
||||
}
|
||||
final Actor actor = event.getActor();
|
||||
|
||||
this.queue = SetQueue.IMP.getQueue(world.getName());
|
||||
// Not a player; bypass history
|
||||
if ((actor == null) || !actor.isPlayer()) {
|
||||
Extent extent = new FastWorldEditExtent(world, this.thread);
|
||||
Extent extent = new FastWorldEditExtent(world, queue);
|
||||
// Everything bypasses
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
|
||||
@ -246,9 +246,10 @@ public class EditSession implements Extent {
|
||||
final String name = actor.getName();
|
||||
final FawePlayer<Object> fp = FawePlayer.wrap(name);
|
||||
final LocalSession session = fp.getSession();
|
||||
this.fastmode = session.hasFastMode();
|
||||
if (fp.hasWorldEditBypass()) {
|
||||
// Bypass skips processing and area restrictions
|
||||
extent = new FastWorldEditExtent(world, this.thread);
|
||||
extent = new FastWorldEditExtent(world, queue);
|
||||
if (this.hasFastMode()) {
|
||||
// Fastmode skips history and memory checks
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
|
||||
@ -260,6 +261,7 @@ public class EditSession implements Extent {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
this.limit = fp.getLimit();
|
||||
final HashSet<RegionWrapper> mask = WEManager.IMP.getMask(fp);
|
||||
if (mask.size() == 0) {
|
||||
if (Perm.hasPermission(fp, "fawe.admin")) {
|
||||
@ -275,7 +277,8 @@ public class EditSession implements Extent {
|
||||
return;
|
||||
}
|
||||
// Process the WorldEdit action
|
||||
extent = this.processed = new ProcessedWEExtent(world, this.thread, fp, mask, maxBlocks);
|
||||
ProcessedWEExtent processed = new ProcessedWEExtent(world, fp, mask, limit, queue);
|
||||
extent = processed;
|
||||
if (this.hasFastMode()) {
|
||||
// Fastmode skips history, masking, and memory checks
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
|
||||
@ -283,7 +286,7 @@ public class EditSession implements Extent {
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY);
|
||||
extent = new ExtentWrapper(extent);
|
||||
// Set the parent. This allows efficient cancelling
|
||||
this.processed.setParent(extent);
|
||||
processed.setParent(extent);
|
||||
this.bypassReorderHistory = extent;
|
||||
this.bypassHistory = extent;
|
||||
this.bypassNone = extent;
|
||||
@ -304,13 +307,13 @@ public class EditSession implements Extent {
|
||||
}
|
||||
// Perform memory checks after reorder
|
||||
extent = new SafeExtentWrapper(fp, extent);
|
||||
this.processed.setParent(extent);
|
||||
processed.setParent(extent);
|
||||
}
|
||||
// Include history, masking and memory checking.
|
||||
Extent wrapped;
|
||||
extent = wrapped = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
|
||||
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
|
||||
extent = this.changeSetExtent = this.wrapper.getHistoryExtent(extent, this.changeSet, fp);
|
||||
extent = this.wrapper.getHistoryExtent(world.getName(), limit, extent, this.changeSet, queue, fp);
|
||||
final Player skp = (Player) actor;
|
||||
final int item = skp.getItemInHand();
|
||||
boolean hasMask = session.getMask() != null;
|
||||
@ -386,10 +389,7 @@ public class EditSession implements Extent {
|
||||
* @param limit the limit (>= 0) or -1 for no limit
|
||||
*/
|
||||
public void setBlockChangeLimit(final int limit) {
|
||||
if (this.processed != null) {
|
||||
this.maxBlocks = limit;
|
||||
this.processed.setMax(limit);
|
||||
}
|
||||
// Nothing
|
||||
}
|
||||
|
||||
/**
|
||||
@ -531,9 +531,7 @@ public class EditSession implements Extent {
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(final Vector2D position) {
|
||||
synchronized (this.thread) {
|
||||
return this.bypassNone.getBiome(position);
|
||||
}
|
||||
return this.bypassNone.getBiome(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -544,16 +542,19 @@ public class EditSession implements Extent {
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(final Vector position) {
|
||||
synchronized (this.thread) {
|
||||
return this.world.getBlock(position);
|
||||
if (limit != null && limit.MAX_CHECKS-- < 0) {
|
||||
return nullBlock;
|
||||
}
|
||||
int combinedId4Data = queue.getCombinedId4Data(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
if (!FaweCache.hasNBT(combinedId4Data >> 4)) {
|
||||
return FaweCache.CACHE_BLOCK[combinedId4Data];
|
||||
}
|
||||
return this.world.getLazyBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BaseBlock getBlock(final Vector position) {
|
||||
synchronized (this.thread) {
|
||||
return this.world.getBlock(position);
|
||||
}
|
||||
public BaseBlock getBlock(final Vector position) {
|
||||
return this.getLazyBlock(position);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -564,10 +565,12 @@ public class EditSession implements Extent {
|
||||
* @deprecated Use {@link #getLazyBlock(Vector)} or {@link #getBlock(Vector)}
|
||||
*/
|
||||
@Deprecated
|
||||
public synchronized int getBlockType(final Vector position) {
|
||||
synchronized (this.thread) {
|
||||
return this.world.getBlockType(position);
|
||||
public int getBlockType(final Vector position) {
|
||||
if (limit != null && limit.MAX_CHECKS-- < 0) {
|
||||
return 0;
|
||||
}
|
||||
int combinedId4Data = queue.getCombinedId4Data(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
return combinedId4Data >> 4;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -578,10 +581,12 @@ public class EditSession implements Extent {
|
||||
* @deprecated Use {@link #getLazyBlock(Vector)} or {@link #getBlock(Vector)}
|
||||
*/
|
||||
@Deprecated
|
||||
public synchronized int getBlockData(final Vector position) {
|
||||
synchronized (this.thread) {
|
||||
return this.world.getBlockData(position);
|
||||
public int getBlockData(final Vector position) {
|
||||
if (limit != null && limit.MAX_CHECKS-- < 0) {
|
||||
return 0;
|
||||
}
|
||||
int combinedId4Data = queue.getCombinedId4Data(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||
return combinedId4Data & 0xF;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -593,7 +598,7 @@ public class EditSession implements Extent {
|
||||
*/
|
||||
@Deprecated
|
||||
public BaseBlock rawGetBlock(final Vector position) {
|
||||
return this.getBlock(position);
|
||||
return this.getLazyBlock(position);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,6 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.extension.platform;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.google.common.base.Joiner;
|
||||
@ -235,7 +238,17 @@ public final class CommandManager {
|
||||
locals.put("arguments", event.getArguments());
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
FawePlayer fp;
|
||||
if (actor.isPlayer()) {
|
||||
fp = Fawe.imp().wrap(actor.getName());
|
||||
if (fp.getMeta("fawe_action") != null) {
|
||||
BBC.WORLDEDIT_COMMAND_LIMIT.send(fp);
|
||||
return;
|
||||
}
|
||||
fp.setMeta("fawe_action", true);
|
||||
} else {
|
||||
fp = null;
|
||||
}
|
||||
try {
|
||||
dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
|
||||
} catch (CommandPermissionsException e) {
|
||||
@ -266,6 +279,9 @@ public final class CommandManager {
|
||||
log.log(Level.SEVERE, "An unknown error occurred", e);
|
||||
}
|
||||
} finally {
|
||||
if (fp != null) {
|
||||
fp.deleteMeta("fawe_action");
|
||||
}
|
||||
EditSession editSession = locals.get(EditSession.class);
|
||||
|
||||
if (editSession != null) {
|
||||
|
@ -1,89 +0,0 @@
|
||||
#################################################
|
||||
ForgeGradle 2.1-SNAPSHOT-unknown
|
||||
https://github.com/MinecraftForge/ForgeGradle
|
||||
#################################################
|
||||
Powered by MCP unknown
|
||||
http://modcoderpack.com
|
||||
by: Searge, ProfMobius, Fesh0r,
|
||||
R4wk, ZeuX, IngisKahn, bspkrs
|
||||
#################################################
|
||||
Version string 'unspecified' does not match SemVer specification
|
||||
You should try SemVer : http://semver.org/
|
||||
:core:compileJava
|
||||
:forge:deobfCompileDummyTask
|
||||
:forge:deobfProvidedDummyTask
|
||||
:forge:extractDependencyATs SKIPPED
|
||||
:forge:extractMcpData
|
||||
:core:compileJava UP-TO-DATE
|
||||
:core:processResources UP-TO-DATE
|
||||
:core:classes UP-TO-DATE
|
||||
:core:jar UP-TO-DATE
|
||||
:forge:extractMcpData SKIPPED
|
||||
:forge:extractMcpMappings SKIPPED
|
||||
:forge:genSrgs SKIPPED
|
||||
:forge:getVersionJson
|
||||
:forge:downloadServer SKIPPED
|
||||
:forge:splitServerJar SKIPPED
|
||||
:forge:deobfMcMCP SKIPPED
|
||||
:forge:sourceApiJava UP-TO-DATE
|
||||
:forge:compileApiJava UP-TO-DATE
|
||||
:forge:processApiResources UP-TO-DATE
|
||||
:forge:apiClasses UP-TO-DATE
|
||||
:forge:sourceMainJava
|
||||
:forge:compileJavaC:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'modid()' in type 'Mod': class file for net.minecraftforge.fml.common.Mod not found
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'name()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'version()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptableRemoteVersions()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'dependencies()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptedMinecraftVersions()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'value()' in type 'Instance': class file for net.minecraftforge.fml.common.Mod$Instance not found
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'serverSide()' in type 'SidedProxy': class file for net.minecraftforge.fml.common.SidedProxy not found
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'clientSide()' in type 'SidedProxy'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'modid()' in type 'Mod': class file for net.minecraftforge.fml.common.Mod not found
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'name()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'version()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptableRemoteVersions()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'dependencies()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptedMinecraftVersions()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'value()' in type 'Instance': class file for net.minecraftforge.fml.common.Mod$Instance not found
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'serverSide()' in type 'SidedProxy': class file for net.minecraftforge.fml.common.SidedProxy not found
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'clientSide()' in type 'SidedProxy'
|
||||
Note: Writing plugin metadata to file:/C:/Users/Jesse/Desktop/OTHER/GitHub/FastAsyncWorldEdit/forge/build/classes/main/mcmod.info
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'modid()' in type 'Mod': class file for net.minecraftforge.fml.common.Mod not found
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'name()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'version()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptableRemoteVersions()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'dependencies()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'acceptedMinecraftVersions()' in type 'Mod'
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'value()' in type 'Instance': class file for net.minecraftforge.fml.common.Mod$Instance not found
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'serverSide()' in type 'SidedProxy': class file for net.minecraftforge.fml.common.SidedProxy not found
|
||||
C:\Users\Jesse\.gradle\caches\modules-2\files-2.1\com.sk89q.worldedit\worldedit-forge-mc1.8.9\6.1.1\dffd7e1882eba256eb2132fe315682c1d26522b1\worldedit-forge-mc1.8.9-6.1.1.jar(com/sk89q/worldedit/forge/ForgeWorldEdit.class): warning: Cannot find annotation method 'clientSide()' in type 'SidedProxy'
|
||||
Note: Some input files use or override a deprecated API.
|
||||
Note: Recompile with -Xlint:deprecation for details.
|
||||
Note: Some input files use unchecked or unsafe operations.
|
||||
Note: Recompile with -Xlint:unchecked for details.
|
||||
27 warnings
|
||||
|
||||
:forge:processResources UP-TO-DATE
|
||||
:forge:classes
|
||||
:forge:jar
|
||||
:forge:sourceTestJava UP-TO-DATE
|
||||
:forge:compileTestJava UP-TO-DATE
|
||||
:forge:processTestResources UP-TO-DATE
|
||||
:forge:testClasses UP-TO-DATE
|
||||
:forge:test UP-TO-DATE
|
||||
:forge:reobfJar
|
||||
:forge:shadowJar
|
||||
:forge:reobfShadowJar
|
||||
:forge:extractRangemapReplacedMain
|
||||
C:\Users\Jesse\Desktop\OTHER\GitHub\FastAsyncWorldEdit\forge\build\sources\main\java
|
||||
:forge:retromapReplacedMain
|
||||
remapping source...
|
||||
:forge:sourceJar
|
||||
:forge:assemble
|
||||
:forge:check UP-TO-DATE
|
||||
:forge:build
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
|
||||
Total time: 36.523 secs
|
@ -19,7 +19,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.mcstats.Metrics;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||
@ -129,7 +128,7 @@ public class FaweSponge implements IFawe {
|
||||
@Override
|
||||
public void startMetrics() {
|
||||
try {
|
||||
Metrics metrics = new Metrics(Sponge.getGame(), Sponge.getPluginManager().fromInstance(plugin).get());
|
||||
SpongeMetrics metrics = new SpongeMetrics(Sponge.getGame(), Sponge.getPluginManager().fromInstance(plugin).get());
|
||||
metrics.start();
|
||||
debug("[FAWE] &6Metrics enabled.");
|
||||
} catch (IOException e) {
|
||||
|
518
forge/src/main/java/com/boydti/fawe/forge/SpongeMetrics.java
Normal file
518
forge/src/main/java/com/boydti/fawe/forge/SpongeMetrics.java
Normal file
@ -0,0 +1,518 @@
|
||||
package com.boydti.fawe.forge;
|
||||
|
||||
/*
|
||||
* Copyright 2011-2013 Tyler Blair. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and contributors and should not be interpreted as representing official policies,
|
||||
* either expressed or implied, of anybody else.
|
||||
*/
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
|
||||
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
|
||||
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
||||
import org.spongepowered.api.Game;
|
||||
import org.spongepowered.api.plugin.PluginContainer;
|
||||
import org.spongepowered.api.scheduler.Task;
|
||||
|
||||
public class SpongeMetrics {
|
||||
|
||||
/**
|
||||
* The current revision number
|
||||
*/
|
||||
private final static int REVISION = 7;
|
||||
|
||||
/**
|
||||
* The base url of the metrics domain
|
||||
*/
|
||||
private static final String BASE_URL = "http://report.mcstats.org";
|
||||
|
||||
/**
|
||||
* The url used to report a server's status
|
||||
*/
|
||||
private static final String REPORT_URL = "/plugin/%s";
|
||||
|
||||
/**
|
||||
* Interval of time to ping (in minutes)
|
||||
*/
|
||||
private static final int PING_INTERVAL = 15;
|
||||
|
||||
/**
|
||||
* The game data is being sent for
|
||||
*/
|
||||
private final Game game;
|
||||
|
||||
/**
|
||||
* The plugin this metrics submits for
|
||||
*/
|
||||
private final PluginContainer plugin;
|
||||
/**
|
||||
* Lock for synchronization
|
||||
*/
|
||||
private final Object optOutLock = new Object();
|
||||
/**
|
||||
* The plugin configuration file
|
||||
*/
|
||||
private CommentedConfigurationNode config;
|
||||
/**
|
||||
* The configuration loader
|
||||
*/
|
||||
private ConfigurationLoader<CommentedConfigurationNode> configurationLoader;
|
||||
/**
|
||||
* The plugin configuration file
|
||||
*/
|
||||
private File configurationFile;
|
||||
/**
|
||||
* Unique server id
|
||||
*/
|
||||
private String guid;
|
||||
/**
|
||||
* Debug mode
|
||||
*/
|
||||
private boolean debug;
|
||||
/**
|
||||
* The scheduled task
|
||||
*/
|
||||
private volatile Task task = null;
|
||||
|
||||
@Inject
|
||||
public SpongeMetrics(final Game game, final PluginContainer plugin) throws IOException {
|
||||
if (plugin == null) {
|
||||
throw new IllegalArgumentException("Plugin cannot be null");
|
||||
}
|
||||
|
||||
this.game = game;
|
||||
this.plugin = plugin;
|
||||
|
||||
loadConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* GZip compress a string of bytes
|
||||
*
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static byte[] gzip(final String input) {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
GZIPOutputStream gzos = null;
|
||||
|
||||
try {
|
||||
gzos = new GZIPOutputStream(baos);
|
||||
gzos.write(input.getBytes("UTF-8"));
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (gzos != null) {
|
||||
try {
|
||||
gzos.close();
|
||||
} catch (final IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a json encoded key/value pair to the given string builder.
|
||||
*
|
||||
* @param json
|
||||
* @param key
|
||||
* @param value
|
||||
* @throws java.io.UnsupportedEncodingException
|
||||
*/
|
||||
private static void appendJSONPair(final StringBuilder json, final String key, final String value) throws UnsupportedEncodingException {
|
||||
boolean isValueNumeric = false;
|
||||
|
||||
try {
|
||||
if (value.equals("0") || !value.endsWith("0")) {
|
||||
Double.parseDouble(value);
|
||||
isValueNumeric = true;
|
||||
}
|
||||
} catch (final NumberFormatException e) {
|
||||
isValueNumeric = false;
|
||||
}
|
||||
|
||||
if (json.charAt(json.length() - 1) != '{') {
|
||||
json.append(',');
|
||||
}
|
||||
|
||||
json.append(escapeJSON(key));
|
||||
json.append(':');
|
||||
|
||||
if (isValueNumeric) {
|
||||
json.append(value);
|
||||
} else {
|
||||
json.append(escapeJSON(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string to create a valid JSON string
|
||||
*
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
private static String escapeJSON(final String text) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append('"');
|
||||
for (int index = 0; index < text.length(); index++) {
|
||||
final char chr = text.charAt(index);
|
||||
|
||||
switch (chr) {
|
||||
case '"':
|
||||
case '\\':
|
||||
builder.append('\\');
|
||||
builder.append(chr);
|
||||
break;
|
||||
case '\b':
|
||||
builder.append("\\b");
|
||||
break;
|
||||
case '\t':
|
||||
builder.append("\\t");
|
||||
break;
|
||||
case '\n':
|
||||
builder.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.append("\\r");
|
||||
break;
|
||||
default:
|
||||
if (chr < ' ') {
|
||||
final String t = "000" + Integer.toHexString(chr);
|
||||
builder.append("\\u" + t.substring(t.length() - 4));
|
||||
} else {
|
||||
builder.append(chr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
builder.append('"');
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode text as UTF-8
|
||||
*
|
||||
* @param text the text to encode
|
||||
* @return the encoded text, as UTF-8
|
||||
*/
|
||||
private static String urlEncode(final String text) throws UnsupportedEncodingException {
|
||||
return URLEncoder.encode(text, "UTF-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configuration
|
||||
*/
|
||||
private void loadConfiguration() {
|
||||
configurationFile = getConfigFile();
|
||||
configurationLoader = HoconConfigurationLoader.builder().setFile(configurationFile).build();
|
||||
|
||||
try {
|
||||
if (!configurationFile.exists()) {
|
||||
configurationFile.createNewFile();
|
||||
config = configurationLoader.load();
|
||||
|
||||
config.setComment("This contains settings for MCStats: http://mcstats.org");
|
||||
config.getNode("mcstats.guid").setValue(UUID.randomUUID().toString());
|
||||
config.getNode("mcstats.opt-out").setValue(false);
|
||||
config.getNode("mcstats.debug").setValue(false);
|
||||
|
||||
configurationLoader.save(config);
|
||||
} else {
|
||||
config = configurationLoader.load();
|
||||
}
|
||||
|
||||
guid = config.getNode("mcstats.guid").getString();
|
||||
debug = config.getNode("mcstats.debug").getBoolean();
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
|
||||
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
|
||||
* ticks.
|
||||
*
|
||||
* @return True if statistics measuring is running, otherwise false.
|
||||
*/
|
||||
public boolean start() {
|
||||
synchronized (optOutLock) {
|
||||
// Did we opt out?
|
||||
if (isOptOut()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is metrics already running?
|
||||
if (task != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Begin hitting the server with glorious data
|
||||
final Task.Builder builder = game.getScheduler().createTaskBuilder();
|
||||
builder.async().interval(PING_INTERVAL, TimeUnit.MINUTES).execute(new Runnable() {
|
||||
|
||||
private boolean firstPost = true;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// This has to be synchronized or it can collide with the disable method.
|
||||
synchronized (optOutLock) {
|
||||
// Disable Task, if it is running and the server owner decided to opt-out
|
||||
if (isOptOut() && (task != null)) {
|
||||
task.cancel();
|
||||
task = null;
|
||||
}
|
||||
}
|
||||
|
||||
// We use the inverse of firstPost because if it is the first time we are posting,
|
||||
// it is not a interval ping, so it evaluates to FALSE
|
||||
// Each time thereafter it will evaluate to TRUE, i.e PING!
|
||||
postPlugin(!firstPost);
|
||||
|
||||
// After the first post we set firstPost to false
|
||||
// Each post thereafter will be a ping
|
||||
firstPost = false;
|
||||
} catch (final IOException e) {
|
||||
if (debug) {
|
||||
Fawe.debug("[Metrics] " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the server owner denied plugin metrics?
|
||||
*
|
||||
* @return true if metrics should be opted out of it
|
||||
*/
|
||||
public boolean isOptOut() {
|
||||
synchronized (optOutLock) {
|
||||
loadConfiguration();
|
||||
|
||||
return config.getNode("mcstats.opt-out").getBoolean();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public void enable() throws IOException {
|
||||
// This has to be synchronized or it can collide with the check in the task.
|
||||
synchronized (optOutLock) {
|
||||
// Check if the server owner has already set opt-out, if not, set it.
|
||||
if (isOptOut()) {
|
||||
config.getNode("mcstats.opt-out").setValue(false);
|
||||
configurationLoader.save(config);
|
||||
}
|
||||
|
||||
// Enable Task, if it is not running
|
||||
if (task == null) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public void disable() throws IOException {
|
||||
// This has to be synchronized or it can collide with the check in the task.
|
||||
synchronized (optOutLock) {
|
||||
// Check if the server owner has already set opt-out, if not, set it.
|
||||
if (!isOptOut()) {
|
||||
config.getNode("mcstats.opt-out").setValue(true);
|
||||
configurationLoader.save(config);
|
||||
}
|
||||
|
||||
// Disable Task, if it is running
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
task = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
|
||||
*
|
||||
* @return the File object for the config file
|
||||
*/
|
||||
public File getConfigFile() {
|
||||
// TODO configDir
|
||||
final File configFolder = new File("config");
|
||||
|
||||
return new File(configFolder, "PluginMetrics.conf");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method that posts a plugin to the metrics website
|
||||
*
|
||||
*/
|
||||
private void postPlugin(final boolean isPing) throws IOException {
|
||||
// Server software specific section
|
||||
final String pluginName = plugin.getName();
|
||||
final boolean onlineMode = game.getServer().getOnlineMode(); // TRUE if online mode is enabled
|
||||
final String pluginVersion = plugin.getVersion().get();
|
||||
// TODO no visible way to get MC version at the moment
|
||||
// TODO added by game.getPlatform().getMinecraftVersion() -- impl in 2.1
|
||||
final String serverVersion = String.format("%s %s", "Sponge", game.getPlatform().getMinecraftVersion());
|
||||
final int playersOnline = game.getServer().getOnlinePlayers().size();
|
||||
|
||||
// END server software specific section -- all code below does not use any code outside of this class / Java
|
||||
|
||||
// Construct the post data
|
||||
final StringBuilder json = new StringBuilder(1024);
|
||||
json.append('{');
|
||||
|
||||
// The plugin's description file containg all of the plugin data such as name, version, author, etc
|
||||
appendJSONPair(json, "guid", guid);
|
||||
appendJSONPair(json, "plugin_version", pluginVersion);
|
||||
appendJSONPair(json, "server_version", serverVersion);
|
||||
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
|
||||
|
||||
// New data as of R6
|
||||
final String osname = System.getProperty("os.name");
|
||||
String osarch = System.getProperty("os.arch");
|
||||
final String osversion = System.getProperty("os.version");
|
||||
final String java_version = System.getProperty("java.version");
|
||||
final int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
// normalize os arch .. amd64 -> x86_64
|
||||
if (osarch.equals("amd64")) {
|
||||
osarch = "x86_64";
|
||||
}
|
||||
|
||||
appendJSONPair(json, "osname", osname);
|
||||
appendJSONPair(json, "osarch", osarch);
|
||||
appendJSONPair(json, "osversion", osversion);
|
||||
appendJSONPair(json, "cores", Integer.toString(coreCount));
|
||||
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
|
||||
appendJSONPair(json, "java_version", java_version);
|
||||
|
||||
// If we're pinging, append it
|
||||
if (isPing) {
|
||||
appendJSONPair(json, "ping", "1");
|
||||
}
|
||||
|
||||
// close json
|
||||
json.append('}');
|
||||
|
||||
// Create the url
|
||||
final URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
|
||||
|
||||
// Connect to the website
|
||||
URLConnection connection;
|
||||
|
||||
// Mineshafter creates a socks proxy, so we can safely bypass it
|
||||
// It does not reroute POST requests so we need to go around it
|
||||
if (isMineshafterPresent()) {
|
||||
connection = url.openConnection(Proxy.NO_PROXY);
|
||||
} else {
|
||||
connection = url.openConnection();
|
||||
}
|
||||
|
||||
final byte[] uncompressed = json.toString().getBytes();
|
||||
final byte[] compressed = gzip(json.toString());
|
||||
|
||||
// Headers
|
||||
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
|
||||
connection.addRequestProperty("Content-Type", "application/json");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip");
|
||||
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
|
||||
connection.setDoOutput(true);
|
||||
|
||||
if (debug) {
|
||||
Fawe.debug("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
|
||||
}
|
||||
|
||||
// Write the data
|
||||
final OutputStream os = connection.getOutputStream();
|
||||
os.write(compressed);
|
||||
os.flush();
|
||||
|
||||
// Now read the response
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String response = reader.readLine();
|
||||
|
||||
// close resources
|
||||
os.close();
|
||||
reader.close();
|
||||
|
||||
if ((response == null) || response.startsWith("ERR") || response.startsWith("7")) {
|
||||
if (response == null) {
|
||||
response = "null";
|
||||
} else if (response.startsWith("7")) {
|
||||
response = response.substring(response.startsWith("7,") ? 2 : 1);
|
||||
}
|
||||
|
||||
throw new IOException(response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
|
||||
*
|
||||
* @return true if mineshafter is installed on the server
|
||||
*/
|
||||
private boolean isMineshafterPresent() {
|
||||
try {
|
||||
Class.forName("mineshafter.MineServer");
|
||||
return true;
|
||||
} catch (final Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user