mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-12-29 12:37:53 +01:00
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:
parent
3c44e75139
commit
7f01ac7790
@ -69,6 +69,7 @@ if ( project.hasProperty("lzNoVersion") ) { // gradle build -PlzNoVersion
|
||||
description = """FastAsyncWorldEdit"""
|
||||
|
||||
subprojects {
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'eclipse'
|
||||
@ -79,10 +80,11 @@ subprojects {
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {url "http://repo.dmulloy2.net/content/groups/public/"}
|
||||
maven {url "https://repo.destroystokyo.com/repository/maven-public//"}
|
||||
maven { url = "https://mvnrepository.com/artifact/"}
|
||||
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://empcraft.com/maven2"}
|
||||
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://repo.maven.apache.org/maven2"}
|
||||
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"}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ dependencies {
|
||||
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.8.8'
|
||||
compile 'com.comphenix.protocol:ProtocolLib-API:4.3.1-SNAPSHOT'
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -11,8 +11,10 @@ import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
|
||||
import com.boydti.fawe.jnbt.anvil.MCAQueue;
|
||||
import com.boydti.fawe.jnbt.anvil.filters.CountFilter;
|
||||
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.MappedReplacePatternFilter;
|
||||
import com.boydti.fawe.jnbt.anvil.filters.PlotTrimFilter;
|
||||
import com.boydti.fawe.jnbt.anvil.filters.RemoveLayerFilter;
|
||||
import com.boydti.fawe.jnbt.anvil.filters.ReplacePatternFilter;
|
||||
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.RunnableVal4;
|
||||
import com.boydti.fawe.object.mask.FaweBlockMatcher;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.SetQueue;
|
||||
import com.boydti.fawe.util.StringMan;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
@ -77,14 +80,22 @@ public class AnvilCommands {
|
||||
* @param <T>
|
||||
* @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) {
|
||||
BBC.WORLD_IS_LOADED.send(player);
|
||||
return null;
|
||||
if (!force) {
|
||||
BBC.WORLD_IS_LOADED.send(player);
|
||||
return null;
|
||||
}
|
||||
copy = true;
|
||||
}
|
||||
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
|
||||
MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
|
||||
return queue.filterWorld(filter);
|
||||
if (copy) {
|
||||
return queue.filterCopy(filter, true);
|
||||
} else {
|
||||
return queue.filterWorld(filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,7 +143,7 @@ public class AnvilCommands {
|
||||
max = 4
|
||||
)
|
||||
@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;
|
||||
if (from == null) {
|
||||
matchFrom = FaweBlockMatcher.NOT_AIR;
|
||||
@ -144,21 +155,60 @@ public class AnvilCommands {
|
||||
}
|
||||
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
|
||||
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()));
|
||||
}
|
||||
|
||||
@Command(
|
||||
aliases = {"deleteallold"},
|
||||
aliases = {"deleteallunvisited", "delunvisited" },
|
||||
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,
|
||||
max = 3
|
||||
)
|
||||
@CommandPermissions("worldedit.anvil.deleteallold")
|
||||
public void deleteAllOld(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileAgeMillis, @Switch('f') boolean force) throws WorldEditException {
|
||||
DeleteUninhabitedFilter filter = new DeleteUninhabitedFilter(fileAgeMillis, inhabitedTicks);
|
||||
DeleteUninhabitedFilter result = runWithWorld(player, folder, filter);
|
||||
@CommandPermissions("worldedit.anvil.deleteallunvisited")
|
||||
public void deleteAllUnvisited(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileDurationMillis, @Switch('f') boolean force) throws WorldEditException {
|
||||
long chunkInactivityMillis = fileDurationMillis; // Use same value for now
|
||||
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()));
|
||||
}
|
||||
|
||||
@ -171,7 +221,7 @@ public class AnvilCommands {
|
||||
max = 4
|
||||
)
|
||||
@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;
|
||||
if (useMap) {
|
||||
if (to instanceof RandomPattern) {
|
||||
@ -190,7 +240,7 @@ public class AnvilCommands {
|
||||
}
|
||||
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()));
|
||||
}
|
||||
|
||||
@ -203,7 +253,7 @@ public class AnvilCommands {
|
||||
max = 3
|
||||
)
|
||||
@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);
|
||||
MCAFilterCounter filter;
|
||||
if (useData || arg.contains(":")) { // Optimize for both cases
|
||||
@ -215,7 +265,7 @@ public class AnvilCommands {
|
||||
searchBlocks.forEach(counter::addBlock);
|
||||
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()));
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ public class Settings extends Config {
|
||||
public String LANGUAGE = "";
|
||||
@Comment("Allow the plugin to update")
|
||||
public boolean UPDATE = true;
|
||||
@Comment("Send anonymous usage statistics to MCStats.org")
|
||||
@Comment("Send anonymous usage statistics to mcstats.org")
|
||||
public boolean METRICS = true;
|
||||
@Comment("FAWE will skip chunks when there's not enough memory available")
|
||||
public boolean PREVENT_CRASHES = false;
|
||||
|
@ -94,7 +94,9 @@ public class MCAFile {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
chunks.clear();
|
||||
synchronized (chunks) {
|
||||
chunks.clear();
|
||||
}
|
||||
locations = null;
|
||||
}
|
||||
|
||||
@ -166,7 +168,9 @@ public class MCAFile {
|
||||
int cx = chunk.getX();
|
||||
int cz = chunk.getZ();
|
||||
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
|
||||
chunks.put(pair, chunk);
|
||||
synchronized (chunks) {
|
||||
chunks.put(pair, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public MCAChunk getChunk(int cx, int cz) throws IOException {
|
||||
@ -275,7 +279,10 @@ public class MCAFile {
|
||||
}
|
||||
|
||||
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) {
|
||||
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i + 2] & 0xFF)));
|
||||
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) {
|
||||
synchronized (raf) {
|
||||
boolean wait;
|
||||
@ -445,9 +467,11 @@ public class MCAFile {
|
||||
final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>();
|
||||
final Int2ObjectOpenHashMap<byte[]> append = new Int2ObjectOpenHashMap<>();
|
||||
boolean modified = false;
|
||||
long now = System.currentTimeMillis();
|
||||
for (MCAChunk chunk : getCachedChunks()) {
|
||||
if (chunk.isModified() || chunk.isDeleted()) {
|
||||
modified = true;
|
||||
chunk.setLastUpdate(now);
|
||||
if (!chunk.isDeleted()) {
|
||||
pool.submit(new Runnable() {
|
||||
@Override
|
||||
|
@ -2,6 +2,8 @@ package com.boydti.fawe.jnbt.anvil;
|
||||
|
||||
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
/**
|
||||
* MCAQueue.filterWorld(MCAFilter)<br>
|
||||
@ -9,6 +11,10 @@ import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
*/
|
||||
public class MCAFilter<T> extends IterableThreadLocal<T> {
|
||||
|
||||
public boolean appliesFile(Path path, BasicFileAttributes attr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a .mca file should be read
|
||||
*
|
||||
|
@ -8,16 +8,20 @@ import com.boydti.fawe.object.FaweChunk;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.RunnableVal2;
|
||||
import com.boydti.fawe.object.RunnableVal4;
|
||||
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@ -269,8 +273,104 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
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) {
|
||||
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
|
||||
public boolean appliesFile(int mcaX, int 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) {
|
||||
return filterWorld(filter, false, null);
|
||||
}
|
||||
|
||||
private <G, T extends MCAFilter<G>> T filterWorld(final T filter, boolean replaceOriginalOnCopy, RunnableVal<MCAFile> onReplaceFail) {
|
||||
File folder = getSaveFolder();
|
||||
final ForkJoinPool pool = new ForkJoinPool();
|
||||
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) {
|
||||
try {
|
||||
String name = path.getFileName().toString();
|
||||
if (!name.endsWith(".mca")) {
|
||||
return;
|
||||
}
|
||||
if (!filter.appliesFile(path, attr)) {
|
||||
return;
|
||||
}
|
||||
String[] split = name.split("\\.");
|
||||
final int mcaX = Integer.parseInt(split[1]);
|
||||
final int mcaZ = Integer.parseInt(split[2]);
|
||||
if (filter.appliesFile(mcaX, mcaZ)) {
|
||||
File file = path.toFile();
|
||||
Fawe.debug("Apply file " + file);
|
||||
MCAFile mcaFile = new MCAFile(MCAQueue.this, file);
|
||||
final MCAFile original = mcaFile;
|
||||
final MCAFile finalFile = filter.applyFile(mcaFile);
|
||||
final MCAFile original = new MCAFile(MCAQueue.this, file);
|
||||
final MCAFile finalFile = filter.applyFile(original);
|
||||
if (finalFile != null && !finalFile.isDeleted()) {
|
||||
finalFile.init();
|
||||
// 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);
|
||||
original.close(pool);
|
||||
if (original != finalFile) finalFile.close(pool);
|
||||
} else if (mcaFile.isDeleted()) {
|
||||
} else if (original.isDeleted()) {
|
||||
try {
|
||||
original.close(pool);
|
||||
file.delete();
|
||||
@ -439,6 +545,36 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
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) {
|
||||
ignore.printStackTrace();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import com.boydti.fawe.object.RunnableVal4;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -21,31 +21,53 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public class DeleteUninhabitedFilter extends MCAFilterCounter {
|
||||
private final long inhabitedTicks;
|
||||
private final long fileAgeMillis;
|
||||
private final long fileDurationMillis;
|
||||
private final long cutoffChunkAgeEpoch;
|
||||
|
||||
public DeleteUninhabitedFilter(long fileAgeMillis, long inhabitedTicks) {
|
||||
this.fileAgeMillis = fileAgeMillis;
|
||||
public DeleteUninhabitedFilter(long fileDurationMillis, long inhabitedTicks, long chunkInactivityMillis) {
|
||||
this.fileDurationMillis = fileDurationMillis;
|
||||
this.inhabitedTicks = inhabitedTicks;
|
||||
this.cutoffChunkAgeEpoch = System.currentTimeMillis() - chunkInactivityMillis;
|
||||
}
|
||||
|
||||
public long getInhabitedTicks() {
|
||||
return inhabitedTicks;
|
||||
}
|
||||
|
||||
public long getFileAgeMillis() {
|
||||
return fileAgeMillis;
|
||||
public long getFileDurationMillis() {
|
||||
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
|
||||
public MCAFile applyFile(MCAFile mca) {
|
||||
try {
|
||||
if (shouldDelete(mca)) {
|
||||
mca.setDeleted(true);
|
||||
get().add(512 * 512 * 256);
|
||||
return null;
|
||||
}
|
||||
} catch (IOException | UnsupportedOperationException ignore) {
|
||||
}
|
||||
try {
|
||||
ForkJoinPool pool = new ForkJoinPool();
|
||||
mca.init();
|
||||
@ -53,18 +75,19 @@ public class DeleteUninhabitedFilter extends MCAFilterCounter {
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
mca.close(pool);
|
||||
pool.shutdown();
|
||||
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean shouldDelete(MCAFile mca) throws IOException {
|
||||
File file = mca.getFile();
|
||||
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
||||
public boolean shouldDelete(File file, BasicFileAttributes attr, int mcaX, int mcaZ) throws IOException {
|
||||
long creation = attr.creationTime().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 false;
|
||||
@ -78,40 +101,34 @@ public class DeleteUninhabitedFilter extends MCAFilterCounter {
|
||||
mca.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||
@Override
|
||||
public void run(Integer x, Integer z, Integer offset, Integer size) {
|
||||
try {
|
||||
int bx = mca.getX() << 5;
|
||||
int bz = mca.getZ() << 5;
|
||||
if (shouldDeleteChunk(mca, bx, bz)) {
|
||||
MCAChunk chunk = new MCAChunk(null, x, z);
|
||||
chunk.setDeleted(true);
|
||||
synchronized (mca) {
|
||||
mca.setChunk(chunk);
|
||||
}
|
||||
get().add(16 * 16 * 256);
|
||||
return;
|
||||
int bx = mca.getX() << 5;
|
||||
int bz = mca.getZ() << 5;
|
||||
if (shouldDeleteChunk(mca, bx, bz)) {
|
||||
MCAChunk chunk = new MCAChunk(null, x, z);
|
||||
chunk.setDeleted(true);
|
||||
synchronized (mca) {
|
||||
mca.setChunk(chunk);
|
||||
}
|
||||
byte[] bytes = mca.getChunkCompressedBytes(offset);
|
||||
if (bytes == null) return;
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mca.streamChunk(offset, new RunnableVal<NBTStreamer>() {
|
||||
@Override
|
||||
public void run(NBTStreamer value) {
|
||||
addReaders(mca, x, z, value);
|
||||
}
|
||||
});
|
||||
} catch (FaweException ignore) {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
pool.submit(task);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
get().add(16 * 16 * 256);
|
||||
return;
|
||||
}
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mca.streamChunk(offset, new RunnableVal<NBTStreamer>() {
|
||||
@Override
|
||||
public void run(NBTStreamer value) {
|
||||
addReaders(mca, x, z, value);
|
||||
}
|
||||
});
|
||||
} catch (FaweException ignore) {
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
pool.submit(task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
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.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.generator.HybridGen;
|
||||
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.PlotArea;
|
||||
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.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
|
||||
@ -32,27 +38,37 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
|
||||
return false;
|
||||
}
|
||||
|
||||
public PlotTrimFilter(PlotArea area, long fileAgeMillis, long inhabitedTicks) {
|
||||
super(fileAgeMillis, inhabitedTicks);
|
||||
public PlotTrimFilter(World world, long fileDuration, long inhabitedTicks, long chunkInactivity) {
|
||||
super(fileDuration, inhabitedTicks, chunkInactivity);
|
||||
String worldName = Fawe.imp().getWorldName(world);
|
||||
PlotArea area = PS.get().getPlotAreaByString(worldName);
|
||||
IndependentPlotGenerator gen = area.getGenerator();
|
||||
if (!(area instanceof HybridPlotWorld) || !(gen instanceof HybridGen)) {
|
||||
throw new UnsupportedOperationException("Trim does not support non hybrid plot worlds");
|
||||
}
|
||||
this.hg = (HybridGen) gen;
|
||||
this.hpw = (HybridPlotWorld) area;
|
||||
|
||||
if (hpw.PLOT_BEDROCK && !hpw.PLOT_SCHEMATIC && hpw.MAIN_BLOCK.length == 1 && hpw.TOP_BLOCK.length == 1) {
|
||||
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;
|
||||
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.occupiedRegions = 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) {
|
||||
plots.removeAll(ExpireManager.IMP.getPendingExpired());
|
||||
}
|
||||
@ -65,13 +81,12 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
|
||||
int ccz2 = pos2.getZ() >> 9;
|
||||
for (int x = ccx1; x <= ccx2; x++) {
|
||||
for (int z = ccz1; z <= ccz2; z++) {
|
||||
int bcx = x << 5;
|
||||
int bcz = z << 5;
|
||||
int tcx = bcx + 32;
|
||||
int tcz = bcz + 32;
|
||||
if (!occupiedRegions.containsKey(x, z)) {
|
||||
occupiedRegions.add(x, z);
|
||||
} else {
|
||||
int bcx = x << 5;
|
||||
int bcz = z << 5;
|
||||
int tcx = bcx + 32;
|
||||
int tcz = bcz + 32;
|
||||
for (int cz = bcz; cz < tcz; cz++) {
|
||||
for (int cx = bcx; cx < tcx; cx++) {
|
||||
unoccupiedChunks.add(cx, cz);
|
||||
@ -84,8 +99,8 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
|
||||
int cz1 = pos1.getZ() >> 4;
|
||||
int cx2 = pos2.getX() >> 4;
|
||||
int cz2 = pos2.getZ() >> 4;
|
||||
for (int cz = cx1; cz < cx2; cz++) {
|
||||
for (int cx = cz1; cx < cz2; cx++) {
|
||||
for (int cz = cz1; cz <= cz2; cz++) {
|
||||
for (int cx = cx1; cx <= cx2; cx++) {
|
||||
unoccupiedChunks.remove(cx, cz);
|
||||
}
|
||||
}
|
||||
@ -93,15 +108,13 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDelete(MCAFile mca) throws IOException {
|
||||
int x = mca.getX();
|
||||
int z = mca.getZ();
|
||||
return !occupiedRegions.containsKey(x, z) || super.shouldDelete(mca);
|
||||
public boolean shouldDelete(File file, BasicFileAttributes attr, int mcaX, int mcaZ) throws IOException {
|
||||
return !occupiedRegions.containsKey(mcaX, mcaZ) || super.shouldDelete(file, attr, mcaX, mcaZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDeleteChunk(MCAFile mca, int cx, int cz) {
|
||||
return !unoccupiedChunks.containsKey(cx, cz);
|
||||
return unoccupiedChunks.containsKey(cx, cz);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -110,17 +123,47 @@ public class PlotTrimFilter extends DeleteUninhabitedFilter {
|
||||
super.filter(mca, pool);
|
||||
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
|
||||
public void run(MCAChunk value) {
|
||||
if (value.getInhabitedTime() < getInhabitedTicks()) {
|
||||
value.setDeleted(true);
|
||||
return;
|
||||
}
|
||||
if (reference.idsEqual(value, false)) {
|
||||
value.setDeleted(true);
|
||||
public void run(Integer x, Integer z, Integer offset, Integer size) {
|
||||
int bx = mca.getX() << 5;
|
||||
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;
|
||||
}
|
||||
Runnable task = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
MCAChunk chunk = mca.getChunk(x, z);
|
||||
if (chunk.getInhabitedTime() <= getInhabitedTicks()) {
|
||||
chunk.setDeleted(true);
|
||||
get().add(16 * 16 * 256);
|
||||
return;
|
||||
}
|
||||
if (reference.idsEqual(chunk, false)) {
|
||||
chunk.setDeleted(true);
|
||||
get().add(16 * 16 * 256);
|
||||
return;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
pool.submit(task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -36,6 +36,23 @@ public class FaweOutputStream extends DataOutputStream {
|
||||
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;
|
||||
|
||||
public void writeNBT(String name, Tag tag) throws IOException {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -1696,7 +1696,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
checkNotNull(region);
|
||||
checkNotNull(pattern);
|
||||
if (pattern instanceof BlockPattern) {
|
||||
return setBlocks(region, ((BaseBlock) pattern));
|
||||
return setBlocks(region, ((BlockPattern) pattern).getBlock());
|
||||
}
|
||||
if (pattern instanceof BaseBlock) {
|
||||
return setBlocks(region, (BaseBlock) pattern);
|
||||
|
@ -3,7 +3,7 @@ repositories {
|
||||
}
|
||||
dependencies {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -46,13 +46,11 @@ public class FaweNukkit implements IFawe, Listener {
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (!event.getReason().equals("disconnectionScreen.serverFull")) {
|
||||
FawePlayer fp = FawePlayer.wrap(player);
|
||||
if (fp != null) {
|
||||
fp.unregister();
|
||||
}
|
||||
Fawe.get().unregister(event.getPlayer().getName());
|
||||
}
|
||||
FawePlayer fp = FawePlayer.wrap(player);
|
||||
if (fp != null) {
|
||||
fp.unregister();
|
||||
}
|
||||
Fawe.get().unregister(event.getPlayer().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user