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"""
|
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"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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.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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
*
|
*
|
||||||
|
@ -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();
|
||||||
|
@ -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 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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(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);
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user