mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2025-01-01 14:08:11 +01:00
Various
Dynamic chunk rendering (experimental section in config) Use local files for CFI heightmaps: file://<file-path> - Root directory is plugins/FastAsyncWorldEdit/heightmap Optimize anvil for 1.12 Add safety checks to anvil commands Move anvil command implementation to com.boydti.fawe.jnbt.anvil.filters Add anvil chunk delete Add MCAWriter mca offset method Fix count -d Fix taskbuilder split task concurrency issue
This commit is contained in:
parent
0f3138e894
commit
7ae2d65607
@ -79,6 +79,7 @@ subprojects {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven {url "https://repo.destroystokyo.com/repository/maven-public//"}
|
||||||
maven { url = "https://mvnrepository.com/artifact/"}
|
maven { url = "https://mvnrepository.com/artifact/"}
|
||||||
maven {url "http://ci.emc.gs/nexus/content/groups/aikar/" }
|
maven {url "http://ci.emc.gs/nexus/content/groups/aikar/" }
|
||||||
maven {url "http://ci.mengcraft.com:8080/plugin/repository/everything/"}
|
maven {url "http://ci.mengcraft.com:8080/plugin/repository/everything/"}
|
||||||
|
@ -2,6 +2,7 @@ repositories {
|
|||||||
flatDir {dirs 'lib'}
|
flatDir {dirs 'lib'}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
|
compile 'com.destroystokyo.paper:paper-api:1.11.2-R0.1-SNAPSHOT'
|
||||||
compile project(':core')
|
compile project(':core')
|
||||||
compile 'org.bukkit.craftbukkitv1_10:craftbukkitv1_10:1.10'
|
compile 'org.bukkit.craftbukkitv1_10:craftbukkitv1_10:1.10'
|
||||||
compile 'org.bukkit.craftbukkitv1_11:Craftbukkit:1.11'
|
compile 'org.bukkit.craftbukkitv1_11:Craftbukkit:1.11'
|
||||||
|
@ -21,7 +21,6 @@ import com.boydti.fawe.object.FaweQueue;
|
|||||||
import com.boydti.fawe.regions.FaweMaskManager;
|
import com.boydti.fawe.regions.FaweMaskManager;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.ReflectionUtils;
|
import com.boydti.fawe.util.ReflectionUtils;
|
||||||
import com.boydti.fawe.util.SetQueue;
|
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
import com.sk89q.worldedit.bukkit.EditSessionBlockChangeDelegate;
|
import com.sk89q.worldedit.bukkit.EditSessionBlockChangeDelegate;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
@ -44,9 +43,6 @@ import org.bukkit.event.EventHandler;
|
|||||||
import org.bukkit.event.EventPriority;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.event.world.ChunkLoadEvent;
|
|
||||||
import org.bukkit.event.world.ChunkPopulateEvent;
|
|
||||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.primesoft.blockshub.BlocksHubBukkit;
|
import org.primesoft.blockshub.BlocksHubBukkit;
|
||||||
|
|
||||||
@ -87,6 +83,9 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
debug(" - This is only a recommendation");
|
debug(" - This is only a recommendation");
|
||||||
debug("==============================");
|
debug("==============================");
|
||||||
}
|
}
|
||||||
|
if (Bukkit.getVersion().contains("git-Paper") && Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING) {
|
||||||
|
new RenderListener(plugin);
|
||||||
|
}
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
MainUtil.handleError(e);
|
MainUtil.handleError(e);
|
||||||
Bukkit.getServer().shutdown();
|
Bukkit.getServer().shutdown();
|
||||||
@ -411,29 +410,6 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private boolean runChunkLoad = false;
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onChunkLoad(ChunkLoadEvent event) {
|
|
||||||
if (runChunkLoad) return;
|
|
||||||
try {
|
|
||||||
runChunkLoad = true;
|
|
||||||
SetQueue.IMP.runMiscTasks();
|
|
||||||
} finally {
|
|
||||||
runChunkLoad = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onChunkUnload(ChunkUnloadEvent event) {
|
|
||||||
SetQueue.IMP.runMiscTasks();
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onChunkPopulate(ChunkPopulateEvent event) {
|
|
||||||
SetQueue.IMP.runMiscTasks();
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.MONITOR)
|
@EventHandler(priority = EventPriority.MONITOR)
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
|
135
bukkit/src/main/java/com/boydti/fawe/bukkit/RenderListener.java
Normal file
135
bukkit/src/main/java/com/boydti/fawe/bukkit/RenderListener.java
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package com.boydti.fawe.bukkit;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.util.TaskManager;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class RenderListener implements Listener {
|
||||||
|
|
||||||
|
private final Map<UUID, int[]> views = new ConcurrentHashMap<>();
|
||||||
|
private Iterator<Map.Entry<UUID, int[]>> entrySet;
|
||||||
|
private final long GLOBAL_START = System.currentTimeMillis();
|
||||||
|
private int OFFSET = 6;
|
||||||
|
|
||||||
|
public RenderListener(Plugin plugin) {
|
||||||
|
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||||
|
TaskManager.IMP.repeat(new Runnable() {
|
||||||
|
private long last = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (views.isEmpty()) return;
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
int tps32 = (int) (Math.round(Fawe.get().getTimer().getTPS()) * 32);
|
||||||
|
long diff = now - last;
|
||||||
|
last = now;
|
||||||
|
if (diff > 75) {
|
||||||
|
OFFSET = diff > 100 ? 0 : 4;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int timeOut;
|
||||||
|
if (diff < 55 && tps32 > 608) {
|
||||||
|
OFFSET = 8;
|
||||||
|
timeOut = 2;
|
||||||
|
} else {
|
||||||
|
int tpsSqr = tps32 * tps32;
|
||||||
|
OFFSET = 1 + (tps32 / 102400);
|
||||||
|
timeOut = 162 - (tps32 / 2560);
|
||||||
|
}
|
||||||
|
if (entrySet == null || !entrySet.hasNext()) {
|
||||||
|
entrySet = views.entrySet().iterator();
|
||||||
|
}
|
||||||
|
int nowTick = (int) (Fawe.get().getTimer().getTick());
|
||||||
|
while (entrySet.hasNext()) {
|
||||||
|
Map.Entry<UUID, int[]> entry = entrySet.next();
|
||||||
|
int[] value = entry.getValue();
|
||||||
|
if (nowTick - value[1] >= timeOut) {
|
||||||
|
value[1] = nowTick + 1;
|
||||||
|
Player player = Bukkit.getPlayer(entry.getKey());
|
||||||
|
setViewDistance(player, Math.max(4, value[0] + 1));
|
||||||
|
long spent = System.currentTimeMillis() - now;
|
||||||
|
if (spent > 5) {
|
||||||
|
if (spent > 10)
|
||||||
|
value[1] = nowTick + 20;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setViewDistance(Player player, int value) {
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
if (value == 10) {
|
||||||
|
views.remove(uuid);
|
||||||
|
} else {
|
||||||
|
int[] val = views.get(uuid);
|
||||||
|
if (val == null) {
|
||||||
|
val = new int[] {value, (int) Fawe.get().getTimer().getTick()};
|
||||||
|
UUID uid = player.getUniqueId();
|
||||||
|
views.put(uid, val);
|
||||||
|
} else {
|
||||||
|
if (value <= val[0]) {
|
||||||
|
val[1] = (int) Fawe.get().getTimer().getTick();
|
||||||
|
}
|
||||||
|
if (val[0] == value) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
val[0] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
player.setViewDistance(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getViewDistance(Player player) {
|
||||||
|
int[] value = views.get(player.getUniqueId());
|
||||||
|
return value == null ? 10 : value[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
|
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
||||||
|
setViewDistance(event.getPlayer(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
|
Location from = event.getFrom();
|
||||||
|
Location to = event.getTo();
|
||||||
|
if (from.getBlockX() >> OFFSET != to.getBlockX() >> OFFSET || from.getBlockZ() >> OFFSET != to.getBlockZ() >> OFFSET) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
int currentView = getViewDistance(player);
|
||||||
|
setViewDistance(player, Math.max(currentView - 1, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
|
||||||
|
public void onPlayerJoin(org.bukkit.event.player.PlayerJoinEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
setViewDistance(player, 1);
|
||||||
|
FawePlayer fp = FawePlayer.wrap(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||||
|
public void onPlayerLeave(org.bukkit.event.player.PlayerQuitEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID uid = player.getUniqueId();
|
||||||
|
views.remove(uid);
|
||||||
|
FawePlayer fp = FawePlayer.wrap(player);
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,7 @@ import net.minecraft.server.v1_10_R1.BiomeBase;
|
|||||||
import net.minecraft.server.v1_10_R1.BiomeCache;
|
import net.minecraft.server.v1_10_R1.BiomeCache;
|
||||||
import net.minecraft.server.v1_10_R1.Block;
|
import net.minecraft.server.v1_10_R1.Block;
|
||||||
import net.minecraft.server.v1_10_R1.BlockPosition;
|
import net.minecraft.server.v1_10_R1.BlockPosition;
|
||||||
|
import net.minecraft.server.v1_10_R1.ChunkCoordIntPair;
|
||||||
import net.minecraft.server.v1_10_R1.ChunkProviderGenerate;
|
import net.minecraft.server.v1_10_R1.ChunkProviderGenerate;
|
||||||
import net.minecraft.server.v1_10_R1.ChunkProviderServer;
|
import net.minecraft.server.v1_10_R1.ChunkProviderServer;
|
||||||
import net.minecraft.server.v1_10_R1.ChunkSection;
|
import net.minecraft.server.v1_10_R1.ChunkSection;
|
||||||
@ -457,6 +458,7 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<net.minecraft.server.v1_10_R
|
|||||||
for (net.minecraft.server.v1_10_R1.Chunk chunk : chunks) {
|
for (net.minecraft.server.v1_10_R1.Chunk chunk : chunks) {
|
||||||
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
|
provider.chunks.put(ChunkCoordIntPair.a(chunk.locX, chunk.locZ), chunk);
|
||||||
sendChunk(chunk, 0);
|
sendChunk(chunk, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import net.minecraft.server.v1_11_R1.BiomeBase;
|
|||||||
import net.minecraft.server.v1_11_R1.BiomeCache;
|
import net.minecraft.server.v1_11_R1.BiomeCache;
|
||||||
import net.minecraft.server.v1_11_R1.Block;
|
import net.minecraft.server.v1_11_R1.Block;
|
||||||
import net.minecraft.server.v1_11_R1.BlockPosition;
|
import net.minecraft.server.v1_11_R1.BlockPosition;
|
||||||
|
import net.minecraft.server.v1_11_R1.ChunkCoordIntPair;
|
||||||
import net.minecraft.server.v1_11_R1.ChunkProviderGenerate;
|
import net.minecraft.server.v1_11_R1.ChunkProviderGenerate;
|
||||||
import net.minecraft.server.v1_11_R1.ChunkProviderServer;
|
import net.minecraft.server.v1_11_R1.ChunkProviderServer;
|
||||||
import net.minecraft.server.v1_11_R1.ChunkSection;
|
import net.minecraft.server.v1_11_R1.ChunkSection;
|
||||||
@ -300,6 +301,7 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
|||||||
for (net.minecraft.server.v1_11_R1.Chunk chunk : chunks) {
|
for (net.minecraft.server.v1_11_R1.Chunk chunk : chunks) {
|
||||||
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
|
provider.chunks.put(ChunkCoordIntPair.a(chunk.locX, chunk.locZ), chunk);
|
||||||
sendChunk(chunk, 0);
|
sendChunk(chunk, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,13 @@ import com.boydti.fawe.object.FawePlayer;
|
|||||||
import com.boydti.fawe.object.RegionWrapper;
|
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.collection.PrimitiveList;
|
||||||
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
||||||
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.boydti.fawe.util.ReflectionUtils;
|
import com.boydti.fawe.util.ReflectionUtils;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
|
import com.boydti.fawe.util.task.TaskBuilder;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.StringTag;
|
import com.sk89q.jnbt.StringTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
@ -34,13 +36,17 @@ 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;
|
||||||
|
import java.util.concurrent.ForkJoinPool;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.LongAdder;
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
import net.minecraft.server.v1_12_R1.BiomeBase;
|
import net.minecraft.server.v1_12_R1.BiomeBase;
|
||||||
import net.minecraft.server.v1_12_R1.BiomeCache;
|
import net.minecraft.server.v1_12_R1.BiomeCache;
|
||||||
import net.minecraft.server.v1_12_R1.Block;
|
import net.minecraft.server.v1_12_R1.Block;
|
||||||
import net.minecraft.server.v1_12_R1.BlockPosition;
|
import net.minecraft.server.v1_12_R1.BlockPosition;
|
||||||
|
import net.minecraft.server.v1_12_R1.ChunkCoordIntPair;
|
||||||
import net.minecraft.server.v1_12_R1.ChunkProviderGenerate;
|
import net.minecraft.server.v1_12_R1.ChunkProviderGenerate;
|
||||||
import net.minecraft.server.v1_12_R1.ChunkProviderServer;
|
import net.minecraft.server.v1_12_R1.ChunkProviderServer;
|
||||||
|
import net.minecraft.server.v1_12_R1.ChunkRegionLoader;
|
||||||
import net.minecraft.server.v1_12_R1.ChunkSection;
|
import net.minecraft.server.v1_12_R1.ChunkSection;
|
||||||
import net.minecraft.server.v1_12_R1.DataPaletteBlock;
|
import net.minecraft.server.v1_12_R1.DataPaletteBlock;
|
||||||
import net.minecraft.server.v1_12_R1.Entity;
|
import net.minecraft.server.v1_12_R1.Entity;
|
||||||
@ -51,6 +57,7 @@ import net.minecraft.server.v1_12_R1.EnumDifficulty;
|
|||||||
import net.minecraft.server.v1_12_R1.EnumGamemode;
|
import net.minecraft.server.v1_12_R1.EnumGamemode;
|
||||||
import net.minecraft.server.v1_12_R1.EnumSkyBlock;
|
import net.minecraft.server.v1_12_R1.EnumSkyBlock;
|
||||||
import net.minecraft.server.v1_12_R1.IBlockData;
|
import net.minecraft.server.v1_12_R1.IBlockData;
|
||||||
|
import net.minecraft.server.v1_12_R1.IChunkLoader;
|
||||||
import net.minecraft.server.v1_12_R1.IDataManager;
|
import net.minecraft.server.v1_12_R1.IDataManager;
|
||||||
import net.minecraft.server.v1_12_R1.MinecraftServer;
|
import net.minecraft.server.v1_12_R1.MinecraftServer;
|
||||||
import net.minecraft.server.v1_12_R1.NBTTagCompound;
|
import net.minecraft.server.v1_12_R1.NBTTagCompound;
|
||||||
@ -100,6 +107,8 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
|||||||
protected static Field fieldBiomes2;
|
protected static Field fieldBiomes2;
|
||||||
protected static Field fieldGenLayer1;
|
protected static Field fieldGenLayer1;
|
||||||
protected static Field fieldGenLayer2;
|
protected static Field fieldGenLayer2;
|
||||||
|
protected static Field fieldChunks;
|
||||||
|
protected static Field fieldChunkLoader;
|
||||||
protected static MutableGenLayer genLayer;
|
protected static MutableGenLayer genLayer;
|
||||||
protected static ChunkSection emptySection;
|
protected static ChunkSection emptySection;
|
||||||
|
|
||||||
@ -130,6 +139,11 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
|||||||
fieldGenLayer1.setAccessible(true);
|
fieldGenLayer1.setAccessible(true);
|
||||||
fieldGenLayer2.setAccessible(true);
|
fieldGenLayer2.setAccessible(true);
|
||||||
|
|
||||||
|
fieldChunks = ChunkProviderServer.class.getDeclaredField("chunks");
|
||||||
|
fieldChunkLoader = ChunkProviderServer.class.getDeclaredField("chunkLoader");
|
||||||
|
fieldChunks.setAccessible(true);
|
||||||
|
fieldChunkLoader.setAccessible(true);
|
||||||
|
|
||||||
fieldPalette = DataPaletteBlock.class.getDeclaredField("c");
|
fieldPalette = DataPaletteBlock.class.getDeclaredField("c");
|
||||||
fieldPalette.setAccessible(true);
|
fieldPalette.setAccessible(true);
|
||||||
fieldSize = DataPaletteBlock.class.getDeclaredField("e");
|
fieldSize = DataPaletteBlock.class.getDeclaredField("e");
|
||||||
@ -252,65 +266,147 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
|||||||
return super.regenerateChunk(world, x, z, biome, seed);
|
return super.regenerateChunk(world, x, z, biome, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void unload(RegionWrapper allowed, PrimitiveList<Long> chunks) {
|
||||||
|
ArrayDeque<net.minecraft.server.v1_12_R1.Chunk> queue = TaskManager.IMP.sync(new RunnableVal<ArrayDeque<net.minecraft.server.v1_12_R1.Chunk>>() {
|
||||||
|
@Override
|
||||||
|
public void run(ArrayDeque<net.minecraft.server.v1_12_R1.Chunk> value) {
|
||||||
|
this.value = new ArrayDeque<>();
|
||||||
|
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
|
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_12_R1.Chunk> iter = provider.a().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
net.minecraft.server.v1_12_R1.Chunk chunk = iter.next();
|
||||||
|
int cx = chunk.locX;
|
||||||
|
int cz = chunk.locZ;
|
||||||
|
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
||||||
|
this.value.add(chunk);
|
||||||
|
if (getPlayerChunk(nmsWorld, cx, cz) != null) {
|
||||||
|
chunks.add(ChunkCoordIntPair.a(chunk.locX, chunk.locZ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (Fawe.get().getMainThread() == Thread.currentThread()) {
|
||||||
|
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
|
for (net.minecraft.server.v1_12_R1.Chunk chunk : queue) {
|
||||||
|
provider.unloadChunk(chunk, true);
|
||||||
|
}
|
||||||
|
World world = getWorld();
|
||||||
|
boolean autoSave = world.isAutoSave();
|
||||||
|
world.setAutoSave(true);
|
||||||
|
for (int i = 0; i < 50 && !provider.getName().endsWith(" 0"); i++) {
|
||||||
|
provider.unloadChunks();
|
||||||
|
}
|
||||||
|
world.setAutoSave(autoSave);
|
||||||
|
} else {
|
||||||
|
new TaskBuilder().syncWhenFree(new TaskBuilder.SplitTask(50) {
|
||||||
|
@Override
|
||||||
|
public Object exec(Object previous) {
|
||||||
|
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
|
for (net.minecraft.server.v1_12_R1.Chunk chunk : queue) {
|
||||||
|
provider.unloadChunk(chunk, true);
|
||||||
|
split();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
IChunkLoader loader = (IChunkLoader) fieldChunkLoader.get(provider);
|
||||||
|
if (loader instanceof ChunkRegionLoader) {
|
||||||
|
ChunkRegionLoader crl = (ChunkRegionLoader) loader;
|
||||||
|
for (int i = 0; i < queue.size() && crl.a(); i++) {
|
||||||
|
split();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMCA(Runnable whileLocked, final RegionWrapper allowed, boolean unload) {
|
public boolean setMCA(Runnable whileLocked, final RegionWrapper allowed, boolean unload) {
|
||||||
try {
|
try {
|
||||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
Object lock = new Object();
|
||||||
|
ForkJoinPool pool = new ForkJoinPool();
|
||||||
|
PrimitiveList<Long> chunks = new PrimitiveList<Long>(Long.class);
|
||||||
|
if (unload && Fawe.get().getMainThread() != Thread.currentThread()) unload(allowed, chunks);
|
||||||
|
Thread operation = new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Object value) {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.wait();
|
||||||
|
}
|
||||||
synchronized (RegionFileCache.class) {
|
synchronized (RegionFileCache.class) {
|
||||||
ArrayDeque<net.minecraft.server.v1_12_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_12_R1.Chunk> iter = provider.a().iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
net.minecraft.server.v1_12_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_12_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();
|
whileLocked.run();
|
||||||
// Load the chunks again
|
|
||||||
if (unload) {
|
|
||||||
for (net.minecraft.server.v1_12_R1.Chunk chunk : chunks) {
|
|
||||||
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
|
||||||
if (chunk != null) {
|
|
||||||
sendChunk(chunk, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
|
@Override
|
||||||
|
public void run(Object value) {
|
||||||
|
try {
|
||||||
|
synchronized (RegionFileCache.class) {
|
||||||
|
operation.start(); // Async
|
||||||
|
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
|
if (unload) unload(allowed, chunks);
|
||||||
|
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();
|
||||||
|
pool.submit(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
regionFile.c();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
|
}
|
||||||
|
synchronized (lock) {
|
||||||
|
lock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
operation.join();
|
||||||
|
|
||||||
|
new TaskBuilder().syncWhenFree(new TaskBuilder.SplitTask(5) {
|
||||||
|
@Override
|
||||||
|
public Object exec(Object previous) {
|
||||||
|
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
|
for (long pos : chunks) {
|
||||||
|
int x = (int) pos;
|
||||||
|
int z = (int) (pos >> 32);
|
||||||
|
net.minecraft.server.v1_12_R1.Chunk chunk = provider.getOrLoadChunkAt(x, z);
|
||||||
|
if (chunk != null) {
|
||||||
|
PlayerChunk pc = getPlayerChunk(nmsWorld, x, z);
|
||||||
|
sendChunk(pc, chunk, 0);
|
||||||
|
}
|
||||||
|
split();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).buildAsync();
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -474,7 +570,7 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
|||||||
public void sendChunk(int x, int z, int bitMask) {
|
public void sendChunk(int x, int z, int bitMask) {
|
||||||
net.minecraft.server.v1_12_R1.Chunk chunk = getCachedChunk(getWorld(), x, z);
|
net.minecraft.server.v1_12_R1.Chunk chunk = getCachedChunk(getWorld(), x, z);
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
sendChunk(chunk, bitMask);
|
sendChunk(getPlayerChunk((WorldServer) chunk.getWorld(), chunk.locX, chunk.locZ), chunk, bitMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -532,28 +628,32 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refreshChunk(FaweChunk fc) {
|
public void refreshChunk(FaweChunk fc) {
|
||||||
net.minecraft.server.v1_12_R1.Chunk chunk = getCachedChunk(getWorld(), fc.getX(), fc.getZ());
|
sendChunk(fc.getX(), fc.getZ(), fc.getBitMask());
|
||||||
if (chunk != null) {
|
|
||||||
sendChunk(chunk, fc.getBitMask());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendChunk(net.minecraft.server.v1_12_R1.Chunk nmsChunk, int mask) {
|
private PlayerChunk getPlayerChunk(WorldServer w, int cx, int cz) {
|
||||||
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
|
||||||
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||||
PlayerChunk playerChunk = chunkMap.getChunk(nmsChunk.locX, nmsChunk.locZ);
|
PlayerChunk playerChunk = chunkMap.getChunk(cx, cz);
|
||||||
if (playerChunk == null) {
|
if (playerChunk == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
if (playerChunk.c.isEmpty()) {
|
if (playerChunk.c.isEmpty()) {
|
||||||
return;
|
return null;
|
||||||
|
}
|
||||||
|
return playerChunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean sendChunk(PlayerChunk playerChunk, net.minecraft.server.v1_12_R1.Chunk nmsChunk, int mask) {
|
||||||
|
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
||||||
|
if (playerChunk == null) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
if (mask == 0) {
|
if (mask == 0) {
|
||||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65535);
|
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65535);
|
||||||
for (EntityPlayer player : playerChunk.c) {
|
for (EntityPlayer player : playerChunk.c) {
|
||||||
player.playerConnection.sendPacket(packet);
|
player.playerConnection.sendPacket(packet);
|
||||||
}
|
}
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
// Send chunks
|
// Send chunks
|
||||||
boolean empty = false;
|
boolean empty = false;
|
||||||
@ -582,6 +682,7 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasEntities(net.minecraft.server.v1_12_R1.Chunk nmsChunk) {
|
public boolean hasEntities(net.minecraft.server.v1_12_R1.Chunk nmsChunk) {
|
||||||
|
@ -4,6 +4,7 @@ import com.boydti.fawe.FaweCache;
|
|||||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
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.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.MathMan;
|
import com.boydti.fawe.util.MathMan;
|
||||||
@ -15,11 +16,13 @@ import com.sk89q.jnbt.Tag;
|
|||||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
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.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -28,6 +31,7 @@ import net.minecraft.server.v1_7_R4.Block;
|
|||||||
import net.minecraft.server.v1_7_R4.Chunk;
|
import net.minecraft.server.v1_7_R4.Chunk;
|
||||||
import net.minecraft.server.v1_7_R4.ChunkCoordIntPair;
|
import net.minecraft.server.v1_7_R4.ChunkCoordIntPair;
|
||||||
import net.minecraft.server.v1_7_R4.ChunkPosition;
|
import net.minecraft.server.v1_7_R4.ChunkPosition;
|
||||||
|
import net.minecraft.server.v1_7_R4.ChunkProviderServer;
|
||||||
import net.minecraft.server.v1_7_R4.ChunkSection;
|
import net.minecraft.server.v1_7_R4.ChunkSection;
|
||||||
import net.minecraft.server.v1_7_R4.Entity;
|
import net.minecraft.server.v1_7_R4.Entity;
|
||||||
import net.minecraft.server.v1_7_R4.EntityPlayer;
|
import net.minecraft.server.v1_7_R4.EntityPlayer;
|
||||||
@ -42,6 +46,8 @@ import net.minecraft.server.v1_7_R4.NBTTagCompound;
|
|||||||
import net.minecraft.server.v1_7_R4.NibbleArray;
|
import net.minecraft.server.v1_7_R4.NibbleArray;
|
||||||
import net.minecraft.server.v1_7_R4.PacketPlayOutMapChunk;
|
import net.minecraft.server.v1_7_R4.PacketPlayOutMapChunk;
|
||||||
import net.minecraft.server.v1_7_R4.PlayerChunkMap;
|
import net.minecraft.server.v1_7_R4.PlayerChunkMap;
|
||||||
|
import net.minecraft.server.v1_7_R4.RegionFile;
|
||||||
|
import net.minecraft.server.v1_7_R4.RegionFileCache;
|
||||||
import net.minecraft.server.v1_7_R4.ServerNBTManager;
|
import net.minecraft.server.v1_7_R4.ServerNBTManager;
|
||||||
import net.minecraft.server.v1_7_R4.TileEntity;
|
import net.minecraft.server.v1_7_R4.TileEntity;
|
||||||
import net.minecraft.server.v1_7_R4.WorldManager;
|
import net.minecraft.server.v1_7_R4.WorldManager;
|
||||||
@ -120,6 +126,74 @@ public class BukkitQueue17 extends BukkitQueue_0<net.minecraft.server.v1_7_R4.Ch
|
|||||||
nmsChunk.mustSave = true;
|
nmsChunk.mustSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setMCA(Runnable whileLocked, RegionWrapper allowed, boolean unload) {
|
||||||
|
try {
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
|
@Override
|
||||||
|
public void run(Object value) {
|
||||||
|
try {
|
||||||
|
synchronized (RegionFileCache.class) {
|
||||||
|
ArrayDeque<Chunk> chunks = new ArrayDeque<>();
|
||||||
|
World world = getWorld();
|
||||||
|
world.setKeepSpawnInMemory(false);
|
||||||
|
ChunkProviderServer provider = nmsWorld.chunkProviderServer;
|
||||||
|
if (unload) { // Unload chunks
|
||||||
|
boolean autoSave = world.isAutoSave();
|
||||||
|
world.setAutoSave(true);
|
||||||
|
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<Chunk> iter = provider.a().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Chunk chunk = iter.next();
|
||||||
|
int cx = chunk.locX;
|
||||||
|
int cz = chunk.locZ;
|
||||||
|
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
||||||
|
provider.unloadQueue.add(ChunkCoordIntPair.a(chunk.locX, chunk.locZ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 50 && !provider.getName().endsWith(" 0"); i++) provider.unloadChunks();
|
||||||
|
world.setAutoSave(autoSave);
|
||||||
|
}
|
||||||
|
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 (Chunk chunk : chunks) {
|
||||||
|
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
||||||
|
if (chunk != null) {
|
||||||
|
provider.chunks.put(ChunkCoordIntPair.a(chunk.locX, chunk.locZ), chunk);
|
||||||
|
sendChunk(chunk, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||||
if (biome != null) {
|
if (biome != null) {
|
||||||
|
@ -4,6 +4,7 @@ import com.boydti.fawe.FaweCache;
|
|||||||
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
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.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.MathMan;
|
import com.boydti.fawe.util.MathMan;
|
||||||
@ -15,9 +16,11 @@ import com.sk89q.jnbt.Tag;
|
|||||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
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.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -25,6 +28,8 @@ import java.util.UUID;
|
|||||||
import net.minecraft.server.v1_8_R3.Block;
|
import net.minecraft.server.v1_8_R3.Block;
|
||||||
import net.minecraft.server.v1_8_R3.BlockPosition;
|
import net.minecraft.server.v1_8_R3.BlockPosition;
|
||||||
import net.minecraft.server.v1_8_R3.Chunk;
|
import net.minecraft.server.v1_8_R3.Chunk;
|
||||||
|
import net.minecraft.server.v1_8_R3.ChunkCoordIntPair;
|
||||||
|
import net.minecraft.server.v1_8_R3.ChunkProviderServer;
|
||||||
import net.minecraft.server.v1_8_R3.ChunkSection;
|
import net.minecraft.server.v1_8_R3.ChunkSection;
|
||||||
import net.minecraft.server.v1_8_R3.Entity;
|
import net.minecraft.server.v1_8_R3.Entity;
|
||||||
import net.minecraft.server.v1_8_R3.EntityPlayer;
|
import net.minecraft.server.v1_8_R3.EntityPlayer;
|
||||||
@ -40,6 +45,8 @@ import net.minecraft.server.v1_8_R3.NibbleArray;
|
|||||||
import net.minecraft.server.v1_8_R3.Packet;
|
import net.minecraft.server.v1_8_R3.Packet;
|
||||||
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
|
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
|
||||||
import net.minecraft.server.v1_8_R3.PlayerChunkMap;
|
import net.minecraft.server.v1_8_R3.PlayerChunkMap;
|
||||||
|
import net.minecraft.server.v1_8_R3.RegionFile;
|
||||||
|
import net.minecraft.server.v1_8_R3.RegionFileCache;
|
||||||
import net.minecraft.server.v1_8_R3.ServerNBTManager;
|
import net.minecraft.server.v1_8_R3.ServerNBTManager;
|
||||||
import net.minecraft.server.v1_8_R3.TileEntity;
|
import net.minecraft.server.v1_8_R3.TileEntity;
|
||||||
import net.minecraft.server.v1_8_R3.WorldData;
|
import net.minecraft.server.v1_8_R3.WorldData;
|
||||||
@ -124,6 +131,74 @@ public class BukkitQueue18R3 extends BukkitQueue_0<net.minecraft.server.v1_8_R3.
|
|||||||
nmsChunk.mustSave = true;
|
nmsChunk.mustSave = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setMCA(Runnable whileLocked, RegionWrapper allowed, boolean unload) {
|
||||||
|
try {
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
|
@Override
|
||||||
|
public void run(Object value) {
|
||||||
|
try {
|
||||||
|
synchronized (RegionFileCache.class) {
|
||||||
|
ArrayDeque<Chunk> chunks = new ArrayDeque<>();
|
||||||
|
World world = getWorld();
|
||||||
|
world.setKeepSpawnInMemory(false);
|
||||||
|
ChunkProviderServer provider = nmsWorld.chunkProviderServer;
|
||||||
|
if (unload) { // Unload chunks
|
||||||
|
boolean autoSave = world.isAutoSave();
|
||||||
|
world.setAutoSave(true);
|
||||||
|
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<Chunk> iter = provider.a().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Chunk chunk = iter.next();
|
||||||
|
int cx = chunk.locX;
|
||||||
|
int cz = chunk.locZ;
|
||||||
|
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
||||||
|
provider.unloadQueue.add(ChunkCoordIntPair.a(chunk.locX, chunk.locZ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 50 && !provider.getName().endsWith(" 0"); i++) provider.unloadChunks();
|
||||||
|
world.setAutoSave(autoSave);
|
||||||
|
}
|
||||||
|
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 (Chunk chunk : chunks) {
|
||||||
|
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
||||||
|
if (chunk != null) {
|
||||||
|
provider.chunks.put(ChunkCoordIntPair.a(chunk.locX, chunk.locZ), chunk);
|
||||||
|
sendChunk(chunk, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||||
if (biome != null) {
|
if (biome != null) {
|
||||||
|
@ -37,6 +37,7 @@ import java.util.Set;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import net.minecraft.server.v1_9_R2.Block;
|
import net.minecraft.server.v1_9_R2.Block;
|
||||||
import net.minecraft.server.v1_9_R2.BlockPosition;
|
import net.minecraft.server.v1_9_R2.BlockPosition;
|
||||||
|
import net.minecraft.server.v1_9_R2.ChunkCoordIntPair;
|
||||||
import net.minecraft.server.v1_9_R2.ChunkProviderServer;
|
import net.minecraft.server.v1_9_R2.ChunkProviderServer;
|
||||||
import net.minecraft.server.v1_9_R2.ChunkSection;
|
import net.minecraft.server.v1_9_R2.ChunkSection;
|
||||||
import net.minecraft.server.v1_9_R2.DataBits;
|
import net.minecraft.server.v1_9_R2.DataBits;
|
||||||
@ -318,6 +319,7 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<net.minecraft.server.v1_9_
|
|||||||
for (net.minecraft.server.v1_9_R2.Chunk chunk : chunks) {
|
for (net.minecraft.server.v1_9_R2.Chunk chunk : chunks) {
|
||||||
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
|
provider.chunks.put(ChunkCoordIntPair.a(chunk.locX, chunk.locZ), chunk);
|
||||||
sendChunk(chunk, 0);
|
sendChunk(chunk, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,4 +164,9 @@ public class AsyncChunk implements Chunk {
|
|||||||
public boolean unload() {
|
public boolean unload() {
|
||||||
return unload(true);
|
return unload(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSlimeChunk() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import org.bukkit.Location;
|
|||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Particle;
|
import org.bukkit.Particle;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.SoundCategory;
|
||||||
import org.bukkit.TreeType;
|
import org.bukkit.TreeType;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldBorder;
|
import org.bukkit.WorldBorder;
|
||||||
@ -46,8 +47,10 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.generator.BlockPopulator;
|
import org.bukkit.generator.BlockPopulator;
|
||||||
import org.bukkit.generator.ChunkGenerator;
|
import org.bukkit.generator.ChunkGenerator;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.material.MaterialData;
|
||||||
import org.bukkit.metadata.MetadataValue;
|
import org.bukkit.metadata.MetadataValue;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.util.Consumer;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -237,6 +240,56 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
|||||||
parent.spawnParticle(particle, location, i, v, v1, v2, v3, t);
|
parent.spawnParticle(particle, location, i, v, v1, v2, v3, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEntityCount() {
|
||||||
|
return TaskManager.IMP.sync(new RunnableVal<Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer value) {
|
||||||
|
this.value = parent.getEntityCount();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTileEntityCount() {
|
||||||
|
return TaskManager.IMP.sync(new RunnableVal<Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer value) {
|
||||||
|
this.value = parent.getTileEntityCount();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTickableTileEntityCount() {
|
||||||
|
return TaskManager.IMP.sync(new RunnableVal<Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer value) {
|
||||||
|
this.value = parent.getTickableTileEntityCount();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getChunkCount() {
|
||||||
|
return TaskManager.IMP.sync(new RunnableVal<Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer value) {
|
||||||
|
this.value = parent.getChunkCount();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPlayerCount() {
|
||||||
|
return TaskManager.IMP.sync(new RunnableVal<Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer value) {
|
||||||
|
this.value = parent.getPlayerCount();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Block getBlockAt(final int x, final int y, final int z) {
|
public Block getBlockAt(final int x, final int y, final int z) {
|
||||||
return new AsyncBlock(this, queue, x, y, z);
|
return new AsyncBlock(this, queue, x, y, z);
|
||||||
@ -300,6 +353,21 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
|||||||
return getChunkAt(block.getX(), block.getZ());
|
return getChunkAt(block.getX(), block.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getChunkAtAsync(int x, int z, ChunkLoadCallback cb) {
|
||||||
|
parent.getChunkAtAsync(x, z, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getChunkAtAsync(Location location, ChunkLoadCallback cb) {
|
||||||
|
parent.getChunkAtAsync(location, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getChunkAtAsync(Block block, ChunkLoadCallback cb) {
|
||||||
|
parent.getChunkAtAsync(block, cb);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isChunkLoaded(Chunk chunk) {
|
public boolean isChunkLoaded(Chunk chunk) {
|
||||||
return chunk.isLoaded();
|
return chunk.isLoaded();
|
||||||
@ -746,6 +814,26 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function) throws IllegalArgumentException {
|
||||||
|
return TaskManager.IMP.sync(new RunnableVal<T>() {
|
||||||
|
@Override
|
||||||
|
public void run(T value) {
|
||||||
|
this.value = parent.spawn(location, clazz, function);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FallingBlock spawnFallingBlock(Location location, MaterialData data) throws IllegalArgumentException {
|
||||||
|
return TaskManager.IMP.sync(new RunnableVal<FallingBlock>() {
|
||||||
|
@Override
|
||||||
|
public void run(FallingBlock value) {
|
||||||
|
this.value = parent.spawnFallingBlock(location, data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public FallingBlock spawnFallingBlock(Location location, Material material, byte data) throws IllegalArgumentException {
|
public FallingBlock spawnFallingBlock(Location location, Material material, byte data) throws IllegalArgumentException {
|
||||||
@ -979,6 +1067,26 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playSound(Location location, Sound sound, SoundCategory category, float volume, float pitch) {
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
|
@Override
|
||||||
|
public void run(Object value) {
|
||||||
|
parent.playSound(location, sound, category, volume, pitch);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void playSound(Location location, String sound, SoundCategory category, float volume, float pitch) {
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
|
@Override
|
||||||
|
public void run(Object value) {
|
||||||
|
parent.playSound(location, sound, category, volume, pitch);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getGameRules() {
|
public String[] getGameRules() {
|
||||||
return parent.getGameRules();
|
return parent.getGameRules();
|
||||||
|
@ -14,12 +14,15 @@ import com.sk89q.jnbt.LongTag;
|
|||||||
import com.sk89q.jnbt.ShortTag;
|
import com.sk89q.jnbt.ShortTag;
|
||||||
import com.sk89q.jnbt.StringTag;
|
import com.sk89q.jnbt.StringTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.blocks.BaseItem;
|
import com.sk89q.worldedit.blocks.BaseItem;
|
||||||
import com.sk89q.worldedit.blocks.BlockType;
|
import com.sk89q.worldedit.blocks.BlockType;
|
||||||
import com.sk89q.worldedit.blocks.ImmutableBlock;
|
import com.sk89q.worldedit.blocks.ImmutableBlock;
|
||||||
import com.sk89q.worldedit.blocks.ImmutableDatalessBlock;
|
import com.sk89q.worldedit.blocks.ImmutableDatalessBlock;
|
||||||
import com.sk89q.worldedit.blocks.ImmutableNBTBlock;
|
import com.sk89q.worldedit.blocks.ImmutableNBTBlock;
|
||||||
|
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||||
|
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
@ -118,6 +121,13 @@ public class FaweCache {
|
|||||||
return getCombined(block.getId(), block.getData());
|
return getCombined(block.getId(), block.getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final BaseBlock getBlock(String block, boolean allAllowed, boolean allowNoData) throws InputParseException {
|
||||||
|
ParserContext context = new ParserContext();
|
||||||
|
context.setRestricted(!allAllowed);
|
||||||
|
context.setPreferringWildcard(allowNoData);
|
||||||
|
return WorldEdit.getInstance().getBlockFactory().parseFromInput(block, context);
|
||||||
|
}
|
||||||
|
|
||||||
public static final Color getColor(int id, int data) {
|
public static final Color getColor(int id, int data) {
|
||||||
Color exact = CACHE_COLOR[getCombined(id, data)];
|
Color exact = CACHE_COLOR[getCombined(id, data)];
|
||||||
if (exact != null) {
|
if (exact != null) {
|
||||||
|
@ -1,31 +1,32 @@
|
|||||||
package com.boydti.fawe.command;
|
package com.boydti.fawe.command;
|
||||||
|
|
||||||
import com.boydti.fawe.Fawe;
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.FaweAPI;
|
||||||
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.NBTStreamer;
|
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAClipboard;
|
import com.boydti.fawe.jnbt.anvil.MCAClipboard;
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAFile;
|
import com.boydti.fawe.jnbt.anvil.MCAFile;
|
||||||
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.MCAFilterCounter;
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAQueue;
|
import com.boydti.fawe.jnbt.anvil.MCAQueue;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.filters.CountFilter;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.filters.CountIdFilter;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.filters.DeleteUninhabitedFilter;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.filters.MappedReplacePatternFilter;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.filters.RemoveLayerFilter;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.filters.ReplacePatternFilter;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.filters.ReplaceSimpleFilter;
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
import com.boydti.fawe.object.FaweQueue;
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
import com.boydti.fawe.object.RegionWrapper;
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
|
||||||
import com.boydti.fawe.object.RunnableVal2;
|
|
||||||
import com.boydti.fawe.object.RunnableVal4;
|
import com.boydti.fawe.object.RunnableVal4;
|
||||||
import com.boydti.fawe.object.mask.FaweBlockMatcher;
|
import com.boydti.fawe.object.mask.FaweBlockMatcher;
|
||||||
import com.boydti.fawe.object.number.MutableLong;
|
|
||||||
import com.boydti.fawe.util.ArrayUtil;
|
|
||||||
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;
|
||||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.MutableBlockVector;
|
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
@ -41,15 +42,12 @@ 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.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.io.RandomAccessFile;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
@ -69,16 +67,70 @@ public class AnvilCommands {
|
|||||||
this.worldEdit = worldEdit;
|
this.worldEdit = worldEdit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run safely on an unloaded world (no selection)
|
||||||
|
* @param player
|
||||||
|
* @param folder
|
||||||
|
* @param filter
|
||||||
|
* @param <G>
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <G, T extends MCAFilter<G>> T runWithWorld(Player player, String folder, T filter) {
|
||||||
|
if (FaweAPI.getWorld(folder) != null) {
|
||||||
|
BBC.WORLD_IS_LOADED.send(player);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
|
||||||
|
MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
|
||||||
|
return queue.filterWorld(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run safely on an existing world within a selection
|
||||||
|
* @param player
|
||||||
|
* @param editSession
|
||||||
|
* @param selection
|
||||||
|
* @param filter
|
||||||
|
* @param <G>
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <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(
|
@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",
|
help = "Replace all blocks in the selection with another\n" +
|
||||||
|
"The -d flag disabled wildcard data matching\n",
|
||||||
|
flags = "df",
|
||||||
min = 2,
|
min = 2,
|
||||||
max = 4
|
max = 4
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.replaceall")
|
@CommandPermissions("worldedit.anvil.replaceall")
|
||||||
public void replaceAll(Player player, EditSession editSession, String folder, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException {
|
public void replaceAll(Player player, String folder, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException {
|
||||||
final FaweBlockMatcher matchFrom;
|
final FaweBlockMatcher matchFrom;
|
||||||
if (from == null) {
|
if (from == null) {
|
||||||
matchFrom = FaweBlockMatcher.NOT_AIR;
|
matchFrom = FaweBlockMatcher.NOT_AIR;
|
||||||
@ -89,15 +141,9 @@ public class AnvilCommands {
|
|||||||
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData);
|
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData);
|
||||||
}
|
}
|
||||||
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");
|
ReplaceSimpleFilter filter = new ReplaceSimpleFilter(matchFrom, matchTo);
|
||||||
MCAQueue queue = new MCAQueue(folder, root, true);
|
ReplaceSimpleFilter result = runWithWorld(player, folder, filter);
|
||||||
MCAFilterCounter counter = queue.filterWorld(new MCAFilterCounter() {
|
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
@Override
|
|
||||||
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong ignore) {
|
|
||||||
if (matchFrom.apply(block)) matchTo.apply(block);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(counter.getTotal()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
@ -108,75 +154,10 @@ public class AnvilCommands {
|
|||||||
max = 3
|
max = 3
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.deleteallold")
|
@CommandPermissions("worldedit.anvil.deleteallold")
|
||||||
public void deleteAllOld(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileAgeMillis) throws WorldEditException {
|
public void deleteAllOld(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileAgeMillis, @Switch('f') boolean force) throws WorldEditException {
|
||||||
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
|
DeleteUninhabitedFilter filter = new DeleteUninhabitedFilter(fileAgeMillis, inhabitedTicks);
|
||||||
MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
|
DeleteUninhabitedFilter result = runWithWorld(player, folder, filter);
|
||||||
MCAFilterCounter result = queue.filterWorld(new MCAFilterCounter() {
|
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
@Override
|
|
||||||
public MCAFile applyFile(MCAFile mca) {
|
|
||||||
File file = mca.getFile();
|
|
||||||
try {
|
|
||||||
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
|
||||||
long creation = attr.creationTime().toMillis();
|
|
||||||
long modified = attr.lastModifiedTime().toMillis();
|
|
||||||
if (modified - creation < fileAgeMillis && modified > creation) {
|
|
||||||
mca.setDeleted(true);
|
|
||||||
get().add(512 * 512 * 256);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
} catch (IOException | UnsupportedOperationException ignore) {}
|
|
||||||
try {
|
|
||||||
ForkJoinPool pool = new ForkJoinPool();
|
|
||||||
mca.init();
|
|
||||||
mca.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
|
||||||
@Override
|
|
||||||
public void run(Integer x, Integer z, Integer offset, Integer size) {
|
|
||||||
try {
|
|
||||||
byte[] bytes = mca.getChunkCompressedBytes(offset);
|
|
||||||
if (bytes == null) return;
|
|
||||||
Runnable task = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
mca.streamChunk(offset, new RunnableVal<NBTStreamer>() {
|
|
||||||
@Override
|
|
||||||
public void run(NBTStreamer value) {
|
|
||||||
value.addReader(".Level.InhabitedTime", new RunnableVal2<Integer, Long>() {
|
|
||||||
@Override
|
|
||||||
public void run(Integer index, Long value) {
|
|
||||||
if (value <= inhabitedTicks) {
|
|
||||||
MCAChunk chunk = new MCAChunk(queue, x, z);
|
|
||||||
chunk.setDeleted(true);
|
|
||||||
synchronized (mca) {
|
|
||||||
mca.setChunk(chunk);
|
|
||||||
}
|
|
||||||
get().add(16 * 16 * 256);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
pool.submit(task);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
|
||||||
mca.close(pool);
|
|
||||||
pool.shutdown();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
@ -189,62 +170,11 @@ public class AnvilCommands {
|
|||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.replaceall")
|
@CommandPermissions("worldedit.anvil.replaceall")
|
||||||
public void replaceAllPattern(Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException {
|
public void replaceAllPattern(Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException {
|
||||||
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
|
MCAFilterCounter filter;
|
||||||
MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
|
|
||||||
MCAFilterCounter counter;
|
|
||||||
if (useMap) {
|
if (useMap) {
|
||||||
List<String> split = StringMan.split(from, ',');
|
|
||||||
if (to instanceof RandomPattern) {
|
if (to instanceof RandomPattern) {
|
||||||
Pattern[] patterns = ((RandomPattern) to).getPatterns().toArray(new Pattern[0]);
|
List<String> split = StringMan.split(from, ',');
|
||||||
if (patterns.length == split.size()) {
|
filter = new MappedReplacePatternFilter(from, (RandomPattern) to, useData);
|
||||||
Pattern[] map = new Pattern[Character.MAX_VALUE + 1];
|
|
||||||
for (int i = 0; i < split.size(); i++) {
|
|
||||||
Pattern pattern = patterns[i];
|
|
||||||
String arg = split.get(i);
|
|
||||||
ArrayList<BaseBlock> blocks = new ArrayList<BaseBlock>();
|
|
||||||
for (String arg2 : arg.split(",")) {
|
|
||||||
BaseBlock block = worldEdit.getBlock(player, arg, true);
|
|
||||||
if (!useData && !arg2.contains(":")) {
|
|
||||||
block = new BaseBlock(block.getId(), -1);
|
|
||||||
}
|
|
||||||
blocks.add(block);
|
|
||||||
}
|
|
||||||
for (BaseBlock block : blocks) {
|
|
||||||
if (block.getData() != -1) {
|
|
||||||
int combined = FaweCache.getCombined(block);
|
|
||||||
map[combined] = pattern;
|
|
||||||
} else {
|
|
||||||
for (int data = 0; data < 16; data++) {
|
|
||||||
int combined = FaweCache.getCombined(block.getId(), data);
|
|
||||||
map[combined] = pattern;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
counter = queue.filterWorld(new MCAFilterCounter() {
|
|
||||||
private final MutableBlockVector mutable = new MutableBlockVector(0, 0, 0);
|
|
||||||
@Override
|
|
||||||
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong ignore) {
|
|
||||||
int id = block.getId();
|
|
||||||
int data = FaweCache.hasData(id) ? block.getData() : 0;
|
|
||||||
int combined = FaweCache.getCombined(id, data);
|
|
||||||
Pattern p = map[combined];
|
|
||||||
if (p != null) {
|
|
||||||
BaseBlock newBlock = p.apply(x, y, z);
|
|
||||||
int currentId = block.getId();
|
|
||||||
if (FaweCache.hasNBT(currentId)) {
|
|
||||||
block.setNbtData(null);
|
|
||||||
}
|
|
||||||
block.setId(newBlock.getId());
|
|
||||||
block.setData(newBlock.getData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
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;
|
return;
|
||||||
@ -254,27 +184,12 @@ public class AnvilCommands {
|
|||||||
if (from == null) {
|
if (from == null) {
|
||||||
matchFrom = FaweBlockMatcher.NOT_AIR;
|
matchFrom = FaweBlockMatcher.NOT_AIR;
|
||||||
} else {
|
} else {
|
||||||
if (from.contains(":")) {
|
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData || from.contains(":"));
|
||||||
useData = true; //override d flag, if they specified data they want it
|
|
||||||
}
|
|
||||||
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData);
|
|
||||||
}
|
}
|
||||||
counter = queue.filterWorld(new MCAFilterCounter() {
|
filter = new ReplacePatternFilter(matchFrom, to);
|
||||||
@Override
|
|
||||||
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong ignore) {
|
|
||||||
if (matchFrom.apply(block)) {
|
|
||||||
BaseBlock newBlock = to.apply(x, y, z);
|
|
||||||
int currentId = block.getId();
|
|
||||||
if (FaweCache.hasNBT(currentId)) {
|
|
||||||
block.setNbtData(null);
|
|
||||||
}
|
|
||||||
block.setId(newBlock.getId());
|
|
||||||
block.setData(newBlock.getData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(counter.getTotal()));
|
MCAFilterCounter result = runWithWorld(player, folder, filter);
|
||||||
|
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
@ -285,70 +200,96 @@ public class AnvilCommands {
|
|||||||
min = 2,
|
min = 2,
|
||||||
max = 3
|
max = 3
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.countallstone")
|
@CommandPermissions("worldedit.anvil.countall")
|
||||||
public void countAll(Player player, EditSession editSession, String folder, String arg, @Switch('d') boolean useData) throws WorldEditException {
|
public void countAll(Player player, EditSession editSession, String folder, String arg, @Switch('d') boolean useData) throws WorldEditException {
|
||||||
File root = new File(folder + File.separator + "region");
|
|
||||||
MCAQueue queue = new MCAQueue(folder, root, true);
|
|
||||||
if (arg.contains(":")) {
|
|
||||||
useData = true; //override d flag, if they specified data they want it
|
|
||||||
}
|
|
||||||
Set<BaseBlock> searchBlocks = worldEdit.getBlocks(player, arg, true);
|
Set<BaseBlock> searchBlocks = worldEdit.getBlocks(player, arg, true);
|
||||||
final boolean[] allowedId = new boolean[FaweCache.getId(Character.MAX_VALUE)];
|
|
||||||
for (BaseBlock block : searchBlocks) {
|
|
||||||
allowedId[block.getId()] = true;
|
|
||||||
}
|
|
||||||
MCAFilterCounter filter;
|
MCAFilterCounter filter;
|
||||||
if (useData) { // Optimize for both cases
|
if (useData || arg.contains(":")) { // Optimize for both cases
|
||||||
final boolean[] allowed = new boolean[Character.MAX_VALUE];
|
CountFilter counter = new CountFilter();
|
||||||
for (BaseBlock block : searchBlocks) {
|
searchBlocks.forEach(counter::addBlock);
|
||||||
allowed[FaweCache.getCombined(block)] = true;
|
filter = counter;
|
||||||
}
|
|
||||||
filter = new MCAFilterCounter() {
|
|
||||||
@Override
|
|
||||||
public MCAChunk applyChunk(MCAChunk chunk, MutableLong count) {
|
|
||||||
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
|
||||||
byte[] ids = chunk.ids[layer];
|
|
||||||
if (ids == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
byte[] datas = chunk.data[layer];
|
|
||||||
for (int i = 0; i < ids.length; i++) {
|
|
||||||
int id = ids[i] & 0xFF;
|
|
||||||
if (!allowedId[id]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int combined = (id) << 4;
|
|
||||||
if (FaweCache.hasData(id)) {
|
|
||||||
combined += chunk.getNibble(i, datas);
|
|
||||||
}
|
|
||||||
if (allowed[combined]) {
|
|
||||||
count.increment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
filter = new MCAFilterCounter() {
|
CountIdFilter counter = new CountIdFilter();
|
||||||
@Override
|
searchBlocks.forEach(counter::addBlock);
|
||||||
public MCAChunk applyChunk(MCAChunk chunk, MutableLong count) {
|
filter = counter;
|
||||||
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
}
|
||||||
byte[] ids = chunk.ids[layer];
|
MCAFilterCounter result = runWithWorld(player, folder, filter);
|
||||||
if (ids != null) {
|
if (result != null) player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(result.getTotal()));
|
||||||
for (byte i : ids) {
|
}
|
||||||
if (allowedId[i & 0xFF]) {
|
|
||||||
count.increment();
|
@Command(
|
||||||
|
aliases = {"clear", "unset"},
|
||||||
|
desc = "Clear the chunks in a selection (delete without defrag)"
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.anvil.replaceall")
|
||||||
|
public void unset(Player player, EditSession editSession, @Selection Region selection) throws WorldEditException {
|
||||||
|
Vector bot = selection.getMinimumPoint();
|
||||||
|
Vector top = selection.getMaximumPoint();
|
||||||
|
RegionWrapper region = new RegionWrapper(bot, top);
|
||||||
|
|
||||||
|
MCAFilterCounter filter = new MCAFilterCounter() {
|
||||||
|
@Override
|
||||||
|
public MCAFile applyFile(MCAFile file) {
|
||||||
|
int X = file.getX();
|
||||||
|
int Z = file.getZ();
|
||||||
|
int bcx = X << 5;
|
||||||
|
int bcz = Z << 5;
|
||||||
|
int bx = X << 9;
|
||||||
|
int bz = Z << 9;
|
||||||
|
if (region.isIn(bx, bz) && region.isIn(bx + 511, bz + 511)) {
|
||||||
|
file.setDeleted(true);
|
||||||
|
get().add(512 * 512 * 256);
|
||||||
|
} else if (region.isInMCA(X, Z)){
|
||||||
|
file.init();
|
||||||
|
final byte[] empty = new byte[4];
|
||||||
|
RandomAccessFile raf = file.getRandomAccessFile();
|
||||||
|
file.forEachChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer cx, Integer cz, Integer offset, Integer size) {
|
||||||
|
if (region.isInChunk(bcx + cx, bcz + cz)) {
|
||||||
|
int index = ((cx & 31) << 2) + ((cz & 31) << 7);
|
||||||
|
try {
|
||||||
|
raf.seek(index);
|
||||||
|
raf.write(empty);
|
||||||
|
get().add(16 * 16 * 256);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return null;
|
file.clear();
|
||||||
}
|
}
|
||||||
};
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MCAFilterCounter result = runWithSelection(player, editSession, selection, filter);
|
||||||
|
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = {"count"},
|
||||||
|
usage = "<ids>",
|
||||||
|
desc = "Count blocks in a selection",
|
||||||
|
flags = "d",
|
||||||
|
min = 1,
|
||||||
|
max = 2
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.anvil.count")
|
||||||
|
public void count(Player player, EditSession editSession, @Selection Region selection, String arg, @Switch('d') boolean useData) throws WorldEditException {
|
||||||
|
Set<BaseBlock> searchBlocks = worldEdit.getBlocks(player, arg, true);
|
||||||
|
MCAFilterCounter filter;
|
||||||
|
if (useData || arg.contains(":")) { // Optimize for both cases
|
||||||
|
CountFilter counter = new CountFilter();
|
||||||
|
searchBlocks.forEach(counter::addBlock);
|
||||||
|
filter = counter;
|
||||||
|
} else {
|
||||||
|
CountIdFilter counter = new CountIdFilter();
|
||||||
|
searchBlocks.forEach(counter::addBlock);
|
||||||
|
filter = counter;
|
||||||
}
|
}
|
||||||
queue.filterWorld(filter);
|
MCAFilterCounter result = runWithSelection(player, editSession, selection, filter);
|
||||||
player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(filter.getTotal()));
|
if (result != null) player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(result.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
@ -426,31 +367,8 @@ public class AnvilCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
@Command(
|
||||||
aliases = {"replace"},
|
aliases = {"replace", "r"},
|
||||||
usage = "[from-block] <to-block>",
|
usage = "[from-block] <to-block>",
|
||||||
desc = "Replace all blocks in the selection with another"
|
desc = "Replace all blocks in the selection with another"
|
||||||
)
|
)
|
||||||
@ -460,23 +378,45 @@ public class AnvilCommands {
|
|||||||
if (from == null) {
|
if (from == null) {
|
||||||
matchFrom = FaweBlockMatcher.NOT_AIR;
|
matchFrom = FaweBlockMatcher.NOT_AIR;
|
||||||
} else {
|
} else {
|
||||||
if (from.contains(":")) {
|
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData || 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));
|
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
|
||||||
MCAFilterCounter filter = runWithSelection(player, editSession, selection, new MCAFilterCounter() {
|
ReplaceSimpleFilter filter = new ReplaceSimpleFilter(matchFrom, matchTo);
|
||||||
@Override
|
MCAFilterCounter result = runWithSelection(player, editSession, selection, filter);
|
||||||
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong count) {
|
if (result != null) {
|
||||||
if (matchFrom.apply(block)) {
|
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
matchTo.apply(block);
|
}
|
||||||
count.increment();
|
}
|
||||||
}
|
|
||||||
|
@Command(
|
||||||
|
aliases = {"replacepattern", "preplace", "rp"},
|
||||||
|
usage = "[from-mask] <to-pattern>",
|
||||||
|
desc = "Replace all blocks in the selection with a pattern"
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.anvil.replace")
|
||||||
|
// Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap
|
||||||
|
public void replacePattern(Player player, EditSession editSession, @Selection Region selection, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException {
|
||||||
|
MCAFilterCounter filter;
|
||||||
|
if (useMap) {
|
||||||
|
if (to instanceof RandomPattern) {
|
||||||
|
List<String> split = StringMan.split(from, ',');
|
||||||
|
filter = new MappedReplacePatternFilter(from, (RandomPattern) to, useData);
|
||||||
|
} else {
|
||||||
|
player.print(BBC.getPrefix() + "Must be a pattern list!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
if (filter != null) {
|
final FaweBlockMatcher matchFrom;
|
||||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(filter.getTotal()));
|
if (from == null) {
|
||||||
|
matchFrom = FaweBlockMatcher.NOT_AIR;
|
||||||
|
} else {
|
||||||
|
matchFrom = FaweBlockMatcher.fromBlocks(worldEdit.getBlocks(player, from, true), useData || from.contains(":"));
|
||||||
|
}
|
||||||
|
filter = new ReplacePatternFilter(matchFrom, to);
|
||||||
|
}
|
||||||
|
MCAFilterCounter result = runWithSelection(player, editSession, selection, filter);
|
||||||
|
if (result != null) {
|
||||||
|
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,39 +432,10 @@ public class AnvilCommands {
|
|||||||
Vector max = selection.getMaximumPoint();
|
Vector max = selection.getMaximumPoint();
|
||||||
int minY = min.getBlockY();
|
int minY = min.getBlockY();
|
||||||
int maxY = max.getBlockY();
|
int maxY = max.getBlockY();
|
||||||
final int startLayer = minY >> 4;
|
RemoveLayerFilter filter = new RemoveLayerFilter(minY, maxY, id);
|
||||||
final int endLayer = maxY >> 4;
|
MCAFilterCounter result = runWithSelection(player, editSession, selection, filter);
|
||||||
MCAFilterCounter filter = runWithSelection(player, editSession, selection, new MCAFilterCounter() {
|
if (result != null) {
|
||||||
@Override
|
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
public MCAChunk applyChunk(MCAChunk chunk, MutableLong cache) {
|
|
||||||
for (int layer = startLayer; layer <= endLayer; layer++) {
|
|
||||||
byte[] ids = chunk.ids[layer];
|
|
||||||
if (ids == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int startY = Math.max(minY, layer << 4) & 15;
|
|
||||||
int endY = Math.min(maxY, 15 + (layer << 4)) & 15;
|
|
||||||
for (int y = startY; y <= endY; y++) {
|
|
||||||
int indexStart = y << 8;
|
|
||||||
int indexEnd = indexStart + 255;
|
|
||||||
for (int index = indexStart; index <= indexEnd; index++) {
|
|
||||||
if (ids[index] != id) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int y = startY; y <= endY; y++) {
|
|
||||||
int indexStart = y << 8;
|
|
||||||
int indexEnd = indexStart + 255;
|
|
||||||
ArrayUtil.fill(ids, indexStart, indexEnd + 1, (byte) 0);
|
|
||||||
}
|
|
||||||
chunk.setModified();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (filter != null) {
|
|
||||||
player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(filter.getTotal()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -601,6 +512,5 @@ public class AnvilCommands {
|
|||||||
}, copyRegion, false);
|
}, copyRegion, false);
|
||||||
}
|
}
|
||||||
}, pasteRegion, true);
|
}, pasteRegion, true);
|
||||||
player.print("Done!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -106,6 +106,8 @@ public enum BBC {
|
|||||||
SELECTION_SHIFT("Region shifted", "WorldEdit.Selection"),
|
SELECTION_SHIFT("Region shifted", "WorldEdit.Selection"),
|
||||||
SELECTION_CLEARED("Selection cleared", "WorldEdit.Selection"),
|
SELECTION_CLEARED("Selection cleared", "WorldEdit.Selection"),
|
||||||
|
|
||||||
|
WORLD_IS_LOADED("The world shouldn't be in use when executing. Unload the world, or use use -f to override (save first)", "WorldEdit.Anvil"),
|
||||||
|
|
||||||
BRUSH_RESET("Reset your brush.", "WorldEdit.Brush"),
|
BRUSH_RESET("Reset your brush.", "WorldEdit.Brush"),
|
||||||
BRUSH_NONE("You aren't holding a brush!", "WorldEdit.Brush"),
|
BRUSH_NONE("You aren't holding a brush!", "WorldEdit.Brush"),
|
||||||
BRUSH_SCROLL_ACTION_SET("Set scroll action to %s0", "WorldEdit.Brush"),
|
BRUSH_SCROLL_ACTION_SET("Set scroll action to %s0", "WorldEdit.Brush"),
|
||||||
|
@ -72,6 +72,7 @@ public class Settings extends Config {
|
|||||||
"Put any minecraft or mod jars for FAWE to be aware of block textures",
|
"Put any minecraft or mod jars for FAWE to be aware of block textures",
|
||||||
})
|
})
|
||||||
public String TEXTURES = "textures";
|
public String TEXTURES = "textures";
|
||||||
|
public String HEIGHTMAP = "heightmap";
|
||||||
public String HISTORY = "history";
|
public String HISTORY = "history";
|
||||||
public String CLIPBOARD = "clipboard";
|
public String CLIPBOARD = "clipboard";
|
||||||
@Comment("Each player has their own sub directory for schematics")
|
@Comment("Each player has their own sub directory for schematics")
|
||||||
@ -281,15 +282,22 @@ public class Settings extends Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Experimental options, use at your own risk",
|
"Experimental options, use at your own risk"
|
||||||
" - Apparently that wasn't enough, need an all caps warning?",
|
|
||||||
" - DO NOT USE IF YOU ARE CLUELESS!"
|
|
||||||
})
|
})
|
||||||
public static class EXPERIMENTAL {
|
public static class EXPERIMENTAL {
|
||||||
@Comment({
|
@Comment({
|
||||||
"Directly modify the region files.",
|
"[UNSAFE] Directly modify the region files. (OBSOLETE - USE ANVIL COMMANDS)",
|
||||||
|
" - IMPROPER USE CAN CAUSE WORLD CORRUPTION!",
|
||||||
})
|
})
|
||||||
public boolean ANVIL_QUEUE_MODE = false;
|
public boolean ANVIL_QUEUE_MODE = false;
|
||||||
|
@Comment({
|
||||||
|
"[SAFE] Dynamically increase the number of chunks rendered",
|
||||||
|
" - Requires Paper: ci.destroystokyo.com/job/PaperSpigot/",
|
||||||
|
" - Set your server view distance to 1 (spigot.yml, server.properties)",
|
||||||
|
" - Based on tps and player movement",
|
||||||
|
" - Please provide feedback",
|
||||||
|
})
|
||||||
|
public boolean DYNAMIC_CHUNK_RENDERING = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class WEB {
|
public static class WEB {
|
||||||
|
@ -16,6 +16,10 @@ public class NBTStreamer {
|
|||||||
readers = new HashMap<>();
|
readers = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the entire stream and runs the applicable readers
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void readFully() throws IOException {
|
public void readFully() throws IOException {
|
||||||
is.readNamedTagLazy(new RunnableVal2<String, RunnableVal2>() {
|
is.readNamedTagLazy(new RunnableVal2<String, RunnableVal2>() {
|
||||||
@Override
|
@Override
|
||||||
@ -26,6 +30,12 @@ public class NBTStreamer {
|
|||||||
is.close();
|
is.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the stream until all readers have been used<br>
|
||||||
|
* - Use readFully if you expect a reader to appear more than once
|
||||||
|
* - Can exit early without having reading the entire file
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void readQuick() throws IOException {
|
public void readQuick() throws IOException {
|
||||||
try {
|
try {
|
||||||
is.readNamedTagLazy(new RunnableVal2<String, RunnableVal2>() {
|
is.readNamedTagLazy(new RunnableVal2<String, RunnableVal2>() {
|
||||||
|
@ -83,6 +83,8 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
|
|||||||
try {
|
try {
|
||||||
if (randomVariation) {
|
if (randomVariation) {
|
||||||
return new RandomTextureUtil(textureUtil);
|
return new RandomTextureUtil(textureUtil);
|
||||||
|
} else if (textureUtil instanceof CachedTextureUtil) {
|
||||||
|
return textureUtil;
|
||||||
} else {
|
} else {
|
||||||
return new CachedTextureUtil(textureUtil);
|
return new CachedTextureUtil(textureUtil);
|
||||||
}
|
}
|
||||||
@ -807,8 +809,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
|
|||||||
@Override
|
@Override
|
||||||
public MCAChunk write(MCAChunk chunk, int csx, int cex, int csz, int cez) {
|
public MCAChunk write(MCAChunk chunk, int csx, int cex, int csz, int cez) {
|
||||||
try {
|
try {
|
||||||
int cx = chunk.getX();
|
|
||||||
int cz = chunk.getZ();
|
|
||||||
int[] indexes = indexStore.get();
|
int[] indexes = indexStore.get();
|
||||||
for (int i = 0; i < chunk.ids.length; i++) {
|
for (int i = 0; i < chunk.ids.length; i++) {
|
||||||
byte[] idsArray = chunk.ids[i];
|
byte[] idsArray = chunk.ids[i];
|
||||||
@ -848,6 +848,27 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
|
|||||||
chunk.blockLight[layer] = new byte[2048];
|
chunk.blockLight[layer] = new byte[2048];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (waterHeight != 0) {
|
||||||
|
maxY = Math.max(maxY, waterHeight);
|
||||||
|
int maxWaterLayer = ((waterHeight + 15) >> 4);
|
||||||
|
for (int layer = 0; layer < maxWaterLayer; layer++) {
|
||||||
|
boolean fillAll = (layer << 4) + 15 <= waterHeight;
|
||||||
|
byte[] ids = chunk.ids[layer];
|
||||||
|
if (ids == null) {
|
||||||
|
chunk.ids[layer] = ids = new byte[4096];
|
||||||
|
chunk.data[layer] = new byte[2048];
|
||||||
|
chunk.skyLight[layer] = new byte[2048];
|
||||||
|
chunk.blockLight[layer] = new byte[2048];
|
||||||
|
Arrays.fill(chunk.skyLight[layer], (byte) 255);
|
||||||
|
}
|
||||||
|
if (fillAll) {
|
||||||
|
Arrays.fill(ids, waterId);
|
||||||
|
} else {
|
||||||
|
int maxIndex = maxWaterLayer << 8;
|
||||||
|
Arrays.fill(ids, 0, maxIndex, waterId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (modifiedMain) { // If the main block is modified, we can't short circuit this
|
if (modifiedMain) { // If the main block is modified, we can't short circuit this
|
||||||
for (int layer = 0; layer < fillLayers; layer++) {
|
for (int layer = 0; layer < fillLayers; layer++) {
|
||||||
byte[] layerIds = chunk.ids[layer];
|
byte[] layerIds = chunk.ids[layer];
|
||||||
@ -876,27 +897,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
|
|||||||
Arrays.fill(chunk.ids[layer], (byte) 1);
|
Arrays.fill(chunk.ids[layer], (byte) 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (waterHeight != 0) {
|
|
||||||
maxY = Math.max(maxY, waterHeight);
|
|
||||||
int maxWaterLayer = ((waterHeight + 15) >> 4);
|
|
||||||
for (int layer = 0; layer < maxWaterLayer; layer++) {
|
|
||||||
boolean fillAll = (layer << 4) + 15 <= waterHeight;
|
|
||||||
byte[] ids = chunk.ids[layer];
|
|
||||||
if (ids == null) {
|
|
||||||
chunk.ids[layer] = ids = new byte[4096];
|
|
||||||
chunk.data[layer] = new byte[2048];
|
|
||||||
chunk.skyLight[layer] = new byte[2048];
|
|
||||||
chunk.blockLight[layer] = new byte[2048];
|
|
||||||
Arrays.fill(chunk.skyLight[layer], (byte) 255);
|
|
||||||
}
|
|
||||||
if (fillAll) {
|
|
||||||
Arrays.fill(ids, waterId);
|
|
||||||
} else {
|
|
||||||
int maxIndex = maxWaterLayer << 8;
|
|
||||||
Arrays.fill(ids, 0, maxIndex, waterId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int layer = fillLayers; layer <= maxLayer; layer++) {
|
for (int layer = fillLayers; layer <= maxLayer; layer++) {
|
||||||
Arrays.fill(chunk.skyLight[layer], (byte) 255);
|
Arrays.fill(chunk.skyLight[layer], (byte) 255);
|
||||||
byte[] layerIds = chunk.ids[layer];
|
byte[] layerIds = chunk.ids[layer];
|
||||||
@ -973,7 +973,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements Extent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int chunkPair = MathMan.pair((short) cx, (short) cz);
|
int chunkPair = MathMan.pair((short) chunk.getX(), (short) chunk.getZ());
|
||||||
char[][][] localBlocks = blocks.get(chunkPair);
|
char[][][] localBlocks = blocks.get(chunkPair);
|
||||||
if (localBlocks != null) {
|
if (localBlocks != null) {
|
||||||
for (int layer = 0; layer < 16; layer++) {
|
for (int layer = 0; layer < 16; layer++) {
|
||||||
|
@ -137,6 +137,10 @@ public class MCAFile {
|
|||||||
return Z;
|
return Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RandomAccessFile getRandomAccessFile() {
|
||||||
|
return raf;
|
||||||
|
}
|
||||||
|
|
||||||
public File getFile() {
|
public File getFile() {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
@ -181,6 +185,11 @@ public class MCAFile {
|
|||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CX, CZ, OFFSET, SIZE
|
||||||
|
* @param onEach
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
public void forEachSortedChunk(RunnableVal4<Integer, Integer, Integer, Integer> onEach) throws IOException {
|
public void forEachSortedChunk(RunnableVal4<Integer, Integer, Integer, Integer> onEach) throws IOException {
|
||||||
char[] offsets = new char[(int) (raf.length() / 4096) - 2];
|
char[] offsets = new char[(int) (raf.length() / 4096) - 2];
|
||||||
Arrays.fill(offsets, Character.MAX_VALUE);
|
Arrays.fill(offsets, Character.MAX_VALUE);
|
||||||
|
@ -2,7 +2,6 @@ package com.boydti.fawe.jnbt.anvil;
|
|||||||
|
|
||||||
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.MathMan;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.ForkJoinPool;
|
||||||
@ -14,6 +13,8 @@ public abstract class MCAWriter {
|
|||||||
private final int length;
|
private final int length;
|
||||||
private final int width;
|
private final int width;
|
||||||
private final int area;
|
private final int area;
|
||||||
|
private int OX, OZ;
|
||||||
|
|
||||||
|
|
||||||
public MCAWriter(int width, int length, File regionFolder) {
|
public MCAWriter(int width, int length, File regionFolder) {
|
||||||
if (!regionFolder.exists()) {
|
if (!regionFolder.exists()) {
|
||||||
@ -37,6 +38,26 @@ public abstract class MCAWriter {
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the MCA file offset (each mca file is 512 blocks)
|
||||||
|
* - A negative value will shift the map negative
|
||||||
|
* - This only applies to generation, not block get/set
|
||||||
|
* @param mcaOX
|
||||||
|
* @param mcaOZ
|
||||||
|
*/
|
||||||
|
public void setMCAOffset(int mcaOX, int mcaOZ) {
|
||||||
|
OX = mcaOX << 9;
|
||||||
|
OZ = mcaOZ << 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOffsetX() {
|
||||||
|
return OX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOffsetZ() {
|
||||||
|
return OZ;
|
||||||
|
}
|
||||||
|
|
||||||
public final int getArea() {
|
public final int getArea() {
|
||||||
return area;
|
return area;
|
||||||
}
|
}
|
||||||
@ -79,11 +100,16 @@ public abstract class MCAWriter {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
byte[] fileBuf = new byte[1 << 16];
|
byte[] fileBuf = new byte[1 << 16];
|
||||||
for (int mcaZ = 0; mcaZ <= (length >> 9); mcaZ++) {
|
int mcaXMin = 0;
|
||||||
for (int mcaX = 0; mcaX <= (width >> 9); mcaX++) {
|
int mcaZMin = 0;
|
||||||
|
int mcaXMax = mcaXMin + width >> 9;
|
||||||
|
int mcaZMax = mcaZMin + length >> 9;
|
||||||
|
|
||||||
|
for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) {
|
||||||
|
for (int mcaX = mcaXMin; mcaX <= mcaXMax; mcaX++) {
|
||||||
final int fmcaX = mcaX;
|
final int fmcaX = mcaX;
|
||||||
final int fmcaZ = mcaZ;
|
final int fmcaZ = mcaZ;
|
||||||
File file = new File(folder, "r." + mcaX + "." + mcaZ + ".mca");
|
File file = new File(folder, "r." + (mcaX + (getOffsetX() >> 9)) + "." + (mcaZ + (getOffsetZ() >> 9)) + ".mca");
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
}
|
}
|
||||||
@ -96,7 +122,6 @@ public abstract class MCAWriter {
|
|||||||
int ecx = Math.min(scx + 31, tcx);
|
int ecx = Math.min(scx + 31, tcx);
|
||||||
int scz = bz >> 4;
|
int scz = bz >> 4;
|
||||||
int ecz = Math.min(scz + 31, tcz);
|
int ecz = Math.min(scz + 31, tcz);
|
||||||
short pair = MathMan.pairByte(mcaX, mcaZ);
|
|
||||||
for (int cz = scz; cz <= ecz; cz++) {
|
for (int cz = scz; cz <= ecz; cz++) {
|
||||||
final int csz = cz << 4;
|
final int csz = cz << 4;
|
||||||
final int cez = Math.min(csz + 15, length - 1);
|
final int cez = Math.min(csz + 15, length - 1);
|
||||||
@ -114,6 +139,9 @@ public abstract class MCAWriter {
|
|||||||
chunk.setLoc(null, fcx, fcz);
|
chunk.setLoc(null, fcx, fcz);
|
||||||
chunk = write(chunk, csx, cex, csz, cez);
|
chunk = write(chunk, csx, cex, csz, cez);
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
|
// Generation offset
|
||||||
|
chunk.setLoc(null, fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
|
||||||
|
// Compress
|
||||||
byte[] bytes = chunk.toBytes(byteStore1.get());
|
byte[] bytes = chunk.toBytes(byteStore1.get());
|
||||||
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
|
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
|
||||||
int blocks = (compressed.length + 4095) >> 12;
|
int blocks = (compressed.length + 4095) >> 12;
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.boydti.fawe.jnbt.anvil.filters;
|
||||||
|
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
|
||||||
|
import com.boydti.fawe.object.number.MutableLong;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
|
||||||
|
public class CountFilter extends MCAFilterCounter {
|
||||||
|
private final boolean[] allowedId = new boolean[FaweCache.getId(Character.MAX_VALUE)];
|
||||||
|
private final boolean[] allowed = new boolean[Character.MAX_VALUE];
|
||||||
|
|
||||||
|
public CountFilter() {}
|
||||||
|
|
||||||
|
public CountFilter addBlock(BaseBlock block) {
|
||||||
|
addBlock(block.getId(), block.getData());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CountFilter addBlock(int id, int data) {
|
||||||
|
allowedId[id] = true;
|
||||||
|
allowed[FaweCache.getCombined(id, data)] = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MCAChunk applyChunk(MCAChunk chunk, MutableLong count) {
|
||||||
|
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
||||||
|
byte[] ids = chunk.ids[layer];
|
||||||
|
if (ids == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
byte[] datas = chunk.data[layer];
|
||||||
|
for (int i = 0; i < ids.length; i++) {
|
||||||
|
int id = ids[i] & 0xFF;
|
||||||
|
if (!allowedId[id]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int combined = (id) << 4;
|
||||||
|
if (FaweCache.hasData(id)) {
|
||||||
|
combined += chunk.getNibble(i, datas);
|
||||||
|
}
|
||||||
|
if (allowed[combined]) {
|
||||||
|
count.increment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.boydti.fawe.jnbt.anvil.filters;
|
||||||
|
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
|
||||||
|
import com.boydti.fawe.object.number.MutableLong;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
|
||||||
|
public class CountIdFilter extends MCAFilterCounter {
|
||||||
|
private final boolean[] allowedId = new boolean[FaweCache.getId(Character.MAX_VALUE)];
|
||||||
|
|
||||||
|
public CountIdFilter() {}
|
||||||
|
|
||||||
|
public CountIdFilter addBlock(int id) {
|
||||||
|
allowedId[id] = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CountIdFilter addBlock(BaseBlock block) {
|
||||||
|
allowedId[block.getId()] = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MCAChunk applyChunk(MCAChunk chunk, MutableLong count) {
|
||||||
|
for (int layer = 0; layer < chunk.ids.length; layer++) {
|
||||||
|
byte[] ids = chunk.ids[layer];
|
||||||
|
if (ids != null) {
|
||||||
|
for (byte i : ids) {
|
||||||
|
if (allowedId[i & 0xFF]) {
|
||||||
|
count.increment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
package com.boydti.fawe.jnbt.anvil.filters;
|
||||||
|
|
||||||
|
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAFile;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
|
||||||
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
|
import com.boydti.fawe.object.RunnableVal2;
|
||||||
|
import com.boydti.fawe.object.RunnableVal4;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.concurrent.ForkJoinPool;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes unvisited MCA files and Chunks<br>
|
||||||
|
* - This a global filter and cannot be used a selection<br>
|
||||||
|
*/
|
||||||
|
public class DeleteUninhabitedFilter extends MCAFilterCounter {
|
||||||
|
private final long inhabitedTicks;
|
||||||
|
private final long fileAgeMillis;
|
||||||
|
|
||||||
|
public DeleteUninhabitedFilter(long fileAgeMillis, long inhabitedTicks) {
|
||||||
|
this.fileAgeMillis = fileAgeMillis;
|
||||||
|
this.inhabitedTicks = inhabitedTicks;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public MCAFile applyFile(MCAFile mca) {
|
||||||
|
File file = mca.getFile();
|
||||||
|
try {
|
||||||
|
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
|
||||||
|
long creation = attr.creationTime().toMillis();
|
||||||
|
long modified = attr.lastModifiedTime().toMillis();
|
||||||
|
if (modified - creation < fileAgeMillis && modified > creation) {
|
||||||
|
mca.setDeleted(true);
|
||||||
|
get().add(512 * 512 * 256);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (IOException | UnsupportedOperationException ignore) {}
|
||||||
|
try {
|
||||||
|
ForkJoinPool pool = new ForkJoinPool();
|
||||||
|
mca.init();
|
||||||
|
mca.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer x, Integer z, Integer offset, Integer size) {
|
||||||
|
try {
|
||||||
|
byte[] bytes = mca.getChunkCompressedBytes(offset);
|
||||||
|
if (bytes == null) return;
|
||||||
|
Runnable task = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
mca.streamChunk(offset, new RunnableVal<NBTStreamer>() {
|
||||||
|
@Override
|
||||||
|
public void run(NBTStreamer value) {
|
||||||
|
value.addReader(".Level.InhabitedTime", new RunnableVal2<Integer, Long>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer index, Long value) {
|
||||||
|
if (value <= inhabitedTicks) {
|
||||||
|
MCAChunk chunk = new MCAChunk(null, x, z);
|
||||||
|
chunk.setDeleted(true);
|
||||||
|
synchronized (mca) {
|
||||||
|
mca.setChunk(chunk);
|
||||||
|
}
|
||||||
|
get().add(16 * 16 * 256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pool.submit(task);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
|
mca.close(pool);
|
||||||
|
pool.shutdown();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
package com.boydti.fawe.jnbt.anvil.filters;
|
||||||
|
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
|
||||||
|
import com.boydti.fawe.object.number.MutableLong;
|
||||||
|
import com.boydti.fawe.util.StringMan;
|
||||||
|
import com.sk89q.worldedit.MutableBlockVector;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||||
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
|
import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MappedReplacePatternFilter extends MCAFilterCounter {
|
||||||
|
private Pattern[] map = new Pattern[Character.MAX_VALUE + 1];
|
||||||
|
|
||||||
|
public MappedReplacePatternFilter() {}
|
||||||
|
|
||||||
|
public MappedReplacePatternFilter(String from, RandomPattern to, boolean useData) throws InputParseException {
|
||||||
|
List<String> split = StringMan.split(from, ',');
|
||||||
|
Pattern[] patterns = ((RandomPattern) to).getPatterns().toArray(new Pattern[0]);
|
||||||
|
if (patterns.length == split.size()) {
|
||||||
|
for (int i = 0; i < split.size(); i++) {
|
||||||
|
Pattern pattern = patterns[i];
|
||||||
|
String arg = split.get(i);
|
||||||
|
ArrayList<BaseBlock> blocks = new ArrayList<BaseBlock>();
|
||||||
|
for (String arg2 : arg.split(",")) {
|
||||||
|
BaseBlock block = FaweCache.getBlock(arg, true, !useData);
|
||||||
|
blocks.add(block);
|
||||||
|
}
|
||||||
|
for (BaseBlock block : blocks) {
|
||||||
|
if (block.getData() != -1) {
|
||||||
|
int combined = FaweCache.getCombined(block);
|
||||||
|
map[combined] = pattern;
|
||||||
|
} else {
|
||||||
|
for (int data = 0; data < 16; data++) {
|
||||||
|
int combined = FaweCache.getCombined(block.getId(), data);
|
||||||
|
map[combined] = pattern;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new InputParseException("Mask:Pattern must be a 1:1 match");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addReplace(BaseBlock block, Pattern pattern) {
|
||||||
|
map[block.getCombined()] = pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final MutableBlockVector mutable = new MutableBlockVector(0, 0, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong ignore) {
|
||||||
|
int id = block.getId();
|
||||||
|
int data = FaweCache.hasData(id) ? block.getData() : 0;
|
||||||
|
int combined = FaweCache.getCombined(id, data);
|
||||||
|
Pattern p = map[combined];
|
||||||
|
if (p != null) {
|
||||||
|
BaseBlock newBlock = p.apply(x, y, z);
|
||||||
|
int currentId = block.getId();
|
||||||
|
if (FaweCache.hasNBT(currentId)) {
|
||||||
|
block.setNbtData(null);
|
||||||
|
}
|
||||||
|
block.setId(newBlock.getId());
|
||||||
|
block.setData(newBlock.getData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.boydti.fawe.jnbt.anvil.filters;
|
||||||
|
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
|
||||||
|
import com.boydti.fawe.object.number.MutableLong;
|
||||||
|
import com.boydti.fawe.util.ArrayUtil;
|
||||||
|
|
||||||
|
public class RemoveLayerFilter extends MCAFilterCounter {
|
||||||
|
private final int startLayer;
|
||||||
|
private final int endLayer;
|
||||||
|
private final int minY, maxY;
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
public RemoveLayerFilter(int minY, int maxY, int id) {
|
||||||
|
this.minY = minY;
|
||||||
|
this.maxY = maxY;
|
||||||
|
this.startLayer = minY >> 4;
|
||||||
|
this.endLayer = maxY >> 4;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MCAChunk applyChunk(MCAChunk chunk, MutableLong cache) {
|
||||||
|
for (int layer = startLayer; layer <= endLayer; layer++) {
|
||||||
|
byte[] ids = chunk.ids[layer];
|
||||||
|
if (ids == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int startY = Math.max(minY, layer << 4) & 15;
|
||||||
|
int endY = Math.min(maxY, 15 + (layer << 4)) & 15;
|
||||||
|
for (int y = startY; y <= endY; y++) {
|
||||||
|
int indexStart = y << 8;
|
||||||
|
int indexEnd = indexStart + 255;
|
||||||
|
for (int index = indexStart; index <= indexEnd; index++) {
|
||||||
|
if (ids[index] != id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int y = startY; y <= endY; y++) {
|
||||||
|
int indexStart = y << 8;
|
||||||
|
int indexEnd = indexStart + 255;
|
||||||
|
ArrayUtil.fill(ids, indexStart, indexEnd + 1, (byte) 0);
|
||||||
|
}
|
||||||
|
chunk.setModified();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.boydti.fawe.jnbt.anvil.filters;
|
||||||
|
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
|
||||||
|
import com.boydti.fawe.object.mask.FaweBlockMatcher;
|
||||||
|
import com.boydti.fawe.object.number.MutableLong;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
|
|
||||||
|
public class ReplacePatternFilter extends MCAFilterCounter {
|
||||||
|
private final FaweBlockMatcher matchFrom;
|
||||||
|
private final Pattern to;
|
||||||
|
|
||||||
|
public ReplacePatternFilter(FaweBlockMatcher from, Pattern to) {
|
||||||
|
this.matchFrom = from;
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong ignore) {
|
||||||
|
if (matchFrom.apply(block)) {
|
||||||
|
BaseBlock newBlock = to.apply(x, y, z);
|
||||||
|
int currentId = block.getId();
|
||||||
|
if (FaweCache.hasNBT(currentId)) {
|
||||||
|
block.setNbtData(null);
|
||||||
|
}
|
||||||
|
block.setId(newBlock.getId());
|
||||||
|
block.setData(newBlock.getData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.boydti.fawe.jnbt.anvil.filters;
|
||||||
|
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAFilterCounter;
|
||||||
|
import com.boydti.fawe.object.mask.FaweBlockMatcher;
|
||||||
|
import com.boydti.fawe.object.number.MutableLong;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
|
||||||
|
public class ReplaceSimpleFilter extends MCAFilterCounter {
|
||||||
|
private final FaweBlockMatcher to;
|
||||||
|
private final FaweBlockMatcher from;
|
||||||
|
|
||||||
|
public ReplaceSimpleFilter(FaweBlockMatcher from, FaweBlockMatcher to) {
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void applyBlock(int x, int y, int z, BaseBlock block, MutableLong count) {
|
||||||
|
if (from.apply(block)) {
|
||||||
|
to.apply(block);
|
||||||
|
count.increment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,6 @@ import java.util.Set;
|
|||||||
* - This will use 8 bytes for every 64 Vector2Ds (about 800x less than a HashSet)
|
* - This will use 8 bytes for every 64 Vector2Ds (about 800x less than a HashSet)
|
||||||
*/
|
*/
|
||||||
public class LocalBlockVector2DSet implements Set<Vector2D> {
|
public class LocalBlockVector2DSet implements Set<Vector2D> {
|
||||||
private boolean chunksValid = true;
|
|
||||||
private final SparseBitSet set;
|
private final SparseBitSet set;
|
||||||
private final MutableBlockVector2D mutable = new MutableBlockVector2D();
|
private final MutableBlockVector2D mutable = new MutableBlockVector2D();
|
||||||
|
|
||||||
@ -115,7 +114,6 @@ public class LocalBlockVector2DSet implements Set<Vector2D> {
|
|||||||
int previous = -1;
|
int previous = -1;
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public void remove() {
|
||||||
chunksValid = false;
|
|
||||||
set.clear(previous);
|
set.clear(previous);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
@ -193,7 +191,6 @@ public class LocalBlockVector2DSet implements Set<Vector2D> {
|
|||||||
boolean value = set.get(index);
|
boolean value = set.get(index);
|
||||||
if (value) {
|
if (value) {
|
||||||
set.clear(index);
|
set.clear(index);
|
||||||
chunksValid = false;
|
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -239,7 +236,6 @@ public class LocalBlockVector2DSet implements Set<Vector2D> {
|
|||||||
if (!c.contains(mutable)) {
|
if (!c.contains(mutable)) {
|
||||||
result = true;
|
result = true;
|
||||||
set.clear(index);
|
set.clear(index);
|
||||||
chunksValid = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -273,6 +269,5 @@ public class LocalBlockVector2DSet implements Set<Vector2D> {
|
|||||||
@Override
|
@Override
|
||||||
public void clear() {
|
public void clear() {
|
||||||
set.clear();
|
set.clear();
|
||||||
chunksValid = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,23 @@ public class PrimitiveList<T> extends AbstractList<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void set(int index, long value) {
|
||||||
|
switch (type) {
|
||||||
|
default:
|
||||||
|
setFast(index, value);
|
||||||
|
return;
|
||||||
|
case Integer:
|
||||||
|
((int[]) arr)[index] = (int) value;
|
||||||
|
return;
|
||||||
|
case Long:
|
||||||
|
((long[]) arr)[index] = value;
|
||||||
|
return;
|
||||||
|
case Double:
|
||||||
|
((double[]) arr)[index] = (double) value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void set(int index, double value) {
|
public void set(int index, double value) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
default:
|
default:
|
||||||
@ -271,6 +288,12 @@ public class PrimitiveList<T> extends AbstractList<T> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean add(long element) {
|
||||||
|
ensureAddCapacity();
|
||||||
|
set(length++, element);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean add(double element) {
|
public boolean add(double element) {
|
||||||
ensureAddCapacity();
|
ensureAddCapacity();
|
||||||
set(length++, element);
|
set(length++, element);
|
||||||
|
@ -8,6 +8,7 @@ import com.boydti.fawe.object.FawePlayer;
|
|||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.util.CleanTextureUtil;
|
import com.boydti.fawe.util.CleanTextureUtil;
|
||||||
import com.boydti.fawe.util.FilteredTextureUtil;
|
import com.boydti.fawe.util.FilteredTextureUtil;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.StringMan;
|
import com.boydti.fawe.util.StringMan;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
import com.intellectualcrafters.plot.PS;
|
import com.intellectualcrafters.plot.PS;
|
||||||
@ -25,7 +26,6 @@ import com.intellectualcrafters.plot.object.RunnableVal3;
|
|||||||
import com.intellectualcrafters.plot.object.worlds.PlotAreaManager;
|
import com.intellectualcrafters.plot.object.worlds.PlotAreaManager;
|
||||||
import com.intellectualcrafters.plot.object.worlds.SinglePlotArea;
|
import com.intellectualcrafters.plot.object.worlds.SinglePlotArea;
|
||||||
import com.intellectualcrafters.plot.object.worlds.SinglePlotAreaManager;
|
import com.intellectualcrafters.plot.object.worlds.SinglePlotAreaManager;
|
||||||
import com.intellectualcrafters.plot.util.MainUtil;
|
|
||||||
import com.plotsquared.general.commands.Command;
|
import com.plotsquared.general.commands.Command;
|
||||||
import com.plotsquared.general.commands.CommandDeclaration;
|
import com.plotsquared.general.commands.CommandDeclaration;
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
@ -85,7 +85,8 @@ public class CreateFromImage extends Command {
|
|||||||
if (generator == null) {
|
if (generator == null) {
|
||||||
final Vector2D dimensions;
|
final Vector2D dimensions;
|
||||||
final BufferedImage image;
|
final BufferedImage image;
|
||||||
if (argList.get(0).toLowerCase().startsWith("http")) {
|
String arg0 = argList.get(0).toLowerCase();
|
||||||
|
if (arg0.startsWith("http") || arg0.startsWith("file://")) {
|
||||||
try {
|
try {
|
||||||
player.sendMessage(BBC.getPrefix() + "Loading image... (1)");
|
player.sendMessage(BBC.getPrefix() + "Loading image... (1)");
|
||||||
image = getImage(argList.get(0), fp);
|
image = getImage(argList.get(0), fp);
|
||||||
@ -113,7 +114,7 @@ public class CreateFromImage extends Command {
|
|||||||
int currentPlots = Settings.Limit.GLOBAL ? player.getPlotCount() : player.getPlotCount(area.worldname);
|
int currentPlots = Settings.Limit.GLOBAL ? player.getPlotCount() : player.getPlotCount(area.worldname);
|
||||||
int diff = player.getAllowedPlots() - currentPlots;
|
int diff = player.getAllowedPlots() - currentPlots;
|
||||||
if (diff < 1) {
|
if (diff < 1) {
|
||||||
MainUtil.sendMessage(player, C.CANT_CLAIM_MORE_PLOTS_NUM, -diff + "");
|
C.CANT_CLAIM_MORE_PLOTS_NUM.send(player, -diff);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (area.getMeta("lastPlot") == null) {
|
if (area.getMeta("lastPlot") == null) {
|
||||||
@ -195,7 +196,8 @@ public class CreateFromImage extends Command {
|
|||||||
}
|
}
|
||||||
int argOffset = 0;
|
int argOffset = 0;
|
||||||
BufferedImage img = null;
|
BufferedImage img = null;
|
||||||
if (argList.get(1).startsWith("http")) {
|
String arg1 = argList.get(1);
|
||||||
|
if (arg1.startsWith("http") || arg1.startsWith("file://")) {
|
||||||
img = getImage(argList.get(1), fp);
|
img = getImage(argList.get(1), fp);
|
||||||
argOffset++;
|
argOffset++;
|
||||||
}
|
}
|
||||||
@ -601,7 +603,12 @@ public class CreateFromImage extends Command {
|
|||||||
if (arg.startsWith("http")) {
|
if (arg.startsWith("http")) {
|
||||||
URL url = new URL(arg);
|
URL url = new URL(arg);
|
||||||
fp.sendMessage(BBC.getPrefix() + "Downloading image... (3)");
|
fp.sendMessage(BBC.getPrefix() + "Downloading image... (3)");
|
||||||
return com.boydti.fawe.util.MainUtil.toRGB(ImageIO.read(url));
|
return MainUtil.toRGB(ImageIO.read(url));
|
||||||
|
}
|
||||||
|
if (arg.startsWith("file://")) {
|
||||||
|
arg = arg.substring(7);
|
||||||
|
File file = MainUtil.getFile(Fawe.imp().getDirectory(), com.boydti.fawe.config.Settings.IMP.PATHS.HEIGHTMAP + File.separator + arg);
|
||||||
|
return MainUtil.toRGB(ImageIO.read(file));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -464,6 +464,7 @@ public class TaskBuilder extends Metadatable {
|
|||||||
private long start;
|
private long start;
|
||||||
private Object asyncWaitLock = new Object();
|
private Object asyncWaitLock = new Object();
|
||||||
private Object syncWaitLock = new Object();
|
private Object syncWaitLock = new Object();
|
||||||
|
|
||||||
private boolean finished;
|
private boolean finished;
|
||||||
|
|
||||||
public SplitTask() {
|
public SplitTask() {
|
||||||
@ -483,6 +484,7 @@ public class TaskBuilder extends Metadatable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
synchronized (asyncWaitLock) {
|
synchronized (asyncWaitLock) {
|
||||||
|
asyncWaitLock.notifyAll();
|
||||||
asyncWaitLock.wait(Long.MAX_VALUE);
|
asyncWaitLock.wait(Long.MAX_VALUE);
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
@ -495,24 +497,31 @@ public class TaskBuilder extends Metadatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
thread.start();
|
try {
|
||||||
|
synchronized (asyncWaitLock) {
|
||||||
|
thread.start();
|
||||||
|
asyncWaitLock.wait();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
while (thread.isAlive()) {
|
while (thread.isAlive()) {
|
||||||
TaskManager.IMP.syncWhenFree(new RunnableVal() {
|
TaskManager.IMP.syncWhenFree(new RunnableVal() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Object ignore) {
|
public void run(Object ignore) {
|
||||||
queue.startSet(true);
|
queue.startSet(true);
|
||||||
start = System.currentTimeMillis();
|
start = System.currentTimeMillis();
|
||||||
synchronized (asyncWaitLock) {
|
try {
|
||||||
asyncWaitLock.notifyAll();
|
|
||||||
}
|
|
||||||
synchronized (syncWaitLock) {
|
|
||||||
if (!finished) {
|
if (!finished) {
|
||||||
try {
|
synchronized (asyncWaitLock) {
|
||||||
syncWaitLock.wait(Long.MAX_VALUE);
|
asyncWaitLock.notifyAll();
|
||||||
} catch (InterruptedException e) {
|
}
|
||||||
e.printStackTrace();
|
synchronized (syncWaitLock) {
|
||||||
|
syncWaitLock.wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
queue.endSet(true);
|
queue.endSet(true);
|
||||||
}
|
}
|
||||||
@ -529,7 +538,7 @@ public class TaskBuilder extends Metadatable {
|
|||||||
syncWaitLock.notifyAll();
|
syncWaitLock.notifyAll();
|
||||||
}
|
}
|
||||||
synchronized (asyncWaitLock) {
|
synchronized (asyncWaitLock) {
|
||||||
asyncWaitLock.wait(Long.MAX_VALUE);
|
asyncWaitLock.wait();
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -680,7 +680,7 @@ public class BrushCommands extends MethodCommands {
|
|||||||
|
|
||||||
private InputStream getHeightmapStream(String filename) {
|
private InputStream getHeightmapStream(String filename) {
|
||||||
String filenamePng = (filename.endsWith(".png") ? filename : filename + ".png");
|
String filenamePng = (filename.endsWith(".png") ? filename : filename + ".png");
|
||||||
File file = new File(Fawe.imp().getDirectory(), "heightmap" + File.separator + filenamePng);
|
File file = new File(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HEIGHTMAP + File.separator + filenamePng);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
if (!filename.equals("#clipboard") && filename.length() >= 7) {
|
if (!filename.equals("#clipboard") && filename.length() >= 7) {
|
||||||
try {
|
try {
|
||||||
|
@ -674,7 +674,8 @@ public class SelectionCommands {
|
|||||||
|
|
||||||
if (useData) {
|
if (useData) {
|
||||||
for (Countable<BaseBlock> c : distributionData) {
|
for (Countable<BaseBlock> c : distributionData) {
|
||||||
String name = BlockType.fromID(c.getID().getId()).getName();
|
BlockType block = BlockType.fromID(c.getID().getId());
|
||||||
|
String name = block != null ? block.getName() : null;
|
||||||
String str = String.format("%-7s (%.3f%%) %s #%d:%d",
|
String str = String.format("%-7s (%.3f%%) %s #%d:%d",
|
||||||
String.valueOf(c.getAmount()),
|
String.valueOf(c.getAmount()),
|
||||||
c.getAmount() / (double) size * 100,
|
c.getAmount() / (double) size * 100,
|
||||||
|
@ -379,9 +379,6 @@ public final class CommandManager {
|
|||||||
try {
|
try {
|
||||||
Object result = dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
|
Object result = dispatcher.call(Joiner.on(" ").join(split), locals, new String[0]);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
while (t.getCause() != null) {
|
|
||||||
t = t.getCause();
|
|
||||||
}
|
|
||||||
// Use the exception converter to convert the exception if any of its causes
|
// Use the exception converter to convert the exception if any of its causes
|
||||||
// can be converted, otherwise throw the original exception
|
// can be converted, otherwise throw the original exception
|
||||||
Throwable next = t;
|
Throwable next = t;
|
||||||
@ -407,26 +404,22 @@ public final class CommandManager {
|
|||||||
BBC.COMMAND_SYNTAX.send(finalActor, e.getSimpleUsageString("/"));
|
BBC.COMMAND_SYNTAX.send(finalActor, e.getSimpleUsageString("/"));
|
||||||
}
|
}
|
||||||
} catch (WrappedCommandException e) {
|
} catch (WrappedCommandException e) {
|
||||||
FaweException faweException = FaweException.get(e);
|
Exception faweException = FaweException.get(e);
|
||||||
|
String message = e.getMessage();
|
||||||
if (faweException != null) {
|
if (faweException != null) {
|
||||||
BBC.WORLDEDIT_CANCEL_REASON.send(finalActor, faweException.getMessage());
|
BBC.WORLDEDIT_CANCEL_REASON.send(finalActor, faweException.getMessage());
|
||||||
} else {
|
} else {
|
||||||
Throwable t = e.getCause();
|
|
||||||
while (t.getCause() != null) {
|
|
||||||
t = t.getCause();
|
|
||||||
}
|
|
||||||
finalActor.printError("There was an error handling a FAWE command: [See console]");
|
finalActor.printError("There was an error handling a FAWE command: [See console]");
|
||||||
finalActor.printRaw(t.getClass().getName() + ": " + t.getMessage());
|
finalActor.printRaw(e.getClass().getName() + ": " + e.getMessage());
|
||||||
log.log(Level.SEVERE, "An unexpected error occurred while handling a FAWE command", t);
|
log.log(Level.SEVERE, "An unexpected error occurred while handling a FAWE command", e);
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (CommandException e) {
|
||||||
e.printStackTrace();
|
|
||||||
String message = e.getMessage();
|
String message = e.getMessage();
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
finalActor.printError(e.getMessage());
|
actor.printError(e.getMessage());
|
||||||
} else {
|
} else {
|
||||||
finalActor.printError("An unknown error has occurred! Please see console.");
|
actor.printError("An unknown FAWE error has occurred! Please see console.");
|
||||||
log.log(Level.SEVERE, "An unknown error occurred", e);
|
log.log(Level.SEVERE, "An unknown FAWE error occurred", e);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
final EditSession editSession = locals.get(EditSession.class);
|
final EditSession editSession = locals.get(EditSession.class);
|
||||||
|
Loading…
Reference in New Issue
Block a user