Various minor

Fix nukkit compile
Fix setBlocks with BlockPattern
MCAQueue filterCopy API (performs operations on a copy of the world)
Add //anvil trimallplots
This commit is contained in:
Jesse Boyd 2017-07-05 18:53:05 +10:00
parent 3c44e75139
commit 7f01ac7790
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
16 changed files with 707 additions and 122 deletions

View File

@ -69,6 +69,7 @@ if ( project.hasProperty("lzNoVersion") ) { // gradle build -PlzNoVersion
description = """FastAsyncWorldEdit""" description = """FastAsyncWorldEdit"""
subprojects { subprojects {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'maven' apply plugin: 'maven'
apply plugin: 'eclipse' apply plugin: 'eclipse'
@ -79,10 +80,11 @@ subprojects {
repositories { repositories {
mavenCentral() mavenCentral()
maven {url "http://repo.dmulloy2.net/content/groups/public/"}
maven {url "https://repo.destroystokyo.com/repository/maven-public//"} maven {url "https://repo.destroystokyo.com/repository/maven-public//"}
maven { url = "https://mvnrepository.com/artifact/"} maven { url = "https://mvnrepository.com/artifact/"}
maven {url "http://ci.emc.gs/nexus/content/groups/aikar/" } maven {url "http://ci.emc.gs/nexus/content/groups/aikar/" }
maven {url "http://ci.mengcraft.com:8080/plugin/repository/everything/"} maven {url "http://ci.mengcraft.com:8080/plugin/repository/everything"}
maven {url "http://ci.athion.net/job/PlotSquared/ws/mvn/"} maven {url "http://ci.athion.net/job/PlotSquared/ws/mvn/"}
maven {url "http://empcraft.com/maven2"} maven {url "http://empcraft.com/maven2"}
maven {url "https://hub.spigotmc.org/nexus/content/groups/public/"} maven {url "https://hub.spigotmc.org/nexus/content/groups/public/"}
@ -90,7 +92,7 @@ subprojects {
maven {url "http://nexus.hc.to/content/repositories/pub_releases"} maven {url "http://nexus.hc.to/content/repositories/pub_releases"}
maven {url "http://repo.maven.apache.org/maven2"} maven {url "http://repo.maven.apache.org/maven2"}
maven {url "http://ci.frostcast.net/plugin/repository/everything"} maven {url "http://ci.frostcast.net/plugin/repository/everything"}
maven {url "http://maven.sk89q.com/artifactory/repo/"} maven {url "http://maven.sk89q.com/artifactory/repo"}
maven {url "http://repo.spongepowered.org/maven"} maven {url "http://repo.spongepowered.org/maven"}
} }
} }

View File

@ -25,6 +25,7 @@ dependencies {
compile 'org.bukkit.craftbukkit.v1_9R2:craftbukkitv1_9R2:1.9.4' compile 'org.bukkit.craftbukkit.v1_9R2:craftbukkitv1_9R2:1.9.4'
compile 'org.bukkit.craftbukkit:Craftbukkit:1.7.10' compile 'org.bukkit.craftbukkit:Craftbukkit:1.7.10'
compile 'org.bukkit.craftbukkit:CraftBukkit:1.8.8' compile 'org.bukkit.craftbukkit:CraftBukkit:1.8.8'
compile 'com.comphenix.protocol:ProtocolLib-API:4.3.1-SNAPSHOT'
} }
processResources { processResources {

View File

@ -0,0 +1,85 @@
package com.boydti.fawe.bukkit.v1_12;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.jnbt.anvil.MCAChunk;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.wrappers.nbt.NbtBase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.server.v1_12_R1.Block;
import net.minecraft.server.v1_12_R1.DataBits;
import net.minecraft.server.v1_12_R1.MathHelper;
public class FaweChunkPacket {
private final MCAChunk chunk;
private final boolean full;
private final boolean biomes;
private final boolean sky;
public FaweChunkPacket(MCAChunk fc, boolean replaceAllSections, boolean sendBiomeData, boolean hasSky) {
this.chunk = fc;
this.full = replaceAllSections;
this.biomes = sendBiomeData;
this.sky = hasSky;
}
public void write(PacketContainer packet) throws IOException {
try {
StructureModifier<Integer> ints = packet.getIntegers();
StructureModifier<byte[]> byteArray = packet.getByteArrays();
StructureModifier<Boolean> bools = packet.getBooleans();
ints.write(0, this.chunk.getX());
ints.write(1, this.chunk.getZ());
bools.write(0, this.full);
ints.write(2, this.chunk.getBitMask()); // writeVarInt
FastByteArrayOutputStream fbaos = new FastByteArrayOutputStream();
FaweOutputStream buffer = new FaweOutputStream(fbaos);
byte[][] ids = chunk.ids;
for (int layer = 0; layer < ids.length; layer++) {
byte[] layerIds = ids[layer];
if (layerIds == null) {
continue;
}
byte[] layerData = chunk.data[layer];
int num = MathHelper.d(Block.REGISTRY_ID.a());
buffer.write(num); // num blocks, anything > 8 - doesn't need to be accurate
buffer.writeVarInt(0); // varint 0 - data palette global
DataBits bits = new DataBits(num, 4096);
for (int i = 0; i < 4096; i++) {
int id = layerIds[i];
if (id != 0) {
int data = FaweCache.hasData(id) ? chunk.getNibble(i, layerData) : 0;
int combined = FaweCache.getCombined(id, data);
bits.a(i, combined);
}
}
buffer.write(bits.a());
buffer.write(chunk.blockLight[layer]);
if (sky) {
buffer.write(chunk.skyLight[layer]);
}
}
if (this.biomes && chunk.biomes != null) {
buffer.write(chunk.biomes);
}
byteArray.write(0, fbaos.toByteArray());
// TODO - empty
StructureModifier<List<NbtBase<?>>> list = packet.getListNbtModifier();
list.write(0, new ArrayList<>());
} catch (Throwable e) {
e.printStackTrace();
}
}
}

View File

@ -11,8 +11,10 @@ import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
import com.boydti.fawe.jnbt.anvil.MCAQueue; import com.boydti.fawe.jnbt.anvil.MCAQueue;
import com.boydti.fawe.jnbt.anvil.filters.CountFilter; import com.boydti.fawe.jnbt.anvil.filters.CountFilter;
import com.boydti.fawe.jnbt.anvil.filters.CountIdFilter; import com.boydti.fawe.jnbt.anvil.filters.CountIdFilter;
import com.boydti.fawe.jnbt.anvil.filters.DeleteOldFilter;
import com.boydti.fawe.jnbt.anvil.filters.DeleteUninhabitedFilter; import com.boydti.fawe.jnbt.anvil.filters.DeleteUninhabitedFilter;
import com.boydti.fawe.jnbt.anvil.filters.MappedReplacePatternFilter; import com.boydti.fawe.jnbt.anvil.filters.MappedReplacePatternFilter;
import com.boydti.fawe.jnbt.anvil.filters.PlotTrimFilter;
import com.boydti.fawe.jnbt.anvil.filters.RemoveLayerFilter; import com.boydti.fawe.jnbt.anvil.filters.RemoveLayerFilter;
import com.boydti.fawe.jnbt.anvil.filters.ReplacePatternFilter; import com.boydti.fawe.jnbt.anvil.filters.ReplacePatternFilter;
import com.boydti.fawe.jnbt.anvil.filters.ReplaceSimpleFilter; import com.boydti.fawe.jnbt.anvil.filters.ReplaceSimpleFilter;
@ -21,6 +23,7 @@ import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.RunnableVal4; import com.boydti.fawe.object.RunnableVal4;
import com.boydti.fawe.object.mask.FaweBlockMatcher; import com.boydti.fawe.object.mask.FaweBlockMatcher;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.SetQueue; import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.StringMan; import com.boydti.fawe.util.StringMan;
import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.Command;
@ -77,15 +80,23 @@ public class AnvilCommands {
* @param <T> * @param <T>
* @return * @return
*/ */
public static <G, T extends MCAFilter<G>> T runWithWorld(Player player, String folder, T filter) { public static <G, T extends MCAFilter<G>> T runWithWorld(Player player, String folder, T filter, boolean force) {
boolean copy = false;
if (FaweAPI.getWorld(folder) != null) { if (FaweAPI.getWorld(folder) != null) {
if (!force) {
BBC.WORLD_IS_LOADED.send(player); BBC.WORLD_IS_LOADED.send(player);
return null; return null;
} }
copy = true;
}
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false); FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky()); MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
if (copy) {
return queue.filterCopy(filter, true);
} else {
return queue.filterWorld(filter); return queue.filterWorld(filter);
} }
}
/** /**
* Run safely on an existing world within a selection * Run safely on an existing world within a selection
@ -132,7 +143,7 @@ public class AnvilCommands {
max = 4 max = 4
) )
@CommandPermissions("worldedit.anvil.replaceall") @CommandPermissions("worldedit.anvil.replaceall")
public void replaceAll(Player player, String folder, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException { public void replaceAll(Player player, String folder, @Optional String from, String to, @Switch('d') boolean useData, @Switch('f') boolean force) throws WorldEditException {
final FaweBlockMatcher matchFrom; final FaweBlockMatcher matchFrom;
if (from == null) { if (from == null) {
matchFrom = FaweBlockMatcher.NOT_AIR; matchFrom = FaweBlockMatcher.NOT_AIR;
@ -144,21 +155,60 @@ public class AnvilCommands {
} }
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true)); final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
ReplaceSimpleFilter filter = new ReplaceSimpleFilter(matchFrom, matchTo); ReplaceSimpleFilter filter = new ReplaceSimpleFilter(matchFrom, matchTo);
ReplaceSimpleFilter result = runWithWorld(player, folder, filter); ReplaceSimpleFilter result = runWithWorld(player, folder, filter, force);
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal())); if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
} }
@Command( @Command(
aliases = {"deleteallold"}, aliases = {"deleteallunvisited", "delunvisited" },
usage = "<folder> <age-ticks> [file-age=60000]", usage = "<folder> <age-ticks> [file-age=60000]",
desc = "Delete all chunks which haven't been occupied for `age-ticks` and have been accessed since `file-age` (ms) after creation", desc = "Delete all chunks which haven't been occupied for `age-ticks` (20t = 1s) and \n" +
"Have not been accessed since `file-duration` (ms) after creation and\n" +
"Have not been used in the past `chunk-inactivity` (ms)" +
"The auto-save interval is the recommended value for `file-duration` and `chunk-inactivity`",
min = 2, min = 2,
max = 3 max = 3
) )
@CommandPermissions("worldedit.anvil.deleteallold") @CommandPermissions("worldedit.anvil.deleteallunvisited")
public void deleteAllOld(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileAgeMillis, @Switch('f') boolean force) throws WorldEditException { public void deleteAllUnvisited(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileDurationMillis, @Switch('f') boolean force) throws WorldEditException {
DeleteUninhabitedFilter filter = new DeleteUninhabitedFilter(fileAgeMillis, inhabitedTicks); long chunkInactivityMillis = fileDurationMillis; // Use same value for now
DeleteUninhabitedFilter result = runWithWorld(player, folder, filter); DeleteUninhabitedFilter filter = new DeleteUninhabitedFilter(fileDurationMillis, inhabitedTicks, chunkInactivityMillis);
DeleteUninhabitedFilter result = runWithWorld(player, folder, filter, force);
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
}
@Command(
aliases = {"deletealloldregions", "deloldreg" },
usage = "<folder> <time>",
desc = "Delete regions which haven't been accessed in a certain amount of time\n" +
"You can use seconds (s), minutes (m), hours (h), days (d), weeks (w), years (y)\n" +
"(months are not a unit of time)\n" +
"E.g. 8h5m12s\n",
min = 2,
max = 3
)
@CommandPermissions("worldedit.anvil.deletealloldregions")
public void deleteAllOldRegions(Player player, String folder, String time, @Switch('f') boolean force) throws WorldEditException {
long duration = MainUtil.timeToSec(time) * 1000l;
DeleteOldFilter filter = new DeleteOldFilter(duration);
DeleteOldFilter result = runWithWorld(player, folder, filter, force);
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
}
@Command(
aliases = {"trimallplots", },
desc = "Trim chunks in a Plot World",
help = "Trim chunks in a Plot World\n" +
"Unclaimed chunks will be deleted\n" +
"Unmodified chunks will be deleted\n" +
"Use -v to also delete unvisited chunks\n"
)
@CommandPermissions("worldedit.anvil.trimallplots")
public void trimAllPlots(Player player, @Switch('v') boolean deleteUnvisited) throws WorldEditException {
String folder = Fawe.imp().getWorldName(player.getWorld());
int visitTime = deleteUnvisited ? 1 : -1;
PlotTrimFilter filter = new PlotTrimFilter(player.getWorld(), 0, visitTime, 600000);
PlotTrimFilter result = runWithWorld(player, folder, filter, true);
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal())); if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
} }
@ -171,7 +221,7 @@ public class AnvilCommands {
max = 4 max = 4
) )
@CommandPermissions("worldedit.anvil.replaceall") @CommandPermissions("worldedit.anvil.replaceall")
public void replaceAllPattern(Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException { public void replaceAllPattern(Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap, @Switch('f') boolean force) throws WorldEditException {
MCAFilterCounter filter; MCAFilterCounter filter;
if (useMap) { if (useMap) {
if (to instanceof RandomPattern) { if (to instanceof RandomPattern) {
@ -190,7 +240,7 @@ public class AnvilCommands {
} }
filter = new ReplacePatternFilter(matchFrom, to); filter = new ReplacePatternFilter(matchFrom, to);
} }
MCAFilterCounter result = runWithWorld(player, folder, filter); MCAFilterCounter result = runWithWorld(player, folder, filter, force);
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal())); if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
} }
@ -203,7 +253,7 @@ public class AnvilCommands {
max = 3 max = 3
) )
@CommandPermissions("worldedit.anvil.countall") @CommandPermissions("worldedit.anvil.countall")
public void countAll(Player player, EditSession editSession, String folder, String arg, @Switch('d') boolean useData) throws WorldEditException { public void countAll(Player player, EditSession editSession, String folder, String arg, @Switch('d') boolean useData, @Switch('f') boolean force) throws WorldEditException {
Set<BaseBlock> searchBlocks = worldEdit.getBlocks(player, arg, true); Set<BaseBlock> searchBlocks = worldEdit.getBlocks(player, arg, true);
MCAFilterCounter filter; MCAFilterCounter filter;
if (useData || arg.contains(":")) { // Optimize for both cases if (useData || arg.contains(":")) { // Optimize for both cases
@ -215,7 +265,7 @@ public class AnvilCommands {
searchBlocks.forEach(counter::addBlock); searchBlocks.forEach(counter::addBlock);
filter = counter; filter = counter;
} }
MCAFilterCounter result = runWithWorld(player, folder, filter); MCAFilterCounter result = runWithWorld(player, folder, filter, force);
if (result != null) player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(result.getTotal())); if (result != null) player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(result.getTotal()));
} }

View File

@ -30,7 +30,7 @@ public class Settings extends Config {
public String LANGUAGE = ""; public String LANGUAGE = "";
@Comment("Allow the plugin to update") @Comment("Allow the plugin to update")
public boolean UPDATE = true; public boolean UPDATE = true;
@Comment("Send anonymous usage statistics to MCStats.org") @Comment("Send anonymous usage statistics to mcstats.org")
public boolean METRICS = true; public boolean METRICS = true;
@Comment("FAWE will skip chunks when there's not enough memory available") @Comment("FAWE will skip chunks when there's not enough memory available")
public boolean PREVENT_CRASHES = false; public boolean PREVENT_CRASHES = false;

View File

@ -94,7 +94,9 @@ public class MCAFile {
e.printStackTrace(); e.printStackTrace();
} }
} }
synchronized (chunks) {
chunks.clear(); chunks.clear();
}
locations = null; locations = null;
} }
@ -166,8 +168,10 @@ public class MCAFile {
int cx = chunk.getX(); int cx = chunk.getX();
int cz = chunk.getZ(); int cz = chunk.getZ();
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31)); int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
synchronized (chunks) {
chunks.put(pair, chunk); chunks.put(pair, chunk);
} }
}
public MCAChunk getChunk(int cx, int cz) throws IOException { public MCAChunk getChunk(int cx, int cz) throws IOException {
MCAChunk cached = getCachedChunk(cx, cz); MCAChunk cached = getCachedChunk(cx, cz);
@ -275,7 +279,10 @@ public class MCAFile {
} }
public List<Integer> getChunks() { public List<Integer> getChunks() {
final List<Integer> values = new ArrayList<>(chunks.size()); final List<Integer> values;
synchronized (chunks) {
values = new ArrayList<>(chunks.size());
}
for (int i = 0; i < locations.length; i += 4) { for (int i = 0; i < locations.length; i += 4) {
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i + 2] & 0xFF))); int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i + 2] & 0xFF)));
values.add(offset); values.add(offset);
@ -433,6 +440,21 @@ public class MCAFile {
} }
} }
public boolean isModified() {
if (isDeleted()) {
return true;
}
synchronized (chunks) {
for (Int2ObjectMap.Entry<MCAChunk> entry : chunks.int2ObjectEntrySet()) {
MCAChunk chunk = entry.getValue();
if (chunk.isModified() || chunk.isDeleted()) {
return true;
}
}
}
return false;
}
public void flush(ForkJoinPool pool) { public void flush(ForkJoinPool pool) {
synchronized (raf) { synchronized (raf) {
boolean wait; boolean wait;
@ -445,9 +467,11 @@ public class MCAFile {
final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>(); final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>();
final Int2ObjectOpenHashMap<byte[]> append = new Int2ObjectOpenHashMap<>(); final Int2ObjectOpenHashMap<byte[]> append = new Int2ObjectOpenHashMap<>();
boolean modified = false; boolean modified = false;
long now = System.currentTimeMillis();
for (MCAChunk chunk : getCachedChunks()) { for (MCAChunk chunk : getCachedChunks()) {
if (chunk.isModified() || chunk.isDeleted()) { if (chunk.isModified() || chunk.isDeleted()) {
modified = true; modified = true;
chunk.setLastUpdate(now);
if (!chunk.isDeleted()) { if (!chunk.isDeleted()) {
pool.submit(new Runnable() { pool.submit(new Runnable() {
@Override @Override

View File

@ -2,6 +2,8 @@ package com.boydti.fawe.jnbt.anvil;
import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
/** /**
* MCAQueue.filterWorld(MCAFilter)<br> * MCAQueue.filterWorld(MCAFilter)<br>
@ -9,6 +11,10 @@ import com.sk89q.worldedit.blocks.BaseBlock;
*/ */
public class MCAFilter<T> extends IterableThreadLocal<T> { public class MCAFilter<T> extends IterableThreadLocal<T> {
public boolean appliesFile(Path path, BasicFileAttributes attr) {
return true;
}
/** /**
* Check whether a .mca file should be read * Check whether a .mca file should be read
* *

View File

@ -8,16 +8,20 @@ import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer; import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue; import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.RunnableVal4; import com.boydti.fawe.object.RunnableVal4;
import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.MainUtil;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.world.biome.BaseBiome; import com.sk89q.worldedit.world.biome.BaseBiome;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
@ -269,8 +273,104 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
pool.shutdown(); pool.shutdown();
} }
public <G, T extends MCAFilter<G>> T filterCopy(final T filter, boolean deleteOnCopyFail) {
this.filterWorld(new MCAFilter<G>() {
@Override
public boolean appliesFile(int mcaX, int mcaZ) {
return filter.appliesFile(mcaX, mcaZ);
}
@Override
public boolean appliesFile(Path path, BasicFileAttributes attr) {
return filter.appliesFile(path, attr);
}
@Override
public MCAFile applyFile(MCAFile mca) {
File file = mca.getFile();
File copyDest = new File(file.getParentFile(), file.getName() + "-copy");
try {
Files.copy(file.toPath(), copyDest.toPath(), StandardCopyOption.REPLACE_EXISTING);
MCAFile copy = new MCAFile(mca.getParent(), copyDest);
MCAFile result = filter.applyFile(copy);
if (result == null) {
if (copy.isDeleted()) {
copy.clear();
result.clear();
if (file.exists()) {
file.delete();
}
if (copyDest.exists()) {
if (!copyDest.delete()) {
copyDest.deleteOnExit();
}
}
} else if (copy.isModified()) {
if (copyDest.exists()) {
copy.clear();
file.delete();
if (!copyDest.renameTo(file) && deleteOnCopyFail) {
if (!copyDest.delete()) {
copyDest.deleteOnExit();
}
}
}
} else {
copy.clear();
if (!copyDest.delete()) {
copyDest.deleteOnExit();
}
}
}
return result;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
@Override
public boolean appliesChunk(int cx, int cz) {
return filter.appliesChunk(cx, cz);
}
@Override
public MCAChunk applyChunk(MCAChunk chunk, G cache) {
return filter.applyChunk(chunk, cache);
}
@Override
public void applyBlock(int x, int y, int z, BaseBlock block, G cache) {
filter.applyBlock(x, y, z, block, cache);
}
}, true, new RunnableVal<MCAFile>() {
@Override
public void run(MCAFile value) {
if (deleteOnCopyFail) {
File file = value.getFile();
boolean result = file.delete();
if (!result) {
file.deleteOnExit();
}
Fawe.debug("Deleted " + file + " = " + result);
}
}
});
return filter;
}
public <G, T extends MCAFilter<G>> T filterRegion(final T filter, final RegionWrapper region) { public <G, T extends MCAFilter<G>> T filterRegion(final T filter, final RegionWrapper region) {
this.filterWorld(new MCAFilter<G>() { this.filterWorld(new MCAFilter<G>() {
@Override
public boolean appliesFile(Path path, BasicFileAttributes attr) {
String name = path.getFileName().toString();
String[] split = name.split("\\.");
final int mcaX = Integer.parseInt(split[1]);
final int mcaZ = Integer.parseInt(split[2]);
return region.isInMCA(mcaX, mcaZ) && filter.appliesFile(path, attr);
}
@Override @Override
public boolean appliesFile(int mcaX, int mcaZ) { public boolean appliesFile(int mcaX, int mcaZ) {
return region.isInMCA(mcaX, mcaZ) && filter.appliesFile(mcaX, mcaZ); return region.isInMCA(mcaX, mcaZ) && filter.appliesFile(mcaX, mcaZ);
@ -356,6 +456,10 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
} }
public <G, T extends MCAFilter<G>> T filterWorld(final T filter) { public <G, T extends MCAFilter<G>> T filterWorld(final T filter) {
return filterWorld(filter, false, null);
}
private <G, T extends MCAFilter<G>> T filterWorld(final T filter, boolean replaceOriginalOnCopy, RunnableVal<MCAFile> onReplaceFail) {
File folder = getSaveFolder(); File folder = getSaveFolder();
final ForkJoinPool pool = new ForkJoinPool(); final ForkJoinPool pool = new ForkJoinPool();
MainUtil.traverse(folder.toPath(), new RunnableVal2<Path, BasicFileAttributes>() { MainUtil.traverse(folder.toPath(), new RunnableVal2<Path, BasicFileAttributes>() {
@ -363,15 +467,20 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
public void run(Path path, BasicFileAttributes attr) { public void run(Path path, BasicFileAttributes attr) {
try { try {
String name = path.getFileName().toString(); String name = path.getFileName().toString();
if (!name.endsWith(".mca")) {
return;
}
if (!filter.appliesFile(path, attr)) {
return;
}
String[] split = name.split("\\."); String[] split = name.split("\\.");
final int mcaX = Integer.parseInt(split[1]); final int mcaX = Integer.parseInt(split[1]);
final int mcaZ = Integer.parseInt(split[2]); final int mcaZ = Integer.parseInt(split[2]);
if (filter.appliesFile(mcaX, mcaZ)) { if (filter.appliesFile(mcaX, mcaZ)) {
File file = path.toFile(); File file = path.toFile();
Fawe.debug("Apply file " + file); Fawe.debug("Apply file " + file);
MCAFile mcaFile = new MCAFile(MCAQueue.this, file); final MCAFile original = new MCAFile(MCAQueue.this, file);
final MCAFile original = mcaFile; final MCAFile finalFile = filter.applyFile(original);
final MCAFile finalFile = filter.applyFile(mcaFile);
if (finalFile != null && !finalFile.isDeleted()) { if (finalFile != null && !finalFile.isDeleted()) {
finalFile.init(); finalFile.init();
// May not do anything, but seems to lead to smaller lag spikes // May not do anything, but seems to lead to smaller lag spikes
@ -428,10 +537,7 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
}); });
} }
}); });
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS); } else if (original.isDeleted()) {
original.close(pool);
if (original != finalFile) finalFile.close(pool);
} else if (mcaFile.isDeleted()) {
try { try {
original.close(pool); original.close(pool);
file.delete(); file.delete();
@ -439,6 +545,36 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
ignore.printStackTrace(); ignore.printStackTrace();
} }
} }
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
original.close(pool);
if (original.isDeleted()) {
file.delete();
}
if (finalFile != null) {
if (original != finalFile) {
if (finalFile.isModified()) {
finalFile.close(pool);
if (finalFile.isDeleted()) {
finalFile.getFile().delete();
if (replaceOriginalOnCopy && file.exists()) {
file.delete();
}
} else if (replaceOriginalOnCopy) {
File from = finalFile.getFile();
file.delete();
if (!from.renameTo(file)) {
Fawe.debug("Could not rename " + from + "to " + file + ".");
if (onReplaceFail != null) {
onReplaceFail.run(finalFile);
}
}
}
} else if (replaceOriginalOnCopy) {
finalFile.clear();
finalFile.getFile().delete();
}
}
}
} }
} catch (Throwable ignore) { } catch (Throwable ignore) {
ignore.printStackTrace(); ignore.printStackTrace();

View File

@ -0,0 +1,28 @@
package com.boydti.fawe.jnbt.anvil.filters;
import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
public class DeleteOldFilter extends MCAFilterCounter {
private final long time;
public DeleteOldFilter(long time) {
this.time = time;
if (time < 1) {
throw new IllegalArgumentException("Time must be positive");
}
}
@Override
public boolean appliesFile(Path path, BasicFileAttributes attr) {
long modified = attr.lastModifiedTime().toMillis();
long access = attr.lastAccessTime().toMillis();
long last = Math.max(modified, access);
if (last != 0 && System.currentTimeMillis() - last > this.time) {
path.toFile().delete();
get().add(512 * 512 * 256);
}
return false;
}
}

View File

@ -10,7 +10,7 @@ import com.boydti.fawe.object.RunnableVal4;
import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.exception.FaweException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -21,31 +21,53 @@ import java.util.concurrent.TimeUnit;
*/ */
public class DeleteUninhabitedFilter extends MCAFilterCounter { public class DeleteUninhabitedFilter extends MCAFilterCounter {
private final long inhabitedTicks; private final long inhabitedTicks;
private final long fileAgeMillis; private final long fileDurationMillis;
private final long cutoffChunkAgeEpoch;
public DeleteUninhabitedFilter(long fileAgeMillis, long inhabitedTicks) { public DeleteUninhabitedFilter(long fileDurationMillis, long inhabitedTicks, long chunkInactivityMillis) {
this.fileAgeMillis = fileAgeMillis; this.fileDurationMillis = fileDurationMillis;
this.inhabitedTicks = inhabitedTicks; this.inhabitedTicks = inhabitedTicks;
this.cutoffChunkAgeEpoch = System.currentTimeMillis() - chunkInactivityMillis;
} }
public long getInhabitedTicks() { public long getInhabitedTicks() {
return inhabitedTicks; return inhabitedTicks;
} }
public long getFileAgeMillis() { public long getFileDurationMillis() {
return fileAgeMillis; return fileDurationMillis;
}
public long getCutoffChunkAgeEpoch() {
return cutoffChunkAgeEpoch;
}
@Override
public boolean appliesFile(Path path, BasicFileAttributes attr) {
String name = path.getFileName().toString();
String[] split = name.split("\\.");
final int mcaX = Integer.parseInt(split[1]);
final int mcaZ = Integer.parseInt(split[2]);
File file = path.toFile();
long lastModified = attr.lastModifiedTime().toMillis();
if (lastModified > cutoffChunkAgeEpoch) {
return false;
}
try {
if (shouldDelete(file, attr, mcaX, mcaZ)) {
file.delete();
get().add(512 * 512 * 256);
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
} }
@Override @Override
public MCAFile applyFile(MCAFile mca) { public MCAFile applyFile(MCAFile mca) {
try {
if (shouldDelete(mca)) {
mca.setDeleted(true);
get().add(512 * 512 * 256);
return null;
}
} catch (IOException | UnsupportedOperationException ignore) {
}
try { try {
ForkJoinPool pool = new ForkJoinPool(); ForkJoinPool pool = new ForkJoinPool();
mca.init(); mca.init();
@ -53,18 +75,19 @@ public class DeleteUninhabitedFilter extends MCAFilterCounter {
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS); pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
mca.close(pool); mca.close(pool);
pool.shutdown(); pool.shutdown();
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} }
return null; return null;
} }
public boolean shouldDelete(MCAFile mca) throws IOException { public boolean shouldDelete(File file, BasicFileAttributes attr, int mcaX, int mcaZ) throws IOException {
File file = mca.getFile();
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
long creation = attr.creationTime().toMillis(); long creation = attr.creationTime().toMillis();
long modified = attr.lastModifiedTime().toMillis(); long modified = attr.lastModifiedTime().toMillis();
if ((modified - creation < fileAgeMillis && modified > creation) || file.length() < 12288) { if ((modified - creation < fileDurationMillis && modified > creation) || file.length() < 12288) {
return true; return true;
} }
return false; return false;
@ -78,7 +101,6 @@ public class DeleteUninhabitedFilter extends MCAFilterCounter {
mca.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() { mca.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
@Override @Override
public void run(Integer x, Integer z, Integer offset, Integer size) { public void run(Integer x, Integer z, Integer offset, Integer size) {
try {
int bx = mca.getX() << 5; int bx = mca.getX() << 5;
int bz = mca.getZ() << 5; int bz = mca.getZ() << 5;
if (shouldDeleteChunk(mca, bx, bz)) { if (shouldDeleteChunk(mca, bx, bz)) {
@ -90,8 +112,6 @@ public class DeleteUninhabitedFilter extends MCAFilterCounter {
get().add(16 * 16 * 256); get().add(16 * 16 * 256);
return; return;
} }
byte[] bytes = mca.getChunkCompressedBytes(offset);
if (bytes == null) return;
Runnable task = new Runnable() { Runnable task = new Runnable() {
@Override @Override
public void run() { public void run() {
@ -109,9 +129,6 @@ public class DeleteUninhabitedFilter extends MCAFilterCounter {
} }
}; };
pool.submit(task); pool.submit(task);
} catch (IOException e) {
e.printStackTrace();
}
} }
}); });
} }

View File

@ -1,8 +1,10 @@
package com.boydti.fawe.jnbt.anvil.filters; package com.boydti.fawe.jnbt.anvil.filters;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.jnbt.anvil.MCAChunk; import com.boydti.fawe.jnbt.anvil.MCAChunk;
import com.boydti.fawe.jnbt.anvil.MCAFile; import com.boydti.fawe.jnbt.anvil.MCAFile;
import com.boydti.fawe.object.RunnableVal; import com.boydti.fawe.object.RunnableVal4;
import com.boydti.fawe.object.collection.LongHashSet;
import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.generator.HybridGen; import com.intellectualcrafters.plot.generator.HybridGen;
import com.intellectualcrafters.plot.generator.HybridPlotWorld; import com.intellectualcrafters.plot.generator.HybridPlotWorld;
@ -11,8 +13,12 @@ import com.intellectualcrafters.plot.object.Location;
import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotArea; import com.intellectualcrafters.plot.object.PlotArea;
import com.intellectualcrafters.plot.util.expiry.ExpireManager; import com.intellectualcrafters.plot.util.expiry.ExpireManager;
import com.sk89q.worldguard.util.collect.LongHashSet; import com.sk89q.worldedit.world.World;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
@ -32,27 +38,37 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
return false; return false;
} }
public PlotTrimFilter(PlotArea area, long fileAgeMillis, long inhabitedTicks) { public PlotTrimFilter(World world, long fileDuration, long inhabitedTicks, long chunkInactivity) {
super(fileAgeMillis, inhabitedTicks); super(fileDuration, inhabitedTicks, chunkInactivity);
String worldName = Fawe.imp().getWorldName(world);
PlotArea area = PS.get().getPlotAreaByString(worldName);
IndependentPlotGenerator gen = area.getGenerator(); IndependentPlotGenerator gen = area.getGenerator();
if (!(area instanceof HybridPlotWorld) || !(gen instanceof HybridGen)) { if (!(area instanceof HybridPlotWorld) || !(gen instanceof HybridGen)) {
throw new UnsupportedOperationException("Trim does not support non hybrid plot worlds"); throw new UnsupportedOperationException("Trim does not support non hybrid plot worlds");
} }
this.hg = (HybridGen) gen; this.hg = (HybridGen) gen;
this.hpw = (HybridPlotWorld) area; this.hpw = (HybridPlotWorld) area;
if (!hpw.PLOT_BEDROCK || hpw.PLOT_SCHEMATIC || hpw.MAIN_BLOCK.length != 1 || hpw.TOP_BLOCK.length != 1) {
if (hpw.PLOT_BEDROCK && !hpw.PLOT_SCHEMATIC && hpw.MAIN_BLOCK.length == 1 && hpw.TOP_BLOCK.length == 1) { throw new UnsupportedOperationException("WIP - will implement later");
this.reference = new MCAChunk(null, 0, 0);
this.reference.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0);
this.reference.fillCuboid(0, 15, 1, hpw.PLOT_HEIGHT - 1, 0, 15, hpw.MAIN_BLOCK[0].id, (byte) 0);
this.reference.fillCuboid(0, 15, hpw.PLOT_HEIGHT, hpw.PLOT_HEIGHT, 0, 15, hpw.TOP_BLOCK[0].id, (byte) 0);
} else {
this.reference = null;
} }
this.occupiedRegions = new LongHashSet(); this.occupiedRegions = new LongHashSet();
this.unoccupiedChunks = new LongHashSet(); this.unoccupiedChunks = new LongHashSet();
ArrayList<Plot> plots = new ArrayList<>();
plots.addAll(PS.get().getPlots(area)); this.reference = calculateReference();
this.calculateClaimedArea();
}
private MCAChunk calculateReference() {
MCAChunk reference = new MCAChunk(null, 0, 0);
reference.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0);
reference.fillCuboid(0, 15, 1, hpw.PLOT_HEIGHT - 1, 0, 15, hpw.MAIN_BLOCK[0].id, (byte) 0);
reference.fillCuboid(0, 15, hpw.PLOT_HEIGHT, hpw.PLOT_HEIGHT, 0, 15, hpw.TOP_BLOCK[0].id, (byte) 0);
return reference;
}
private void calculateClaimedArea() {
ArrayList<Plot> plots = new ArrayList<>(hpw.getPlots());
if (ExpireManager.IMP != null) { if (ExpireManager.IMP != null) {
plots.removeAll(ExpireManager.IMP.getPendingExpired()); plots.removeAll(ExpireManager.IMP.getPendingExpired());
} }
@ -65,13 +81,12 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
int ccz2 = pos2.getZ() >> 9; int ccz2 = pos2.getZ() >> 9;
for (int x = ccx1; x <= ccx2; x++) { for (int x = ccx1; x <= ccx2; x++) {
for (int z = ccz1; z <= ccz2; z++) { for (int z = ccz1; z <= ccz2; z++) {
if (!occupiedRegions.containsKey(x, z)) {
occupiedRegions.add(x, z);
int bcx = x << 5; int bcx = x << 5;
int bcz = z << 5; int bcz = z << 5;
int tcx = bcx + 32; int tcx = bcx + 32;
int tcz = bcz + 32; int tcz = bcz + 32;
if (!occupiedRegions.containsKey(x, z)) {
occupiedRegions.add(x, z);
} else {
for (int cz = bcz; cz < tcz; cz++) { for (int cz = bcz; cz < tcz; cz++) {
for (int cx = bcx; cx < tcx; cx++) { for (int cx = bcx; cx < tcx; cx++) {
unoccupiedChunks.add(cx, cz); unoccupiedChunks.add(cx, cz);
@ -84,8 +99,8 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
int cz1 = pos1.getZ() >> 4; int cz1 = pos1.getZ() >> 4;
int cx2 = pos2.getX() >> 4; int cx2 = pos2.getX() >> 4;
int cz2 = pos2.getZ() >> 4; int cz2 = pos2.getZ() >> 4;
for (int cz = cx1; cz < cx2; cz++) { for (int cz = cz1; cz <= cz2; cz++) {
for (int cx = cz1; cx < cz2; cx++) { for (int cx = cx1; cx <= cx2; cx++) {
unoccupiedChunks.remove(cx, cz); unoccupiedChunks.remove(cx, cz);
} }
} }
@ -93,15 +108,13 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
} }
@Override @Override
public boolean shouldDelete(MCAFile mca) throws IOException { public boolean shouldDelete(File file, BasicFileAttributes attr, int mcaX, int mcaZ) throws IOException {
int x = mca.getX(); return !occupiedRegions.containsKey(mcaX, mcaZ) || super.shouldDelete(file, attr, mcaX, mcaZ);
int z = mca.getZ();
return !occupiedRegions.containsKey(x, z) || super.shouldDelete(mca);
} }
@Override @Override
public boolean shouldDeleteChunk(MCAFile mca, int cx, int cz) { public boolean shouldDeleteChunk(MCAFile mca, int cx, int cz) {
return !unoccupiedChunks.containsKey(cx, cz); return unoccupiedChunks.containsKey(cx, cz);
} }
@Override @Override
@ -110,17 +123,47 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
super.filter(mca, pool); super.filter(mca, pool);
return; return;
} }
mca.forEachChunk(new RunnableVal<MCAChunk>() { Path file = mca.getFile().toPath();
BasicFileAttributes attr = Files.readAttributes(file, BasicFileAttributes.class);
long creationDate = attr.creationTime().toMillis();
mca.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
@Override @Override
public void run(MCAChunk value) { public void run(Integer x, Integer z, Integer offset, Integer size) {
if (value.getInhabitedTime() < getInhabitedTicks()) { int bx = mca.getX() << 5;
value.setDeleted(true); int bz = mca.getZ() << 5;
int cx = bx + x;
int cz = bz + z;
if (shouldDeleteChunk(mca, cx, cz)) {
MCAChunk chunk = new MCAChunk(null, x, z);
chunk.setDeleted(true);
synchronized (mca) {
mca.setChunk(chunk);
}
get().add(16 * 16 * 256);
return; return;
} }
if (reference.idsEqual(value, false)) { Runnable task = new Runnable() {
value.setDeleted(true); @Override
public void run() {
try {
MCAChunk chunk = mca.getChunk(x, z);
if (chunk.getInhabitedTime() <= getInhabitedTicks()) {
chunk.setDeleted(true);
get().add(16 * 16 * 256);
return; return;
} }
if (reference.idsEqual(chunk, false)) {
chunk.setDeleted(true);
get().add(16 * 16 * 256);
return;
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
pool.submit(task);
} }
}); });
} }

View File

@ -36,6 +36,23 @@ public class FaweOutputStream extends DataOutputStream {
write((byte) (m)); write((byte) (m));
} }
public void writeVarInt(int i) throws IOException {
while((i & -128) != 0) {
this.writeByte(i & 127 | 128);
i >>>= 7;
}
this.writeByte(i);
}
public void write(long[] data) throws IOException {
this.writeVarInt(data.length);
for(int j = 0; j < data.length; ++j) {
this.writeLong(data[j]);
}
}
private NBTOutputStream nbtOut; private NBTOutputStream nbtOut;
public void writeNBT(String name, Tag tag) throws IOException { public void writeNBT(String name, Tag tag) throws IOException {

View File

@ -0,0 +1,178 @@
/*
* WorldGuard, a suite of tools for Minecraft
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldGuard team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.boydti.fawe.object.collection;
import java.util.Arrays;
public class LongHashSet {
protected long[][][] values = new long[256][][];
protected int count = 0;
public static long toLong(int msw, int lsw) {
return ((long) msw << 32) + lsw - Integer.MIN_VALUE;
}
public static int msw(long l) {
return (int) (l >> 32);
}
public static int lsw(long l) {
return (int) (l & 0xFFFFFFFF) + Integer.MIN_VALUE;
}
public boolean containsKey(int msw, int lsw) {
return containsKey(toLong(msw, lsw));
}
public void remove(int msw, int lsw) {
remove(toLong(msw, lsw));
}
public boolean isEmpty() {
return this.count == 0;
}
public int size() {
return count;
}
public void add(int msw, int lsw) {
add(toLong(msw, lsw));
}
public void add(long key) {
int mainIdx = (int) (key & 255);
long outer[][] = this.values[mainIdx];
if (outer == null) this.values[mainIdx] = outer = new long[256][];
int outerIdx = (int) ((key >> 32) & 255);
long inner[] = outer[outerIdx];
if (inner == null) {
synchronized (this) {
outer[outerIdx] = inner = new long[1];
inner[0] = key;
this.count++;
}
} else {
int i;
for (i = 0; i < inner.length; i++) {
if (inner[i] == key) {
return;
}
}
inner = Arrays.copyOf(inner, i + 1);
outer[outerIdx] = inner;
inner[i] = key;
this.count++;
}
}
public boolean containsKey(long key) {
long[][] outer = this.values[(int) (key & 255)];
if (outer == null) return false;
long[] inner = outer[(int) ((key >> 32) & 255)];
if (inner == null) return false;
for (long entry : inner) {
if (entry == key) return true;
}
return false;
}
public void remove(long key) {
long[][] outer = this.values[(int) (key & 255)];
if (outer == null) return;
long[] inner = outer[(int) ((key >> 32) & 255)];
if (inner == null) return;
int max = inner.length - 1;
for (int i = 0; i <= max; i++) {
if (inner[i] == key) {
this.count--;
if (i != max) {
inner[i] = inner[max];
}
outer[(int) ((key >> 32) & 255)] = (max == 0 ? null : Arrays.copyOf(inner, max));
return;
}
}
}
public long popFirst() {
for (long[][] outer: this.values) {
if (outer == null) continue;
for (int i = 0; i < outer.length; i++) {
long[] inner = outer[i];
if (inner == null || inner.length == 0) continue;
this.count--;
long ret = inner[inner.length - 1];
outer[i] = Arrays.copyOf(inner, inner.length - 1);
return ret;
}
}
return 0;
}
public long[] popAll() {
int index = 0;
long[] ret = new long[this.count];
for (long[][] outer : this.values) {
if (outer == null) continue;
for (int oIdx = outer.length - 1; oIdx >= 0; oIdx--) {
long[] inner = outer[oIdx];
if (inner == null) continue;
for (long entry: inner) {
ret[index++] = entry;
}
outer[oIdx] = null;
}
}
count = 0;
return ret;
}
public long[] keys() {
int index = 0;
long[] ret = new long[this.count];
for (long[][] outer : this.values) {
if (outer == null) continue;
for (long[] inner : outer) {
if (inner == null) continue;
for (long entry : inner) {
ret[index++] = entry;
}
}
}
return ret;
}
}

View File

@ -1696,7 +1696,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
checkNotNull(region); checkNotNull(region);
checkNotNull(pattern); checkNotNull(pattern);
if (pattern instanceof BlockPattern) { if (pattern instanceof BlockPattern) {
return setBlocks(region, ((BaseBlock) pattern)); return setBlocks(region, ((BlockPattern) pattern).getBlock());
} }
if (pattern instanceof BaseBlock) { if (pattern instanceof BaseBlock) {
return setBlocks(region, (BaseBlock) pattern); return setBlocks(region, (BaseBlock) pattern);

View File

@ -3,7 +3,7 @@ repositories {
} }
dependencies { dependencies {
compile project(':core') compile project(':core')
compile 'cn.nukkit:nukkit:1.0-SNAPSHOT' compile group: "cn.nukkit", name: "nukkit", version: "1.0-20170704.231613-609", changing: true
compile name: 'worldedit-core-6.1.4-SNAPSHOT-dist', changing: true compile name: 'worldedit-core-6.1.4-SNAPSHOT-dist', changing: true
} }

View File

@ -46,14 +46,12 @@ public class FaweNukkit implements IFawe, Listener {
@EventHandler @EventHandler
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (!event.getReason().equals("disconnectionScreen.serverFull")) {
FawePlayer fp = FawePlayer.wrap(player); FawePlayer fp = FawePlayer.wrap(player);
if (fp != null) { if (fp != null) {
fp.unregister(); fp.unregister();
} }
Fawe.get().unregister(event.getPlayer().getName()); Fawe.get().unregister(event.getPlayer().getName());
} }
}
@Override @Override
public void debug(String s) { public void debug(String s) {