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:
Jesse Boyd 2016-04-06 01:11:24 +10:00
parent ba04eb9fc8
commit fb4ed9362d
25 changed files with 767 additions and 234 deletions

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.bukkit;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MainUtil;
@ -157,9 +158,9 @@ public class WEListener implements Listener {
final String cmd = message.toLowerCase(); final String cmd = message.toLowerCase();
final boolean single = true; final boolean single = true;
final String[] split = cmd.split(" "); final String[] split = cmd.split(" ");
FaweLimit limit = player.getLimit();
final long maxVolume = Settings.WE_MAX_VOLUME; final long maxVolume = limit.MAX_FAILS + limit.MAX_CHANGES;
final long maxIterations = Settings.WE_MAX_ITERATIONS; final long maxIterations = limit.MAX_ITERATIONS;
// if (player.hasPermission("fawe.bypass")) { // if (player.hasPermission("fawe.bypass")) {
// return true; // return true;
// } // }

View File

@ -2,8 +2,10 @@ package com.boydti.fawe.bukkit.v0;
import com.boydti.fawe.bukkit.logging.BlocksHubHook; import com.boydti.fawe.bukkit.logging.BlocksHubHook;
import com.boydti.fawe.object.EditSessionWrapper; import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
@ -20,13 +22,12 @@ public class BukkitEditSessionWrapper_0 extends EditSessionWrapper {
} }
@Override @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 (this.hook != null) {
// If we are doing logging, return a custom logging extent // If we are doing logging, return a custom logging extent
return this.hook.getLoggingExtent(parent, set, player); return this.hook.getLoggingExtent(parent, set, player);
} }
// Otherwise return the normal history extent // Otherwise return the normal history extent
return super.getHistoryExtent(parent, set, player); return super.getHistoryExtent(world, limit, parent, set, queue, player);
} }
} }

View File

@ -266,6 +266,9 @@ public class BukkitQueue_1_8 extends BukkitQueue_0 {
} }
lcx = cx; lcx = cx;
lcz = cz; lcz = cz;
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
return 0;
}
lc = methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call(); lc = methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call();
} else if (cy == lcy) { } else if (cy == lcy) {
return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0; return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0;

View File

@ -242,6 +242,9 @@ public class BukkitQueue_1_9 extends BukkitQueue_0 {
} }
lcx = cx; lcx = cx;
lcz = cz; lcz = cz;
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
return 0;
}
lc = methodGetType.of(methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call()); lc = methodGetType.of(methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call());
} }
int combined = (int) methodGetCombinedId.call(lc.call(x & 15, y, z & 15)); int combined = (int) methodGetCombinedId.call(lc.call(x & 15, y, z & 15));

View File

@ -1,6 +1,7 @@
package com.boydti.fawe; package com.boydti.fawe;
import com.boydti.fawe.object.PseudoRandom; import com.boydti.fawe.object.PseudoRandom;
import com.sk89q.worldedit.blocks.BaseBlock;
public class FaweCache { public class FaweCache {
public final static short[][][] CACHE_I = new short[256][16][16]; 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 short[] CACHE_ID = new short[65535];
public final static byte[] CACHE_DATA = new byte[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) // Faster than java random (since the game just needs to look random)
public final static PseudoRandom RANDOM = new PseudoRandom(); public final static PseudoRandom RANDOM = new PseudoRandom();
@ -36,6 +39,12 @@ public class FaweCache {
CACHE_ID[i] = (short) j; CACHE_ID[i] = (short) j;
CACHE_DATA[i] = (byte) k; 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) { public static boolean hasData(int id) {

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.command;
import com.boydti.fawe.Fawe; import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.FaweCommand; import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.util.MainUtil;
public class Reload extends FaweCommand { public class Reload extends FaweCommand {
@ -13,7 +14,7 @@ public class Reload extends FaweCommand {
@Override @Override
public boolean execute(final FawePlayer player, final String... args) { public boolean execute(final FawePlayer player, final String... args) {
Fawe.get().setupConfigs(); Fawe.get().setupConfigs();
player.sendMessage("&d[FAWE] Reloaded configuration"); MainUtil.sendMessage(player, "&d[FAWE] Reloaded configuration");
return true; return true;
} }
} }

View 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;
}
}

View File

@ -24,6 +24,7 @@ public enum BBC {
FIX_LIGHTING_SELECTION("&7Lighting has been fixed in %s0 chunks. Relog to see the affect.", "Info"), 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"), NO_REGION("&cYou have no current WorldEdit region", "Error"),
SET_REGION("&7Selection set to your current WorldEdit region", "Info"), 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_DELAYED("&7Please wait while we process your WorldEdit action...", "Info"),
WORLDEDIT_RUN("&7Apologies for the delay. Now executing: %s", "Info"), WORLDEDIT_RUN("&7Apologies for the delay. Now executing: %s", "Info"),
WORLDEDIT_COMPLETE("&7WorldEdit action completed.", "Info"), WORLDEDIT_COMPLETE("&7WorldEdit action completed.", "Info"),

View File

@ -1,6 +1,8 @@
package com.boydti.fawe.config; package com.boydti.fawe.config;
import com.boydti.fawe.configuration.file.YamlConfiguration; 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 com.sk89q.worldedit.LocalSession;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -12,10 +14,6 @@ import java.util.Map.Entry;
public class Settings { 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 REQUIRE_SELECTION = false;
public static boolean FIX_ALL_LIGHTING = true; public static boolean FIX_ALL_LIGHTING = true;
public static boolean COMMAND_PROCESSOR = false; public static boolean COMMAND_PROCESSOR = false;
@ -27,6 +25,25 @@ public class Settings {
public static int BUFFER_SIZE = 531441; public static int BUFFER_SIZE = 531441;
public static boolean METRICS = true; 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) { public static void setup(final File file) {
if (!file.exists()) { if (!file.exists()) {
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
@ -38,11 +55,9 @@ public class Settings {
} }
final YamlConfiguration config = YamlConfiguration.loadConfiguration(file); final YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
limits = new HashMap<>();
final Map<String, Object> options = 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("require-selection-in-mask", REQUIRE_SELECTION);
options.put("command-blacklist", WE_BLACKLIST); options.put("command-blacklist", WE_BLACKLIST);
options.put("command-processor", COMMAND_PROCESSOR); options.put("command-processor", COMMAND_PROCESSOR);
@ -53,6 +68,18 @@ public class Settings {
options.put("history.compress", false); options.put("history.compress", false);
options.put("metrics", METRICS); 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()) { for (final Entry<String, Object> node : options.entrySet()) {
if (!config.contains(node.getKey())) { if (!config.contains(node.getKey())) {
config.set(node.getKey(), node.getValue()); config.set(node.getKey(), node.getValue());
@ -60,10 +87,6 @@ public class Settings {
} }
FIX_ALL_LIGHTING = config.getBoolean("fix-all-lighting"); FIX_ALL_LIGHTING = config.getBoolean("fix-all-lighting");
COMMAND_PROCESSOR = config.getBoolean("command-processor"); 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"); MEM_FREE = config.getInt("max-memory-percent");
REQUIRE_SELECTION = config.getBoolean("require-selection-in-mask"); REQUIRE_SELECTION = config.getBoolean("require-selection-in-mask");
WE_BLACKLIST = config.getStringList("command-blacklist"); WE_BLACKLIST = config.getStringList("command-blacklist");

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.object; package com.boydti.fawe.object;
import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.blocks.BlockType;
@ -26,7 +27,7 @@ public class EditSessionWrapper {
return minY; return minY;
} }
public Extent getHistoryExtent(final Extent parent, FaweChangeSet set, final FawePlayer<?> player) { public Extent getHistoryExtent(String world, FaweLimit limit, Extent parent, FaweChangeSet set, FaweQueue queue, FawePlayer<?> player) {
return new HistoryExtent(player.getLocation().world, parent, set); return new HistoryExtent(world, limit, parent, set, queue);
} }
} }

View 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;
}
}

View File

@ -27,7 +27,7 @@ public abstract class FawePlayer<T> {
/** /**
* The metadata map. * The metadata map.
*/ */
private ConcurrentHashMap<String, Object> meta; private volatile ConcurrentHashMap<String, Object> meta;
public static <T> FawePlayer<T> wrap(final Object obj) { public static <T> FawePlayer<T> wrap(final Object obj) {
return Fawe.imp().wrap(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 String getName();
public abstract UUID getUUID(); public abstract UUID getUUID();

View File

@ -3,7 +3,6 @@ package com.boydti.fawe.object;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.changeset.FaweChangeSet; import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.util.FaweQueue; import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.SetQueue;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; 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 com.boydti.fawe.object.changeset.FaweChangeSet changeSet;
private final FaweQueue queue; private final FaweQueue queue;
private final FaweLimit limit;
/** /**
* Create a new instance. * Create a new instance.
@ -37,9 +37,10 @@ public class HistoryExtent extends AbstractDelegateExtent {
* @param extent the extent * @param extent the extent
* @param changeSet the change set * @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); super(extent);
this.queue = SetQueue.IMP.getQueue(world); this.limit = limit;
this.queue = queue;
checkNotNull(changeSet); checkNotNull(changeSet);
this.changeSet = changeSet; this.changeSet = changeSet;
} }

View File

@ -175,11 +175,13 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
try { try {
OutputStream stream = getBAOS(x, y, z); OutputStream stream = getBAOS(x, y, z);
//x //x
stream.write((x - ox) & 0xff); x-=ox;
stream.write(((x - ox) >> 8) & 0xff); stream.write((x) & 0xff);
stream.write(((x) >> 8) & 0xff);
//z //z
stream.write((z - oz) & 0xff); z-=oz;
stream.write(((z - oz) >> 8) & 0xff); stream.write((z) & 0xff);
stream.write(((z) >> 8) & 0xff);
//y //y
stream.write((byte) y); stream.write((byte) y);
//from //from
@ -375,8 +377,8 @@ public class DiskStorageHistory implements ChangeSet, FaweChangeSet {
public Change read() { public Change read() {
try { try {
int x = gis.read() + (gis.read() << 8) + ox; int x = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + ox;
int z = gis.read() + (gis.read() << 8) + oz; int z = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + oz;
int y = gis.read() & 0xff; int y = gis.read() & 0xff;
int from1 = gis.read(); int from1 = gis.read();
int from2 = gis.read(); int from2 = gis.read();

View File

@ -64,11 +64,13 @@ public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
try { try {
OutputStream stream = getBAOS(x, y, z); OutputStream stream = getBAOS(x, y, z);
//x //x
stream.write((x - ox) & 0xff); x -= ox;
stream.write(((x - ox) >> 8) & 0xff); z -= oz;
stream.write((x & 0xff));
stream.write(((x >> 8) & 0xff));
//z //z
stream.write((z - oz) & 0xff); stream.write((z & 0xff));
stream.write(((z - oz) >> 8) & 0xff); stream.write( ((z >> 8) & 0xff));
//y //y
stream.write((byte) y); stream.write((byte) y);
//from //from
@ -150,8 +152,6 @@ public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
idsStream = new ByteArrayOutputStream(Settings.BUFFER_SIZE); idsStream = new ByteArrayOutputStream(Settings.BUFFER_SIZE);
idsStreamZip = new LZ4OutputStream(idsStream, Settings.BUFFER_SIZE, factory.fastCompressor()); idsStreamZip = new LZ4OutputStream(idsStream, Settings.BUFFER_SIZE, factory.fastCompressor());
if (Settings.COMPRESSION_LEVEL > 0) { 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()); idsStreamZip = new LZ4OutputStream(idsStreamZip, Settings.BUFFER_SIZE, factory.highCompressor());
} }
ox = x; ox = x;
@ -198,8 +198,8 @@ public class MemoryOptimizedHistory implements ChangeSet, FaweChangeSet {
public Change read() { public Change read() {
try { try {
int x = gis.read() + (gis.read() << 8) + ox; int x = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + ox;
int z = gis.read() + (gis.read() << 8) + oz; int z = ((byte) gis.read() & 0xFF) + ((byte) gis.read() << 8) + oz;
int y = gis.read() & 0xff; int y = gis.read() & 0xff;
int from1 = gis.read(); int from1 = gis.read();
int from2 = gis.read(); int from2 = gis.read();

View File

@ -2,7 +2,6 @@ package com.boydti.fawe.object.extent;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
import com.boydti.fawe.util.FaweQueue; import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
@ -21,13 +20,11 @@ import java.util.List;
public class FastWorldEditExtent extends AbstractDelegateExtent { public class FastWorldEditExtent extends AbstractDelegateExtent {
private final Thread thread;
private final FaweQueue queue; private final FaweQueue queue;
public FastWorldEditExtent(final World world, final Thread thread) { public FastWorldEditExtent(final World world, FaweQueue queue) {
super(world); super(world);
this.thread = thread; this.queue = queue;
this.queue = SetQueue.IMP.getQueue(world.getName());
} }
@Override @Override
@ -46,10 +43,8 @@ public class FastWorldEditExtent extends AbstractDelegateExtent {
if (!queue.isChunkLoaded(position.getBlockX() >> 4, position.getBlockZ() >> 4)) { if (!queue.isChunkLoaded(position.getBlockX() >> 4, position.getBlockZ() >> 4)) {
return EditSession.nullBiome; return EditSession.nullBiome;
} }
synchronized (this.thread) {
return super.getBiome(position); return super.getBiome(position);
} }
}
private BaseBlock lastBlock; private BaseBlock lastBlock;
private BlockVector lastVector; private BlockVector lastVector;
@ -67,25 +62,19 @@ public class FastWorldEditExtent extends AbstractDelegateExtent {
return EditSession.nullBlock; return EditSession.nullBlock;
} }
} }
synchronized (this.thread) {
this.lastVector = position.toBlockVector(); this.lastVector = position.toBlockVector();
return this.lastBlock = super.getBlock(position); return this.lastBlock = super.getBlock(position);
} }
}
@Override @Override
public List<? extends Entity> getEntities() { public List<? extends Entity> getEntities() {
synchronized (this.thread) {
return super.getEntities(); return super.getEntities();
} }
}
@Override @Override
public List<? extends Entity> getEntities(final Region region) { public List<? extends Entity> getEntities(final Region region) {
synchronized (this.thread) {
return super.getEntities(region); return super.getEntities(region);
} }
}
@Override @Override
public BaseBlock getBlock(final Vector position) { public BaseBlock getBlock(final Vector position) {

View File

@ -1,13 +1,10 @@
package com.boydti.fawe.object.extent; package com.boydti.fawe.object.extent;
import com.boydti.fawe.FaweCache; import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.util.FaweQueue; 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.TaskManager;
import com.boydti.fawe.util.WEManager; import com.boydti.fawe.util.WEManager;
import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.BlockVector;
@ -29,30 +26,18 @@ import java.util.List;
public class ProcessedWEExtent extends AbstractDelegateExtent { public class ProcessedWEExtent extends AbstractDelegateExtent {
private final FaweQueue queue; private final FaweQueue queue;
private final FaweLimit limit;
private Extent parent; 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 FawePlayer<?> user;
private final HashSet<RegionWrapper> mask; 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); super(world);
this.user = player; this.user = player;
this.queue = SetQueue.IMP.getQueue(world.getName()); this.queue = queue;
this.max = max != -1 ? max : Integer.MAX_VALUE;
this.mask = mask; this.mask = mask;
this.thread = thread; this.limit = limit;
}
public void setMax(final int max) {
this.max = max != -1 ? max : Integer.MAX_VALUE;
} }
public void setParent(final Extent parent) { public void setParent(final Extent parent) {
@ -61,14 +46,9 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
@Override @Override
public Entity createEntity(final Location location, final BaseEntity entity) { public Entity createEntity(final Location location, final BaseEntity entity) {
if (this.Eblocked) { if (limit.MAX_ENTITIES-- < 0) {
return null; 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())) { if (WEManager.IMP.maskContains(this.mask, location.getBlockX(), location.getBlockZ())) {
TaskManager.IMP.task(new Runnable() { TaskManager.IMP.task(new Runnable() {
@Override @Override
@ -85,16 +65,17 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
if (!queue.isChunkLoaded(position.getBlockX() >> 4, position.getBlockZ() >> 4)) { if (!queue.isChunkLoaded(position.getBlockX() >> 4, position.getBlockZ() >> 4)) {
return EditSession.nullBiome; return EditSession.nullBiome;
} }
synchronized (this.thread) {
return super.getBiome(position); return super.getBiome(position);
} }
}
private BaseBlock lastBlock; private BaseBlock lastBlock;
private BlockVector lastVector; private BlockVector lastVector;
@Override @Override
public BaseBlock getLazyBlock(final Vector position) { public BaseBlock getLazyBlock(final Vector position) {
// TODO get fast!
// TODO caches base blocks
if ((this.lastBlock != null) && this.lastVector.equals(position.toBlockVector())) { if ((this.lastBlock != null) && this.lastVector.equals(position.toBlockVector())) {
return this.lastBlock; return this.lastBlock;
} }
@ -106,25 +87,19 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
return EditSession.nullBlock; return EditSession.nullBlock;
} }
} }
synchronized (this.thread) {
this.lastVector = position.toBlockVector(); this.lastVector = position.toBlockVector();
return this.lastBlock = super.getLazyBlock(position); return super.getLazyBlock(position);
}
} }
@Override @Override
public List<? extends Entity> getEntities() { public List<? extends Entity> getEntities() {
synchronized (this.thread) {
return super.getEntities(); return super.getEntities();
} }
}
@Override @Override
public List<? extends Entity> getEntities(final Region region) { public List<? extends Entity> getEntities(final Region region) {
synchronized (this.thread) {
return super.getEntities(region); return super.getEntities(region);
} }
}
@Override @Override
public BaseBlock getBlock(final Vector position) { public BaseBlock getBlock(final Vector position) {
@ -171,18 +146,13 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
case 33: case 33:
case 151: case 151:
case 178: { case 178: {
if (this.BSblocked) { if (limit.MAX_BLOCKSTATES-- < 0) {
return false; 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 x = location.getBlockX();
final int z = location.getBlockZ(); final int z = location.getBlockZ();
if (WEManager.IMP.maskContains(this.mask, x, z)) { if (WEManager.IMP.maskContains(this.mask, x, z)) {
if (this.count++ > this.max) { if (limit.MAX_CHANGES-- < 0) {
if (this.parent != null) { if (this.parent != null) {
WEManager.IMP.cancelEdit(this.parent); WEManager.IMP.cancelEdit(this.parent);
this.parent = null; 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); queue.setBlock(x, location.getBlockY(), z, id, FaweCache.hasData(id) ? (byte) block.getData() : 0);
return true; return true;
} else if (limit.MAX_FAILS-- < 0) {
if (this.parent != null) {
WEManager.IMP.cancelEdit(this.parent);
this.parent = null;
}
} }
return false; return false;
} }
@ -212,7 +187,7 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
final int y = location.getBlockY(); final int y = location.getBlockY();
final int z = location.getBlockZ(); final int z = location.getBlockZ();
if (WEManager.IMP.maskContains(this.mask, location.getBlockX(), 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); WEManager.IMP.cancelEdit(this.parent);
this.parent = null; this.parent = null;
return false; return false;
@ -306,6 +281,11 @@ public class ProcessedWEExtent extends AbstractDelegateExtent {
return true; return true;
} }
} }
} else if (limit.MAX_FAILS-- < 0) {
if (this.parent != null) {
WEManager.IMP.cancelEdit(this.parent);
this.parent = null;
}
} }
return false; return false;
} }

View File

@ -40,11 +40,7 @@ public class PlotSquaredFeature extends FaweMaskManager {
final PlotId id = plot.getId(); final PlotId id = plot.getId();
boolean hasPerm = false; boolean hasPerm = false;
if (plot.owner != null) { if (plot.owner != null) {
if (plot.owner.equals(pp.getUUID())) { hasPerm = plot.isOwner(pp.getUUID()) || plot.getTrusted().contains(pp.getUUID()) || (plot.getMembers().contains(pp.getUUID()) && pp.hasPermission("fawe.plotsquared.member"));
hasPerm = true;
} else if (plot.isAdded(pp.getUUID()) && pp.hasPermission("fawe.plotsquared.member")) {
hasPerm = true;
}
if (hasPerm) { if (hasPerm) {
RegionWrapper region = plot.getLargestRegion(); RegionWrapper region = plot.getLargestRegion();
HashSet<RegionWrapper> regions = plot.getRegions(); HashSet<RegionWrapper> regions = plot.getRegions();

View File

@ -26,7 +26,6 @@ public class WEManager {
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
parent = null;
} }
public boolean maskContains(final HashSet<RegionWrapper> mask, final int x, final int z) { public boolean maskContains(final HashSet<RegionWrapper> mask, final int x, final int z) {

View File

@ -24,6 +24,7 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings; import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.EditSessionWrapper; import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.NullChangeSet; import com.boydti.fawe.object.NullChangeSet;
import com.boydti.fawe.object.RegionWrapper; 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.ProcessedWEExtent;
import com.boydti.fawe.object.extent.SafeExtentWrapper; import com.boydti.fawe.object.extent.SafeExtentWrapper;
import com.boydti.fawe.util.ExtentWrapper; import com.boydti.fawe.util.ExtentWrapper;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.MemUtil;
import com.boydti.fawe.util.Perm; import com.boydti.fawe.util.Perm;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.WEManager; import com.boydti.fawe.util.WEManager;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
@ -153,14 +156,14 @@ public class EditSession implements Extent {
protected final World world; protected final World world;
private FaweChangeSet changeSet; private FaweChangeSet changeSet;
private final EditSessionWrapper wrapper; private final EditSessionWrapper wrapper;
private @Nullable Extent changeSetExtent;
private MaskingExtent maskingExtent; private MaskingExtent maskingExtent;
private @Nullable ProcessedWEExtent processed;
private final Extent bypassReorderHistory; private final Extent bypassReorderHistory;
private final Extent bypassHistory; private final Extent bypassHistory;
private final Extent bypassNone; private final Extent bypassNone;
private boolean fastmode; private boolean fastmode;
private Mask oldMask; private Mask oldMask;
private FaweLimit limit = FaweLimit.MAX;
private FaweQueue queue;
public static BaseBiome nullBiome = new BaseBiome(0); public static BaseBiome nullBiome = new BaseBiome(0);
public static BaseBlock nullBlock = new BaseBlock(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)); this(WorldEdit.getInstance().getEventBus(), world, maxBlocks, blockBag, new EditSessionEvent(world, null, maxBlocks, null));
} }
private final Thread thread;
private int changes = 0; private int changes = 0;
private int maxBlocks; private int maxBlocks;
private BlockBag blockBag; private BlockBag blockBag;
@ -212,7 +213,6 @@ public class EditSession implements Extent {
this.blockBag = blockBag; this.blockBag = blockBag;
this.maxBlocks = maxBlocks; this.maxBlocks = maxBlocks;
this.thread = Fawe.get().getMainThread();
this.world = world; this.world = world;
this.wrapper = Fawe.imp().getEditSessionWrapper(this); this.wrapper = Fawe.imp().getEditSessionWrapper(this);
// this.changeSet = new BlockOptimizedHistory(); // this.changeSet = new BlockOptimizedHistory();
@ -227,10 +227,10 @@ public class EditSession implements Extent {
return; return;
} }
final Actor actor = event.getActor(); final Actor actor = event.getActor();
this.queue = SetQueue.IMP.getQueue(world.getName());
// Not a player; bypass history // Not a player; bypass history
if ((actor == null) || !actor.isPlayer()) { if ((actor == null) || !actor.isPlayer()) {
Extent extent = new FastWorldEditExtent(world, this.thread); Extent extent = new FastWorldEditExtent(world, queue);
// Everything bypasses // Everything bypasses
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE); extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER); extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER);
@ -246,9 +246,10 @@ public class EditSession implements Extent {
final String name = actor.getName(); final String name = actor.getName();
final FawePlayer<Object> fp = FawePlayer.wrap(name); final FawePlayer<Object> fp = FawePlayer.wrap(name);
final LocalSession session = fp.getSession(); final LocalSession session = fp.getSession();
this.fastmode = session.hasFastMode();
if (fp.hasWorldEditBypass()) { if (fp.hasWorldEditBypass()) {
// Bypass skips processing and area restrictions // Bypass skips processing and area restrictions
extent = new FastWorldEditExtent(world, this.thread); extent = new FastWorldEditExtent(world, queue);
if (this.hasFastMode()) { if (this.hasFastMode()) {
// Fastmode skips history and memory checks // Fastmode skips history and memory checks
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE); extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
@ -260,6 +261,7 @@ public class EditSession implements Extent {
return; return;
} }
} else { } else {
this.limit = fp.getLimit();
final HashSet<RegionWrapper> mask = WEManager.IMP.getMask(fp); final HashSet<RegionWrapper> mask = WEManager.IMP.getMask(fp);
if (mask.size() == 0) { if (mask.size() == 0) {
if (Perm.hasPermission(fp, "fawe.admin")) { if (Perm.hasPermission(fp, "fawe.admin")) {
@ -275,7 +277,8 @@ public class EditSession implements Extent {
return; return;
} }
// Process the WorldEdit action // 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()) { if (this.hasFastMode()) {
// Fastmode skips history, masking, and memory checks // Fastmode skips history, masking, and memory checks
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE); 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 = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_HISTORY);
extent = new ExtentWrapper(extent); extent = new ExtentWrapper(extent);
// Set the parent. This allows efficient cancelling // Set the parent. This allows efficient cancelling
this.processed.setParent(extent); processed.setParent(extent);
this.bypassReorderHistory = extent; this.bypassReorderHistory = extent;
this.bypassHistory = extent; this.bypassHistory = extent;
this.bypassNone = extent; this.bypassNone = extent;
@ -304,13 +307,13 @@ public class EditSession implements Extent {
} }
// Perform memory checks after reorder // Perform memory checks after reorder
extent = new SafeExtentWrapper(fp, extent); extent = new SafeExtentWrapper(fp, extent);
this.processed.setParent(extent); processed.setParent(extent);
} }
// Include history, masking and memory checking. // Include history, masking and memory checking.
Extent wrapped; Extent wrapped;
extent = wrapped = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE); extent = wrapped = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_CHANGE);
extent = this.wrapExtent(extent, eventBus, event, Stage.BEFORE_REORDER); 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 Player skp = (Player) actor;
final int item = skp.getItemInHand(); final int item = skp.getItemInHand();
boolean hasMask = session.getMask() != null; boolean hasMask = session.getMask() != null;
@ -386,10 +389,7 @@ public class EditSession implements Extent {
* @param limit the limit (&gt;= 0) or -1 for no limit * @param limit the limit (&gt;= 0) or -1 for no limit
*/ */
public void setBlockChangeLimit(final int limit) { public void setBlockChangeLimit(final int limit) {
if (this.processed != null) { // Nothing
this.maxBlocks = limit;
this.processed.setMax(limit);
}
} }
/** /**
@ -531,10 +531,8 @@ public class EditSession implements Extent {
@Override @Override
public BaseBiome getBiome(final Vector2D position) { public BaseBiome getBiome(final Vector2D position) {
synchronized (this.thread) {
return this.bypassNone.getBiome(position); return this.bypassNone.getBiome(position);
} }
}
@Override @Override
public boolean setBiome(final Vector2D position, final BaseBiome biome) { public boolean setBiome(final Vector2D position, final BaseBiome biome) {
@ -544,16 +542,19 @@ public class EditSession implements Extent {
@Override @Override
public BaseBlock getLazyBlock(final Vector position) { public BaseBlock getLazyBlock(final Vector position) {
synchronized (this.thread) { if (limit != null && limit.MAX_CHECKS-- < 0) {
return this.world.getBlock(position); 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 @Override
public synchronized BaseBlock getBlock(final Vector position) { public BaseBlock getBlock(final Vector position) {
synchronized (this.thread) { return this.getLazyBlock(position);
return this.world.getBlock(position);
}
} }
/** /**
@ -564,10 +565,12 @@ public class EditSession implements Extent {
* @deprecated Use {@link #getLazyBlock(Vector)} or {@link #getBlock(Vector)} * @deprecated Use {@link #getLazyBlock(Vector)} or {@link #getBlock(Vector)}
*/ */
@Deprecated @Deprecated
public synchronized int getBlockType(final Vector position) { public int getBlockType(final Vector position) {
synchronized (this.thread) { if (limit != null && limit.MAX_CHECKS-- < 0) {
return this.world.getBlockType(position); 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 Use {@link #getLazyBlock(Vector)} or {@link #getBlock(Vector)}
*/ */
@Deprecated @Deprecated
public synchronized int getBlockData(final Vector position) { public int getBlockData(final Vector position) {
synchronized (this.thread) { if (limit != null && limit.MAX_CHECKS-- < 0) {
return this.world.getBlockData(position); 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 @Deprecated
public BaseBlock rawGetBlock(final Vector position) { public BaseBlock rawGetBlock(final Vector position) {
return this.getBlock(position); return this.getLazyBlock(position);
} }
/** /**

View File

@ -19,6 +19,9 @@
package com.sk89q.worldedit.extension.platform; 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.SetQueue;
import com.boydti.fawe.util.TaskManager; import com.boydti.fawe.util.TaskManager;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
@ -235,7 +238,17 @@ public final class CommandManager {
locals.put("arguments", event.getArguments()); locals.put("arguments", event.getArguments());
long start = System.currentTimeMillis(); 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 { try {
dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]); dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
} catch (CommandPermissionsException e) { } catch (CommandPermissionsException e) {
@ -266,6 +279,9 @@ public final class CommandManager {
log.log(Level.SEVERE, "An unknown error occurred", e); log.log(Level.SEVERE, "An unknown error occurred", e);
} }
} finally { } finally {
if (fp != null) {
fp.deleteMeta("fawe_action");
}
EditSession editSession = locals.get(EditSession.class); EditSession editSession = locals.get(EditSession.class);
if (editSession != null) { if (editSession != null) {

View File

@ -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

View File

@ -19,7 +19,6 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.mcstats.Metrics;
import org.spongepowered.api.Sponge; import org.spongepowered.api.Sponge;
import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.text.serializer.TextSerializers; import org.spongepowered.api.text.serializer.TextSerializers;
@ -129,7 +128,7 @@ public class FaweSponge implements IFawe {
@Override @Override
public void startMetrics() { public void startMetrics() {
try { 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(); metrics.start();
debug("[FAWE] &6Metrics enabled."); debug("[FAWE] &6Metrics enabled.");
} catch (IOException e) { } catch (IOException e) {

View 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;
}
}
}