Anvil replace + masking extent biomes
This commit is contained in:
parent
b39ab79f16
commit
c7d959d6dc
@ -217,7 +217,7 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
Settings.IMP.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
|
Settings.IMP.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
|
||||||
Settings.IMP.HISTORY.COMBINE_STAGES = false; // Performing a chunk copy (if possible) wouldn't be faster using the BukkitAPI
|
Settings.IMP.HISTORY.COMBINE_STAGES = false; // Performing a chunk copy (if possible) wouldn't be faster using the BukkitAPI
|
||||||
if (hasNMS) {
|
if (hasNMS) {
|
||||||
ignore.printStackTrace();
|
|
||||||
debug("====== NO NMS BLOCK PLACER FOUND ======");
|
debug("====== NO NMS BLOCK PLACER FOUND ======");
|
||||||
debug("FAWE couldn't find a fast block placer");
|
debug("FAWE couldn't find a fast block placer");
|
||||||
debug("Bukkit version: " + Bukkit.getVersion());
|
debug("Bukkit version: " + Bukkit.getVersion());
|
||||||
@ -227,6 +227,8 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
debug("Download the version of FAWE for your platform");
|
debug("Download the version of FAWE for your platform");
|
||||||
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
|
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
|
||||||
debug("=======================================");
|
debug("=======================================");
|
||||||
|
ignore.printStackTrace();
|
||||||
|
debug("=======================================");
|
||||||
TaskManager.IMP.laterAsync(new Runnable() {
|
TaskManager.IMP.laterAsync(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -262,9 +264,11 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
} catch (Throwable ignore) {
|
} catch (Throwable ignore) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Throwable error = null;
|
||||||
try {
|
try {
|
||||||
return plugin.getQueue(world);
|
return plugin.getQueue(world);
|
||||||
} catch (Throwable ignore) {
|
} catch (Throwable ignore) {
|
||||||
|
error = ignore;
|
||||||
}
|
}
|
||||||
// Disable incompatible settings
|
// Disable incompatible settings
|
||||||
Settings.IMP.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
|
Settings.IMP.QUEUE.PARALLEL_THREADS = 1; // BukkitAPI placer is too slow to parallel thread at the chunk level
|
||||||
@ -273,12 +277,14 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
debug("====== NO NMS BLOCK PLACER FOUND ======");
|
debug("====== NO NMS BLOCK PLACER FOUND ======");
|
||||||
debug("FAWE couldn't find a fast block placer");
|
debug("FAWE couldn't find a fast block placer");
|
||||||
debug("Bukkit version: " + Bukkit.getVersion());
|
debug("Bukkit version: " + Bukkit.getVersion());
|
||||||
debug("NMS label: " + plugin.getClass().getSimpleName().split("_")[1]);
|
debug("NMS label: " + plugin.getClass().getSimpleName());
|
||||||
debug("Fallback placer: " + BukkitQueue_All.class);
|
debug("Fallback placer: " + BukkitQueue_All.class);
|
||||||
debug("=======================================");
|
debug("=======================================");
|
||||||
debug("Download the version of FAWE for your platform");
|
debug("Download the version of FAWE for your platform");
|
||||||
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
|
debug(" - http://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/artifact/target");
|
||||||
debug("=======================================");
|
debug("=======================================");
|
||||||
|
error.printStackTrace();
|
||||||
|
debug("=======================================");
|
||||||
TaskManager.IMP.laterAsync(new Runnable() {
|
TaskManager.IMP.laterAsync(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -11,11 +11,13 @@ import com.boydti.fawe.object.FawePlayer;
|
|||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
||||||
import com.boydti.fawe.util.MathMan;
|
import com.boydti.fawe.util.MathMan;
|
||||||
|
import com.boydti.fawe.util.ReflectionUtils;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||||
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.RandomAccessFile;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -204,6 +206,11 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
|||||||
private static Field fieldTimingsEnabled;
|
private static Field fieldTimingsEnabled;
|
||||||
private static Field fieldAsyncCatcherEnabled;
|
private static Field fieldAsyncCatcherEnabled;
|
||||||
private static Method methodCheck;
|
private static Method methodCheck;
|
||||||
|
private static Class<?> classRegionFile;
|
||||||
|
private static Class<?> classRegionFileCache;
|
||||||
|
private static Field fieldRegionMap;
|
||||||
|
private static Field fieldRegionFile;
|
||||||
|
private static Method methodUnloadChunk;
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
fieldAsyncCatcherEnabled = Class.forName("org.spigotmc.AsyncCatcher").getField("enabled");
|
fieldAsyncCatcherEnabled = Class.forName("org.spigotmc.AsyncCatcher").getField("enabled");
|
||||||
@ -215,6 +222,29 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
|||||||
methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled");
|
methodCheck = Class.forName("co.aikar.timings.TimingsManager").getDeclaredMethod("recheckEnabled");
|
||||||
methodCheck.setAccessible(true);
|
methodCheck.setAccessible(true);
|
||||||
} catch (Throwable ignore){}
|
} catch (Throwable ignore){}
|
||||||
|
try {
|
||||||
|
classRegionFile = ReflectionUtils.getNmsClass("RegionFile");
|
||||||
|
classRegionFileCache = ReflectionUtils.getNmsClass("RegionFileCache");
|
||||||
|
for (Field field : classRegionFileCache.getDeclaredFields()) {
|
||||||
|
if (Map.class.isAssignableFrom(field.getType())) {
|
||||||
|
fieldRegionMap = field;
|
||||||
|
fieldRegionMap.setAccessible(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Field field : classRegionFile.getDeclaredFields()) {
|
||||||
|
if (RandomAccessFile.class.isAssignableFrom(field.getType())) {
|
||||||
|
fieldRegionFile = field;
|
||||||
|
fieldRegionFile.setAccessible(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Class<?> classCraftWorld = ReflectionUtils.getCbClass("CraftWorld");
|
||||||
|
methodUnloadChunk = classCraftWorld.getDeclaredMethod("unloadChunk0", int.class, int.class, boolean.class);
|
||||||
|
methodUnloadChunk.setAccessible(true);
|
||||||
|
} catch (Throwable ignore) {
|
||||||
|
ignore.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -7,6 +7,7 @@ import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
|||||||
import com.boydti.fawe.example.CharFaweChunk;
|
import com.boydti.fawe.example.CharFaweChunk;
|
||||||
import com.boydti.fawe.object.FaweChunk;
|
import com.boydti.fawe.object.FaweChunk;
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.object.brush.visualization.VisualChunk;
|
import com.boydti.fawe.object.brush.visualization.VisualChunk;
|
||||||
import com.boydti.fawe.object.number.LongAdder;
|
import com.boydti.fawe.object.number.LongAdder;
|
||||||
@ -26,9 +27,11 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -57,6 +60,8 @@ import net.minecraft.server.v1_11_R1.PacketPlayOutMapChunk;
|
|||||||
import net.minecraft.server.v1_11_R1.PacketPlayOutMultiBlockChange;
|
import net.minecraft.server.v1_11_R1.PacketPlayOutMultiBlockChange;
|
||||||
import net.minecraft.server.v1_11_R1.PlayerChunk;
|
import net.minecraft.server.v1_11_R1.PlayerChunk;
|
||||||
import net.minecraft.server.v1_11_R1.PlayerChunkMap;
|
import net.minecraft.server.v1_11_R1.PlayerChunkMap;
|
||||||
|
import net.minecraft.server.v1_11_R1.RegionFile;
|
||||||
|
import net.minecraft.server.v1_11_R1.RegionFileCache;
|
||||||
import net.minecraft.server.v1_11_R1.ServerNBTManager;
|
import net.minecraft.server.v1_11_R1.ServerNBTManager;
|
||||||
import net.minecraft.server.v1_11_R1.TileEntity;
|
import net.minecraft.server.v1_11_R1.TileEntity;
|
||||||
import net.minecraft.server.v1_11_R1.WorldChunkManager;
|
import net.minecraft.server.v1_11_R1.WorldChunkManager;
|
||||||
@ -241,6 +246,72 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
|||||||
return super.regenerateChunk(world, x, z, biome, seed);
|
return super.regenerateChunk(world, x, z, biome, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setMCA(Runnable whileLocked, final RegionWrapper allowed, boolean unload) {
|
||||||
|
try {
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
|
@Override
|
||||||
|
public void run(Object value) {
|
||||||
|
try {
|
||||||
|
synchronized (RegionFileCache.class) {
|
||||||
|
ArrayDeque<net.minecraft.server.v1_11_R1.Chunk> chunks = new ArrayDeque<>();
|
||||||
|
World world = getWorld();
|
||||||
|
world.setKeepSpawnInMemory(false);
|
||||||
|
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
|
if (unload) { // Unload chunks
|
||||||
|
int bcx = (allowed.minX >> 9) << 5;
|
||||||
|
int bcz = (allowed.minZ >> 9) << 5;
|
||||||
|
int tcx = 31 + (allowed.maxX >> 9) << 5;
|
||||||
|
int tcz = 31 + (allowed.maxZ >> 9) << 5;
|
||||||
|
Iterator<net.minecraft.server.v1_11_R1.Chunk> iter = provider.a().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
net.minecraft.server.v1_11_R1.Chunk chunk = iter.next();
|
||||||
|
int cx = chunk.locX;
|
||||||
|
int cz = chunk.locZ;
|
||||||
|
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
||||||
|
chunks.add(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (net.minecraft.server.v1_11_R1.Chunk chunk : chunks) {
|
||||||
|
provider.unloadChunk(chunk, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
provider.c();
|
||||||
|
|
||||||
|
if (unload) { // Unload regions
|
||||||
|
Map<File, RegionFile> map = RegionFileCache.a;
|
||||||
|
Iterator<Map.Entry<File, RegionFile>> iter = map.entrySet().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Map.Entry<File, RegionFile> entry = iter.next();
|
||||||
|
RegionFile regionFile = entry.getValue();
|
||||||
|
regionFile.c();
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
whileLocked.run();
|
||||||
|
// Load the chunks again
|
||||||
|
if (unload) {
|
||||||
|
for (net.minecraft.server.v1_11_R1.Chunk chunk : chunks) {
|
||||||
|
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
||||||
|
if (chunk != null) {
|
||||||
|
sendChunk(chunk, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setHeightMap(FaweChunk chunk, byte[] heightMap) {
|
public void setHeightMap(FaweChunk chunk, byte[] heightMap) {
|
||||||
CraftChunk craftChunk = (CraftChunk) chunk.getChunk();
|
CraftChunk craftChunk = (CraftChunk) chunk.getChunk();
|
||||||
|
@ -63,6 +63,7 @@ import com.sk89q.worldedit.extension.platform.CommandManager;
|
|||||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||||
import com.sk89q.worldedit.extension.platform.PlayerProxy;
|
import com.sk89q.worldedit.extension.platform.PlayerProxy;
|
||||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||||
|
import com.sk89q.worldedit.extent.MaskingExtent;
|
||||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.SchematicReader;
|
import com.sk89q.worldedit.extent.clipboard.io.SchematicReader;
|
||||||
@ -440,6 +441,7 @@ public class Fawe {
|
|||||||
// Regions
|
// Regions
|
||||||
CuboidRegion.inject(); // Optimizations
|
CuboidRegion.inject(); // Optimizations
|
||||||
// Extents
|
// Extents
|
||||||
|
MaskingExtent.inject(); // Features
|
||||||
BlockTransformExtent.inject(); // Fix for cache not being mutable
|
BlockTransformExtent.inject(); // Fix for cache not being mutable
|
||||||
AbstractDelegateExtent.inject(); // Optimizations
|
AbstractDelegateExtent.inject(); // Optimizations
|
||||||
BlockBagExtent.inject(); // Fixes + Optimizations
|
BlockBagExtent.inject(); // Fixes + Optimizations
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
package com.boydti.fawe.command;
|
package com.boydti.fawe.command;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
import com.boydti.fawe.FaweCache;
|
import com.boydti.fawe.FaweCache;
|
||||||
import com.boydti.fawe.config.BBC;
|
import com.boydti.fawe.config.BBC;
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAFilter;
|
import com.boydti.fawe.jnbt.anvil.MCAFilter;
|
||||||
|
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.object.FaweQueue;
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.object.mask.FaweBlockMatcher;
|
import com.boydti.fawe.object.mask.FaweBlockMatcher;
|
||||||
import com.boydti.fawe.object.number.LongAdder;
|
import com.boydti.fawe.object.number.MutableLong;
|
||||||
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;
|
||||||
@ -17,13 +20,19 @@ import com.sk89q.worldedit.MutableBlockVector;
|
|||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.blocks.BlockType;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.function.pattern.RandomPattern;
|
import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||||
|
import com.sk89q.worldedit.internal.annotation.Selection;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.util.command.binding.Switch;
|
import com.sk89q.worldedit.util.command.binding.Switch;
|
||||||
import com.sk89q.worldedit.util.command.parametric.Optional;
|
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -45,7 +54,7 @@ public class AnvilCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
aliases = {"/replaceall", "/rea", "/repall"},
|
aliases = {"replaceall", "rea", "repall"},
|
||||||
usage = "<folder> [from-block] <to-block>",
|
usage = "<folder> [from-block] <to-block>",
|
||||||
desc = "Replace all blocks in the selection with another",
|
desc = "Replace all blocks in the selection with another",
|
||||||
flags = "d",
|
flags = "d",
|
||||||
@ -66,13 +75,13 @@ public class AnvilCommands {
|
|||||||
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
|
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
|
||||||
File root = new File(folder + File.separator + "region");
|
File root = new File(folder + File.separator + "region");
|
||||||
MCAQueue queue = new MCAQueue(folder, root, true);
|
MCAQueue queue = new MCAQueue(folder, root, true);
|
||||||
queue.filterWorld(new MCAFilter() {
|
MCAFilterCounter counter = queue.filterWorld(new MCAFilterCounter() {
|
||||||
@Override
|
@Override
|
||||||
public void applyBlock(int x, int y, int z, BaseBlock block) {
|
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong ignore) {
|
||||||
if (matchFrom.apply(block)) matchTo.apply(block);
|
if (matchFrom.apply(block)) matchTo.apply(block);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(-1));
|
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(counter.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
@ -87,6 +96,7 @@ public class AnvilCommands {
|
|||||||
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) throws WorldEditException {
|
||||||
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());
|
||||||
|
MCAFilterCounter counter;
|
||||||
if (useMap) {
|
if (useMap) {
|
||||||
List<String> split = StringMan.split(from, ',');
|
List<String> split = StringMan.split(from, ',');
|
||||||
if (to instanceof RandomPattern) {
|
if (to instanceof RandomPattern) {
|
||||||
@ -116,10 +126,11 @@ public class AnvilCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queue.filterWorld(new MCAFilter() {
|
|
||||||
|
counter = queue.filterWorld(new MCAFilterCounter() {
|
||||||
private final MutableBlockVector mutable = new MutableBlockVector(0, 0, 0);
|
private final MutableBlockVector mutable = new MutableBlockVector(0, 0, 0);
|
||||||
@Override
|
@Override
|
||||||
public void applyBlock(int x, int y, int z, BaseBlock block) {
|
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong ignore) {
|
||||||
int id = block.getId();
|
int id = block.getId();
|
||||||
int data = FaweCache.hasData(id) ? block.getData() : 0;
|
int data = FaweCache.hasData(id) ? block.getData() : 0;
|
||||||
int combined = FaweCache.getCombined(id, data);
|
int combined = FaweCache.getCombined(id, data);
|
||||||
@ -137,9 +148,11 @@ public class AnvilCommands {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
player.print(BBC.getPrefix() + "Mask:Pattern must be a 1:1 match");
|
player.print(BBC.getPrefix() + "Mask:Pattern must be a 1:1 match");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
player.print(BBC.getPrefix() + "Must be a pattern list!");
|
player.print(BBC.getPrefix() + "Must be a pattern list!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
final FaweBlockMatcher matchFrom;
|
final FaweBlockMatcher matchFrom;
|
||||||
@ -151,9 +164,9 @@ public class AnvilCommands {
|
|||||||
}
|
}
|
||||||
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData);
|
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData);
|
||||||
}
|
}
|
||||||
queue.filterWorld(new MCAFilter() {
|
counter = queue.filterWorld(new MCAFilterCounter() {
|
||||||
@Override
|
@Override
|
||||||
public void applyBlock(int x, int y, int z, BaseBlock block) {
|
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong ignore) {
|
||||||
if (matchFrom.apply(block)) {
|
if (matchFrom.apply(block)) {
|
||||||
BaseBlock newBlock = to.apply(x, y, z);
|
BaseBlock newBlock = to.apply(x, y, z);
|
||||||
int currentId = block.getId();
|
int currentId = block.getId();
|
||||||
@ -166,11 +179,11 @@ public class AnvilCommands {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(-1));
|
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(counter.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
aliases = {"/countall"},
|
aliases = {"countall"},
|
||||||
usage = "<folder> [hasSky] <id>",
|
usage = "<folder> [hasSky] <id>",
|
||||||
desc = "Count all blocks in a world",
|
desc = "Count all blocks in a world",
|
||||||
flags = "d",
|
flags = "d",
|
||||||
@ -181,7 +194,6 @@ public class AnvilCommands {
|
|||||||
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) throws WorldEditException {
|
||||||
File root = new File(folder + File.separator + "region");
|
File root = new File(folder + File.separator + "region");
|
||||||
MCAQueue queue = new MCAQueue(folder, root, true);
|
MCAQueue queue = new MCAQueue(folder, root, true);
|
||||||
final LongAdder count = new LongAdder();
|
|
||||||
if (arg.contains(":")) {
|
if (arg.contains(":")) {
|
||||||
useData = true; //override d flag, if they specified data they want it
|
useData = true; //override d flag, if they specified data they want it
|
||||||
}
|
}
|
||||||
@ -190,15 +202,15 @@ public class AnvilCommands {
|
|||||||
for (BaseBlock block : searchBlocks) {
|
for (BaseBlock block : searchBlocks) {
|
||||||
allowedId[block.getId()] = true;
|
allowedId[block.getId()] = true;
|
||||||
}
|
}
|
||||||
MCAFilter filter;
|
MCAFilterCounter filter;
|
||||||
if (useData) { // Optimize for both cases
|
if (useData) { // Optimize for both cases
|
||||||
final boolean[] allowed = new boolean[Character.MAX_VALUE];
|
final boolean[] allowed = new boolean[Character.MAX_VALUE];
|
||||||
for (BaseBlock block : searchBlocks) {
|
for (BaseBlock block : searchBlocks) {
|
||||||
allowed[FaweCache.getCombined(block)] = true;
|
allowed[FaweCache.getCombined(block)] = true;
|
||||||
}
|
}
|
||||||
filter = new MCAFilter() {
|
filter = new MCAFilterCounter() {
|
||||||
@Override
|
@Override
|
||||||
public MCAChunk applyChunk(MCAChunk chunk) {
|
public MCAChunk applyChunk(MCAChunk chunk, MutableLong count) {
|
||||||
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
||||||
byte[] ids = chunk.ids[layer];
|
byte[] ids = chunk.ids[layer];
|
||||||
if (ids == null) {
|
if (ids == null) {
|
||||||
@ -215,7 +227,7 @@ public class AnvilCommands {
|
|||||||
combined += chunk.getNibble(i, datas);
|
combined += chunk.getNibble(i, datas);
|
||||||
}
|
}
|
||||||
if (allowed[combined]) {
|
if (allowed[combined]) {
|
||||||
count.add(1);
|
count.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -223,15 +235,15 @@ public class AnvilCommands {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
filter = new MCAFilter() {
|
filter = new MCAFilterCounter() {
|
||||||
@Override
|
@Override
|
||||||
public MCAChunk applyChunk(MCAChunk chunk) {
|
public MCAChunk applyChunk(MCAChunk chunk, MutableLong count) {
|
||||||
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
||||||
byte[] ids = chunk.ids[layer];
|
byte[] ids = chunk.ids[layer];
|
||||||
if (ids != null) {
|
if (ids != null) {
|
||||||
for (byte i : ids) {
|
for (byte i : ids) {
|
||||||
if (allowedId[i & 0xFF]) {
|
if (allowedId[i & 0xFF]) {
|
||||||
count.add(1);
|
count.increment();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,7 +253,202 @@ public class AnvilCommands {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
queue.filterWorld(filter);
|
queue.filterWorld(filter);
|
||||||
player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(count.longValue()));
|
player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(filter.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = {"distr"},
|
||||||
|
desc = "Replace all blocks in the selection with another"
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.anvil.distr")
|
||||||
|
public void distr(Player player, EditSession editSession, @Selection Region selection, @Switch('d') boolean useData) throws WorldEditException {
|
||||||
|
long total = 0;
|
||||||
|
long[] count;
|
||||||
|
MCAFilter<long[]> counts;
|
||||||
|
if (useData) {
|
||||||
|
counts = runWithSelection(player, editSession, selection, new MCAFilter<long[]>() {
|
||||||
|
@Override
|
||||||
|
public void applyBlock(int x, int y, int z, BaseBlock block, long[] counts) {
|
||||||
|
counts[block.getCombined()]++;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public long[] init() {
|
||||||
|
return new long[Character.MAX_VALUE + 1];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count = new long[Character.MAX_VALUE + 1];
|
||||||
|
} else {
|
||||||
|
counts = runWithSelection(player, editSession, selection, new MCAFilter<long[]>() {
|
||||||
|
@Override
|
||||||
|
public void applyBlock(int x, int y, int z, BaseBlock block, long[] counts) {
|
||||||
|
counts[block.getId()]++;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public long[] init() {
|
||||||
|
return new long[4096];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
count = new long[4096];
|
||||||
|
}
|
||||||
|
for (long[] value : counts) {
|
||||||
|
for (int i = 0; i < value.length; i++) {
|
||||||
|
count[i] += value[i];
|
||||||
|
total += value[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ArrayList<long[]> map = new ArrayList<>();
|
||||||
|
for (int i = 0; i < count.length; i++) {
|
||||||
|
if (count[i] != 0) map.add(new long[] { i, count[i]});
|
||||||
|
}
|
||||||
|
Collections.sort(map, new Comparator<long[]>() {
|
||||||
|
@Override
|
||||||
|
public int compare(long[] a, long[] b) {
|
||||||
|
long vA = a[1];
|
||||||
|
long vB = b[1];
|
||||||
|
return (vA < vB) ? -1 : ((vA == vB) ? 0 : 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (useData) {
|
||||||
|
for (long[] c : map) {
|
||||||
|
BaseBlock block = FaweCache.CACHE_BLOCK[(int) c[0]];
|
||||||
|
String name = BlockType.fromID(block.getId()).getName();
|
||||||
|
String str = String.format("%-7s (%.3f%%) %s #%d:%d",
|
||||||
|
String.valueOf(c[1]),
|
||||||
|
((c[1] * 10000) / total) / 100d,
|
||||||
|
name == null ? "Unknown" : name,
|
||||||
|
block.getType(), block.getData());
|
||||||
|
player.print(BBC.getPrefix() + str);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (long[] c : map) {
|
||||||
|
BlockType block = BlockType.fromID((int) c[0]);
|
||||||
|
String str = String.format("%-7s (%.3f%%) %s #%d",
|
||||||
|
String.valueOf(c[1]),
|
||||||
|
((c[1] * 10000) / total) / 100d,
|
||||||
|
block == null ? "Unknown" : block.getName(), c[0]);
|
||||||
|
player.print(BBC.getPrefix() + str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <G, T extends MCAFilter<G>> T runWithSelection(Player player, EditSession editSession, Region selection, T filter) {
|
||||||
|
if (!(selection instanceof CuboidRegion)) {
|
||||||
|
BBC.NO_REGION.send(player);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
CuboidRegion cuboid = (CuboidRegion) selection;
|
||||||
|
RegionWrapper wrappedRegion = new RegionWrapper(cuboid.getMinimumPoint(), cuboid.getMaximumPoint());
|
||||||
|
String worldName = Fawe.imp().getWorldName(editSession.getWorld());
|
||||||
|
FaweQueue tmp = SetQueue.IMP.getNewQueue(worldName, true, false);
|
||||||
|
File folder = tmp.getSaveFolder();
|
||||||
|
MCAQueue queue = new MCAQueue(worldName, folder, tmp.hasSky());
|
||||||
|
player.print(BBC.getPrefix() + "Safely unloading regions...");
|
||||||
|
tmp.setMCA(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
player.print(BBC.getPrefix() + "Performing operation...");
|
||||||
|
queue.filterRegion(filter, wrappedRegion);
|
||||||
|
player.print(BBC.getPrefix() + "Safely loading regions...");
|
||||||
|
}
|
||||||
|
}, wrappedRegion, true);
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = {"replace"},
|
||||||
|
usage = "[from-block] <to-block>",
|
||||||
|
desc = "Replace all blocks in the selection with another"
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.anvil.replace")
|
||||||
|
public void replace(Player player, EditSession editSession, @Selection Region selection, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException {
|
||||||
|
final FaweBlockMatcher matchFrom;
|
||||||
|
if (from == null) {
|
||||||
|
matchFrom = FaweBlockMatcher.NOT_AIR;
|
||||||
|
} else {
|
||||||
|
if (from.contains(":")) {
|
||||||
|
useData = true; //override d flag, if they specified data they want it
|
||||||
|
}
|
||||||
|
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData);
|
||||||
|
}
|
||||||
|
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
|
||||||
|
MCAFilterCounter filter = runWithSelection(player, editSession, selection, new MCAFilterCounter() {
|
||||||
|
@Override
|
||||||
|
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong count) {
|
||||||
|
if (matchFrom.apply(block)) {
|
||||||
|
matchTo.apply(block);
|
||||||
|
count.increment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (filter != null) {
|
||||||
|
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(filter.getTotal()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// @Command(
|
||||||
|
// aliases = {"copychunks"},
|
||||||
|
// desc = "Lazily copy chunks to your anvil clipboard"
|
||||||
|
// )
|
||||||
|
// @CommandPermissions("worldedit.anvil.copychunks")
|
||||||
|
// public void copy(Player player, LocalSession session, EditSession editSession, @Selection Region selection) throws WorldEditException {
|
||||||
|
// if (!(selection instanceof CuboidRegion)) {
|
||||||
|
// BBC.NO_REGION.send(player);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// CuboidRegion cuboid = (CuboidRegion) selection;
|
||||||
|
// String worldName = Fawe.imp().getWorldName(editSession.getWorld());
|
||||||
|
// FaweQueue tmp = SetQueue.IMP.getNewQueue(worldName, true, false);
|
||||||
|
// File folder = tmp.getSaveFolder();
|
||||||
|
// MCAQueue queue = new MCAQueue(worldName, folder, tmp.hasSky());
|
||||||
|
// Vector origin = session.getPlacementPosition(player);
|
||||||
|
// MCAClipboard clipboard = new MCAClipboard(queue, cuboid, origin);
|
||||||
|
// FawePlayer fp = FawePlayer.wrap(player);
|
||||||
|
// fp.setMeta(FawePlayer.METADATA_KEYS.ANVIL_CLIPBOARD, clipboard);
|
||||||
|
// BBC.COMMAND_COPY.send(player, selection.getArea());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Command(
|
||||||
|
// aliases = {"pastechunks"},
|
||||||
|
// desc = "Paste chunks from your anvil clipboard"
|
||||||
|
// )
|
||||||
|
// @CommandPermissions("worldedit.anvil.pastechunks")
|
||||||
|
// public void paste(Player player, LocalSession session, EditSession editSession) throws WorldEditException {
|
||||||
|
// FawePlayer fp = FawePlayer.wrap(player);
|
||||||
|
// MCAClipboard clipboard = fp.getMeta(FawePlayer.METADATA_KEYS.ANVIL_CLIPBOARD);
|
||||||
|
// if (clipboard == null) {
|
||||||
|
// fp.sendMessage(BBC.getPrefix() + "You must first copy to your clipboard");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// CuboidRegion cuboid = clipboard.getRegion();
|
||||||
|
// RegionWrapper copyRegion = new RegionWrapper(cuboid.getMinimumPoint(), cuboid.getMaximumPoint());
|
||||||
|
// Vector offset = player.getPosition().subtract(clipboard.getOrigin());
|
||||||
|
// int oX = offset.getBlockX();
|
||||||
|
// int oZ = offset.getBlockZ();
|
||||||
|
// RegionWrapper pasteRegion = new RegionWrapper(copyRegion.minX + oX, copyRegion.maxX + oX, copyRegion.minZ + oZ, copyRegion.maxZ + oZ);
|
||||||
|
// String pasteWorldName = Fawe.imp().getWorldName(editSession.getWorld());
|
||||||
|
// FaweQueue tmpTo = SetQueue.IMP.getNewQueue(pasteWorldName, true, false);
|
||||||
|
// FaweQueue tmpFrom = SetQueue.IMP.getNewQueue(clipboard.getQueue().getWorldName(), true, false);
|
||||||
|
// File folder = tmpTo.getSaveFolder();
|
||||||
|
// MCAQueue copyQueue = clipboard.getQueue();
|
||||||
|
// MCAQueue pasteQueue = new MCAQueue(pasteWorldName, folder, tmpTo.hasSky());
|
||||||
|
// player.print(BBC.getPrefix() + "Safely unloading regions...");
|
||||||
|
// tmpTo.setMCA(new Runnable() {
|
||||||
|
// @Override
|
||||||
|
// public void run() {
|
||||||
|
// tmpFrom.setMCA(new Runnable() {
|
||||||
|
// @Override
|
||||||
|
// public void run() {
|
||||||
|
// try {
|
||||||
|
// player.print(BBC.getPrefix() + "Performing operation...");
|
||||||
|
// pasteQueue.pasteRegion(copyQueue, copyRegion, offset);
|
||||||
|
// player.print(BBC.getPrefix() + "Safely loading regions...");
|
||||||
|
// } catch (Throwable e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }, copyRegion, false);
|
||||||
|
// }
|
||||||
|
// }, pasteRegion, true);
|
||||||
|
// player.print("Done!");
|
||||||
|
// }
|
||||||
}
|
}
|
@ -62,7 +62,7 @@ public class Rollback extends FaweCommand {
|
|||||||
BBC.COMMAND_SYNTAX.send(player, "/frb <info|undo> u:<uuid> r:<radius> t:<time>");
|
BBC.COMMAND_SYNTAX.send(player, "/frb <info|undo> u:<uuid> r:<radius> t:<time>");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
player.deleteMeta("rollback");
|
player.deleteMeta(FawePlayer.METADATA_KEYS.ROLLBACK);
|
||||||
final FaweLocation origin = player.getLocation();
|
final FaweLocation origin = player.getLocation();
|
||||||
rollback(player, !player.hasPermission("fawe.rollback.deep"), Arrays.copyOfRange(args, 1, args.length), new RunnableVal<List<DiskStorageHistory>>() {
|
rollback(player, !player.hasPermission("fawe.rollback.deep"), Arrays.copyOfRange(args, 1, args.length), new RunnableVal<List<DiskStorageHistory>>() {
|
||||||
@Override
|
@Override
|
||||||
@ -91,7 +91,7 @@ public class Rollback extends FaweCommand {
|
|||||||
player.sendMessage("&dSize: " + (((double) (total / 1024)) / 1000) + "MB");
|
player.sendMessage("&dSize: " + (((double) (total / 1024)) / 1000) + "MB");
|
||||||
player.sendMessage("&dTo rollback: /frb undo");
|
player.sendMessage("&dTo rollback: /frb undo");
|
||||||
player.sendMessage("&d==================================================");
|
player.sendMessage("&d==================================================");
|
||||||
player.setMeta("rollback", edits);
|
player.setMeta(FawePlayer.METADATA_KEYS.ROLLBACK, edits);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@ -102,8 +102,8 @@ public class Rollback extends FaweCommand {
|
|||||||
BBC.NO_PERM.send(player, "fawe.rollback.perform");
|
BBC.NO_PERM.send(player, "fawe.rollback.perform");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final List<DiskStorageHistory> edits = (List<DiskStorageHistory>) player.getMeta("rollback");
|
final List<DiskStorageHistory> edits = (List<DiskStorageHistory>) player.getMeta(FawePlayer.METADATA_KEYS.ROLLBACK);
|
||||||
player.deleteMeta("rollback");
|
player.deleteMeta(FawePlayer.METADATA_KEYS.ROLLBACK);
|
||||||
if (edits == null) {
|
if (edits == null) {
|
||||||
BBC.COMMAND_SYNTAX.send(player, "/frb info u:<uuid> r:<radius> t:<time>");
|
BBC.COMMAND_SYNTAX.send(player, "/frb info u:<uuid> r:<radius> t:<time>");
|
||||||
return false;
|
return false;
|
||||||
|
@ -259,6 +259,11 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, CHUNKSECTIONS, SECTION> exte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
lastSectionX = Integer.MIN_VALUE;
|
||||||
|
lastSectionZ = Integer.MIN_VALUE;
|
||||||
|
lastSectionY = -1;
|
||||||
|
lastChunk = null;
|
||||||
|
lastChunkSections = null;
|
||||||
map.clear();
|
map.clear();
|
||||||
runTasks();
|
runTasks();
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -50,8 +51,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
private long lastUpdate;
|
private long lastUpdate;
|
||||||
private int[] heightMap;
|
private int[] heightMap;
|
||||||
|
|
||||||
public int compressedSize;
|
private int modified;
|
||||||
private boolean modified;
|
|
||||||
private boolean deleted;
|
private boolean deleted;
|
||||||
|
|
||||||
public byte[] toBytes(byte[] buffer) throws IOException {
|
public byte[] toBytes(byte[] buffer) throws IOException {
|
||||||
@ -113,6 +113,91 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
return buffered.toByteArray();
|
return buffered.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void copyFrom(MCAChunk other, int minY, int maxY) {
|
||||||
|
for (int layer = 0; layer < ids.length; layer++) {
|
||||||
|
byte[] otherIds = other.ids[layer];
|
||||||
|
byte[] currentIds = ids[layer];
|
||||||
|
int by = layer << 4;
|
||||||
|
int ty = layer >> 4;
|
||||||
|
if (by >= minY && ty <= maxY) {
|
||||||
|
if (otherIds != null) {
|
||||||
|
ids[layer] = otherIds;
|
||||||
|
data[layer] = other.data[layer];
|
||||||
|
skyLight[layer] = other.skyLight[layer];
|
||||||
|
blockLight[layer] = other.blockLight[layer];
|
||||||
|
} else {
|
||||||
|
ids[layer] = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
by = Math.max(by, minY) & 15;
|
||||||
|
ty = Math.min(ty, maxY) & 15;
|
||||||
|
int indexStart = by << 8;
|
||||||
|
int indexEnd = 255 + (ty << 8);
|
||||||
|
int indexStartShift = indexStart >> 1;
|
||||||
|
int indexEndShift = indexEnd >> 1;
|
||||||
|
if (otherIds == null) {
|
||||||
|
if (currentIds != null) {
|
||||||
|
Arrays.fill(currentIds, indexStart, indexEnd, (byte) 0);
|
||||||
|
Arrays.fill(data[layer], indexStartShift, indexEndShift, (byte) 0);
|
||||||
|
Arrays.fill(skyLight[layer], indexStartShift, indexEndShift, (byte) 0);
|
||||||
|
Arrays.fill(blockLight[layer], indexStartShift, indexEndShift, (byte) 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (currentIds == null) {
|
||||||
|
currentIds = this.ids[layer] = new byte[4096];
|
||||||
|
this.data[layer] = new byte[2048];
|
||||||
|
this.skyLight[layer] = new byte[2048];
|
||||||
|
this.blockLight[layer] = new byte[2048];
|
||||||
|
}
|
||||||
|
System.arraycopy(other.ids[layer], indexStart, ids[layer], indexStart, indexEnd - indexStart);
|
||||||
|
System.arraycopy(other.data[layer], indexStartShift, data[layer], indexStartShift, indexEndShift - indexStartShift);
|
||||||
|
System.arraycopy(other.skyLight[layer], indexStartShift, skyLight[layer], indexStartShift, indexEndShift - indexStartShift);
|
||||||
|
System.arraycopy(other.blockLight[layer], indexStartShift, blockLight[layer], indexStartShift, indexEndShift - indexStartShift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Copy nbt
|
||||||
|
if (!tiles.isEmpty()) {
|
||||||
|
Iterator<Map.Entry<Short, CompoundTag>> iter = tiles.entrySet().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
int y = MathMan.untripleBlockCoordY(iter.next().getKey());
|
||||||
|
if (y >= minY && y <= maxY) iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!other.tiles.isEmpty()) {
|
||||||
|
for (Map.Entry<Short, CompoundTag> entry : other.tiles.entrySet()) {
|
||||||
|
short key = entry.getKey();
|
||||||
|
int y = MathMan.untripleBlockCoordY(key);
|
||||||
|
if (y >= minY && y <= maxY) {
|
||||||
|
tiles.put(key, entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!other.entities.isEmpty()) {
|
||||||
|
for (Map.Entry<UUID, CompoundTag> entry : other.entities.entrySet()) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinLayer() {
|
||||||
|
for (int layer = 0; layer < ids.length; layer++) {
|
||||||
|
if (ids[layer] != null) {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxLayer() {
|
||||||
|
for (int layer = ids.length - 1; layer >= 0; layer--) {
|
||||||
|
if (ids[layer] != null) {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
public CompoundTag toTag() {
|
public CompoundTag toTag() {
|
||||||
if (deleted) {
|
if (deleted) {
|
||||||
return null;
|
return null;
|
||||||
@ -164,7 +249,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
this.entities = new HashMap<>();
|
this.entities = new HashMap<>();
|
||||||
this.lastUpdate = System.currentTimeMillis();
|
this.lastUpdate = System.currentTimeMillis();
|
||||||
this.heightMap = new int[256];
|
this.heightMap = new int[256];
|
||||||
this.modified = true;
|
this.setModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MCAChunk(MCAChunk parent, boolean shallow) {
|
public MCAChunk(MCAChunk parent, boolean shallow) {
|
||||||
@ -180,7 +265,6 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
this.inhabitedTime = parent.inhabitedTime;
|
this.inhabitedTime = parent.inhabitedTime;
|
||||||
this.lastUpdate = parent.lastUpdate;
|
this.lastUpdate = parent.lastUpdate;
|
||||||
this.heightMap = parent.heightMap;
|
this.heightMap = parent.heightMap;
|
||||||
this.compressedSize = parent.compressedSize;
|
|
||||||
this.modified = parent.modified;
|
this.modified = parent.modified;
|
||||||
this.deleted = parent.deleted;
|
this.deleted = parent.deleted;
|
||||||
} else {
|
} else {
|
||||||
@ -194,7 +278,6 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
this.inhabitedTime = parent.inhabitedTime;
|
this.inhabitedTime = parent.inhabitedTime;
|
||||||
this.lastUpdate = parent.lastUpdate;
|
this.lastUpdate = parent.lastUpdate;
|
||||||
this.heightMap = parent.heightMap.clone();
|
this.heightMap = parent.heightMap.clone();
|
||||||
this.compressedSize = parent.compressedSize;
|
|
||||||
this.modified = parent.modified;
|
this.modified = parent.modified;
|
||||||
this.deleted = parent.deleted;
|
this.deleted = parent.deleted;
|
||||||
}
|
}
|
||||||
@ -206,7 +289,6 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
data = new byte[16][];
|
data = new byte[16][];
|
||||||
skyLight = new byte[16][];
|
skyLight = new byte[16][];
|
||||||
blockLight = new byte[16][];
|
blockLight = new byte[16][];
|
||||||
this.compressedSize = compressedSize;
|
|
||||||
NBTStreamer streamer = new NBTStreamer(nis);
|
NBTStreamer streamer = new NBTStreamer(nis);
|
||||||
streamer.addReader(".Level.InhabitedTime", new RunnableVal2<Integer, Long>() {
|
streamer.addReader(".Level.InhabitedTime", new RunnableVal2<Integer, Long>() {
|
||||||
@Override
|
@Override
|
||||||
@ -281,12 +363,16 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isModified() {
|
public boolean isModified() {
|
||||||
|
return modified != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getModified() {
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public final void setModified() {
|
public final void setModified() {
|
||||||
this.modified = true;
|
this.modified++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -302,7 +388,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTile(int x, int y, int z, CompoundTag tile) {
|
public void setTile(int x, int y, int z, CompoundTag tile) {
|
||||||
modified = true;
|
setModified();
|
||||||
short pair = MathMan.tripleBlockCoord(x, y, z);
|
short pair = MathMan.tripleBlockCoord(x, y, z);
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
tiles.put(pair, tile);
|
tiles.put(pair, tile);
|
||||||
@ -313,7 +399,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEntity(CompoundTag entityTag) {
|
public void setEntity(CompoundTag entityTag) {
|
||||||
modified = true;
|
setModified();
|
||||||
long least = entityTag.getLong("UUIDLeast");
|
long least = entityTag.getLong("UUIDLeast");
|
||||||
long most = entityTag.getLong("UUIDMost");
|
long most = entityTag.getLong("UUIDMost");
|
||||||
entities.put(new UUID(most, least), entityTag);
|
entities.put(new UUID(most, least), entityTag);
|
||||||
@ -321,7 +407,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBiome(int x, int z, byte biome) {
|
public void setBiome(int x, int z, byte biome) {
|
||||||
modified = true;
|
setModified();
|
||||||
biomes[x + (z << 4)] = biome;
|
biomes[x + (z << 4)] = biome;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,7 +468,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setSkyLight(int x, int y, int z, int value) {
|
public void setSkyLight(int x, int y, int z, int value) {
|
||||||
modified = true;
|
setModified();
|
||||||
int layer = y >> 4;
|
int layer = y >> 4;
|
||||||
byte[] skyLayer = skyLight[layer];
|
byte[] skyLayer = skyLight[layer];
|
||||||
if (skyLayer == null) {
|
if (skyLayer == null) {
|
||||||
@ -393,7 +479,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setBlockLight(int x, int y, int z, int value) {
|
public void setBlockLight(int x, int y, int z, int value) {
|
||||||
modified = true;
|
setModified();
|
||||||
int layer = y >> 4;
|
int layer = y >> 4;
|
||||||
byte[] blockLayer = blockLight[layer];
|
byte[] blockLayer = blockLight[layer];
|
||||||
if (blockLayer == null) {
|
if (blockLayer == null) {
|
||||||
@ -424,7 +510,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setFullbright() {
|
public void setFullbright() {
|
||||||
modified = true;
|
setModified();
|
||||||
for (byte[] array : skyLight) {
|
for (byte[] array : skyLight) {
|
||||||
if (array != null) {
|
if (array != null) {
|
||||||
Arrays.fill(array, (byte) 255);
|
Arrays.fill(array, (byte) 255);
|
||||||
@ -478,7 +564,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBlock(int x, int y, int z, int id, int data) {
|
public void setBlock(int x, int y, int z, int id, int data) {
|
||||||
modified = true;
|
setModified();
|
||||||
int layer = y >> 4;
|
int layer = y >> 4;
|
||||||
byte[] idsLayer = ids[layer];
|
byte[] idsLayer = ids[layer];
|
||||||
if (idsLayer == null) {
|
if (idsLayer == null) {
|
||||||
@ -500,7 +586,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeEntity(UUID uuid) {
|
public void removeEntity(UUID uuid) {
|
||||||
modified = true;
|
setModified();
|
||||||
entities.remove(uuid);
|
entities.remove(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.boydti.fawe.jnbt.anvil;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
|
|
||||||
|
public class MCAClipboard {
|
||||||
|
private final MCAQueue queue;
|
||||||
|
private final CuboidRegion region;
|
||||||
|
private final Vector origin;
|
||||||
|
|
||||||
|
public MCAClipboard(MCAQueue queue, CuboidRegion region, Vector origin) {
|
||||||
|
this.queue = queue;
|
||||||
|
this.region = region;
|
||||||
|
this.origin = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MCAQueue getQueue() {
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CuboidRegion getRegion() {
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector getOrigin() {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
}
|
@ -8,13 +8,12 @@ import com.boydti.fawe.object.RunnableVal4;
|
|||||||
import com.boydti.fawe.object.exception.FaweException;
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
||||||
import com.boydti.fawe.object.io.FastByteArrayInputStream;
|
import com.boydti.fawe.object.io.FastByteArrayInputStream;
|
||||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.MathMan;
|
import com.boydti.fawe.util.MathMan;
|
||||||
import com.sk89q.jnbt.NBTInputStream;
|
import com.sk89q.jnbt.NBTInputStream;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
@ -25,7 +24,6 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.ForkJoinPool;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.zip.DeflaterOutputStream;
|
|
||||||
import java.util.zip.Inflater;
|
import java.util.zip.Inflater;
|
||||||
import java.util.zip.InflaterInputStream;
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
@ -37,30 +35,24 @@ public class MCAFile {
|
|||||||
|
|
||||||
private static Field fieldBuf2;
|
private static Field fieldBuf2;
|
||||||
private static Field fieldBuf3;
|
private static Field fieldBuf3;
|
||||||
private static Field fieldBuf4;
|
|
||||||
private static Field fieldBuf5;
|
|
||||||
private static Field fieldBuf6;
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
fieldBuf2 = InflaterInputStream.class.getDeclaredField("buf");
|
fieldBuf2 = InflaterInputStream.class.getDeclaredField("buf");
|
||||||
fieldBuf2.setAccessible(true);
|
fieldBuf2.setAccessible(true);
|
||||||
fieldBuf3 = NBTInputStream.class.getDeclaredField("buf");
|
fieldBuf3 = NBTInputStream.class.getDeclaredField("buf");
|
||||||
fieldBuf3.setAccessible(true);
|
fieldBuf3.setAccessible(true);
|
||||||
fieldBuf4 = FastByteArrayOutputStream.class.getDeclaredField("buffer");
|
|
||||||
fieldBuf4.setAccessible(true);
|
|
||||||
fieldBuf5 = DeflaterOutputStream.class.getDeclaredField("buf");
|
|
||||||
fieldBuf5.setAccessible(true);
|
|
||||||
fieldBuf6 = BufferedOutputStream.class.getDeclaredField("buf");
|
|
||||||
fieldBuf6.setAccessible(true);
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private FaweQueue queue;
|
private final FaweQueue queue;
|
||||||
private File file;
|
private final File file;
|
||||||
private RandomAccessFile raf;
|
private RandomAccessFile raf;
|
||||||
private byte[] locations;
|
private byte[] locations;
|
||||||
|
private boolean deleted;
|
||||||
|
private final int X, Z;
|
||||||
|
private final Int2ObjectOpenHashMap<MCAChunk> chunks = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
|
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
|
||||||
@Override
|
@Override
|
||||||
@ -81,10 +73,6 @@ public class MCAFile {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final int X, Z;
|
|
||||||
|
|
||||||
private Int2ObjectOpenHashMap<MCAChunk> chunks = new Int2ObjectOpenHashMap<>();
|
|
||||||
|
|
||||||
public MCAFile(FaweQueue parent, File file) {
|
public MCAFile(FaweQueue parent, File file) {
|
||||||
this.queue = parent;
|
this.queue = parent;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
@ -96,6 +84,26 @@ public class MCAFile {
|
|||||||
Z = Integer.parseInt(split[2]);
|
Z = Integer.parseInt(split[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
if (raf != null) {
|
||||||
|
try {
|
||||||
|
raf.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chunks.clear();
|
||||||
|
locations = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeleted(boolean deleted) {
|
||||||
|
this.deleted = deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDeleted() {
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
public FaweQueue getParent() {
|
public FaweQueue getParent() {
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
@ -105,9 +113,12 @@ public class MCAFile {
|
|||||||
if (raf == null) {
|
if (raf == null) {
|
||||||
this.locations = new byte[4096];
|
this.locations = new byte[4096];
|
||||||
this.raf = new RandomAccessFile(file, "rw");
|
this.raf = new RandomAccessFile(file, "rw");
|
||||||
raf.seek(0);
|
if (raf.length() < 8192) {
|
||||||
raf.readFully(locations);
|
raf.setLength(8192);
|
||||||
|
} else {
|
||||||
|
raf.seek(0);
|
||||||
|
raf.readFully(locations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -137,6 +148,13 @@ public class MCAFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setChunk(MCAChunk chunk) {
|
||||||
|
int cx = chunk.getX();
|
||||||
|
int cz = chunk.getZ();
|
||||||
|
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
|
||||||
|
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);
|
||||||
if (cached != null) {
|
if (cached != null) {
|
||||||
@ -348,6 +366,10 @@ public class MCAFile {
|
|||||||
|
|
||||||
private void writeHeader(RandomAccessFile raf, int cx, int cz, int offsetMedium, int sizeByte, boolean writeTime) throws IOException {
|
private void writeHeader(RandomAccessFile raf, int cx, int cz, int offsetMedium, int sizeByte, boolean writeTime) throws IOException {
|
||||||
int i = ((cx & 31) << 2) + ((cz & 31) << 7);
|
int i = ((cx & 31) << 2) + ((cz & 31) << 7);
|
||||||
|
locations[i] = (byte) (offsetMedium >> 16);
|
||||||
|
locations[i + 1] = (byte) (offsetMedium >> 8);
|
||||||
|
locations[i + 2] = (byte) (offsetMedium);
|
||||||
|
locations[i + 3] = (byte) sizeByte;
|
||||||
raf.seek(i);
|
raf.seek(i);
|
||||||
raf.write((offsetMedium >> 16));
|
raf.write((offsetMedium >> 16));
|
||||||
raf.write((offsetMedium >> 8));
|
raf.write((offsetMedium >> 8));
|
||||||
@ -370,11 +392,8 @@ public class MCAFile {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
file = null;
|
|
||||||
raf = null;
|
raf = null;
|
||||||
locations = null;
|
locations = null;
|
||||||
queue = null;
|
|
||||||
chunks = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,6 +408,7 @@ public class MCAFile {
|
|||||||
Int2ObjectOpenHashMap<byte[]> relocate = new Int2ObjectOpenHashMap<>();
|
Int2ObjectOpenHashMap<byte[]> relocate = new Int2ObjectOpenHashMap<>();
|
||||||
final Int2ObjectOpenHashMap<Integer> offsetMap = new Int2ObjectOpenHashMap<>(); // Offset -> <byte cx, byte cz, short size>
|
final Int2ObjectOpenHashMap<Integer> offsetMap = new Int2ObjectOpenHashMap<>(); // Offset -> <byte cx, byte cz, short size>
|
||||||
final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>();
|
final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
final Int2ObjectOpenHashMap<byte[]> append = new Int2ObjectOpenHashMap<>();
|
||||||
boolean modified = false;
|
boolean modified = false;
|
||||||
for (MCAChunk chunk : getCachedChunks()) {
|
for (MCAChunk chunk : getCachedChunks()) {
|
||||||
if (chunk.isModified()) {
|
if (chunk.isModified()) {
|
||||||
@ -400,8 +420,14 @@ public class MCAFile {
|
|||||||
try {
|
try {
|
||||||
byte[] compressed = toBytes(chunk);
|
byte[] compressed = toBytes(chunk);
|
||||||
int pair = MathMan.pair((short) (chunk.getX() & 31), (short) (chunk.getZ() & 31));
|
int pair = MathMan.pair((short) (chunk.getX() & 31), (short) (chunk.getZ() & 31));
|
||||||
synchronized (compressedMap) {
|
Int2ObjectOpenHashMap map;
|
||||||
compressedMap.put(pair, compressed);
|
if (getOffset(chunk.getX(), chunk.getZ()) == 0) {
|
||||||
|
map = append;
|
||||||
|
} else {
|
||||||
|
map = compressedMap;
|
||||||
|
}
|
||||||
|
synchronized (map) {
|
||||||
|
map.put(pair, compressed);
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -473,7 +499,8 @@ public class MCAFile {
|
|||||||
short nextCXZ = MathMan.unpairX(nextLoc);
|
short nextCXZ = MathMan.unpairX(nextLoc);
|
||||||
int nextCX = MathMan.unpairShortX(nextCXZ);
|
int nextCX = MathMan.unpairShortX(nextCXZ);
|
||||||
int nextCZ = MathMan.unpairShortY(nextCXZ);
|
int nextCZ = MathMan.unpairShortY(nextCXZ);
|
||||||
if (getCachedChunk(nextCX, nextCZ) == null) {
|
MCAChunk cached = getCachedChunk(nextCX, nextCZ);
|
||||||
|
if (cached == null || !cached.isModified()) {
|
||||||
byte[] nextBytes = getChunkCompressedBytes(nextOffset2);
|
byte[] nextBytes = getChunkCompressedBytes(nextOffset2);
|
||||||
relocate.put(MathMan.pair((short) (nextCX & 31), (short) (nextCZ & 31)), nextBytes);
|
relocate.put(MathMan.pair((short) (nextCX & 31), (short) (nextCZ & 31)), nextBytes);
|
||||||
}
|
}
|
||||||
@ -490,6 +517,22 @@ public class MCAFile {
|
|||||||
written = start + newBytes.length + 5;
|
written = start + newBytes.length + 5;
|
||||||
start += newSize << 12;
|
start += newSize << 12;
|
||||||
}
|
}
|
||||||
|
// TODO this doesn't work
|
||||||
|
if (!append.isEmpty()) {
|
||||||
|
for (Int2ObjectMap.Entry<byte[]> entry : append.int2ObjectEntrySet()) {
|
||||||
|
int pair = entry.getIntKey();
|
||||||
|
short cx = MathMan.unpairX(pair);
|
||||||
|
short cz = MathMan.unpairY(pair);
|
||||||
|
byte[] bytes = entry.getValue();
|
||||||
|
int len = bytes.length + 5;
|
||||||
|
int newSize = (len + 4095) >> 12;
|
||||||
|
writeSafe(raf, start, bytes);
|
||||||
|
writeHeader(raf, cx, cz, start >> 12, newSize, true);
|
||||||
|
written = start + bytes.length + 5;
|
||||||
|
start += newSize << 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
raf.setLength(4096 * ((written + 4095) / 4096));
|
raf.setLength(4096 * ((written + 4095) / 4096));
|
||||||
if (raf instanceof BufferedRandomAccessFile) {
|
if (raf instanceof BufferedRandomAccessFile) {
|
||||||
((BufferedRandomAccessFile) raf).flush();
|
((BufferedRandomAccessFile) raf).flush();
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
package com.boydti.fawe.jnbt.anvil;
|
package com.boydti.fawe.jnbt.anvil;
|
||||||
|
|
||||||
|
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MCAQueue.filterWorld(MCAFilter)<br>
|
* MCAQueue.filterWorld(MCAFilter)<br>
|
||||||
* - Read and modify the world
|
* - Read and modify the world
|
||||||
*/
|
*/
|
||||||
public class MCAFilter {
|
public class MCAFilter<T> extends IterableThreadLocal<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether a .mca file should be read
|
* Check whether a .mca file should be read
|
||||||
@ -46,7 +47,7 @@ public class MCAFilter {
|
|||||||
* @param chunk
|
* @param chunk
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public MCAChunk applyChunk(MCAChunk chunk) {
|
public MCAChunk applyChunk(MCAChunk chunk, T cache) {
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,5 +60,13 @@ public class MCAFilter {
|
|||||||
* @param z
|
* @param z
|
||||||
* @param block
|
* @param block
|
||||||
*/
|
*/
|
||||||
public void applyBlock(int x, int y, int z, BaseBlock block) {}
|
public void applyBlock(int x, int y, int z, BaseBlock block, T cache) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do something with the MCAChunk after block filtering<br>
|
||||||
|
* @param chunk
|
||||||
|
* @param cache
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public void finishChunk(MCAChunk chunk, T cache) {}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.boydti.fawe.jnbt.anvil;
|
||||||
|
|
||||||
|
import com.boydti.fawe.object.number.MutableLong;
|
||||||
|
|
||||||
|
public class MCAFilterCounter extends MCAFilter<MutableLong> {
|
||||||
|
@Override
|
||||||
|
public void finishChunk(MCAChunk chunk, MutableLong cache) {
|
||||||
|
cache.add(chunk.getModified());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MutableLong init() {
|
||||||
|
return new MutableLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotal() {
|
||||||
|
long total = 0;
|
||||||
|
for (MutableLong value : getAll()) {
|
||||||
|
total += value.get();
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
}
|
@ -2,13 +2,21 @@ package com.boydti.fawe.jnbt.anvil;
|
|||||||
|
|
||||||
import com.boydti.fawe.example.CharFaweChunk;
|
import com.boydti.fawe.example.CharFaweChunk;
|
||||||
import com.boydti.fawe.example.NMSMappedFaweQueue;
|
import com.boydti.fawe.example.NMSMappedFaweQueue;
|
||||||
|
import com.boydti.fawe.example.NullFaweChunk;
|
||||||
import com.boydti.fawe.object.FaweChunk;
|
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.RunnableVal2;
|
||||||
import com.boydti.fawe.object.RunnableVal4;
|
import com.boydti.fawe.object.RunnableVal4;
|
||||||
|
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.world.biome.BaseBiome;
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -22,6 +30,12 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
private NMSMappedFaweQueue parentNMS;
|
private NMSMappedFaweQueue parentNMS;
|
||||||
private final boolean hasSky;
|
private final boolean hasSky;
|
||||||
private final File saveFolder;
|
private final File saveFolder;
|
||||||
|
private final ThreadLocal<MutableMCABackedBaseBlock> blockStore = new ThreadLocal<MutableMCABackedBaseBlock>() {
|
||||||
|
@Override
|
||||||
|
protected MutableMCABackedBaseBlock initialValue() {
|
||||||
|
return new MutableMCABackedBaseBlock();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public MCAQueue(FaweQueue parent) {
|
public MCAQueue(FaweQueue parent) {
|
||||||
super(parent.getWEWorld(), new MCAQueueMap());
|
super(parent.getWEWorld(), new MCAQueueMap());
|
||||||
@ -67,100 +81,260 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void filterWorld(final MCAFilter filter) {
|
public void pasteRegion(MCAQueue from, final RegionWrapper regionFrom, Vector offset) throws IOException {
|
||||||
|
offset = new Vector((offset.getBlockX() >> 4) << 4, 0, (offset.getBlockZ() >> 4) << 4);
|
||||||
|
int oX = offset.getBlockX();
|
||||||
|
int oZ = offset.getBlockZ();
|
||||||
|
int oY = offset.getBlockY();
|
||||||
|
int oCX = oX >> 4;
|
||||||
|
int oCZ = oZ >> 4;
|
||||||
|
RegionWrapper regionTo = new RegionWrapper(regionFrom.minX + oX, regionFrom.maxX + oX, regionFrom.minZ + oZ, regionFrom.maxZ + oZ);
|
||||||
File folder = getSaveFolder();
|
File folder = getSaveFolder();
|
||||||
final ForkJoinPool pool = new ForkJoinPool();
|
final ForkJoinPool pool = new ForkJoinPool();
|
||||||
final ThreadLocal<MutableMCABackedBaseBlock> blockStore = new ThreadLocal<MutableMCABackedBaseBlock>() {
|
int bMcaX = (regionTo.minX >> 9);
|
||||||
@Override
|
int bMcaZ = (regionTo.minZ >> 9);
|
||||||
protected MutableMCABackedBaseBlock initialValue() {
|
int tMcaX = (regionTo.maxX >> 9);
|
||||||
return new MutableMCABackedBaseBlock();
|
int tMcaZ = (regionTo.maxZ >> 9);
|
||||||
}
|
for (int mcaZ = bMcaZ; mcaZ <= tMcaZ; mcaZ++) {
|
||||||
};
|
for (int mcaX = bMcaX; mcaX <= tMcaX; mcaX++) {
|
||||||
for (final File file : folder.listFiles()) {
|
int bcx = Math.max(mcaX << 5, regionTo.minX >> 4);
|
||||||
try {
|
int bcz = Math.max(mcaZ << 5, regionTo.minZ >> 4);
|
||||||
String name = file.getName();
|
int tcx = Math.min((mcaX << 5) + 31, regionTo.maxX >> 4);
|
||||||
String[] split = name.split("\\.");
|
int tcz = Math.min((mcaZ << 5) + 31, regionTo.maxZ >> 4);
|
||||||
final int mcaX = Integer.parseInt(split[1]);
|
File file = new File(folder, "r." + mcaX + "." + mcaZ + ".mca");
|
||||||
final int mcaZ = Integer.parseInt(split[2]);
|
if (!file.exists()) {
|
||||||
if (filter.appliesFile(mcaX, mcaZ)) {
|
file.createNewFile();
|
||||||
MCAFile mcaFile = new MCAFile(this, file);
|
}
|
||||||
final MCAFile original = mcaFile;
|
MCAFile mcaFile = new MCAFile(null, file);
|
||||||
final MCAFile finalFile = filter.applyFile(mcaFile);
|
mcaFile.init();
|
||||||
if (finalFile != null) {
|
// If oX & 15 == 0 && oZ && 15 == 0
|
||||||
finalFile.init();
|
if ((oX & 15) == 0 && (oZ & 15) == 0) {
|
||||||
// May not do anything, but seems to lead to smaller lag spikes
|
if (oY == 0) {
|
||||||
final int cbx = mcaX << 5;
|
if (regionFrom.minY == 0 && regionFrom.maxY == 255) {
|
||||||
final int cbz = mcaZ << 5;
|
for (int cz = bcz; cz <= tcz; cz++) {
|
||||||
|
for (int cx = bcx; cx <= tcx; cx++) {
|
||||||
|
FaweChunk chunk = from.getFaweChunk(cx - oCX, cz - oCZ);
|
||||||
|
if (!(chunk instanceof NullFaweChunk)) {
|
||||||
|
MCAChunk mcaChunk = (MCAChunk) chunk;
|
||||||
|
mcaChunk.setLoc(null, cx, cz);
|
||||||
|
mcaChunk.setModified();
|
||||||
|
mcaFile.setChunk(mcaChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int cz = bcz; cz <= tcz; cz++) {
|
||||||
|
for (int cx = bcx; cx <= tcx; cx++) {
|
||||||
|
FaweChunk chunk = from.getFaweChunk(cx - oCX, cz - oCZ);
|
||||||
|
if (!(chunk instanceof NullFaweChunk)) {
|
||||||
|
MCAChunk mcaChunk = (MCAChunk) chunk;
|
||||||
|
MCAChunk toChunk = mcaFile.getChunk(cx, cz);
|
||||||
|
if (toChunk == null || (toChunk.getMinLayer() << 4 >= regionTo.minY && (toChunk.getMaxLayer() << 4) + 15 <= regionTo.maxY)) {
|
||||||
|
mcaChunk.setLoc(null, cx, cz);
|
||||||
|
mcaChunk.setModified();
|
||||||
|
mcaFile.setChunk(mcaChunk);
|
||||||
|
} else {
|
||||||
|
|
||||||
finalFile.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
}
|
||||||
@Override
|
}
|
||||||
public void run(final Integer rcx, final Integer rcz, Integer offset, Integer size) {
|
}
|
||||||
pool.submit(new Runnable() {
|
}
|
||||||
@Override
|
}
|
||||||
public void run() {
|
} else if ((oY & 15) == 0) {
|
||||||
int cx = cbx + rcx;
|
} else {
|
||||||
int cz = cbz + rcz;
|
}
|
||||||
if (filter.appliesChunk(cx, cz)) {
|
} else {
|
||||||
|
}
|
||||||
|
mcaFile.close(pool);
|
||||||
|
from.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <G, T extends MCAFilter<G>> T filterRegion(final T filter, final RegionWrapper region) {
|
||||||
|
this.filterWorld(new MCAFilter<G>() {
|
||||||
|
@Override
|
||||||
|
public boolean appliesFile(int mcaX, int mcaZ) {
|
||||||
|
return region.isInMCA(mcaX, mcaZ) && filter.appliesFile(mcaX, mcaZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MCAFile applyFile(MCAFile file) {
|
||||||
|
return filter.applyFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean appliesChunk(int cx, int cz) {
|
||||||
|
return region.isInChunk(cx, cz) && filter.appliesChunk(cx, cz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public G get() {
|
||||||
|
return filter.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MCAChunk applyChunk(MCAChunk chunk, G value) {
|
||||||
|
chunk = filter.applyChunk(chunk, value);
|
||||||
|
if (chunk != null) {
|
||||||
|
final MutableMCABackedBaseBlock mutableBlock = blockStore.get();
|
||||||
|
mutableBlock.setChunk(chunk);
|
||||||
|
int bx = chunk.getX() << 4;
|
||||||
|
int bz = chunk.getZ() << 4;
|
||||||
|
int tx = bx + 15;
|
||||||
|
int tz = bz + 15;
|
||||||
|
bx = Math.max(bx, region.minX);
|
||||||
|
bz = Math.max(bz, region.minZ);
|
||||||
|
tx = Math.min(tx, region.maxX);
|
||||||
|
tz = Math.min(tz, region.maxZ);
|
||||||
|
int minLayer = region.minY >> 4;
|
||||||
|
int maxLayer = region.maxY >> 4;
|
||||||
|
for (int layer = minLayer; layer <= maxLayer; layer++) {
|
||||||
|
if (chunk.doesSectionExist(layer)) {
|
||||||
|
mutableBlock.setArrays(layer);
|
||||||
|
int yStart = layer << 4;
|
||||||
|
int yEnd = yStart + 15;
|
||||||
|
yStart = Math.max(yStart, region.minY);
|
||||||
|
yEnd = Math.min(yEnd, region.maxY);
|
||||||
|
for (int y = yStart, y0 = (yStart & 15); y <= yEnd; y++, y0++) {
|
||||||
|
int yIndex = ((y0) << 8);
|
||||||
|
mutableBlock.setY(y);
|
||||||
|
for (int z = bz, z0 = bz & 15; z <= tz; z++, z0++) {
|
||||||
|
int zIndex = yIndex + ((z0) << 4);
|
||||||
|
mutableBlock.setZ(z);
|
||||||
|
for (int x = bx, x0 = bx & 15; x <= tx; x++, x0++) {
|
||||||
|
int xIndex = zIndex + x0;
|
||||||
|
mutableBlock.setX(x);
|
||||||
|
mutableBlock.setIndex(xIndex);
|
||||||
|
filter.applyBlock(x, y, z, mutableBlock, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishChunk(MCAChunk chunk, G cache) {
|
||||||
|
super.finishChunk(chunk, cache);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <G, T extends MCAFilter<G>> T createRegion(final T filter, final RegionWrapper region) {
|
||||||
|
int botMcaX = region.minX >> 9;
|
||||||
|
int botMcaZ = region.minZ >> 9;
|
||||||
|
int topMcaX = region.maxX >> 9;
|
||||||
|
int topMcaZ = region.maxZ >> 9;
|
||||||
|
for (int mcaX = botMcaX >> 9; mcaX <= topMcaX; mcaX++) {
|
||||||
|
for (int mcaZ = botMcaZ >> 9; mcaZ <= topMcaZ; mcaZ++) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <G, T extends MCAFilter<G>> T filterWorld(final T filter) {
|
||||||
|
File folder = getSaveFolder();
|
||||||
|
final ForkJoinPool pool = new ForkJoinPool();
|
||||||
|
MainUtil.traverse(folder.toPath(), new RunnableVal2<Path, BasicFileAttributes>() {
|
||||||
|
@Override
|
||||||
|
public void run(Path path, BasicFileAttributes attr) {
|
||||||
|
try {
|
||||||
|
String name = path.getFileName().toString();
|
||||||
|
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();
|
||||||
|
MCAFile mcaFile = new MCAFile(MCAQueue.this, file);
|
||||||
|
final MCAFile original = mcaFile;
|
||||||
|
final MCAFile finalFile = filter.applyFile(mcaFile);
|
||||||
|
if (finalFile != null && !finalFile.isDeleted()) {
|
||||||
|
finalFile.init();
|
||||||
|
// May not do anything, but seems to lead to smaller lag spikes
|
||||||
|
final int cbx = mcaX << 5;
|
||||||
|
final int cbz = mcaZ << 5;
|
||||||
|
|
||||||
|
finalFile.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(final Integer rcx, final Integer rcz, Integer offset, Integer size) {
|
||||||
|
pool.submit(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
try {
|
try {
|
||||||
MCAChunk chunk = finalFile.getChunk(cx, cz);
|
int cx = cbx + rcx;
|
||||||
try {
|
int cz = cbz + rcz;
|
||||||
chunk = filter.applyChunk(chunk);
|
if (filter.appliesChunk(cx, cz)) {
|
||||||
if (chunk != null) {
|
MCAChunk chunk = finalFile.getChunk(cx, cz);
|
||||||
final MutableMCABackedBaseBlock mutableBlock = blockStore.get();
|
try {
|
||||||
mutableBlock.setChunk(chunk);
|
final G value = filter.get();
|
||||||
int bx = cx << 4;
|
chunk = filter.applyChunk(chunk, value);
|
||||||
int bz = cz << 4;
|
if (chunk != null) {
|
||||||
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
final MutableMCABackedBaseBlock mutableBlock = blockStore.get();
|
||||||
if (chunk.doesSectionExist(layer)) {
|
mutableBlock.setChunk(chunk);
|
||||||
mutableBlock.setArrays(layer);
|
int bx = cx << 4;
|
||||||
int yStart = layer << 4;
|
int bz = cz << 4;
|
||||||
int index = 0;
|
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
||||||
for (int y = yStart; y < yStart + 16; y++) {
|
if (chunk.doesSectionExist(layer)) {
|
||||||
mutableBlock.setY(y);
|
mutableBlock.setArrays(layer);
|
||||||
for (int z = bz; z < bz + 16; z++) {
|
int yStart = layer << 4;
|
||||||
mutableBlock.setZ(z);
|
int index = 0;
|
||||||
for (int x = bx; x < bx + 16; x++,index++) {
|
for (int y = yStart; y < yStart + 16; y++) {
|
||||||
mutableBlock.setX(x);
|
mutableBlock.setY(y);
|
||||||
mutableBlock.setIndex(index);
|
for (int z = bz; z < bz + 16; z++) {
|
||||||
filter.applyBlock(x, y, z, mutableBlock);
|
mutableBlock.setZ(z);
|
||||||
|
for (int x = bx; x < bx + 16; x++, index++) {
|
||||||
|
mutableBlock.setX(x);
|
||||||
|
mutableBlock.setIndex(index);
|
||||||
|
filter.applyBlock(x, y, z, mutableBlock, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
filter.finishChunk(chunk, value);
|
||||||
}
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
System.out.println("Failed to load: r." + mcaX + "." + mcaZ + ".mca -> (local) " + rcx + "," + rcz);
|
System.out.println("Failed to load: r." + mcaX + "." + mcaZ + ".mca -> (local) " + rcx + "," + rcz);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
});
|
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
|
||||||
original.close(pool);
|
|
||||||
if (original != finalFile) finalFile.close(pool);
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
original.close(pool);
|
original.close(pool);
|
||||||
file.delete();
|
if (original != finalFile) finalFile.close(pool);
|
||||||
} catch (Throwable ignore) {}
|
} else if (mcaFile.isDeleted()) {
|
||||||
|
try {
|
||||||
|
original.close(pool);
|
||||||
|
file.delete();
|
||||||
|
} catch (Throwable ignore) {
|
||||||
|
ignore.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Throwable ignore) {
|
||||||
|
ignore.printStackTrace();
|
||||||
}
|
}
|
||||||
} catch (Throwable ignore) {
|
|
||||||
ignore.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
pool.shutdown();
|
pool.shutdown();
|
||||||
try {
|
try {
|
||||||
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -133,7 +133,16 @@ public class MCAQueueMap implements IFaweQueueMap {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
for (Map.Entry<Long, MCAFile> entry : mcaFileMap.entrySet()) {
|
||||||
|
entry.getValue().clear();
|
||||||
|
}
|
||||||
mcaFileMap.clear();
|
mcaFileMap.clear();
|
||||||
|
lastChunk = null;
|
||||||
|
lastFile = null;
|
||||||
|
lastFileX = Integer.MIN_VALUE;
|
||||||
|
lastFileZ = Integer.MIN_VALUE;
|
||||||
|
lastX = Integer.MIN_VALUE;
|
||||||
|
lastZ = Integer.MIN_VALUE;
|
||||||
if (isHybridQueue) {
|
if (isHybridQueue) {
|
||||||
queue.clear();
|
queue.clear();
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,11 @@ public abstract class FawePlayer<T> extends Metadatable {
|
|||||||
public final T parent;
|
public final T parent;
|
||||||
private LocalSession session;
|
private LocalSession session;
|
||||||
|
|
||||||
|
public static final class METADATA_KEYS {
|
||||||
|
public static final String ANVIL_CLIPBOARD = "anvil-clipboard";
|
||||||
|
public static final String ROLLBACK = "rollback";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap some object into a FawePlayer<br>
|
* Wrap some object into a FawePlayer<br>
|
||||||
* - org.bukkit.entity.Player
|
* - org.bukkit.entity.Player
|
||||||
|
@ -220,6 +220,10 @@ public abstract class FaweQueue implements HasFaweQueue {
|
|||||||
|
|
||||||
public abstract Collection<FaweChunk> getFaweChunks();
|
public abstract Collection<FaweChunk> getFaweChunks();
|
||||||
|
|
||||||
|
public boolean setMCA(Runnable whileLocked, RegionWrapper region, boolean unload) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void setChunk(final FaweChunk chunk);
|
public abstract void setChunk(final FaweChunk chunk);
|
||||||
|
|
||||||
public abstract File getSaveFolder();
|
public abstract File getSaveFolder();
|
||||||
|
@ -61,6 +61,22 @@ public class RegionWrapper {
|
|||||||
return lr && (x >= this.minX && x <= this.maxX);
|
return lr && (x >= this.minX && x <= this.maxX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isInChunk(int cx, int cz) {
|
||||||
|
int bx = cx << 4;
|
||||||
|
int bz = cz << 4;
|
||||||
|
int tx = bx + 15;
|
||||||
|
int tz = bz + 15;
|
||||||
|
return ((tx >= this.minX) && (bx <= this.maxX) && (tz >= this.minZ) && (bz <= this.maxZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInMCA(int mcaX, int mcaZ) {
|
||||||
|
int bx = mcaX << 9;
|
||||||
|
int bz = mcaZ << 9;
|
||||||
|
int tx = bx + 511;
|
||||||
|
int tz = bz + 511;
|
||||||
|
return ((tx >= this.minX) && (bx <= this.maxX) && (tz >= this.minZ) && (bz <= this.maxZ));
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isIn(final int x, final int z) {
|
public boolean isIn(final int x, final int z) {
|
||||||
return ((x >= this.minX) && (x <= this.maxX) && (z >= this.minZ) && (z <= this.maxZ));
|
return ((x >= this.minX) && (x <= this.maxX) && (z >= this.minZ) && (z <= this.maxZ));
|
||||||
}
|
}
|
||||||
@ -110,7 +126,7 @@ public class RegionWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.minX + "," + this.minZ + "->" + this.maxX + "," + this.maxZ;
|
return this.minX + "," + this.minY + "," + this.minZ + "->" + this.maxX + "," + this.maxY + "," + this.maxZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector getBottomVector() {
|
public Vector getBottomVector() {
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
package com.boydti.fawe.object.brush;
|
||||||
|
|
||||||
|
public class FallingSphere {
|
||||||
|
}
|
@ -170,7 +170,6 @@ public class CPUOptimizedClipboard extends FaweClipboard {
|
|||||||
for (int z = 0; z < length; z++) {
|
for (int z = 0; z < length; z++) {
|
||||||
for (int x = 0; x < width; x++, index++) {
|
for (int x = 0; x < width; x++, index++) {
|
||||||
BaseBlock block = getBlock(index);
|
BaseBlock block = getBlock(index);
|
||||||
System.out.println(block);
|
|
||||||
if (block.getId() != 0) {
|
if (block.getId() != 0) {
|
||||||
task.run(x, y, z, block);
|
task.run(x, y, z, block);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.boydti.fawe.object.collection;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||||
|
|
||||||
|
public abstract class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T> {
|
||||||
|
private ThreadLocal<T> flag;
|
||||||
|
private ConcurrentLinkedDeque<T> allValues = new ConcurrentLinkedDeque<T>();
|
||||||
|
|
||||||
|
public IterableThreadLocal() { }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final T initialValue() {
|
||||||
|
T value = init();
|
||||||
|
if (value != null) {
|
||||||
|
allValues.add(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Iterator<T> iterator() {
|
||||||
|
return getAll().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T init() { return null; }
|
||||||
|
|
||||||
|
public final Collection<T> getAll() {
|
||||||
|
return Collections.unmodifiableCollection(allValues);
|
||||||
|
}
|
||||||
|
}
|
@ -1,126 +0,0 @@
|
|||||||
package com.boydti.fawe.object.extent;
|
|
||||||
|
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAFile;
|
|
||||||
import com.boydti.fawe.object.FaweQueue;
|
|
||||||
import com.boydti.fawe.object.HasFaweQueue;
|
|
||||||
import com.boydti.fawe.util.MathMan;
|
|
||||||
import com.sk89q.worldedit.Vector;
|
|
||||||
import com.sk89q.worldedit.Vector2D;
|
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
|
||||||
import com.sk89q.worldedit.entity.BaseEntity;
|
|
||||||
import com.sk89q.worldedit.entity.Entity;
|
|
||||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
|
||||||
import com.sk89q.worldedit.function.operation.Operation;
|
|
||||||
import com.sk89q.worldedit.regions.Region;
|
|
||||||
import com.sk89q.worldedit.util.Location;
|
|
||||||
import com.sk89q.worldedit.world.World;
|
|
||||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public class MCAExtent extends AbstractDelegateExtent implements HasFaweQueue {
|
|
||||||
private final FaweQueue queue;
|
|
||||||
private final File folder;
|
|
||||||
|
|
||||||
private Map<Long, MCAFile> regions;
|
|
||||||
|
|
||||||
public MCAExtent(World world, FaweQueue queue) {
|
|
||||||
super(world);
|
|
||||||
this.queue = queue;
|
|
||||||
this.folder = new File(queue.getSaveFolder(), "regions");
|
|
||||||
this.regions = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public FaweQueue getQueue() {
|
|
||||||
return queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int lastX = Integer.MAX_VALUE;
|
|
||||||
private int lastZ = Integer.MAX_VALUE;
|
|
||||||
private MCAFile lastMCA;
|
|
||||||
|
|
||||||
private MCAFile getMCA(int x, int y, int z) {
|
|
||||||
int MCAX = x >> 9;
|
|
||||||
int MCAZ = z >> 9;
|
|
||||||
if (MCAX == lastX && MCAZ == lastZ) {
|
|
||||||
return lastMCA;
|
|
||||||
}
|
|
||||||
lastX = MCAX;
|
|
||||||
lastZ = MCAZ;
|
|
||||||
long pair = MathMan.pairInt(lastX, lastZ);
|
|
||||||
lastMCA = regions.get(pair);
|
|
||||||
if (lastMCA == null) {
|
|
||||||
// lastMCA = new MCAFile(folder, lastX, lastZ);
|
|
||||||
// TODO
|
|
||||||
regions.put(pair, lastMCA);
|
|
||||||
}
|
|
||||||
return lastMCA;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BaseBlock getBlock(Vector position) {
|
|
||||||
// TODO get block from MCA
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BaseBlock getLazyBlock(Vector position) {
|
|
||||||
// TODO set block in MCA
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
|
|
||||||
// TODO set block in MCA
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public Entity createEntity(Location location, BaseEntity entity) {
|
|
||||||
// TODO add entity to MCA
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<? extends Entity> getEntities() {
|
|
||||||
// TODO get entities from MCA
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<? extends Entity> getEntities(Region region) {
|
|
||||||
// TODO get entities from MCA
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BaseBiome getBiome(Vector2D position) {
|
|
||||||
// TODO get biome from MCA
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vector getMinimumPoint() {
|
|
||||||
return super.getMinimumPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vector getMaximumPoint() {
|
|
||||||
return super.getMaximumPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Operation commitBefore() {
|
|
||||||
// Save MCA file if modified
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.boydti.fawe.object.number;
|
||||||
|
|
||||||
|
public final class MutableLong {
|
||||||
|
private long value;
|
||||||
|
|
||||||
|
public final void increment() {
|
||||||
|
value++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(long value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long get() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(long amount) {
|
||||||
|
this.value += amount;
|
||||||
|
}
|
||||||
|
}
|
@ -364,6 +364,8 @@ public class CreateFromImage extends Command {
|
|||||||
player.sendMessage("Invalid mask " + e.getMessage());
|
player.sendMessage("Invalid mask " + e.getMessage());
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
player.sendMessage("Error " + e.getMessage());
|
player.sendMessage("Error " + e.getMessage());
|
||||||
|
} finally {
|
||||||
|
Request.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, true, false);
|
}, true, false);
|
||||||
|
@ -136,6 +136,7 @@ public class PlotTrim implements Listener {
|
|||||||
ChunkLoc loc = new ChunkLoc(mcaX, mcaZ);
|
ChunkLoc loc = new ChunkLoc(mcaX, mcaZ);
|
||||||
if (mcas.contains(loc)) {
|
if (mcas.contains(loc)) {
|
||||||
player.sendMessage("Delete MCA " + mca);
|
player.sendMessage("Delete MCA " + mca);
|
||||||
|
mca.setDeleted(true);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -159,7 +160,7 @@ public class PlotTrim implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MCAChunk applyChunk(MCAChunk chunk) {
|
public MCAChunk applyChunk(MCAChunk chunk, Object ignore) {
|
||||||
long pair = MathMan.pairInt(chunk.getX(), chunk.getZ());
|
long pair = MathMan.pairInt(chunk.getX(), chunk.getZ());
|
||||||
if (chunks.containsKey(pair)) {
|
if (chunks.containsKey(pair)) {
|
||||||
chunk.setDeleted(true);
|
chunk.setDeleted(true);
|
||||||
|
@ -5,6 +5,7 @@ import com.boydti.fawe.example.Relighter;
|
|||||||
import com.boydti.fawe.object.FaweChunk;
|
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.RunnableVal2;
|
import com.boydti.fawe.object.RunnableVal2;
|
||||||
import com.boydti.fawe.object.exception.FaweException;
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
@ -43,6 +44,11 @@ public class DelegateFaweQueue extends FaweQueue {
|
|||||||
parent.sendChunk(x, z, bitMask);
|
parent.sendChunk(x, z, bitMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setMCA(Runnable whileLocked, RegionWrapper region, boolean unload) {
|
||||||
|
return parent.setMCA(whileLocked, region, unload);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWorldName() {
|
public String getWorldName() {
|
||||||
return parent.getWorldName();
|
return parent.getWorldName();
|
||||||
|
@ -1303,7 +1303,6 @@ public class LocalSession {
|
|||||||
if (transform != null) {
|
if (transform != null) {
|
||||||
editSession.addTransform(transform);
|
editSession.addTransform(transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
return editSession;
|
return editSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -948,7 +948,7 @@ public class BrushCommands {
|
|||||||
if (player.hasPermission("worldedit.butcher")) {
|
if (player.hasPermission("worldedit.butcher")) {
|
||||||
maxRadius = Math.max(config.maxBrushRadius, config.butcherMaxRadius);
|
maxRadius = Math.max(config.maxBrushRadius, config.butcherMaxRadius);
|
||||||
}
|
}
|
||||||
if (radius > maxRadius) {
|
if (radius > maxRadius && maxRadius != -1) {
|
||||||
BBC.TOOL_RADIUS_ERROR.send(player, maxRadius);
|
BBC.TOOL_RADIUS_ERROR.send(player, maxRadius);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -94,9 +94,9 @@ public class ToolUtilCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mask == null) {
|
if (mask == null) {
|
||||||
BBC.BRUSH_SOURCE_MASK_DISABLED.send(player);
|
BBC.BRUSH_MASK_DISABLED.send(player);
|
||||||
} else {
|
} else {
|
||||||
BBC.BRUSH_SOURCE_MASK.send(player);
|
BBC.BRUSH_MASK.send(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,6 +318,7 @@ public class BrushTool implements DoubleActionTraceTool, ScrollTool, MovableTool
|
|||||||
bag.flushChanges();
|
bag.flushChanges();
|
||||||
}
|
}
|
||||||
session.remember(editSession);
|
session.remember(editSession);
|
||||||
|
Request.reset();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,9 @@ public final class CommandManager {
|
|||||||
|
|
||||||
|
|
||||||
dispatcher = graph
|
dispatcher = graph
|
||||||
.registerMethods(new AnvilCommands(worldEdit))
|
.group("/anvil", "anvil")
|
||||||
|
.describeAs("Anvil command")
|
||||||
|
.registerMethods(new AnvilCommands(worldEdit)).parent()
|
||||||
.registerMethods(new BiomeCommands(worldEdit))
|
.registerMethods(new BiomeCommands(worldEdit))
|
||||||
.registerMethods(new ChunkCommands(worldEdit))
|
.registerMethods(new ChunkCommands(worldEdit))
|
||||||
.registerMethods(new ClipboardCommands(worldEdit))
|
.registerMethods(new ClipboardCommands(worldEdit))
|
||||||
@ -425,6 +427,7 @@ public final class CommandManager {
|
|||||||
if (time > 250 && hasSession) {
|
if (time > 250 && hasSession) {
|
||||||
BBC.ACTION_COMPLETE.send(finalActor, (time / 1000d));
|
BBC.ACTION_COMPLETE.send(finalActor, (time / 1000d));
|
||||||
}
|
}
|
||||||
|
Request.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit 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.sk89q.worldedit.extent;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.MutableBlockVector;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.Vector2D;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
|
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires that all mutating methods pass a given {@link Mask}.
|
||||||
|
*/
|
||||||
|
public class MaskingExtent extends AbstractDelegateExtent {
|
||||||
|
|
||||||
|
private Mask mask;
|
||||||
|
private MutableBlockVector mutable = new MutableBlockVector();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
*
|
||||||
|
* @param extent the extent
|
||||||
|
* @param mask the mask
|
||||||
|
*/
|
||||||
|
public MaskingExtent(Extent extent, Mask mask) {
|
||||||
|
super(extent);
|
||||||
|
checkNotNull(mask);
|
||||||
|
this.mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the mask.
|
||||||
|
*
|
||||||
|
* @return the mask
|
||||||
|
*/
|
||||||
|
public Mask getMask() {
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a mask.
|
||||||
|
*
|
||||||
|
* @param mask a mask
|
||||||
|
*/
|
||||||
|
public void setMask(Mask mask) {
|
||||||
|
checkNotNull(mask);
|
||||||
|
this.mask = mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBlock(Vector location, BaseBlock block) throws WorldEditException {
|
||||||
|
return mask.test(location) && super.setBlock(location, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||||
|
return mask.test(mutable.setComponents(position.getBlockX(), 0, position.getBlockZ())) && super.setBiome(position, biome);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Class<?> inject() {
|
||||||
|
return MaskingExtent.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -312,14 +312,6 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
|||||||
recalculate();
|
recalculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void shift(Vector change) throws RegionOperationException {
|
|
||||||
pos1 = pos1.add(change);
|
|
||||||
pos2 = pos2.add(change);
|
|
||||||
|
|
||||||
recalculate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Vector2D> getChunks() {
|
public Set<Vector2D> getChunks() {
|
||||||
Vector min = getMinimumPoint();
|
Vector min = getMinimumPoint();
|
||||||
@ -378,6 +370,14 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shift(Vector change) throws RegionOperationException {
|
||||||
|
pos1 = pos1.add(change);
|
||||||
|
pos2 = pos2.add(change);
|
||||||
|
|
||||||
|
recalculate();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Vector> getChunkCubes() {
|
public Set<Vector> getChunkCubes() {
|
||||||
Set chunks = new LocalBlockVectorSet();
|
Set chunks = new LocalBlockVectorSet();
|
||||||
|
@ -70,9 +70,5 @@ public class ForgeMain {
|
|||||||
if (player.worldObj.isRemote) {
|
if (player.worldObj.isRemote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FawePlayer fp = FawePlayer.wrap(player);
|
|
||||||
if (fp.getMeta("lastWorld") != event.getWorld()) {
|
|
||||||
fp.setMeta("lastWorld", event.getWorld());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,5 @@ public class ForgeMain {
|
|||||||
if (player.world.isRemote) {
|
if (player.world.isRemote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FawePlayer fp = FawePlayer.wrap(player);
|
|
||||||
if (fp.getMeta("lastWorld") != event.getWorld()) {
|
|
||||||
fp.setMeta("lastWorld", event.getWorld());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,9 +71,5 @@ public class ForgeMain {
|
|||||||
if (player.worldObj.isRemote) {
|
if (player.worldObj.isRemote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FawePlayer fp = FawePlayer.wrap(player);
|
|
||||||
if (fp.getMeta("lastWorld") != event.world) {
|
|
||||||
fp.setMeta("lastWorld", event.world);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,9 +71,5 @@ public class ForgeMain {
|
|||||||
if (player.worldObj.isRemote) {
|
if (player.worldObj.isRemote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FawePlayer fp = FawePlayer.wrap(player);
|
|
||||||
if (fp.getMeta("lastWorld") != event.world) {
|
|
||||||
fp.setMeta("lastWorld", event.world);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,9 +70,5 @@ public class ForgeMain {
|
|||||||
if (player.worldObj.isRemote) {
|
if (player.worldObj.isRemote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
FawePlayer fp = FawePlayer.wrap(player);
|
|
||||||
if (fp.getMeta("lastWorld") != event.getWorld()) {
|
|
||||||
fp.setMeta("lastWorld", event.getWorld());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
region/r.-1.-1.mca
Normal file
BIN
region/r.-1.-1.mca
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user