geforkt von Mirrors/FastAsyncWorldEdit
Merge branch 'commanding-pipeline' of https://github.com/IntellectualSites/FastAsyncWorldEdit-1.13 into commanding-pipeline
Conflicts: worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitPlayer.java worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java worldedit-core/src/main/java/com/boydti/fawe/beta/filters/DistrFilter.java worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ChunkCache.java worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/ParallelQueueExtent.java worldedit-core/src/main/java/com/boydti/fawe/command/CFICommands.java worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/cfi/HeightMapMCAGenerator.java worldedit-core/src/main/java/com/boydti/fawe/object/brush/visualization/cfi/MCAWriter.java worldedit-core/src/main/java/com/boydti/fawe/wrappers/WorldWrapper.java worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolUtilCommands.java worldedit-core/src/main/java/com/sk89q/worldedit/world/NullWorld.java worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockTypes.java
Dieser Commit ist enthalten in:
Commit
d8d7c8c53f
@ -20,6 +20,7 @@ repositories {
|
||||
maven { url = uri("https://repo.destroystokyo.com/repository/maven-public//") }
|
||||
maven { url = uri("http://repo.dmulloy2.net/content/groups/public/") }
|
||||
maven { url = uri("http://ci.ender.zone/plugin/repository/everything/") }
|
||||
maven { url = uri("https://repo.inventivetalent.org/content/groups/public/")}
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
@ -49,6 +50,9 @@ dependencies {
|
||||
exclude("com.sk89q.worldedit.worldedit-libs", "bukkit")
|
||||
exclude("com.sk89q.worldedit.worldedit-libs", "core")
|
||||
}
|
||||
"implementation"("org.inventivetalent:mapmanager:1.7.3-SNAPSHOT") { isTransitive = false }
|
||||
"implementation"("org.inventivetalent:mapmanager:1.7.3-SNAPSHOT") { isTransitive = false }
|
||||
|
||||
"implementation"("com.massivecraft:factions:2.8.0") { isTransitive = false }
|
||||
"implementation"("com.drtshock:factions:1.6.9.5") { isTransitive = false }
|
||||
"implementation"("com.github.TechFortress:GriefPrevention:16.12.0") { isTransitive = false }
|
||||
|
@ -2,7 +2,9 @@ package com.boydti.fawe.bukkit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.IFawe;
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.cache.preloader.AsyncPreloader;
|
||||
import com.boydti.fawe.beta.implementation.cache.preloader.Preloader;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitQueueHandler;
|
||||
import com.boydti.fawe.bukkit.listener.BrushListener;
|
||||
import com.boydti.fawe.bukkit.listener.BukkitImageListener;
|
||||
@ -54,14 +56,14 @@ import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class FaweBukkit implements IFawe, Listener {
|
||||
|
||||
// private final WorldEditPlugin plugin;
|
||||
private final Plugin plugin;
|
||||
private VaultUtil vault;
|
||||
private ItemUtil itemUtil;
|
||||
|
||||
private boolean listeningImages;
|
||||
private BukkitImageListener imageListener;
|
||||
//private CFIPacketListener packetListener;
|
||||
|
||||
public static boolean PAPER;
|
||||
|
||||
public VaultUtil getVault() {
|
||||
return this.vault;
|
||||
@ -69,6 +71,13 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
|
||||
public FaweBukkit(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
try {
|
||||
Class.forName("com.destroystokyo.paper.Namespaced");
|
||||
PAPER = true;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
// TODO no paper
|
||||
}
|
||||
try {
|
||||
Settings.IMP.TICK_LIMITER.ENABLED = !Bukkit.hasWhitelist();
|
||||
Fawe.set(this);
|
||||
@ -103,7 +112,6 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
} catch (ClassNotFoundException e) {
|
||||
new ChunkListener_9();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@ -129,15 +137,15 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
PluginManager manager = Bukkit.getPluginManager();
|
||||
|
||||
if (manager.getPlugin("PacketListenerApi") == null) {
|
||||
File output = new File(plugin.getDataFolder().getParentFile(), "PacketListenerAPI_v3.6.0-SNAPSHOT.jar");
|
||||
byte[] jarData = Jars.PL_v3_6_0.download();
|
||||
File output = new File(plugin.getDataFolder().getParentFile(), "PacketListenerAPI_v3.7.3-SNAPSHOT.jar");
|
||||
byte[] jarData = Jars.PL_v3_7_3.download();
|
||||
try (FileOutputStream fos = new FileOutputStream(output)) {
|
||||
fos.write(jarData);
|
||||
}
|
||||
}
|
||||
if (manager.getPlugin("MapManager") == null) {
|
||||
File output = new File(plugin.getDataFolder().getParentFile(), "MapManager_v1.4.0-SNAPSHOT.jar");
|
||||
byte[] jarData = Jars.MM_v1_4_0.download();
|
||||
File output = new File(plugin.getDataFolder().getParentFile(), "MapManager_v1.7.3-SNAPSHOT.jar");
|
||||
byte[] jarData = Jars.MM_v1_7_3.download();
|
||||
try (FileOutputStream fos = new FileOutputStream(output)) {
|
||||
fos.write(jarData);
|
||||
}
|
||||
@ -397,4 +405,12 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
return null;
|
||||
// return ((BlocksHubBukkit) blocksHubPlugin).getApi();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Preloader getPreloader() {
|
||||
if (PAPER) {
|
||||
return new AsyncPreloader();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.listener.ChunkListener;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
@ -2,6 +2,7 @@ package com.boydti.fawe.bukkit.adapter.mc1_14;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArray4096;
|
||||
@ -10,6 +11,7 @@ import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import net.jpountz.util.UnsafeUtils;
|
||||
import net.minecraft.server.v1_14_R1.Block;
|
||||
import net.minecraft.server.v1_14_R1.Chunk;
|
||||
@ -21,6 +23,7 @@ import net.minecraft.server.v1_14_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_14_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_14_R1.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_14_R1.IBlockData;
|
||||
import net.minecraft.server.v1_14_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_14_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_14_R1.PlayerChunkMap;
|
||||
import org.bukkit.craftbukkit.v1_14_R1.CraftChunk;
|
||||
@ -78,7 +81,7 @@ public class BukkitAdapter_1_14 {
|
||||
fieldDirtyBits.setAccessible(true);
|
||||
|
||||
{
|
||||
Field tmp = null;
|
||||
Field tmp;
|
||||
try {
|
||||
tmp = DataPaletteBlock.class.getDeclaredField("writeLock");
|
||||
} catch (NoSuchFieldException paper) {
|
||||
@ -133,8 +136,6 @@ public class BukkitAdapter_1_14 {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean PAPER = true;
|
||||
|
||||
public static Chunk ensureLoaded(net.minecraft.server.v1_14_R1.World nmsWorld, int X, int Z) {
|
||||
Chunk nmsChunk = nmsWorld.getChunkIfLoaded(X, Z);
|
||||
if (nmsChunk != null) {
|
||||
@ -143,7 +144,7 @@ public class BukkitAdapter_1_14 {
|
||||
if (Fawe.isMainThread()) {
|
||||
return nmsWorld.getChunkAt(X, Z);
|
||||
}
|
||||
if (PAPER) {
|
||||
if (FaweBukkit.PAPER) {
|
||||
CraftWorld craftWorld = nmsWorld.getWorld();
|
||||
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(X, Z, true);
|
||||
try {
|
||||
@ -154,15 +155,14 @@ public class BukkitAdapter_1_14 {
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Throwable e) {
|
||||
System.out.println("Error, cannot load chunk async (paper not installed?)");
|
||||
PAPER = false;
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO optimize
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z));
|
||||
}
|
||||
|
||||
private static PlayerChunk getPlayerChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, final int cx, final int cz) {
|
||||
public static PlayerChunk getPlayerChunk(net.minecraft.server.v1_14_R1.WorldServer nmsWorld, final int cx, final int cz) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
PlayerChunk playerChunk = chunkMap.visibleChunks.get(ChunkCoordIntPair.pair(cx, cz));
|
||||
if (playerChunk == null) {
|
||||
@ -274,7 +274,7 @@ public class BukkitAdapter_1_14 {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
final int ordinal = paletteToBlock[i];
|
||||
blockToPalette[ordinal] = Integer.MAX_VALUE;
|
||||
final BlockState state = BlockTypes.states[ordinal];
|
||||
final BlockState state = BlockTypesCache.states[ordinal];
|
||||
final IBlockData ibd = ((BlockMaterial_1_14) state.getMaterial()).getState();
|
||||
palette.a(ibd);
|
||||
}
|
||||
|
@ -3,11 +3,10 @@ package com.boydti.fawe.bukkit.adapter.mc1_14;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.object.collection.AdaptedMap;
|
||||
import com.boydti.fawe.object.collection.AdaptedSetCollection;
|
||||
import com.boydti.fawe.object.collection.BitArray4096;
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.google.common.collect.Iterables;
|
||||
@ -58,7 +57,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
public Chunk nmsChunk;
|
||||
public CraftWorld world;
|
||||
public int X, Z;
|
||||
private boolean forceLoad;
|
||||
// private boolean forceLoad;
|
||||
|
||||
public BukkitGetBlocks_1_14(World world, int X, int Z, boolean forceLoad) {
|
||||
this.world = (CraftWorld) world;
|
||||
@ -76,6 +75,15 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
public int getX() {
|
||||
return X;
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return Z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
BiomeBase base = getChunk().getBiomeIndex()[(z << 4) + x];
|
||||
@ -304,7 +312,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
||||
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
|
||||
continue;
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
updateGet(this, nmsChunk, sections, newSection, getArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_14;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import net.minecraft.server.v1_14_R1.NBTBase;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_14_R1.PacketPlayOutMapChunk;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
public class MapChunkUtil_1_14 {
|
||||
private static final Field fieldX;
|
||||
|
||||
private static final Field fieldZ;
|
||||
|
||||
private static final Field fieldHeightMap;
|
||||
|
||||
private static final Field fieldBitMask;
|
||||
|
||||
private static final Field fieldChunkData;
|
||||
|
||||
private static final Field fieldBlockEntities;
|
||||
|
||||
private static final Field fieldFull;
|
||||
|
||||
|
||||
static {
|
||||
try {
|
||||
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
|
||||
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
|
||||
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
|
||||
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
|
||||
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("e");
|
||||
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("f");
|
||||
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("g");
|
||||
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static PacketPlayOutMapChunk create(BukkitImplAdapter<NBTBase> adapter, ChunkPacket packet) {
|
||||
PacketPlayOutMapChunk nmsPacket = new PacketPlayOutMapChunk();
|
||||
|
||||
try {
|
||||
fieldX.setInt(nmsPacket, packet.getChunkX());
|
||||
fieldZ.setInt(nmsPacket, packet.getChunkZ());
|
||||
|
||||
fieldBitMask.set(nmsPacket, packet.getChunk().getBitMask());
|
||||
NBTBase heightMap = adapter.fromNative(packet.getHeightMap());
|
||||
fieldHeightMap.set(nmsPacket, heightMap);
|
||||
fieldChunkData.set(nmsPacket, packet.get());
|
||||
|
||||
Map<BlockVector3, CompoundTag> tiles = packet.getChunk().getTiles();
|
||||
ArrayList<NBTTagCompound> nmsTiles = new ArrayList<>(tiles.size());
|
||||
for (Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
NBTBase nmsTag = adapter.fromNative(entry.getValue());
|
||||
nmsTiles.add((NBTTagCompound) nmsTag);
|
||||
}
|
||||
fieldBlockEntities.set(nmsPacket, nmsTiles);
|
||||
fieldFull.set(nmsPacket, packet.isFull());
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return nmsPacket;
|
||||
}
|
||||
}
|
@ -20,6 +20,8 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_14;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
@ -62,6 +64,7 @@ import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_14_R1.Block;
|
||||
@ -75,6 +78,7 @@ import net.minecraft.server.v1_14_R1.Chunk;
|
||||
import net.minecraft.server.v1_14_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_14_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_14_R1.Entity;
|
||||
import net.minecraft.server.v1_14_R1.EntityPlayer;
|
||||
import net.minecraft.server.v1_14_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_14_R1.EnumDirection;
|
||||
import net.minecraft.server.v1_14_R1.EnumHand;
|
||||
@ -102,7 +106,9 @@ import net.minecraft.server.v1_14_R1.NBTTagLongArray;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagShort;
|
||||
import net.minecraft.server.v1_14_R1.NBTTagString;
|
||||
import net.minecraft.server.v1_14_R1.PacketPlayOutEntityStatus;
|
||||
import net.minecraft.server.v1_14_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_14_R1.PacketPlayOutTileEntityData;
|
||||
import net.minecraft.server.v1_14_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_14_R1.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_14_R1.TileEntity;
|
||||
import net.minecraft.server.v1_14_R1.Vec3D;
|
||||
@ -132,10 +138,12 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -171,7 +179,7 @@ public final class Spigot_v1_14_R4 extends CachedBukkitAdapter implements Bukkit
|
||||
if (idbToStateOrdinal != null) return false;
|
||||
idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
|
||||
for (int i = 0; i < idbToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypes.states[i];
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
BlockMaterial_1_14 material = (BlockMaterial_1_14) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
idbToStateOrdinal[id] = state.getOrdinalChar();
|
||||
@ -590,6 +598,13 @@ public final class Spigot_v1_14_R4 extends CachedBukkitAdapter implements Bukkit
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
BlockMaterial_1_14 material = (BlockMaterial_1_14) state.getMaterial();
|
||||
IBlockData mcState = material.getCraftBlockData().getState();
|
||||
return OptionalInt.of(Block.REGISTRY_ID.getId(mcState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState adapt(BlockData blockData) {
|
||||
CraftBlockData cbd = ((CraftBlockData) blockData);
|
||||
@ -598,7 +613,7 @@ public final class Spigot_v1_14_R4 extends CachedBukkitAdapter implements Bukkit
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypes.states[adaptToInt(ibd)];
|
||||
return BlockTypesCache.states[adaptToInt(ibd)];
|
||||
}
|
||||
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
@ -648,6 +663,35 @@ public final class Spigot_v1_14_R4 extends CachedBukkitAdapter implements Bukkit
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||
PlayerChunk map = BukkitAdapter_1_14.getPlayerChunk(nmsWorld, packet.getChunkX(), packet.getChunkZ());
|
||||
if (map != null && map.hasBeenLoaded()) {
|
||||
boolean flag = false;
|
||||
PlayerChunk.d players = map.players;
|
||||
Stream<EntityPlayer> stream = players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag);
|
||||
|
||||
EntityPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle();
|
||||
stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer)
|
||||
.forEach(entityPlayer -> {
|
||||
synchronized (packet) {
|
||||
PacketPlayOutMapChunk nmsPacket = (PacketPlayOutMapChunk) packet.getNativePacket();
|
||||
if (nmsPacket == null) {
|
||||
nmsPacket = MapChunkUtil_1_14.create(this, packet);
|
||||
packet.setNativePacket(nmsPacket);
|
||||
}
|
||||
try {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(true);
|
||||
entityPlayer.playerConnection.sendPacket(nmsPacket);
|
||||
} finally {
|
||||
FaweCache.IMP.CHUNK_FLAG.get().set(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static EnumDirection adapt(Direction face) {
|
||||
switch (face) {
|
||||
case NORTH: return EnumDirection.NORTH;
|
||||
|
@ -0,0 +1,34 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_14.test;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.events.ListenerPriority;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.wrappers.WrappedBlockData;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TestChunkPacketSend {
|
||||
public TestChunkPacketSend(Plugin plugin) {
|
||||
// Disable all sound effects
|
||||
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
protocolManager.addPacketListener(
|
||||
new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP_CHUNK) {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
if (event.getPacketType() != PacketType.Play.Server.MAP_CHUNK) {
|
||||
return;
|
||||
}
|
||||
PacketContainer packet = event.getPacket();
|
||||
StructureModifier<Byte> bytes = packet.getBytes();
|
||||
StructureModifier<WrappedBlockData> blockData = packet.getBlockData();
|
||||
List<WrappedBlockData> values = blockData.getValues();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.chat;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import org.apache.commons.lang.Validate;
|
||||
|
||||
/**
|
||||
* Represents a wrapper around an array class of an arbitrary reference type,
|
||||
* which properly implements "value" hash code and equality functions.
|
||||
* <p>
|
||||
* This class is intended for use as a key to a map.
|
||||
* </p>
|
||||
*
|
||||
* @param <E> The type of elements in the array.
|
||||
* @author Glen Husman
|
||||
* @see Arrays
|
||||
*/
|
||||
public final class ArrayWrapper<E> {
|
||||
|
||||
/**
|
||||
* Creates an array wrapper with some elements.
|
||||
*
|
||||
* @param elements The elements of the array.
|
||||
*/
|
||||
@SafeVarargs
|
||||
public ArrayWrapper(E... elements) {
|
||||
setArray(elements);
|
||||
}
|
||||
|
||||
private E[] _array;
|
||||
|
||||
/**
|
||||
* Retrieves a reference to the wrapped array instance.
|
||||
*
|
||||
* @return The array wrapped by this instance.
|
||||
*/
|
||||
public E[] getArray() {
|
||||
return _array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this wrapper to wrap a new array instance.
|
||||
*
|
||||
* @param array The new wrapped array.
|
||||
*/
|
||||
public void setArray(E[] array) {
|
||||
Validate.notNull(array, "The array must not be null.");
|
||||
_array = array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this object has a value equivalent to another object.
|
||||
*
|
||||
* @see Arrays#equals(Object[], Object[])
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof ArrayWrapper)) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(_array, ((ArrayWrapper) other)._array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hash code represented by this objects value.
|
||||
*
|
||||
* @return This object's hash code.
|
||||
* @see Arrays#hashCode(Object[])
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(_array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an iterable element collection to an array of elements.
|
||||
* The iteration order of the specified object will be used as the array element order.
|
||||
*
|
||||
* @param list The iterable of objects which will be converted to an array.
|
||||
* @param c The type of the elements of the array.
|
||||
* @return An array of elements in the specified iterable.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T[] toArray(Iterable<? extends T> list, Class<T> c) {
|
||||
int size = -1;
|
||||
if (list instanceof Collection<?>) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Collection coll = (Collection) list;
|
||||
size = coll.size();
|
||||
}
|
||||
|
||||
|
||||
if (size < 0) {
|
||||
size = 0;
|
||||
// Ugly hack: Count it ourselves
|
||||
for (@SuppressWarnings("unused") T element : list) {
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
T[] result = (T[]) Array.newInstance(c, size);
|
||||
int i = 0;
|
||||
for (T element : list) { // Assumes iteration order is consistent
|
||||
result[i++] = element; // Assign array element at index THEN increment counter
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.chat;
|
||||
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Represents an object that can be serialized to a JSON writer instance.
|
||||
*/
|
||||
interface JsonRepresentedObject {
|
||||
|
||||
/**
|
||||
* Writes the JSON representation of this object to the specified writer.
|
||||
* @param writer The JSON writer which will receive the object.
|
||||
* @throws IOException If an error occurs writing to the stream.
|
||||
*/
|
||||
public void writeJson(JsonWriter writer) throws IOException;
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.chat;
|
||||
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
||||
|
||||
/**
|
||||
* Represents a JSON string value.
|
||||
* Writes by this object will not write name values nor begin/end objects in the JSON stream.
|
||||
* All writes merely write the represented string value.
|
||||
*/
|
||||
final class JsonString implements JsonRepresentedObject, ConfigurationSerializable {
|
||||
|
||||
private String _value;
|
||||
|
||||
public JsonString(CharSequence value) {
|
||||
_value = value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException {
|
||||
writer.value(getValue());
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
public Map<String, Object> serialize() {
|
||||
HashMap<String, Object> theSingleValue = new HashMap<>();
|
||||
theSingleValue.put("stringValue", _value);
|
||||
return theSingleValue;
|
||||
}
|
||||
|
||||
public static JsonString deserialize(Map<String, Object> map) {
|
||||
return new JsonString(map.get("stringValue").toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.chat;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
/**
|
||||
* A class containing static utility methods and caches which are intended as reflective conveniences.
|
||||
* Unless otherwise noted, upon failure methods will return {@code null}.
|
||||
*/
|
||||
public final class Reflection {
|
||||
|
||||
/**
|
||||
* Stores loaded classes from the {@code net.minecraft.server} package.
|
||||
*/
|
||||
private static final Map<String, Class<?>> _loadedNMSClasses = new HashMap<>();
|
||||
/**
|
||||
* Stores loaded classes from the {@code org.bukkit.craftbukkit} package (and subpackages).
|
||||
*/
|
||||
private static final Map<String, Class<?>> _loadedOBCClasses = new HashMap<>();
|
||||
private static final Map<Class<?>, Map<String, Field>> _loadedFields = new HashMap<>();
|
||||
/**
|
||||
* Contains loaded methods in a cache.
|
||||
* The map maps [types to maps of [method names to maps of [parameter types to method instances]]].
|
||||
*/
|
||||
private static final Map<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>> _loadedMethods = new HashMap<>();
|
||||
private static String _versionString;
|
||||
|
||||
private Reflection() { }
|
||||
|
||||
/**
|
||||
* Gets the version string from the package name of the CraftBukkit server implementation.
|
||||
* This is needed to bypass the JAR package name changing on each update.
|
||||
*
|
||||
* @return The version string of the OBC and NMS packages, <em>including the trailing dot</em>.
|
||||
*/
|
||||
public synchronized static String getVersion() {
|
||||
if (_versionString == null) {
|
||||
String name = Bukkit.getServer().getClass().getPackage().getName();
|
||||
_versionString = name.substring(name.lastIndexOf('.') + 1) + ".";
|
||||
}
|
||||
|
||||
return _versionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package.
|
||||
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
|
||||
*
|
||||
* @param className The name of the class, excluding the package, within NMS.
|
||||
* @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded.
|
||||
*/
|
||||
public synchronized static Class<?> getNMSClass(String className) {
|
||||
if (_loadedNMSClasses.containsKey(className)) {
|
||||
return _loadedNMSClasses.get(className);
|
||||
}
|
||||
|
||||
String fullName = "net.minecraft.server." + getVersion() + className;
|
||||
Class<?> clazz;
|
||||
try {
|
||||
clazz = Class.forName(fullName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
_loadedNMSClasses.put(className, null);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
_loadedNMSClasses.put(className, clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package.
|
||||
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
|
||||
*
|
||||
* @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory.CraftItemStack}.
|
||||
* @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded.
|
||||
*/
|
||||
public synchronized static Class<?> getOBCClass(String className) {
|
||||
if (_loadedOBCClasses.containsKey(className)) {
|
||||
return _loadedOBCClasses.get(className);
|
||||
}
|
||||
|
||||
String fullName = "org.bukkit.craftbukkit." + getVersion() + className;
|
||||
Class<?> clazz;
|
||||
try {
|
||||
clazz = Class.forName(fullName);
|
||||
} catch (ClassNotFoundException e) {
|
||||
_loadedOBCClasses.put(className, null);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
_loadedOBCClasses.put(className, clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get the NMS handle of a CraftBukkit object.
|
||||
* <p>
|
||||
* The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the runtime type of the specified object.
|
||||
* </p>
|
||||
*
|
||||
* @param obj The object for which to retrieve an NMS handle.
|
||||
* @return The NMS handle of the specified object, or {@code null} if it could not be retrieved using {@code getHandle()}.
|
||||
*/
|
||||
public synchronized static Object getHandle(Object obj) throws InvocationTargetException, IllegalAccessException, IllegalArgumentException {
|
||||
return getMethod(obj.getClass(), "getHandle").invoke(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a {@link Field} instance declared by the specified class with the specified name.
|
||||
* Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field
|
||||
* returned will be an instance or static field.
|
||||
* <p>
|
||||
* A global caching mechanism within this class is used to store fields. Combined with synchronization, this guarantees that
|
||||
* no field will be reflectively looked up twice.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a field is deemed suitable for return, {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
|
||||
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
|
||||
* </p>
|
||||
*
|
||||
* @param clazz The class which contains the field to retrieve.
|
||||
* @param name The declared name of the field in the class.
|
||||
* @return A field object with the specified name declared by the specified class.
|
||||
* @see Class#getDeclaredField(String)
|
||||
*/
|
||||
public synchronized static Field getField(Class<?> clazz, String name) {
|
||||
Map<String, Field> loaded;
|
||||
if (!_loadedFields.containsKey(clazz)) {
|
||||
loaded = new HashMap<>();
|
||||
_loadedFields.put(clazz, loaded);
|
||||
} else {
|
||||
loaded = _loadedFields.get(clazz);
|
||||
}
|
||||
if (loaded.containsKey(name)) {
|
||||
// If the field is loaded (or cached as not existing), return the relevant value, which might be null
|
||||
return loaded.get(name);
|
||||
}
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
loaded.put(name, field);
|
||||
return field;
|
||||
} catch (NoSuchFieldException | SecurityException e) {
|
||||
// Error loading
|
||||
e.printStackTrace();
|
||||
// Cache field as not existing
|
||||
loaded.put(name, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a {@link Method} instance declared by the specified class with the specified name and argument types.
|
||||
* Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field
|
||||
* returned will be an instance or static field.
|
||||
* <p>
|
||||
* A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that
|
||||
* no method will be reflectively looked up twice.
|
||||
* <p>
|
||||
* If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
|
||||
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
|
||||
* <p>
|
||||
* This method does <em>not</em> search superclasses of the specified type for methods with the specified signature.
|
||||
* Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}.
|
||||
*
|
||||
* @param clazz The class which contains the method to retrieve.
|
||||
* @param name The declared name of the method in the class.
|
||||
* @param args The formal argument types of the method.
|
||||
* @return A method object with the specified name declared by the specified class.
|
||||
*/
|
||||
public synchronized static Method getMethod(Class<?> clazz, String name, Class<?>... args) {
|
||||
if (!_loadedMethods.containsKey(clazz)) {
|
||||
_loadedMethods.put(clazz, new HashMap<>());
|
||||
}
|
||||
|
||||
Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz);
|
||||
if (!loadedMethodNames.containsKey(name)) {
|
||||
loadedMethodNames.put(name, new HashMap<>());
|
||||
}
|
||||
|
||||
Map<ArrayWrapper<Class<?>>, Method> loadedSignatures = loadedMethodNames.get(name);
|
||||
ArrayWrapper<Class<?>> wrappedArg = new ArrayWrapper<>(args);
|
||||
if (loadedSignatures.containsKey(wrappedArg)) {
|
||||
return loadedSignatures.get(wrappedArg);
|
||||
}
|
||||
|
||||
for (Method m : clazz.getMethods()) {
|
||||
if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) {
|
||||
m.setAccessible(true);
|
||||
loadedSignatures.put(wrappedArg, m);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
loadedSignatures.put(wrappedArg, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.command.CFICommands;
|
||||
import com.boydti.fawe.object.RunnableVal3;
|
||||
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||
@ -15,20 +16,32 @@ import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.ChunkCoordIntPair;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.event.platform.BlockInteractEvent;
|
||||
import com.sk89q.worldedit.event.platform.Interaction;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* The CFIPacketListener handles packets for editing the VirtualWorld
|
||||
@ -45,99 +58,90 @@ public class CFIPacketListener implements Listener {
|
||||
this.plugin = plugin;
|
||||
this.protocolmanager = ProtocolLibrary.getProtocolManager();
|
||||
|
||||
// TODO NOT IMPLEMENTED
|
||||
// // Direct digging to the virtual world
|
||||
// registerBlockEvent(PacketType.Play.Client.BLOCK_DIG, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
// @Override
|
||||
// public void run(Builder event, URI gen, String pt) {
|
||||
// try {
|
||||
// Player plr = event.getPlayer();
|
||||
// BlockVector3 realPos = pt.add(gen.getOrigin().toBlockPoint());
|
||||
// if (!sendBlockChange(plr, gen, pt, Interaction.HIT)) {
|
||||
// gen.setBlock(pt, BlockTypes.AIR.getDefaultState());
|
||||
// }
|
||||
// } catch (WorldEditException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // Direct placing to the virtual world
|
||||
// RunnableVal3<PacketEvent, VirtualWorld, BlockVector3> placeTask = new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
// @Override
|
||||
// public void run(Builder event, URI gen, String pt) {
|
||||
// try {
|
||||
// Player plr = event.getPlayer();
|
||||
// List<EnumWrappers.Hand> hands = event.getPacket().getHands().getValues();
|
||||
//
|
||||
// EnumWrappers.Hand enumHand = hands.isEmpty() ? EnumWrappers.Hand.MAIN_HAND : hands.get(0);
|
||||
// PlayerInventory inv = plr.getInventory();
|
||||
// ItemStack hand = enumHand == EnumWrappers.Hand.MAIN_HAND ? inv.getItemInMainHand() : inv.getItemInOffHand();
|
||||
// if (hand.getType().isBlock()) {
|
||||
// Material type = hand.getType();
|
||||
// switch (type) {
|
||||
// case AIR:
|
||||
// case CAVE_AIR:
|
||||
// case VOID_AIR:
|
||||
// break;
|
||||
// default: {
|
||||
// BlockStateHolder block = BukkitAdapter.asBlockState(hand);
|
||||
// if (block != null) {
|
||||
// gen.setBlock(pt, block);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// pt = getRelPos(event, gen);
|
||||
// sendBlockChange(plr, gen, pt, Interaction.OPEN);
|
||||
// } catch (WorldEditException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// registerBlockEvent(PacketType.Play.Client.BLOCK_PLACE, true, placeTask);
|
||||
// registerBlockEvent(PacketType.Play.Client.USE_ITEM, true, placeTask);
|
||||
//
|
||||
// // Cancel block change packets where the real world overlaps with the virtual one
|
||||
// registerBlockEvent(PacketType.Play.Server.BLOCK_CHANGE, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
// @Override
|
||||
// public void run(Builder event, URI gen, String pt) {
|
||||
// // Do nothing
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // Modify chunk packets where the real world overlaps with the virtual one
|
||||
// protocolmanager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP_CHUNK) {
|
||||
// @Override
|
||||
// public void onPacketSending(PacketEvent event) {
|
||||
// if (!event.isServerPacket()) return;
|
||||
//
|
||||
// VirtualWorld gen = getGenerator(event);
|
||||
// if (gen != null) {
|
||||
// BlockVector3 origin = gen.getOrigin().toBlockPoint();
|
||||
// PacketContainer packet = event.getPacket();
|
||||
// StructureModifier<Integer> ints = packet.getIntegers();
|
||||
// int cx = ints.read(0);
|
||||
// int cz = ints.read(1);
|
||||
//
|
||||
// int ocx = origin.getBlockX() >> 4;
|
||||
// int ocz = origin.getBlockZ() >> 4;
|
||||
//
|
||||
// if (gen.contains(BlockVector3.at((cx - ocx) << 4, 0, (cz - ocz) << 4))) {
|
||||
// event.setCancelled(true);
|
||||
//
|
||||
// Player plr = event.getPlayer();
|
||||
//
|
||||
// FaweQueue queue = SetQueue.IMP.getNewQueue(plr.getWorld().getName(), true, false);
|
||||
//
|
||||
// FaweChunk toSend = gen.getSnapshot(cx - ocx, cz - ocz);
|
||||
// toSend.setLoc(gen, cx, cz);
|
||||
// queue.sendChunkUpdate(toSend, FawePlayer.wrap(plr));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// Direct digging to the virtual world
|
||||
registerBlockEvent(PacketType.Play.Client.BLOCK_DIG, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
@Override
|
||||
public void run(PacketEvent event, VirtualWorld gen, BlockVector3 pt) {
|
||||
try {
|
||||
Player plr = event.getPlayer();
|
||||
BlockVector3 realPos = pt.add(gen.getOrigin().toBlockPoint());
|
||||
if (!sendBlockChange(plr, gen, pt, Interaction.HIT)) {
|
||||
gen.setBlock(pt, BlockTypes.AIR.getDefaultState());
|
||||
}
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Direct placing to the virtual world
|
||||
RunnableVal3<PacketEvent, VirtualWorld, BlockVector3> placeTask = new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
@Override
|
||||
public void run(PacketEvent event, VirtualWorld gen, BlockVector3 pt) {
|
||||
try {
|
||||
Player plr = event.getPlayer();
|
||||
List<EnumWrappers.Hand> hands = event.getPacket().getHands().getValues();
|
||||
|
||||
EnumWrappers.Hand enumHand = hands.isEmpty() ? EnumWrappers.Hand.MAIN_HAND : hands.get(0);
|
||||
PlayerInventory inv = plr.getInventory();
|
||||
ItemStack hand = enumHand == EnumWrappers.Hand.MAIN_HAND ? inv.getItemInMainHand() : inv.getItemInOffHand();
|
||||
if (hand.getType().isBlock()) {
|
||||
Material type = hand.getType();
|
||||
switch (type) {
|
||||
case AIR:
|
||||
case CAVE_AIR:
|
||||
case VOID_AIR:
|
||||
break;
|
||||
default: {
|
||||
BlockStateHolder block = BukkitAdapter.asBlockState(hand);
|
||||
if (block != null) {
|
||||
gen.setBlock(pt, block);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pt = getRelPos(event, gen);
|
||||
sendBlockChange(plr, gen, pt, Interaction.OPEN);
|
||||
} catch (WorldEditException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
registerBlockEvent(PacketType.Play.Client.BLOCK_PLACE, true, placeTask);
|
||||
registerBlockEvent(PacketType.Play.Client.USE_ITEM, true, placeTask);
|
||||
|
||||
// Cancel block change packets where the real world overlaps with the virtual one
|
||||
registerBlockEvent(PacketType.Play.Server.BLOCK_CHANGE, false, new RunnableVal3<PacketEvent, VirtualWorld, BlockVector3>() {
|
||||
@Override
|
||||
public void run(PacketEvent event, VirtualWorld gen, BlockVector3 pt) {
|
||||
// Do nothing
|
||||
}
|
||||
});
|
||||
|
||||
// Modify chunk packets where the real world overlaps with the virtual one
|
||||
protocolmanager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.MAP_CHUNK) {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
if (!event.isServerPacket() || FaweCache.IMP.CHUNK_FLAG.get().get()) return;
|
||||
VirtualWorld gen = getGenerator(event);
|
||||
if (gen != null) {
|
||||
BlockVector3 origin = gen.getOrigin().toBlockPoint();
|
||||
PacketContainer packet = event.getPacket();
|
||||
StructureModifier<Integer> ints = packet.getIntegers();
|
||||
int cx = ints.read(0);
|
||||
int cz = ints.read(1);
|
||||
|
||||
int ocx = origin.getBlockX() >> 4;
|
||||
int ocz = origin.getBlockZ() >> 4;
|
||||
|
||||
if (gen.contains(BlockVector3.at((cx - ocx) << 4, 0, (cz - ocz) << 4))) {
|
||||
event.setCancelled(true);
|
||||
gen.refreshChunk(cx - ocx, cz - ocz);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// The following few listeners are to ignore block collisions where the virtual and real world overlap
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
|
||||
public class ChunkCache {
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
package com.boydti.fawe.bukkit.preloader;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.plugin.PluginBase;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.PluginLoader;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PluginPreloader extends PluginBase {
|
||||
private World world;
|
||||
private Set<BlockVector2> loaded;
|
||||
private int index;
|
||||
private AtomicBoolean invalidator;
|
||||
private final Object invalidatorLock;
|
||||
|
||||
public PluginPreloader() {
|
||||
invalidator = new AtomicBoolean();
|
||||
invalidatorLock = new Object();
|
||||
}
|
||||
|
||||
public AtomicBoolean invalidate() {
|
||||
synchronized (invalidatorLock) {
|
||||
invalidator.set(false);
|
||||
return invalidator = new AtomicBoolean(true);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void unload() {
|
||||
World oldWorld = world;
|
||||
if (oldWorld != null) {
|
||||
Set<BlockVector2> toUnload = loaded;
|
||||
if (loaded != null && index > 0) {
|
||||
Iterator<BlockVector2> iter = toUnload.iterator();
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
for (int i = 0; i < index && iter.hasNext(); i++) {
|
||||
BlockVector2 chunk = iter.next();
|
||||
world.removePluginChunkTicket(chunk.getX(), chunk.getZ(), this);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
this.world = null;
|
||||
this.loaded = null;
|
||||
this.index = 0;
|
||||
}
|
||||
|
||||
public void update(Region region) {
|
||||
AtomicBoolean invalidator = invalidate();
|
||||
synchronized (this) {
|
||||
com.sk89q.worldedit.world.World weWorld = region.getWorld();
|
||||
if (weWorld == null) {
|
||||
return;
|
||||
}
|
||||
unload();
|
||||
index = 0;
|
||||
world = BukkitAdapter.adapt(weWorld);
|
||||
loaded = region.getChunks();
|
||||
Iterator<BlockVector2> iter = loaded.iterator();
|
||||
|
||||
if (!invalidator.get()) return;
|
||||
Fawe.get().getQueueHandler().syncWhenFree(() -> {
|
||||
for (; iter.hasNext() && invalidator.get();index++) {
|
||||
BlockVector2 chunk = iter.next();
|
||||
if (!world.isChunkLoaded(chunk.getX(), chunk.getZ())) {
|
||||
world.addPluginChunkTicket(chunk.getX(), chunk.getZ(), this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
invalidate();
|
||||
unload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull File getDataFolder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PluginDescriptionFile getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull FileConfiguration getConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable InputStream getResource(@NotNull String filename) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveConfig() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveDefaultConfig() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveResource(@NotNull String resourcePath, boolean replace) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PluginLoader getPluginLoader() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Server getServer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNaggable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNaggable(boolean canNag) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, @Nullable String id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Logger getLogger() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -19,173 +19,173 @@ import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
//import org.inventivetalent.mapmanager.MapManagerPlugin;
|
||||
//import org.inventivetalent.mapmanager.controller.MapController;
|
||||
//import org.inventivetalent.mapmanager.controller.MultiMapController;
|
||||
//import org.inventivetalent.mapmanager.manager.MapManager;
|
||||
//import org.inventivetalent.mapmanager.wrapper.MapWrapper;
|
||||
import org.inventivetalent.mapmanager.MapManagerPlugin;
|
||||
import org.inventivetalent.mapmanager.controller.MapController;
|
||||
import org.inventivetalent.mapmanager.controller.MultiMapController;
|
||||
import org.inventivetalent.mapmanager.manager.MapManager;
|
||||
import org.inventivetalent.mapmanager.wrapper.MapWrapper;
|
||||
|
||||
public class BukkitImageViewer implements ImageViewer {
|
||||
// private final MapManager mapManager;
|
||||
// private final Player player;
|
||||
// private BufferedImage last;
|
||||
private final MapManager mapManager;
|
||||
private final Player player;
|
||||
private BufferedImage last;
|
||||
private ItemFrame[][] frames;
|
||||
// private boolean reverse;
|
||||
private boolean reverse;
|
||||
|
||||
public BukkitImageViewer(Player player) {
|
||||
// mapManager = ((MapManagerPlugin) Bukkit.getPluginManager().getPlugin("MapManager")).getMapManager();
|
||||
// this.player = player;
|
||||
mapManager = ((MapManagerPlugin) Bukkit.getPluginManager().getPlugin("MapManager")).getMapManager();
|
||||
this.player = player;
|
||||
}
|
||||
//
|
||||
|
||||
public void selectFrame(ItemFrame start) {
|
||||
// Location pos1 = start.getLocation().clone();
|
||||
// Location pos2 = start.getLocation().clone();
|
||||
//
|
||||
// BlockFace facing = start.getFacing();
|
||||
// int planeX = facing.getModX() == 0 ? 1 : 0;
|
||||
// int planeY = facing.getModY() == 0 ? 1 : 0;
|
||||
// int planeZ = facing.getModZ() == 0 ? 1 : 0;
|
||||
//
|
||||
// ItemFrame[][] res = find(pos1, pos2, facing);
|
||||
// Location tmp;
|
||||
// while (true) {
|
||||
// if (res != null) {
|
||||
// frames = res;
|
||||
// }
|
||||
// tmp = pos1.clone().subtract(planeX, planeY, planeZ);
|
||||
// if ((res = find(tmp, pos2, facing)) != null) {
|
||||
// pos1 = tmp;
|
||||
// continue;
|
||||
// }
|
||||
// tmp = pos2.clone().add(planeX, planeY, planeZ);
|
||||
// if ((res = find(pos1, tmp, facing)) != null) {
|
||||
// pos2 = tmp;
|
||||
// continue;
|
||||
// }
|
||||
// tmp = pos1.clone().subtract(planeX, 0, planeZ);
|
||||
// if ((res = find(tmp, pos2, facing)) != null) {
|
||||
// pos1 = tmp;
|
||||
// continue;
|
||||
// }
|
||||
// tmp = pos2.clone().add(planeX, 0, planeZ);
|
||||
// if ((res = find(pos1, tmp, facing)) != null) {
|
||||
// pos2 = tmp;
|
||||
// continue;
|
||||
// }
|
||||
// tmp = pos1.clone().subtract(0, 1, 0);
|
||||
// if ((res = find(tmp, pos2, facing)) != null) {
|
||||
// pos1 = tmp;
|
||||
// continue;
|
||||
// }
|
||||
// tmp = pos2.clone().add(0, 1, 0);
|
||||
// if ((res = find(pos1, tmp, facing)) != null) {
|
||||
// pos2 = tmp;
|
||||
// continue;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
Location pos1 = start.getLocation().clone();
|
||||
Location pos2 = start.getLocation().clone();
|
||||
|
||||
BlockFace facing = start.getFacing();
|
||||
int planeX = facing.getModX() == 0 ? 1 : 0;
|
||||
int planeY = facing.getModY() == 0 ? 1 : 0;
|
||||
int planeZ = facing.getModZ() == 0 ? 1 : 0;
|
||||
|
||||
ItemFrame[][] res = find(pos1, pos2, facing);
|
||||
Location tmp;
|
||||
while (true) {
|
||||
if (res != null) {
|
||||
frames = res;
|
||||
}
|
||||
tmp = pos1.clone().subtract(planeX, planeY, planeZ);
|
||||
if ((res = find(tmp, pos2, facing)) != null) {
|
||||
pos1 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos2.clone().add(planeX, planeY, planeZ);
|
||||
if ((res = find(pos1, tmp, facing)) != null) {
|
||||
pos2 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos1.clone().subtract(planeX, 0, planeZ);
|
||||
if ((res = find(tmp, pos2, facing)) != null) {
|
||||
pos1 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos2.clone().add(planeX, 0, planeZ);
|
||||
if ((res = find(pos1, tmp, facing)) != null) {
|
||||
pos2 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos1.clone().subtract(0, 1, 0);
|
||||
if ((res = find(tmp, pos2, facing)) != null) {
|
||||
pos1 = tmp;
|
||||
continue;
|
||||
}
|
||||
tmp = pos2.clone().add(0, 1, 0);
|
||||
if ((res = find(pos1, tmp, facing)) != null) {
|
||||
pos2 = tmp;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
public ItemFrame[][] getItemFrames() {
|
||||
return frames;
|
||||
}
|
||||
//
|
||||
// private ItemFrame[][] find(Location pos1, Location pos2, BlockFace facing) {
|
||||
// try {
|
||||
// Location distance = pos2.clone().subtract(pos1).add(1, 1, 1);
|
||||
// int width = Math.max(distance.getBlockX(), distance.getBlockZ());
|
||||
// ItemFrame[][] frames = new ItemFrame[width][distance.getBlockY()];
|
||||
//
|
||||
// World world = pos1.getWorld();
|
||||
//
|
||||
// this.reverse = (facing == BlockFace.NORTH || facing == BlockFace.EAST);
|
||||
// int v = 0;
|
||||
// for (double y = pos1.getY(); y <= pos2.getY(); y++, v++) {
|
||||
// int h = 0;
|
||||
// for (double z = pos1.getZ(); z <= pos2.getZ(); z++) {
|
||||
// for (double x = pos1.getX(); x <= pos2.getX(); x++, h++) {
|
||||
// Location pos = new Location(world, x, y, z);
|
||||
// Collection<Entity> entities = world.getNearbyEntities(pos, 0.1, 0.1, 0.1);
|
||||
// boolean contains = false;
|
||||
// for (Entity ent : entities) {
|
||||
// if (ent instanceof ItemFrame && ((ItemFrame) ent).getFacing() == facing) {
|
||||
// ItemFrame itemFrame = (ItemFrame) ent;
|
||||
// itemFrame.setRotation(Rotation.NONE);
|
||||
// contains = true;
|
||||
// frames[reverse ? width - 1 - h : h][v] = (ItemFrame) ent;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (!contains) return null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return frames;
|
||||
// } catch (Throwable e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
private ItemFrame[][] find(Location pos1, Location pos2, BlockFace facing) {
|
||||
try {
|
||||
Location distance = pos2.clone().subtract(pos1).add(1, 1, 1);
|
||||
int width = Math.max(distance.getBlockX(), distance.getBlockZ());
|
||||
ItemFrame[][] frames = new ItemFrame[width][distance.getBlockY()];
|
||||
|
||||
World world = pos1.getWorld();
|
||||
|
||||
this.reverse = (facing == BlockFace.NORTH || facing == BlockFace.EAST);
|
||||
int v = 0;
|
||||
for (double y = pos1.getY(); y <= pos2.getY(); y++, v++) {
|
||||
int h = 0;
|
||||
for (double z = pos1.getZ(); z <= pos2.getZ(); z++) {
|
||||
for (double x = pos1.getX(); x <= pos2.getX(); x++, h++) {
|
||||
Location pos = new Location(world, x, y, z);
|
||||
Collection<Entity> entities = world.getNearbyEntities(pos, 0.1, 0.1, 0.1);
|
||||
boolean contains = false;
|
||||
for (Entity ent : entities) {
|
||||
if (ent instanceof ItemFrame && ((ItemFrame) ent).getFacing() == facing) {
|
||||
ItemFrame itemFrame = (ItemFrame) ent;
|
||||
itemFrame.setRotation(Rotation.NONE);
|
||||
contains = true;
|
||||
frames[reverse ? width - 1 - h : h][v] = (ItemFrame) ent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!contains) return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return frames;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void view(Drawable drawable) {
|
||||
// view(null, drawable);
|
||||
view(null, drawable);
|
||||
}
|
||||
//
|
||||
// private void view(@Nullable BufferedImage image, @Nullable Drawable drawable) {
|
||||
// if (image == null && drawable == null) throw new IllegalArgumentException("An image or drawable must be provided. Both cannot be null");
|
||||
// boolean initializing = last == null;
|
||||
//
|
||||
// if (this.frames != null) {
|
||||
// if (image == null && drawable != null) image = drawable.draw();
|
||||
// last = image;
|
||||
// int width = frames.length;
|
||||
// int height = frames[0].length;
|
||||
// BufferedImage scaled = ImageUtil.getScaledInstance(image, 128 * width, 128 * height, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
|
||||
// MapWrapper mapWrapper = mapManager.wrapMultiImage(scaled, width, height);
|
||||
// MultiMapController controller = (MultiMapController) mapWrapper.getController();
|
||||
// controller.addViewer(player);
|
||||
// controller.sendContent(player);
|
||||
// controller.showInFrames(player, frames, true);
|
||||
// } else {
|
||||
// int slot = getMapSlot(player);
|
||||
// if (slot == -1) {
|
||||
// if (initializing) {
|
||||
// player.getInventory().setItemInMainHand(new ItemStack(Material.MAP));
|
||||
// } else {
|
||||
// return;
|
||||
// }
|
||||
// } else if (player.getInventory().getHeldItemSlot() != slot) {
|
||||
// player.getInventory().setHeldItemSlot(slot);
|
||||
// }
|
||||
// if (image == null && drawable != null) image = drawable.draw();
|
||||
// last = image;
|
||||
// BufferedImage scaled = ImageUtil.getScaledInstance(image, 128, 128, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
|
||||
// MapWrapper mapWrapper = mapManager.wrapImage(scaled);
|
||||
// MapController controller = mapWrapper.getController();
|
||||
// controller.addViewer(player);
|
||||
// controller.sendContent(player);
|
||||
// controller.showInHand(player, true);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private int getMapSlot(Player player) {
|
||||
// PlayerInventory inventory = player.getInventory();
|
||||
// for (int i = 0; i < 9; i++) {
|
||||
// ItemStack item = inventory.getItem(i);
|
||||
// if (item != null && item.getType() == Material.MAP) {
|
||||
// return i;
|
||||
// }
|
||||
// }
|
||||
// return -1;
|
||||
// }
|
||||
//
|
||||
|
||||
private void view(@Nullable BufferedImage image, @Nullable Drawable drawable) {
|
||||
if (image == null && drawable == null) throw new IllegalArgumentException("An image or drawable must be provided. Both cannot be null");
|
||||
boolean initializing = last == null;
|
||||
|
||||
if (this.frames != null) {
|
||||
if (image == null && drawable != null) image = drawable.draw();
|
||||
last = image;
|
||||
int width = frames.length;
|
||||
int height = frames[0].length;
|
||||
BufferedImage scaled = ImageUtil.getScaledInstance(image, 128 * width, 128 * height, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
|
||||
MapWrapper mapWrapper = mapManager.wrapMultiImage(scaled, width, height);
|
||||
MultiMapController controller = (MultiMapController) mapWrapper.getController();
|
||||
controller.addViewer(player);
|
||||
controller.sendContent(player);
|
||||
controller.showInFrames(player, frames, true);
|
||||
} else {
|
||||
int slot = getMapSlot(player);
|
||||
if (slot == -1) {
|
||||
if (initializing) {
|
||||
player.getInventory().setItemInMainHand(new ItemStack(Material.MAP));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (player.getInventory().getHeldItemSlot() != slot) {
|
||||
player.getInventory().setHeldItemSlot(slot);
|
||||
}
|
||||
if (image == null && drawable != null) image = drawable.draw();
|
||||
last = image;
|
||||
BufferedImage scaled = ImageUtil.getScaledInstance(image, 128, 128, RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
|
||||
MapWrapper mapWrapper = mapManager.wrapImage(scaled);
|
||||
MapController controller = mapWrapper.getController();
|
||||
controller.addViewer(player);
|
||||
controller.sendContent(player);
|
||||
controller.showInHand(player, true);
|
||||
}
|
||||
}
|
||||
|
||||
private int getMapSlot(Player player) {
|
||||
PlayerInventory inventory = player.getInventory();
|
||||
for (int i = 0; i < 9; i++) {
|
||||
ItemStack item = inventory.getItem(i);
|
||||
if (item != null && item.getType() == Material.MAP) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
// if (last != null) view(last, null);
|
||||
if (last != null) view(last, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// last = null;
|
||||
last = null;
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@ -57,7 +58,7 @@ public class AsyncBlock implements Block {
|
||||
}
|
||||
|
||||
public int getPropertyId() {
|
||||
return world.getBlock(x, y, z).getInternalId() >> BlockTypes.BIT_OFFSET;
|
||||
return world.getBlock(x, y, z).getInternalId() >> BlockTypesCache.BIT_OFFSET;
|
||||
}
|
||||
|
||||
public int getCombinedId() {
|
||||
@ -105,7 +106,7 @@ public class AsyncBlock implements Block {
|
||||
|
||||
@Deprecated
|
||||
public boolean setTypeIdAndPropertyId(int id, int propertyId) {
|
||||
return setCombinedId(id + (propertyId << BlockTypes.BIT_OFFSET));
|
||||
return setCombinedId(id + (propertyId << BlockTypesCache.BIT_OFFSET));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
@ -9,6 +9,7 @@ import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@ -42,7 +43,7 @@ public class AsyncBlockState implements BlockState {
|
||||
}
|
||||
|
||||
public int getPropertyId() {
|
||||
return state.getInternalId() >> BlockTypes.BIT_OFFSET;
|
||||
return state.getInternalId() >> BlockTypesCache.BIT_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,12 +159,12 @@ public class AsyncBlockState implements BlockState {
|
||||
|
||||
@Override
|
||||
public byte getRawData() {
|
||||
return (byte) (state.getInternalId() >> BlockTypes.BIT_OFFSET);
|
||||
return (byte) (state.getInternalId() >> BlockTypesCache.BIT_OFFSET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRawData(byte data) {
|
||||
int combinedId = getTypeId() + (data << BlockTypes.BIT_OFFSET);
|
||||
int combinedId = getTypeId() + (data << BlockTypesCache.BIT_OFFSET);
|
||||
state = com.sk89q.worldedit.world.block.BlockState.getFromInternalId(combinedId).toBaseBlock(state.getNbtData());
|
||||
this.blockData = BukkitAdapter.adapt(state);
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ public enum BukkitAdapter {
|
||||
*/
|
||||
public static Player adapt(com.sk89q.worldedit.entity.Player player) {
|
||||
player = PlayerProxy.unwrap(player);
|
||||
return ((BukkitPlayer) player).getPlayer();
|
||||
return player == null ? null : ((BukkitPlayer) player).getPlayer();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,6 +34,7 @@ import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public class BukkitBlockRegistry extends BundledBlockRegistry {
|
||||
|
||||
@ -93,6 +94,10 @@ public class BukkitBlockRegistry extends BundledBlockRegistry {
|
||||
this.material = bukkitMaterial;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return material.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
switch (material) {
|
||||
@ -132,4 +137,9 @@ public class BukkitBlockRegistry extends BundledBlockRegistry {
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
return WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBlockStateId(state);
|
||||
}
|
||||
}
|
||||
|
@ -47,11 +47,6 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||
import com.sk89q.worldedit.world.gamemode.GameModes;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
@ -62,23 +57,44 @@ import org.bukkit.event.player.PlayerDropItemEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class BukkitPlayer extends AbstractPlayerActor {
|
||||
|
||||
private Player player;
|
||||
private WorldEditPlugin plugin;
|
||||
|
||||
public BukkitPlayer(Player player) {
|
||||
this(WorldEditPlugin.getInstance(), player);
|
||||
super(getExistingMap(WorldEditPlugin.getInstance(), player));
|
||||
this.plugin = WorldEditPlugin.getInstance();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public BukkitPlayer(WorldEditPlugin plugin, Player player) {
|
||||
this.plugin = plugin;
|
||||
this.player = player;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (Settings.IMP.CLIPBOARD.USE_DISK) {
|
||||
loadClipboardFromDisk();
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, Object> getExistingMap(WorldEditPlugin plugin, Player player) {
|
||||
BukkitPlayer cached = plugin.getCachedPlayer(player);
|
||||
if (cached != null) {
|
||||
return cached.getRawMeta();
|
||||
}
|
||||
return new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return player.getUniqueId();
|
||||
@ -87,16 +103,16 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
@Override
|
||||
public BaseItemStack getItemInHand(HandSide handSide) {
|
||||
ItemStack itemStack = handSide == HandSide.MAIN_HAND
|
||||
? player.getInventory().getItemInMainHand()
|
||||
: player.getInventory().getItemInOffHand();
|
||||
? getPlayer().getInventory().getItemInMainHand()
|
||||
: getPlayer().getInventory().getItemInOffHand();
|
||||
return BukkitAdapter.adapt(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlockInHand(HandSide handSide) throws WorldEditException {
|
||||
ItemStack itemStack = handSide == HandSide.MAIN_HAND
|
||||
? player.getInventory().getItemInMainHand()
|
||||
: player.getInventory().getItemInOffHand();
|
||||
? getPlayer().getInventory().getItemInMainHand()
|
||||
: getPlayer().getInventory().getItemInOffHand();
|
||||
return BukkitAdapter.asBlockState(itemStack).toBaseBlock();
|
||||
}
|
||||
|
||||
@ -107,18 +123,18 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return player.getDisplayName();
|
||||
return getPlayer().getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void giveItem(BaseItemStack itemStack) {
|
||||
final PlayerInventory inv = player.getInventory();
|
||||
final PlayerInventory inv = getPlayer().getInventory();
|
||||
ItemStack newItem = BukkitAdapter.adapt(itemStack);
|
||||
if (itemStack.getType().getId().equalsIgnoreCase(WorldEdit.getInstance().getConfiguration().wandItem)) {
|
||||
inv.remove(newItem);
|
||||
}
|
||||
final ItemStack item = player.getInventory().getItemInMainHand();
|
||||
player.getInventory().setItemInMainHand(newItem);
|
||||
final ItemStack item = getPlayer().getInventory().getItemInMainHand();
|
||||
getPlayer().getInventory().setItemInMainHand(newItem);
|
||||
HashMap<Integer, ItemStack> overflow = inv.addItem(item);
|
||||
if (!overflow.isEmpty()) {
|
||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||
@ -128,7 +144,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
ItemStack stack = entry.getValue();
|
||||
if (stack.getType() != Material.AIR && stack.getAmount() > 0) {
|
||||
Item
|
||||
dropped = player.getWorld().dropItem(player.getLocation(), stack);
|
||||
dropped = getPlayer().getWorld().dropItem(getPlayer().getLocation(), stack);
|
||||
PlayerDropItemEvent event = new PlayerDropItemEvent(player, dropped);
|
||||
if (event.isCancelled()) {
|
||||
dropped.remove();
|
||||
@ -138,45 +154,45 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
}
|
||||
});
|
||||
}
|
||||
player.updateInventory();
|
||||
getPlayer().updateInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printRaw(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
player.sendMessage(part);
|
||||
getPlayer().sendMessage(part);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
player.sendMessage("\u00A7d" + part);
|
||||
getPlayer().sendMessage("\u00A7d" + part);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printDebug(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
player.sendMessage("\u00A77" + part);
|
||||
getPlayer().sendMessage("\u00A77" + part);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printError(String msg) {
|
||||
for (String part : msg.split("\n")) {
|
||||
player.sendMessage("§c" + part);
|
||||
getPlayer().sendMessage("§c" + part);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(Component component) {
|
||||
TextAdapter.sendComponent(player, WorldEditText.format(component));
|
||||
TextAdapter.sendComponent(getPlayer(), WorldEditText.format(component));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPosition(Vector3 pos, float pitch, float yaw) {
|
||||
org.bukkit.World world = player.getWorld();
|
||||
org.bukkit.World world = getPlayer().getWorld();
|
||||
if (pos instanceof com.sk89q.worldedit.util.Location) {
|
||||
com.sk89q.worldedit.util.Location loc = (com.sk89q.worldedit.util.Location) pos;
|
||||
Extent extent = loc.getExtent();
|
||||
@ -184,42 +200,41 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
world = Bukkit.getWorld(((World) extent).getName());
|
||||
}
|
||||
}
|
||||
player.teleport(new Location(world, pos.getX(), pos.getY(), pos.getZ(), yaw, pitch));
|
||||
getPlayer().teleport(new Location(world, pos.getX(), pos.getY(), pos.getZ(), yaw, pitch));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getGroups() {
|
||||
return plugin.getPermissionsResolver().getGroups(player);
|
||||
return plugin.getPermissionsResolver().getGroups(getPlayer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockBag getInventoryBlockBag() {
|
||||
return new BukkitPlayerBlockBag(player);
|
||||
return new BukkitPlayerBlockBag(getPlayer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameMode getGameMode() {
|
||||
return GameModes.get(player.getGameMode().name().toLowerCase(Locale.ROOT));
|
||||
return GameModes.get(getPlayer().getGameMode().name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameMode(GameMode gameMode) {
|
||||
player.setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT)));
|
||||
getPlayer().setGameMode(org.bukkit.GameMode.valueOf(gameMode.getId().toUpperCase(Locale.ROOT)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String perm) {
|
||||
return (!plugin.getLocalConfiguration().noOpPermissions && player.isOp())
|
||||
|| plugin.getPermissionsResolver().hasPermission(
|
||||
player.getWorld().getName(), player, perm);
|
||||
|| plugin.getPermissionsResolver().hasPermission(player.getWorld().getName(), player, perm);
|
||||
}
|
||||
|
||||
@Override public boolean togglePermission(String permission) {
|
||||
if (this.hasPermission(permission)) {
|
||||
player.addAttachment(plugin).setPermission(permission, false);
|
||||
getPlayer().addAttachment(plugin).setPermission(permission, false);
|
||||
return false;
|
||||
} else {
|
||||
player.addAttachment(plugin).setPermission(permission, true);
|
||||
getPlayer().addAttachment(plugin).setPermission(permission, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -231,19 +246,19 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
* - The `/wea` command will give/remove the required bypass permission
|
||||
*/
|
||||
if (Fawe.<FaweBukkit>imp().getVault() == null || Fawe.<FaweBukkit> imp().getVault().permission == null) {
|
||||
player.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission(permission, value);
|
||||
getPlayer().addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission(permission, value);
|
||||
} else if (value) {
|
||||
if (!Fawe.<FaweBukkit> imp().getVault().permission.playerAdd(player, permission)) {
|
||||
player.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission(permission, value);
|
||||
getPlayer().addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission(permission, value);
|
||||
}
|
||||
} else if (!Fawe.<FaweBukkit>imp().getVault().permission.playerRemove(player, permission)) {
|
||||
player.addAttachment(Fawe.<FaweBukkit>imp().getPlugin()).setPermission(permission, value);
|
||||
getPlayer().addAttachment(Fawe.<FaweBukkit>imp().getPlugin()).setPermission(permission, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return BukkitAdapter.adapt(player.getWorld());
|
||||
return BukkitAdapter.adapt(getPlayer().getWorld());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -253,21 +268,30 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
if (params.length > 0) {
|
||||
send = send + "|" + StringUtil.joinString(params, "|");
|
||||
}
|
||||
player.sendPluginMessage(plugin, WorldEditPlugin.CUI_PLUGIN_CHANNEL, send.getBytes(CUIChannelListener.UTF_8_CHARSET));
|
||||
getPlayer().sendPluginMessage(plugin, WorldEditPlugin.CUI_PLUGIN_CHANNEL, send.getBytes(CUIChannelListener.UTF_8_CHARSET));
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
if (!player.isValid()) {
|
||||
Player tmp = Bukkit.getPlayer(getUniqueId());
|
||||
if (tmp != null) {
|
||||
player = tmp;
|
||||
} else {
|
||||
System.out.println("Invalid player " + player.getName());
|
||||
new Exception().printStackTrace();
|
||||
}
|
||||
}
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowedToFly() {
|
||||
return player.getAllowFlight();
|
||||
return getPlayer().getAllowFlight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFlying(boolean flying) {
|
||||
player.setFlying(flying);
|
||||
getPlayer().setFlying(flying);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -277,7 +301,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
|
||||
@Override
|
||||
public com.sk89q.worldedit.util.Location getLocation() {
|
||||
Location nativeLocation = player.getLocation();
|
||||
Location nativeLocation = getPlayer().getLocation();
|
||||
Vector3 position = BukkitAdapter.asVector(nativeLocation);
|
||||
return new com.sk89q.worldedit.util.Location(
|
||||
getWorld(),
|
||||
@ -288,7 +312,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
|
||||
@Override
|
||||
public boolean setLocation(com.sk89q.worldedit.util.Location location) {
|
||||
return player.teleport(BukkitAdapter.adapt(location));
|
||||
return getPlayer().teleport(BukkitAdapter.adapt(location));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -299,7 +323,7 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
|
||||
@Override
|
||||
public SessionKey getSessionKey() {
|
||||
return new SessionKeyImpl(this.player.getUniqueId(), player.getName());
|
||||
return new SessionKeyImpl(getUniqueId(), getName());
|
||||
}
|
||||
|
||||
private static class SessionKeyImpl implements SessionKey {
|
||||
@ -342,11 +366,11 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> void sendFakeBlock(BlockVector3 pos, B block) {
|
||||
Location loc = new Location(player.getWorld(), pos.getX(), pos.getY(), pos.getZ());
|
||||
Location loc = new Location(getPlayer().getWorld(), pos.getX(), pos.getY(), pos.getZ());
|
||||
if (block == null) {
|
||||
player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData());
|
||||
getPlayer().sendBlockChange(loc, getPlayer().getWorld().getBlockAt(loc).getBlockData());
|
||||
} else {
|
||||
player.sendBlockChange(loc, BukkitAdapter.adapt(block));
|
||||
getPlayer().sendBlockChange(loc, BukkitAdapter.adapt(block));
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
@ -361,8 +385,13 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
|
||||
@Override
|
||||
public void sendTitle(String title, String sub) {
|
||||
player.sendTitle(ChatColor.GOLD + title, ChatColor.GOLD + sub, 0, 70, 20);
|
||||
getPlayer().sendTitle(ChatColor.GOLD + title, ChatColor.GOLD + sub, 0, 70, 20);
|
||||
Bukkit.getServer().dispatchCommand(player, "title " + getName() + " subtitle [{\"text\":\"" + sub + "\",\"color\":\"gold\"}]");
|
||||
Bukkit.getServer().dispatchCommand(player, "title " + getName() + " title [{\"text\":\"" + title + "\",\"color\":\"gold\"}]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister() {
|
||||
getPlayer().removeMetadata("WE", WorldEditPlugin.getInstance());
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,10 @@ package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_14.BukkitGetBlocks_1_14;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
@ -31,6 +34,7 @@ import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.history.change.BlockChange;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -52,6 +56,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bukkit.Effect;
|
||||
import org.bukkit.TreeType;
|
||||
import org.bukkit.World;
|
||||
@ -317,8 +322,19 @@ public class BukkitWorld extends AbstractWorld {
|
||||
@Override
|
||||
public void checkLoadedChunk(BlockVector3 pt) {
|
||||
World world = getWorld();
|
||||
|
||||
world.getChunkAt(pt.getBlockX() >> 4, pt.getBlockZ() >> 4);
|
||||
int X = pt.getBlockX() >> 4;
|
||||
int Z = pt.getBlockZ() >> 4;
|
||||
if (Fawe.isMainThread()) {
|
||||
world.getChunkAt(X, Z);
|
||||
} else if (!world.isChunkLoaded(X, Z)) {
|
||||
if (FaweBukkit.PAPER) {
|
||||
world.getChunkAtAsync(X, Z, true);
|
||||
} else {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
world.getChunkAt(X, Z);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -516,11 +532,18 @@ public class BukkitWorld extends AbstractWorld {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendChunk(int chunkX, int chunkZ, int bitMask) {
|
||||
public void refreshChunk(int X, int Z) {
|
||||
getWorld().refreshChunk(X, Z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_14(getWorldChecked(), chunkX, chunkZ, Settings.IMP.QUEUE.POOL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(Player player, ChunkPacket packet) {
|
||||
org.bukkit.entity.Player bukkitPlayer = BukkitAdapter.adapt(player);
|
||||
WorldEditPlugin.getInstance().getBukkitImplAdapter().sendFakeChunk(getWorld(), bukkitPlayer, packet);
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
import org.bukkit.event.world.WorldInitEvent;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
@ -559,15 +560,26 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
* @return a wrapped player
|
||||
*/
|
||||
public BukkitPlayer wrapPlayer(Player player) {
|
||||
synchronized (player) {
|
||||
@NotNull List<MetadataValue> meta = player.getMetadata("WE");
|
||||
if (meta == null || meta.isEmpty()) {
|
||||
BukkitPlayer wePlayer = new BukkitPlayer(this, player);
|
||||
player.setMetadata("WE", new FixedMetadataValue(this, wePlayer));
|
||||
return wePlayer;
|
||||
BukkitPlayer wePlayer = getCachedPlayer(player);
|
||||
if (wePlayer == null) {
|
||||
synchronized (player) {
|
||||
wePlayer = getCachedPlayer(player);
|
||||
if (wePlayer == null) {
|
||||
wePlayer = new BukkitPlayer(this, player);
|
||||
player.setMetadata("WE", new FixedMetadataValue(this, wePlayer));
|
||||
return wePlayer;
|
||||
}
|
||||
}
|
||||
return (BukkitPlayer) meta.get(0).value();
|
||||
}
|
||||
return wePlayer;
|
||||
}
|
||||
|
||||
public BukkitPlayer getCachedPlayer(Player player) {
|
||||
List<MetadataValue> meta = player.getMetadata("WE");
|
||||
if (meta == null || meta.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return (BukkitPlayer) meta.get(0).value();
|
||||
}
|
||||
|
||||
public Actor wrapCommandSender(CommandSender sender) {
|
||||
|
@ -20,6 +20,7 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
@ -141,6 +142,13 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
*/
|
||||
void sendFakeOP(Player player);
|
||||
|
||||
/**
|
||||
* Send a fake chunk packet to a player
|
||||
* @param player
|
||||
* @param packet
|
||||
*/
|
||||
void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet);
|
||||
|
||||
/**
|
||||
* Simulates a player using an item.
|
||||
*
|
||||
|
@ -6,6 +6,7 @@ import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.item.ItemTypes;
|
||||
import java.util.List;
|
||||
@ -58,7 +59,7 @@ public abstract class CachedBukkitAdapter implements IBukkitAdapter {
|
||||
@Override
|
||||
public BlockType adapt(Material material) {
|
||||
try {
|
||||
return BlockTypes.values[blockTypes[material.ordinal()]];
|
||||
return BlockTypesCache.values[blockTypes[material.ordinal()]];
|
||||
} catch (NullPointerException e) {
|
||||
if (init()) return adapt(material);
|
||||
throw e;
|
||||
|
@ -154,3 +154,76 @@ permissions:
|
||||
worldedit.extinguish: true
|
||||
worldedit.calc: true
|
||||
worldedit.fill: true
|
||||
fawe.voxelbrush:
|
||||
default: op
|
||||
children:
|
||||
voxelsniper.brush.ball: true
|
||||
voxelsniper.brush.biome: true
|
||||
voxelsniper.brush.blendball: true
|
||||
voxelsniper.brush.blenddisc: true
|
||||
voxelsniper.brush.blendvoxel: true
|
||||
voxelsniper.brush.blendvoxeldisc: true
|
||||
voxelsniper.brush.blob: true
|
||||
voxelsniper.brush.blockreset: true
|
||||
voxelsniper.brush.blockresetsurface: true
|
||||
voxelsniper.brush.canyon: true
|
||||
voxelsniper.brush.canyonselection: true
|
||||
voxelsniper.brush.checkervoxeldisc: true
|
||||
voxelsniper.brush.cleansnow: true
|
||||
voxelsniper.brush.clonestamp: true
|
||||
voxelsniper.brush.copypasta: true
|
||||
voxelsniper.brush.cylinder: true
|
||||
voxelsniper.brush.disc: true
|
||||
voxelsniper.brush.discface: true
|
||||
voxelsniper.brush.dome: true
|
||||
voxelsniper.brush.drain: true
|
||||
voxelsniper.brush.ellipse: true
|
||||
voxelsniper.brush.ellipsoid: true
|
||||
voxelsniper.brush.eraser: true
|
||||
voxelsniper.brush.erode: true
|
||||
voxelsniper.brush.extrude: true
|
||||
voxelsniper.brush.filldown: true
|
||||
voxelsniper.brush.flatocean: true
|
||||
voxelsniper.brush.heatray: true
|
||||
voxelsniper.brush.jaggedline: true
|
||||
voxelsniper.brush.line: true
|
||||
voxelsniper.brush.move: true
|
||||
voxelsniper.brush.ocean: true
|
||||
voxelsniper.brush.overlay: true
|
||||
voxelsniper.brush.pull: true
|
||||
voxelsniper.brush.randomerode: true
|
||||
voxelsniper.brush.ring: true
|
||||
voxelsniper.brush.rot2d: true
|
||||
voxelsniper.brush.rot2dvert: true
|
||||
voxelsniper.brush.rot3d: true
|
||||
voxelsniper.brush.ruler: true
|
||||
voxelsniper.brush.scanner: true
|
||||
voxelsniper.brush.set: true
|
||||
voxelsniper.brush.setredstoneflip: true
|
||||
voxelsniper.brush.setredstonerotate: true
|
||||
voxelsniper.brush.shellball: true
|
||||
voxelsniper.brush.shellset: true
|
||||
voxelsniper.brush.shellvoxel: true
|
||||
voxelsniper.brush.signoverwrite: true
|
||||
voxelsniper.brush.snipe: true
|
||||
voxelsniper.brush.snowcone: true
|
||||
voxelsniper.brush.spiralstaircase: true
|
||||
voxelsniper.brush.splatterball: true
|
||||
voxelsniper.brush.splatterdisc: true
|
||||
voxelsniper.brush.splatteroverlay: true
|
||||
voxelsniper.brush.splattervoxel: true
|
||||
voxelsniper.brush.splattervoxeldisc: true
|
||||
voxelsniper.brush.spline: true
|
||||
voxelsniper.brush.stamp: true
|
||||
voxelsniper.brush.stencil: true
|
||||
voxelsniper.brush.stencillist: true
|
||||
voxelsniper.brush.threepointcircle: true
|
||||
voxelsniper.brush.triangle: true
|
||||
voxelsniper.brush.underlay: true
|
||||
voxelsniper.brush.voltmeter: true
|
||||
voxelsniper.brush.voxel: true
|
||||
voxelsniper.brush.voxeldisc: true
|
||||
voxelsniper.brush.voxeldiscface: true
|
||||
voxelsniper.brush.warp: true
|
||||
voxelsniper.goto: true
|
||||
voxelsniper.sniper: true
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.brush.visualization.VisualQueue;
|
||||
@ -16,7 +16,6 @@ import com.boydti.fawe.util.TextureUtil;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.github.luben.zstd.util.Native;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.factory.DefaultTransformParser;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.session.request.Request;
|
||||
@ -30,12 +29,9 @@ import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryMXBean;
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
import java.lang.management.MemoryUsage;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
|
@ -7,7 +7,6 @@ import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.object.extent.LightingExtent;
|
||||
import com.boydti.fawe.object.schematic.Schematic;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
@ -192,7 +191,7 @@ public class FaweAPI {
|
||||
* @see ClipboardFormat
|
||||
* @see Schematic
|
||||
*/
|
||||
public static Schematic load(File file) throws IOException {
|
||||
public static Clipboard load(File file) throws IOException {
|
||||
return ClipboardFormats.findByFile(file).load(file);
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import com.sk89q.worldedit.math.MutableBlockVector3;
|
||||
import com.sk89q.worldedit.math.MutableVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
@ -38,10 +39,14 @@ import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
@ -101,19 +106,25 @@ public enum FaweCache implements Trimable {
|
||||
|
||||
@Override
|
||||
public synchronized boolean trim(boolean aggressive) {
|
||||
BLOCK_TO_PALETTE.clean();
|
||||
PALETTE_TO_BLOCK.clean();
|
||||
BLOCK_STATES.clean();
|
||||
SECTION_BLOCKS.clean();
|
||||
PALETTE_CACHE.clean();
|
||||
PALETTE_TO_BLOCK_CHAR.clean();
|
||||
INDEX_STORE.clean();
|
||||
if (aggressive) {
|
||||
CleanableThreadLocal.cleanAll();
|
||||
} else {
|
||||
CHUNK_FLAG.clean();
|
||||
BYTE_BUFFER_8192.clean();
|
||||
BLOCK_TO_PALETTE.clean();
|
||||
PALETTE_TO_BLOCK.clean();
|
||||
BLOCK_STATES.clean();
|
||||
SECTION_BLOCKS.clean();
|
||||
PALETTE_CACHE.clean();
|
||||
PALETTE_TO_BLOCK_CHAR.clean();
|
||||
INDEX_STORE.clean();
|
||||
|
||||
MUTABLE_VECTOR3.clean();
|
||||
MUTABLE_BLOCKVECTOR3.clean();
|
||||
SECTION_BITS_TO_CHAR.clean();
|
||||
for (Map.Entry<Class, CleanableThreadLocal> entry : REGISTERED_SINGLETONS.entrySet()) {
|
||||
entry.getValue().clean();
|
||||
MUTABLE_VECTOR3.clean();
|
||||
MUTABLE_BLOCKVECTOR3.clean();
|
||||
SECTION_BITS_TO_CHAR.clean();
|
||||
for (Map.Entry<Class, CleanableThreadLocal> entry : REGISTERED_SINGLETONS.entrySet()) {
|
||||
entry.getValue().clean();
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Class, Pool> entry : REGISTERED_POOLS.entrySet()) {
|
||||
Pool pool = entry.getValue();
|
||||
@ -197,13 +208,19 @@ public enum FaweCache implements Trimable {
|
||||
public static final FaweException LOW_MEMORY = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_LOW_MEMORY);
|
||||
public static final FaweException MAX_ENTITIES = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_ENTITIES);
|
||||
public static final FaweException MAX_TILES = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_TILES);
|
||||
public static final FaweException MAX_ITERATIONS = new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_ITERATIONS);
|
||||
|
||||
/*
|
||||
thread cache
|
||||
*/
|
||||
public final CleanableThreadLocal<AtomicBoolean> CHUNK_FLAG = new CleanableThreadLocal<>(AtomicBoolean::new); // resets to false
|
||||
|
||||
public final CleanableThreadLocal<long[]> LONG_BUFFER_1024 = new CleanableThreadLocal<>(() -> new long[1024]);
|
||||
|
||||
public final CleanableThreadLocal<byte[]> BYTE_BUFFER_8192 = new CleanableThreadLocal<>(() -> new byte[8192]);
|
||||
|
||||
public final CleanableThreadLocal<int[]> BLOCK_TO_PALETTE = new CleanableThreadLocal<>(() -> {
|
||||
int[] result = new int[BlockTypes.states.length];
|
||||
int[] result = new int[BlockTypesCache.states.length];
|
||||
Arrays.fill(result, Integer.MAX_VALUE);
|
||||
return result;
|
||||
});
|
||||
@ -228,6 +245,8 @@ public enum FaweCache implements Trimable {
|
||||
* Holds data for a palette used in a chunk section
|
||||
*/
|
||||
public final class Palette {
|
||||
public int bitsPerEntry;
|
||||
|
||||
public int paletteToBlockLength;
|
||||
/**
|
||||
* Reusable buffer array, MUST check paletteToBlockLength for actual length
|
||||
@ -278,7 +297,7 @@ public enum FaweCache implements Trimable {
|
||||
int ordinal = blocksChars[i];
|
||||
int palette = blockToPalette[ordinal];
|
||||
if (palette == Integer.MAX_VALUE) {
|
||||
// BlockState state = BlockTypes.states[ordinal];
|
||||
// BlockState state = BlockTypesCache.states[ordinal];
|
||||
blockToPalette[ordinal] = palette = num_palette;
|
||||
paletteToBlock[num_palette] = ordinal;
|
||||
num_palette++;
|
||||
@ -290,7 +309,7 @@ public enum FaweCache implements Trimable {
|
||||
int ordinal = blocksInts[i];
|
||||
int palette = blockToPalette[ordinal];
|
||||
if (palette == Integer.MAX_VALUE) {
|
||||
BlockState state = BlockTypes.states[ordinal];
|
||||
BlockState state = BlockTypesCache.states[ordinal];
|
||||
blockToPalette[ordinal] = palette = num_palette;
|
||||
paletteToBlock[num_palette] = ordinal;
|
||||
num_palette++;
|
||||
@ -319,6 +338,7 @@ public enum FaweCache implements Trimable {
|
||||
|
||||
// Construct palette
|
||||
Palette palette = PALETTE_CACHE.get();
|
||||
palette.bitsPerEntry = bitsPerEntry;
|
||||
palette.paletteToBlockLength = num_palette;
|
||||
palette.paletteToBlock = paletteToBlock;
|
||||
|
||||
@ -499,6 +519,31 @@ public enum FaweCache implements Trimable {
|
||||
return new ThreadPoolExecutor(nThreads, nThreads,
|
||||
0L, TimeUnit.MILLISECONDS, queue
|
||||
, Executors.defaultThreadFactory(),
|
||||
new ThreadPoolExecutor.CallerRunsPolicy());
|
||||
new ThreadPoolExecutor.CallerRunsPolicy()) {
|
||||
protected void afterExecute(Runnable r, Throwable t) {
|
||||
try {
|
||||
super.afterExecute(r, t);
|
||||
if (t == null && r instanceof Future<?>) {
|
||||
try {
|
||||
Future<?> future = (Future<?>) r;
|
||||
if (future.isDone()) {
|
||||
future.get();
|
||||
}
|
||||
} catch (CancellationException ce) {
|
||||
t = ce;
|
||||
} catch (ExecutionException ee) {
|
||||
t = ee.getCause();
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if (t != null) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package com.boydti.fawe;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.cache.preloader.Preloader;
|
||||
import com.boydti.fawe.object.FaweCommand;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.image.ImageViewer;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.io.File;
|
||||
@ -54,4 +54,6 @@ public interface IFawe {
|
||||
|
||||
QueueHandler getQueueHandler();
|
||||
|
||||
Preloader getPreloader();
|
||||
|
||||
}
|
||||
|
@ -1,61 +0,0 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class ChunkFuture implements Future<Void> {
|
||||
|
||||
private final IChunk chunk;
|
||||
private volatile boolean cancelled;
|
||||
private volatile boolean done;
|
||||
|
||||
public ChunkFuture(IChunk chunk) {
|
||||
this.chunk = chunk;
|
||||
}
|
||||
|
||||
public IChunk getChunk() {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
cancelled = true;
|
||||
return !done;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return done;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void get() throws InterruptedException, ExecutionException {
|
||||
synchronized (chunk) {
|
||||
if (!done) {
|
||||
this.wait();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
synchronized (chunk) {
|
||||
if (!done) {
|
||||
this.wait(unit.toMillis(timeout));
|
||||
if (!done) {
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.filter.block.FilterBlock;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import javax.annotation.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.filter.block.FilterBlock;
|
||||
|
||||
public interface FilterBlockMask {
|
||||
|
||||
boolean applyBlock(FilterBlock block);
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.implementation.QueueHandler;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.implementation.EmptyBatchProcessor;
|
||||
import com.boydti.fawe.beta.implementation.MultiBatchProcessor;
|
||||
import com.boydti.fawe.beta.implementation.processors.EmptyBatchProcessor;
|
||||
import com.boydti.fawe.beta.implementation.processors.MultiBatchProcessor;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -46,7 +46,7 @@ public interface IBatchProcessor {
|
||||
if (set.hasSection(layer)) {
|
||||
if (layer == minLayer) {
|
||||
char[] arr = set.getArray(layer);
|
||||
int index = (minY & 15) << 12;
|
||||
int index = (minY & 15) << 8;
|
||||
for (int i = 0; i < index; i++) arr[i] = 0;
|
||||
set.setBlocks(layer, arr);
|
||||
} else {
|
||||
@ -59,7 +59,7 @@ public interface IBatchProcessor {
|
||||
if (set.hasSection(layer)) {
|
||||
if (layer == minLayer) {
|
||||
char[] arr = set.getArray(layer);
|
||||
int index = ((maxY + 1) & 15) << 12;
|
||||
int index = ((maxY + 1) & 15) << 8;
|
||||
for (int i = index; i < arr.length; i++) arr[i] = 0;
|
||||
set.setBlocks(layer, arr);
|
||||
} else {
|
||||
|
@ -1,10 +1,20 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.collection.BitArray4096;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.registry.BlockRegistry;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@ -19,5 +29,115 @@ public interface IBlocks extends Trimable {
|
||||
|
||||
BlockState getBlock(int x, int y, int z);
|
||||
|
||||
Map<BlockVector3, CompoundTag> getTiles();
|
||||
|
||||
Set<CompoundTag> getEntities();
|
||||
|
||||
BiomeType getBiomeType(int x, int z);
|
||||
|
||||
default int getBitMask() {
|
||||
int mask = 0;
|
||||
for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
|
||||
if (hasSection(layer)) {
|
||||
mask += (1 << layer);
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
IBlocks reset();
|
||||
|
||||
default byte[] toByteArray(boolean writeBiomes) {
|
||||
return toByteArray(null, writeBiomes);
|
||||
}
|
||||
|
||||
default byte[] toByteArray(byte[] buffer, boolean writeBiomes) {
|
||||
if (buffer == null) {
|
||||
buffer = new byte[1024];
|
||||
}
|
||||
|
||||
BlockRegistry registry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry();
|
||||
FastByteArrayOutputStream sectionByteArray = new FastByteArrayOutputStream(buffer);
|
||||
FaweOutputStream sectionWriter = new FaweOutputStream(sectionByteArray);
|
||||
try {
|
||||
for (int layer = 0; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
|
||||
if (!this.hasSection(layer)) continue;
|
||||
|
||||
char[] ids = this.getArray(layer);
|
||||
|
||||
int nonEmpty = 0; // TODO optimize into same loop as toPalette
|
||||
for (char id : ids) {
|
||||
if (id != 0) nonEmpty++;
|
||||
}
|
||||
|
||||
sectionWriter.writeShort(nonEmpty); // non empty
|
||||
|
||||
sectionWriter.writeByte(14); // globalPaletteBitsPerBlock
|
||||
|
||||
if (true) {
|
||||
BitArray4096 bits = new BitArray4096(14); // globalPaletteBitsPerBlock
|
||||
bits.setAt(0, 0);
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
int ordinal = ids[i];
|
||||
BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||
if (!state.getMaterial().isAir()) {
|
||||
int mcId = registry.getInternalBlockStateId(state).getAsInt();
|
||||
bits.setAt(i, mcId);
|
||||
}
|
||||
}
|
||||
sectionWriter.write(bits.getData());
|
||||
} else {
|
||||
|
||||
FaweCache.Palette palette = FaweCache.IMP.toPalette(0, ids);
|
||||
|
||||
sectionWriter.writeByte(palette.bitsPerEntry); // bits per block
|
||||
sectionWriter.writeVarInt(palette.paletteToBlockLength);
|
||||
for (int i = 0; i < palette.paletteToBlockLength; i++) {
|
||||
int ordinal = palette.paletteToBlock[i];
|
||||
switch (ordinal) {
|
||||
case BlockID.CAVE_AIR:
|
||||
case BlockID.VOID_AIR:
|
||||
case BlockID.AIR:
|
||||
case BlockID.__RESERVED__:
|
||||
sectionWriter.writeVarInt(0);
|
||||
break;
|
||||
default:
|
||||
BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||
int mcId = registry.getInternalBlockStateId(state).getAsInt();
|
||||
sectionWriter.writeVarInt(mcId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
sectionWriter.writeVarInt(palette.blockStatesLength);
|
||||
for (int i = 0; i < palette.blockStatesLength; i++) {
|
||||
sectionWriter.writeLong(palette.blockStates[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (writeBiomes) {
|
||||
// for (int x = 0; x < 16; x++) {
|
||||
// for (int z = 0; z < 16; z++) {
|
||||
// BiomeType biome = this.getBiomeType(x, z);
|
||||
// if (biome == null) {
|
||||
// if (writeBiomes) {
|
||||
// break;
|
||||
// } else {
|
||||
// biome = BiomeTypes.FOREST;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (writeBiomes) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
// TODO biomes
|
||||
sectionWriter.writeInt(0);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return sectionByteArray.toByteArray();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
@ -27,12 +28,6 @@ public interface IChunk<T extends Future<T>> extends Trimable, Callable<T>, IChu
|
||||
*/
|
||||
void init(IQueueExtent extent, int x, int z);
|
||||
|
||||
/**
|
||||
* Get the queue
|
||||
* @return
|
||||
*/
|
||||
IQueueExtent getQueue();
|
||||
|
||||
/**
|
||||
* Get chunkX
|
||||
* @return
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
|
@ -28,8 +28,10 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent {
|
||||
|
||||
CompoundTag getTag(int x, int y, int z);
|
||||
|
||||
@Override
|
||||
Map<BlockVector3, CompoundTag> getTiles();
|
||||
|
||||
@Override
|
||||
Set<CompoundTag> getEntities();
|
||||
|
||||
@Override
|
||||
|
@ -38,8 +38,13 @@ public interface IChunkSet extends IBlocks, OutputExtent {
|
||||
|
||||
BiomeType[] getBiomes();
|
||||
|
||||
@Override
|
||||
BiomeType getBiomeType(int x, int z);
|
||||
|
||||
@Override
|
||||
Map<BlockVector3, CompoundTag> getTiles();
|
||||
|
||||
@Override
|
||||
Set<CompoundTag> getEntities();
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
@ -38,11 +39,6 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
|
||||
return getParent().call(set, finalize);
|
||||
}
|
||||
|
||||
@Override
|
||||
default IQueueExtent getQueue() {
|
||||
return getParent().getQueue();
|
||||
}
|
||||
|
||||
@Override
|
||||
default CompoundTag getTag(int x, int y, int z) {
|
||||
return getParent().getTag(x, y, z);
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.filter.block.FilterBlock;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.IChunkCache;
|
||||
import com.boydti.fawe.beta.implementation.MultiBatchProcessor;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.function.generator.GenBase;
|
||||
@ -45,16 +43,6 @@ public interface IDelegateQueueExtent extends IQueueExtent {
|
||||
return getParent().isQueueEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void clearBlockUpdates(Player... players) {
|
||||
getParent().clearBlockUpdates(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendBlockUpdates(Player... players) {
|
||||
getParent().sendBlockUpdates(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void enableQueue() {
|
||||
getParent().enableQueue();
|
||||
|
@ -1,15 +1,15 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.implementation.IBatchProcessorHolder;
|
||||
import com.boydti.fawe.beta.implementation.IChunkCache;
|
||||
import com.boydti.fawe.beta.implementation.MultiBatchProcessor;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.processors.IBatchProcessorHolder;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
@ -17,7 +17,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.Flushable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
@ -31,22 +31,6 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, IBatchProcess
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any block updates
|
||||
* @param players
|
||||
*/
|
||||
default void clearBlockUpdates(Player... players) {
|
||||
throw new UnsupportedOperationException("TODO NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send all the chunks as block updates
|
||||
* @param players
|
||||
*/
|
||||
default void sendBlockUpdates(Player... players) {
|
||||
throw new UnsupportedOperationException("TODO NOT IMPLEMENTED");
|
||||
}
|
||||
|
||||
/**
|
||||
* Must ensure that it is enqueued with QueueHandler
|
||||
*/
|
||||
@ -204,4 +188,35 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, IBatchProcess
|
||||
* @return <tt>true</tt> if this queue contains no elements
|
||||
*/
|
||||
boolean isEmpty();
|
||||
|
||||
default ChunkFilterBlock apply(ChunkFilterBlock block, Filter filter, Region region, int chunkX, int chunkZ) {
|
||||
if (!filter.appliesChunk(chunkX, chunkZ)) {
|
||||
return block;
|
||||
}
|
||||
IChunk chunk = this.getOrCreateChunk(chunkX, chunkZ);
|
||||
// Initialize
|
||||
chunk.init(this, chunkX, chunkZ);
|
||||
|
||||
IChunk newChunk = filter.applyChunk(chunk, region);
|
||||
if (newChunk != null) {
|
||||
chunk = newChunk;
|
||||
if (block == null) {
|
||||
block = this.initFilterBlock();
|
||||
}
|
||||
chunk.filterBlocks(filter, block, region);
|
||||
}
|
||||
this.submit(chunk);
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
default <T extends Filter> T apply(Region region, T filter) {
|
||||
final Set<BlockVector2> chunks = region.getChunks();
|
||||
ChunkFilterBlock block = null;
|
||||
for (BlockVector2 chunk : chunks) {
|
||||
block = apply(block, filter, region, chunk.getX(), chunk.getZ());
|
||||
}
|
||||
flush();
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
|
@ -1,105 +0,0 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
public class NorthVector extends BlockVector3 {
|
||||
|
||||
private final BlockVector3 parent;
|
||||
|
||||
public NorthVector(BlockVector3 parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public BlockVector3 south(BlockVector3 orDefault) {
|
||||
// return parent;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return parent.getX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return parent.getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return parent.getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setOrdinal(Extent orDefault, int ordinal) {
|
||||
return orDefault.setBlock(this, BlockState.getFromOrdinal(ordinal));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Extent orDefault, BlockState state) {
|
||||
return orDefault.setBlock(this, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setFullBlock(Extent orDefault, BaseBlock block) {
|
||||
return orDefault.setBlock(this, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(Extent orDefault, BiomeType biome) {
|
||||
return orDefault.setBiome(getX(), getY(), getZ(), biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrdinal(Extent orDefault) {
|
||||
return getBlock(orDefault).getOrdinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getOrdinalChar(Extent orDefault) {
|
||||
return (char) getOrdinal(orDefault);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(Extent orDefault) {
|
||||
return orDefault.getBlock(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(Extent orDefault) {
|
||||
return orDefault.getFullBlock(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getNbtData(Extent orDefault) {
|
||||
return orDefault.getFullBlock(getX(), getY(), getZ()).getNbtData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getOrdinalBelow(Extent orDefault) {
|
||||
return getStateRelative(orDefault, 0, -1, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getStateAbove(Extent orDefault) {
|
||||
return getStateRelative(orDefault, 0, 1, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getStateRelativeY(Extent orDefault, int y) {
|
||||
return getStateRelative(orDefault, 0, y, 0);
|
||||
}
|
||||
|
||||
public BlockState getStateRelative(Extent orDefault, int x, int y, int z) {
|
||||
return getFullBlockRelative(orDefault, x, y, z).toBlockState();
|
||||
}
|
||||
|
||||
public BaseBlock getFullBlockRelative(Extent orDefault, int x, int y, int z) {
|
||||
return orDefault.getFullBlock(x + getX(), y + getY(), z + getZ());
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
|
||||
public class BatchProcessorHolder implements IBatchProcessorHolder {
|
||||
private IBatchProcessor processor = EmptyBatchProcessor.INSTANCE;
|
||||
|
||||
@Override
|
||||
public IBatchProcessor getProcessor() {
|
||||
return processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProcessor(IBatchProcessor set) {
|
||||
this.processor = set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "{" + getProcessor() + "}";
|
||||
}
|
||||
}
|
@ -115,6 +115,11 @@ public class BitSetBlocks implements IChunkSet {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
return null;
|
||||
|
@ -7,11 +7,12 @@ import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class CharBlocks implements IBlocks {
|
||||
public abstract class CharBlocks implements IBlocks {
|
||||
|
||||
public static final Section FULL = new Section() {
|
||||
@Override
|
||||
@ -96,7 +97,7 @@ public class CharBlocks implements IBlocks {
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypes.states[get(x, y, z)];
|
||||
return BlockTypesCache.states[get(x, y, z)];
|
||||
}
|
||||
|
||||
public char get(int x, int y, int z) {
|
||||
|
@ -5,17 +5,18 @@ import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
return BlockTypes.states[get(x, y, z)].toBaseBlock();
|
||||
return BlockTypesCache.states[get(x, y, z)].toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypes.states[get(x, y, z)];
|
||||
return BlockTypesCache.states[get(x, y, z)];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -13,6 +13,7 @@ import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@ -43,6 +44,11 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
return biomes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
return biomes[(z << 4) | x];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
return tiles == null ? Collections.emptyMap() : tiles;
|
||||
@ -69,7 +75,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypes.states[get(x, y, z)];
|
||||
return BlockTypesCache.states[get(x, y, z)];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.blocks;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.blocks;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.blocks;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
@ -1,10 +1,12 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.cache;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
public class ChunkCache<T extends Trimable> implements IChunkCache<T> {
|
||||
@ -12,11 +14,18 @@ public class ChunkCache<T extends Trimable> implements IChunkCache<T> {
|
||||
protected final Long2ObjectLinkedOpenHashMap<WeakReference<T>> getCache;
|
||||
private final IChunkCache<T> delegate;
|
||||
|
||||
protected ChunkCache(IChunkCache<T> delegate) {
|
||||
public ChunkCache(IChunkCache<T> delegate) {
|
||||
this.getCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create the IGetBlocks
|
||||
*
|
||||
* @param index chunk index {@link com.boydti.fawe.util.MathMan#pairInt(int, int)}
|
||||
* @param provider used to create if it isn't already cached
|
||||
* @return cached IGetBlocks
|
||||
*/
|
||||
@Override
|
||||
public synchronized T get(int x, int z) {
|
||||
long pair = MathMan.pairInt(x, z);
|
110
worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/cache/preloader/AsyncPreloader.java
vendored
Normale Datei
110
worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/cache/preloader/AsyncPreloader.java
vendored
Normale Datei
@ -0,0 +1,110 @@
|
||||
package com.boydti.fawe.beta.implementation.cache.preloader;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.collection.MutablePair;
|
||||
import com.boydti.fawe.util.FaweTimer;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
public class AsyncPreloader implements Preloader, Runnable {
|
||||
private final ConcurrentHashMap<UUID, MutablePair<World, Set<BlockVector2>>> update;
|
||||
|
||||
public AsyncPreloader() {
|
||||
this.update = new ConcurrentHashMap<>();
|
||||
Fawe.get().getQueueHandler().async(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(Player player) {
|
||||
cancelAndGet(player);
|
||||
}
|
||||
|
||||
private MutablePair<World, Set<BlockVector2>> cancelAndGet(Player player) {
|
||||
MutablePair<World, Set<BlockVector2>> existing = update.get(player.getUniqueId());
|
||||
if (existing != null) {
|
||||
existing.setValue(null);
|
||||
}
|
||||
return existing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Player player) {
|
||||
LocalSession session = WorldEdit.getInstance().getSessionManager().getIfPresent(player);
|
||||
if (session == null) return;
|
||||
World world = player.getWorld();
|
||||
MutablePair<World, Set<BlockVector2>> existing = cancelAndGet(player);
|
||||
try {
|
||||
Region region = session.getSelection(world);
|
||||
if (!(region instanceof CuboidRegion) || region.getArea() > 50466816) {
|
||||
// TOO LARGE or NOT CUBOID
|
||||
return;
|
||||
}
|
||||
if (existing == null) {
|
||||
MutablePair<World, Set<BlockVector2>> previous = update.putIfAbsent(player.getUniqueId(), existing = new MutablePair<>());
|
||||
if (previous != null) {
|
||||
existing = previous;
|
||||
}
|
||||
synchronized (existing) { // Ensure key & value are mutated together
|
||||
existing.setKey(world);
|
||||
existing.setValue(region.getChunks());
|
||||
}
|
||||
synchronized (update) {
|
||||
update.notify();
|
||||
}
|
||||
}
|
||||
} catch (IncompleteRegionException ignore){}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
FaweTimer timer = Fawe.get().getTimer();
|
||||
try {
|
||||
while (true) {
|
||||
if (!update.isEmpty()) {
|
||||
if (timer.getTPS() > 19) {
|
||||
Iterator<Map.Entry<UUID, MutablePair<World, Set<BlockVector2>>>> plrIter = update.entrySet().iterator();
|
||||
Map.Entry<UUID, MutablePair<World, Set<BlockVector2>>> entry = plrIter.next();
|
||||
MutablePair<World, Set<BlockVector2>> pair = entry.getValue();
|
||||
World world = pair.getKey();
|
||||
Set<BlockVector2> chunks = pair.getValue();
|
||||
if (chunks != null) {
|
||||
Iterator<BlockVector2> chunksIter = chunks.iterator();
|
||||
while (chunksIter.hasNext() && pair.getValue() == chunks) { // Ensure the queued load is still valid
|
||||
BlockVector2 chunk = chunksIter.next();
|
||||
queueLoad(world, chunk);
|
||||
}
|
||||
}
|
||||
plrIter.remove();
|
||||
} else {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
} else {
|
||||
synchronized (update) {
|
||||
update.wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void queueLoad(World world, BlockVector2 chunk) {
|
||||
world.checkLoadedChunk(BlockVector3.at(chunk.getX() << 4, 0, chunk.getZ() << 4));
|
||||
}
|
||||
}
|
9
worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/cache/preloader/Preloader.java
vendored
Normale Datei
9
worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/cache/preloader/Preloader.java
vendored
Normale Datei
@ -0,0 +1,9 @@
|
||||
package com.boydti.fawe.beta.implementation.cache.preloader;
|
||||
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
|
||||
public interface Preloader {
|
||||
void cancel(Player player);
|
||||
|
||||
void update(Player player);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
package com.boydti.fawe.beta.implementation.chunk;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.FilterBlockMask;
|
||||
import com.boydti.fawe.beta.Flood;
|
||||
@ -59,11 +59,6 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IQueueExtent getQueue() {
|
||||
return extent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
return false;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
package com.boydti.fawe.beta.implementation.chunk;
|
||||
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IDelegateChunk;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
package com.boydti.fawe.beta.implementation.chunk;
|
||||
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
@ -0,0 +1,137 @@
|
||||
package com.boydti.fawe.beta.implementation.chunk;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.FilterBlockMask;
|
||||
import com.boydti.fawe.beta.Flood;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public enum NullChunk implements IChunk {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public void init(IQueueExtent extent, int x, int z) {}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future call() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BlockStateHolder block) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] getArray(int layer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypes.__RESERVED__.getDefaultState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
return BlockTypes.__RESERVED__.getDefaultState().toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTag(int x, int y, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future call(IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
package com.boydti.fawe.beta.implementation.chunk;
|
||||
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IDelegateChunk;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
package com.boydti.fawe.beta.implementation.chunk;
|
||||
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
@ -1,16 +1,10 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
package com.boydti.fawe.beta.implementation.chunk;
|
||||
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A {@link ReferenceChunk} using {@link WeakReference} to hold the chunk.
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.beta.filters;
|
||||
package com.boydti.fawe.beta.implementation.filter;
|
||||
|
||||
import com.boydti.fawe.beta.FilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.FilterBlock;
|
||||
import com.boydti.fawe.beta.FilterBlockMask;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.beta.filters;
|
||||
package com.boydti.fawe.beta.implementation.filter;
|
||||
|
||||
import com.boydti.fawe.beta.FilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.FilterBlock;
|
||||
|
||||
public class CountFilter extends ForkedFilter<CountFilter> {
|
||||
|
@ -1,12 +1,14 @@
|
||||
package com.boydti.fawe.beta.filters;
|
||||
package com.boydti.fawe.beta.implementation.filter;
|
||||
|
||||
import com.boydti.fawe.beta.FilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.FilterBlock;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.function.mask.ABlockMask;
|
||||
import com.sk89q.worldedit.util.Countable;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -14,7 +16,7 @@ import java.util.List;
|
||||
|
||||
public class DistrFilter extends ForkedFilter<DistrFilter> {
|
||||
|
||||
private final int[] counter = new int[BlockTypes.states.length];
|
||||
private final int[] counter = new int[BlockTypesCache.states.length];
|
||||
|
||||
public DistrFilter() {
|
||||
super(null);
|
||||
@ -45,7 +47,7 @@ public class DistrFilter extends ForkedFilter<DistrFilter> {
|
||||
int total = 0;
|
||||
for (int i = 0; i < counter.length; i++) {
|
||||
int value = counter[i];
|
||||
if (value != 0 && mask.test(BlockTypes.states[i])) {
|
||||
if (value != 0 && mask.test(BlockTypesCache.states[i])) {
|
||||
total += value;
|
||||
}
|
||||
}
|
||||
@ -61,7 +63,7 @@ public class DistrFilter extends ForkedFilter<DistrFilter> {
|
||||
for (int i = 0; i < counter.length; i++) {
|
||||
final int count = counter[i];
|
||||
if (count != 0) {
|
||||
distribution.add(new Countable<>(BlockTypes.states[i], count));
|
||||
distribution.add(new Countable<>(BlockTypesCache.states[i], count));
|
||||
}
|
||||
}
|
||||
Collections.sort(distribution);
|
||||
@ -70,18 +72,18 @@ public class DistrFilter extends ForkedFilter<DistrFilter> {
|
||||
|
||||
public List<Countable<BlockType>> getTypeDistribution() {
|
||||
final List<Countable<BlockType>> distribution = new ArrayList<>();
|
||||
int[] typeCounter = new int[BlockTypes.values.length];
|
||||
int[] typeCounter = new int[BlockTypesCache.values.length];
|
||||
for (int i = 0; i < counter.length; i++) {
|
||||
final int count = counter[i];
|
||||
if (count != 0) {
|
||||
BlockState state = BlockTypes.states[i];
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
typeCounter[state.getBlockType().getInternalId()] += count;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < typeCounter.length; i++) {
|
||||
final int count = typeCounter[i];
|
||||
if (count != 0) {
|
||||
distribution.add(new Countable<>(BlockTypes.values[i], count));
|
||||
distribution.add(new Countable<>(BlockTypesCache.values[i], count));
|
||||
}
|
||||
}
|
||||
Collections.sort(distribution);
|
||||
@ -89,10 +91,10 @@ public class DistrFilter extends ForkedFilter<DistrFilter> {
|
||||
}
|
||||
|
||||
public void print(Actor actor, long size) {
|
||||
for (Countable<BlockState> c : getDistribution()) {
|
||||
for (Countable c : getDistribution()) {
|
||||
final String name = c.getID().toString();
|
||||
final String str = String.format("%-7s (%.3f%%) %s",
|
||||
c.getAmount(),
|
||||
String.valueOf(c.getAmount()),
|
||||
c.getAmount() / (double) size * 100,
|
||||
name);
|
||||
actor.print(str);
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.filters;
|
||||
package com.boydti.fawe.beta.implementation.filter;
|
||||
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import java.util.Map;
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.beta.filters;
|
||||
package com.boydti.fawe.beta.implementation.filter;
|
||||
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.FilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.FilterBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
public class SetFilter implements Filter {
|
@ -0,0 +1,94 @@
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class AbstractFilterBlock extends FilterBlock {
|
||||
|
||||
public abstract BaseBlock getFullBlock();
|
||||
public abstract void setFullBlock(BaseBlock block);
|
||||
public abstract BlockVector3 getPosition();
|
||||
|
||||
@Override
|
||||
public Extent getExtent() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return getPosition().getX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return getPosition().getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return getPosition().getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrdinal() {
|
||||
return getBlock().getOrdinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrdinal(int ordinal) {
|
||||
setBlock(BlockState.getFromOrdinal(ordinal));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock() {
|
||||
return getFullBlock().toBlockState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(BlockState state) {
|
||||
setFullBlock(state.toBaseBlock(getBlock().getNbtData()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getNbtData() {
|
||||
return getFullBlock().getNbtData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNbtData(@Nullable CompoundTag nbtData) {
|
||||
setFullBlock(getFullBlock().toBaseBlock(nbtData));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMinimumPoint() {
|
||||
return BlockVector3.at(getX(), getY(), getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMaximumPoint() {
|
||||
return BlockVector3.at(getX(), getY(), getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block)
|
||||
throws WorldEditException {
|
||||
if (x == this.getX() && y == this.getY() && z == this.getZ()) {
|
||||
setFullBlock(block.toBaseBlock());
|
||||
return true;
|
||||
}
|
||||
return getExtent().setBlock(x,y, z, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
return getExtent().setBiome(x, y, z,biome);
|
||||
}
|
||||
}
|
@ -1,25 +1,21 @@
|
||||
package com.boydti.fawe.beta;
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SingleFilterBlock extends FilterBlock {
|
||||
public abstract class AbstractSingleFilterBlock extends FilterBlock {
|
||||
|
||||
private BaseBlock block;
|
||||
private int x, y, z;
|
||||
|
||||
public SingleFilterBlock init(int x, int y, int z, BaseBlock block) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
public AbstractSingleFilterBlock init(BaseBlock block) {
|
||||
this.block = block;
|
||||
return this;
|
||||
}
|
||||
@ -69,35 +65,20 @@ public class SingleFilterBlock extends FilterBlock {
|
||||
block = block.toBaseBlock(nbtData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMinimumPoint() {
|
||||
return BlockVector3.at(x, y, z);
|
||||
return BlockVector3.at(getX(), getY(), getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getMaximumPoint() {
|
||||
return BlockVector3.at(x, y, z);
|
||||
return BlockVector3.at(getX(), getY(), getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block)
|
||||
throws WorldEditException {
|
||||
if (x == this.x && y == this.y && z == this.z) {
|
||||
if (x == this.getX() && y == this.getY() && z == this.getZ()) {
|
||||
setFullBlock(block.toBaseBlock());
|
||||
return true;
|
||||
}
|
||||
@ -106,6 +87,6 @@ public class SingleFilterBlock extends FilterBlock {
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
return getExtent().setBiome(x,y, z,biome);
|
||||
return getExtent().setBiome(x, y, z,biome);
|
||||
}
|
||||
}
|
@ -1,15 +1,16 @@
|
||||
package com.boydti.fawe.beta;
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ArrayFilterBlock extends SimpleFilterBlock {
|
||||
@ -52,7 +53,7 @@ public class ArrayFilterBlock extends SimpleFilterBlock {
|
||||
|
||||
@Override
|
||||
public BlockState getBlock() {
|
||||
return BlockTypes.states[ordinal];
|
||||
return BlockTypesCache.states[ordinal];
|
||||
}
|
||||
|
||||
@Override
|
@ -1,7 +1,13 @@
|
||||
package com.boydti.fawe.beta;
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import static com.sk89q.worldedit.world.block.BlockTypes.states;
|
||||
import static com.sk89q.worldedit.world.block.BlockTypesCache.states;
|
||||
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.FilterBlockMask;
|
||||
import com.boydti.fawe.beta.Flood;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
@ -13,6 +19,7 @@ import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -225,7 +232,7 @@ public class CharFilterBlock extends ChunkFilterBlock {
|
||||
@Override
|
||||
public final BlockState getBlock() {
|
||||
final int ordinal = getArr[index];
|
||||
return BlockTypes.states[ordinal];
|
||||
return BlockTypesCache.states[ordinal];
|
||||
}
|
||||
|
||||
@Override
|
@ -1,5 +1,10 @@
|
||||
package com.boydti.fawe.beta;
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.FilterBlockMask;
|
||||
import com.boydti.fawe.beta.Flood;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
|
||||
@ -15,7 +20,7 @@ public abstract class ChunkFilterBlock extends SimpleFilterBlock {
|
||||
int layer);
|
||||
|
||||
public abstract void flood(IChunkGet iget, IChunkSet iset, int layer,
|
||||
Flood flood, FilterBlockMask mask);
|
||||
Flood flood, FilterBlockMask mask);
|
||||
|
||||
|
||||
public abstract void filter(Filter filter, int x, int y, int z);
|
@ -1,4 +1,7 @@
|
||||
package com.boydti.fawe.beta;
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.IDelegateFilter;
|
||||
|
||||
public abstract class DelegateFilter<T extends Filter> implements IDelegateFilter {
|
||||
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta;
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
@ -0,0 +1,35 @@
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
|
||||
public class ExtentFilterBlock extends AbstractFilterBlock {
|
||||
private final Extent extent;
|
||||
private BlockVector3 pos;
|
||||
|
||||
public ExtentFilterBlock(Extent extent) {
|
||||
this.extent = extent;
|
||||
this.pos = BlockVector3.ZERO;
|
||||
}
|
||||
|
||||
public ExtentFilterBlock init(BlockVector3 pos) {
|
||||
this.pos = pos;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock() {
|
||||
return pos.getFullBlock(extent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFullBlock(BaseBlock block) {
|
||||
pos.setFullBlock(extent, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getPosition() {
|
||||
return pos;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta;
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta;
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
@ -0,0 +1,31 @@
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
|
||||
public class SingleFilterBlock extends AbstractSingleFilterBlock {
|
||||
|
||||
private int x, y, z;
|
||||
|
||||
public SingleFilterBlock init(int x, int y, int z, BaseBlock block) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
super.init(block);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return z;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.boydti.fawe.beta.implementation.filter.block;
|
||||
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
|
||||
public class VectorSingleFilterBlock extends AbstractSingleFilterBlock {
|
||||
private final BlockVector3 mutable;
|
||||
|
||||
public VectorSingleFilterBlock(BlockVector3 mutable) {
|
||||
this.mutable = mutable;
|
||||
}
|
||||
|
||||
public VectorSingleFilterBlock init(BaseBlock block) {
|
||||
super.init(block);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return mutable.getX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return mutable.getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return mutable.getZ();
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package com.boydti.fawe.beta.implementation.packet;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ChunkPacket implements Function<byte[], byte[]>, Supplier<byte[]> {
|
||||
|
||||
private final boolean full;
|
||||
private final Supplier<IBlocks> chunkSupplier;
|
||||
private IBlocks chunk;
|
||||
|
||||
private int chunkX;
|
||||
private int chunkZ;
|
||||
private byte[] sectionBytes;
|
||||
private Object nativePacket;
|
||||
|
||||
public ChunkPacket(int chunkX, int chunkZ, Supplier<IBlocks> chunkSupplier, boolean replaceAllSections) {
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
this.chunkSupplier = chunkSupplier;
|
||||
this.full = replaceAllSections;
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
public synchronized void setPosition(int chunkX, int chunkZ) {
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
nativePacket = null;
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return full;
|
||||
}
|
||||
|
||||
public IBlocks getChunk() {
|
||||
if (this.chunk == null) {
|
||||
synchronized (this) {
|
||||
if (this.chunk == null) {
|
||||
this.chunk = chunkSupplier.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private byte[] getSectionBytes() {
|
||||
byte[] tmp = this.sectionBytes;
|
||||
if (tmp == null) {
|
||||
synchronized (this) {
|
||||
if (sectionBytes == null) {
|
||||
sectionBytes = getChunk().toByteArray(FaweCache.IMP.BYTE_BUFFER_8192.get(), this.full);
|
||||
}
|
||||
tmp = sectionBytes;
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public Object getNativePacket() {
|
||||
return nativePacket;
|
||||
}
|
||||
|
||||
public void setNativePacket(Object nativePacket) {
|
||||
this.nativePacket = nativePacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public byte[] get() {
|
||||
return apply(FaweCache.IMP.BYTE_BUFFER_8192.get());
|
||||
}
|
||||
|
||||
public CompoundTag getHeightMap() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("MOTION_BLOCKING", new long[36]);
|
||||
CompoundTag tag = FaweCache.IMP.asTag(map);
|
||||
// TODO
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] apply(byte[] buffer) {
|
||||
try {
|
||||
byte[] sectionBytes = getSectionBytes();
|
||||
|
||||
FastByteArrayOutputStream baos = new FastByteArrayOutputStream(buffer);
|
||||
FaweOutputStream fos = new FaweOutputStream(baos);
|
||||
|
||||
fos.writeInt(this.chunkX);
|
||||
fos.writeInt(this.chunkZ);
|
||||
|
||||
fos.writeBoolean(this.full);
|
||||
|
||||
fos.writeVarInt(getChunk().getBitMask());
|
||||
|
||||
|
||||
fos.writeNBT("", getHeightMap());
|
||||
|
||||
fos.writeVarInt(sectionBytes.length);
|
||||
fos.write(sectionBytes);
|
||||
// TODO entities / NBT
|
||||
// Set<CompoundTag> entities = chunk.getEntities();
|
||||
// Map<BlockVector3, CompoundTag> tiles = chunk.getTiles();
|
||||
fos.writeVarInt(0); // (Entities / NBT)
|
||||
return baos.toByteArray();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.boydti.fawe.beta.implementation.processors;
|
||||
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
|
||||
public class BatchProcessorHolder implements IBatchProcessorHolder {
|
||||
private IBatchProcessor processor = EmptyBatchProcessor.INSTANCE;
|
||||
|
||||
@Override
|
||||
public IBatchProcessor getProcessor() {
|
||||
return processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||
return getProcessor().processSet(chunk, get, set);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProcessor(IBatchProcessor set) {
|
||||
this.processor = set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
IBatchProcessor tmp = getProcessor();
|
||||
return super.toString() + "{" + (tmp == this ? "" : getProcessor()) + "}";
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.boydti.fawe.beta.implementation.processors;
|
||||
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ChunkSendProcessor implements IBatchProcessor {
|
||||
private final Supplier<Stream<Player>> players;
|
||||
private final World world;
|
||||
|
||||
public ChunkSendProcessor(World world, Supplier<Stream<Player>> players) {
|
||||
this.players = players;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||
int chunkX = chunk.getX();
|
||||
int chunkZ = chunk.getZ();
|
||||
boolean replaceAll = true;
|
||||
ChunkPacket packet = new ChunkPacket(chunkX, chunkZ, () -> set, replaceAll);
|
||||
Stream<Player> stream = this.players.get();
|
||||
if (stream == null) {
|
||||
world.sendFakeChunk(null, packet);
|
||||
} else {
|
||||
stream.filter(player -> player.getWorld().equals(world))
|
||||
.forEach(player -> world.sendFakeChunk(player, packet));
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent construct(Extent child) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.processors;
|
||||
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IChunk;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.processors;
|
||||
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IChunk;
|
@ -0,0 +1,634 @@
|
||||
package com.boydti.fawe.beta.implementation.processors;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ExtentFilterBlock;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.PassthroughExtent;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.function.generator.GenBase;
|
||||
import com.sk89q.worldedit.function.generator.Resource;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.Countable;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LimitExtent extends PassthroughExtent {
|
||||
private final FaweLimit limit;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent the extent
|
||||
*/
|
||||
public LimitExtent(Extent extent, FaweLimit limit) {
|
||||
super(extent);
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public List<? extends Entity> getEntities(Region region) {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
try {
|
||||
return getExtent().getEntities(region);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public List<? extends Entity> getEntities() {
|
||||
limit.THROW_MAX_CHECKS();
|
||||
try {
|
||||
return getExtent().getEntities();
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Entity createEntity(Location location, BaseEntity entity) {
|
||||
limit.THROW_MAX_CHANGES();
|
||||
limit.THROW_MAX_ENTITIES();
|
||||
try {
|
||||
return getExtent().createEntity(location, entity);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public void removeEntity(int x, int y, int z, UUID uuid) {
|
||||
limit.THROW_MAX_CHANGES();
|
||||
limit.THROW_MAX_ENTITIES();
|
||||
try {
|
||||
getExtent().removeEntity(x, y, z, uuid);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) {
|
||||
limit.THROW_MAX_CHANGES(Character.MAX_VALUE);
|
||||
try {
|
||||
return getExtent().regenerateChunk(x, z, type, seed);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
try {
|
||||
return getExtent().getHighestTerrainBlock(x, z, minY, maxY);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
try {
|
||||
return getExtent().getHighestTerrainBlock(x, z, minY, maxY, filter);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
try {
|
||||
return getExtent().getNearestSurfaceLayer(x, z, y, minY, maxY);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
try {
|
||||
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
try {
|
||||
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
try {
|
||||
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
try {
|
||||
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) {
|
||||
limit.THROW_MAX_CHECKS(FaweCache.IMP.WORLD_HEIGHT);
|
||||
try {
|
||||
return getExtent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCaves(Region region) throws WorldEditException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
getExtent().addCaves(region);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(Region region, GenBase gen) throws WorldEditException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
getExtent().generate(region, gen);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws WorldEditException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
getExtent().addSchems(region, mask, clipboards, rarity, rotate);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
getExtent().spawnResource(region, gen, rarity, frequency);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
getExtent().addOre(region, mask, material, size, frequency, rarity, minY, maxY);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOres(Region region, Mask mask) throws WorldEditException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
getExtent().addOres(region, mask);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Countable<BlockType>> getBlockDistribution(Region region) {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
try {
|
||||
return getExtent().getBlockDistribution(region);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
try {
|
||||
return getExtent().getBlockDistributionWithData(region);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
try {
|
||||
return getExtent().countBlocks(region, searchBlocks);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countBlocks(Region region, Mask searchMask) {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
try {
|
||||
return getExtent().countBlocks(region, searchMask);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
return getExtent().setBlocks(region, block);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
return getExtent().setBlocks(region, pattern);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
return getExtent().replaceBlocks(region, filter, replacement);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
return getExtent().replaceBlocks(region, filter, pattern);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
return getExtent().replaceBlocks(region, mask, pattern);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int center(Region region, Pattern pattern) throws MaxChangedBlocksException {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
return getExtent().center(region, pattern);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
|
||||
limit.THROW_MAX_CHANGES(vset.size());
|
||||
try {
|
||||
return getExtent().setBlocks(vset, pattern);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Filter> T apply(Region region, T filter) {
|
||||
limit.THROW_MAX_CHECKS(region.getArea());
|
||||
limit.THROW_MAX_CHANGES(region.getArea());
|
||||
try {
|
||||
return getExtent().apply(region, filter);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Filter> T apply(Iterable<BlockVector3> positions, T filter) {
|
||||
int size;
|
||||
if (positions instanceof Collection) {
|
||||
size = ((Collection<BlockVector3>) positions).size();
|
||||
} else if (positions instanceof Region) {
|
||||
BlockVector3 dim = ((Region) positions).getDimensions();
|
||||
size = dim.getX() * dim.getY() * dim.getZ();
|
||||
} else if (positions instanceof Extent) {
|
||||
BlockVector3 min = ((Extent) positions).getMinimumPoint();
|
||||
BlockVector3 max = ((Extent) positions).getMinimumPoint();
|
||||
BlockVector3 dim = max.subtract(min).add(BlockVector3.ONE);
|
||||
size = dim.getX() * dim.getY() * dim.getZ();
|
||||
} else {
|
||||
ExtentFilterBlock block = new ExtentFilterBlock(this);
|
||||
for (BlockVector3 pos : positions) {
|
||||
limit.THROW_MAX_CHECKS();
|
||||
filter.applyBlock(block.init(pos));
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
limit.THROW_MAX_CHECKS(size);
|
||||
limit.THROW_MAX_CHANGES(size);
|
||||
try {
|
||||
return getExtent().apply(positions, filter);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
public BlockState getBlock(BlockVector3 position) {
|
||||
limit.THROW_MAX_CHECKS();
|
||||
try {
|
||||
return getExtent().getBlock(position);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return BlockTypes.AIR.getDefaultState();
|
||||
}
|
||||
}
|
||||
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
limit.THROW_MAX_CHECKS();
|
||||
try {
|
||||
return getExtent().getBlock(x, y, z);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return BlockTypes.AIR.getDefaultState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
limit.THROW_MAX_CHECKS();
|
||||
try {
|
||||
return getExtent().getFullBlock(position);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
limit.THROW_MAX_CHECKS();
|
||||
try {
|
||||
return getExtent().getFullBlock(x, y, z);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public BiomeType getBiome(BlockVector2 position) {
|
||||
limit.THROW_MAX_CHECKS();
|
||||
try {
|
||||
return getExtent().getBiome(position);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return BiomeTypes.FOREST;
|
||||
}
|
||||
}
|
||||
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
limit.THROW_MAX_CHECKS();
|
||||
try {
|
||||
return getExtent().getBiomeType(x, z);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return BiomeTypes.FOREST;
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block) throws WorldEditException {
|
||||
limit.THROW_MAX_CHANGES();
|
||||
if (block.hasNbtData()) limit.MAX_BLOCKSTATES();
|
||||
try {
|
||||
return getExtent().setBlock(position, block);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block) throws WorldEditException {
|
||||
limit.THROW_MAX_CHANGES();
|
||||
if (block.hasNbtData()) limit.MAX_BLOCKSTATES();
|
||||
try {
|
||||
return getExtent().setBlock(x, y, z, block);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
||||
limit.THROW_MAX_CHANGES();
|
||||
limit.MAX_BLOCKSTATES();
|
||||
try {
|
||||
return getExtent().setTile(x, y, z, tile);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setBiome(BlockVector2 position, BiomeType biome) {
|
||||
limit.THROW_MAX_CHANGES();
|
||||
try {
|
||||
return getExtent().setBiome(position, biome);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
limit.THROW_MAX_CHANGES();
|
||||
try {
|
||||
return getExtent().setBiome(x, y, z, biome);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_FAILS()) {
|
||||
throw e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.boydti.fawe.beta.implementation.processors;
|
||||
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.object.FaweLimit;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
public class LimitProcessor implements IBatchProcessor {
|
||||
private final FaweLimit limit;
|
||||
private final IBatchProcessor parent;
|
||||
public LimitProcessor(FaweLimit limit, IBatchProcessor parent) {
|
||||
this.limit = limit;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||
try {
|
||||
return parent.processSet(chunk, get, set);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_CHANGES()) {
|
||||
throw e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processGet(int chunkX, int chunkZ) {
|
||||
try {
|
||||
return parent.processGet(chunkX, chunkZ);
|
||||
} catch (FaweException e) {
|
||||
if (!limit.MAX_CHECKS()) {
|
||||
throw e;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent construct(Extent child) {
|
||||
return new LimitExtent(parent.construct(child), limit);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.processors;
|
||||
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
@ -55,13 +55,18 @@ public class MultiBatchProcessor implements IBatchProcessor {
|
||||
|
||||
@Override
|
||||
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||
for (IBatchProcessor processor : this.processors) {
|
||||
set = processor.processSet(chunk, get, set);
|
||||
if (set == null) {
|
||||
return null;
|
||||
try {
|
||||
for (IBatchProcessor processor : this.processors) {
|
||||
set = processor.processSet(chunk, get, set);
|
||||
if (set == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return set;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
@ -0,0 +1,21 @@
|
||||
package com.boydti.fawe.beta.implementation.processors;
|
||||
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.NullExtent;
|
||||
|
||||
public enum NullProcessor implements IBatchProcessor {
|
||||
INSTANCE;
|
||||
@Override
|
||||
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent construct(Extent child) {
|
||||
return new NullExtent();
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.queue;
|
||||
|
||||
import com.boydti.fawe.beta.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.IQueueWrapper;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.filters.CountFilter;
|
||||
import com.boydti.fawe.beta.filters.DistrFilter;
|
||||
import com.boydti.fawe.beta.implementation.filter.CountFilter;
|
||||
import com.boydti.fawe.beta.implementation.filter.DistrFilter;
|
||||
import com.boydti.fawe.beta.implementation.processors.BatchProcessorHolder;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.object.clipboard.WorldCopyClipboard;
|
||||
@ -27,12 +28,15 @@ import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrapper {
|
||||
|
||||
private final World world;
|
||||
@ -67,26 +71,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
|
||||
return super.enableHistory(changeSet);
|
||||
}
|
||||
|
||||
private ChunkFilterBlock apply(ChunkFilterBlock block, Filter filter, IQueueExtent queue, Region region, int X, int Z) {
|
||||
if (!filter.appliesChunk(X, Z)) {
|
||||
return block;
|
||||
}
|
||||
IChunk chunk = queue.getOrCreateChunk(X, Z);
|
||||
// Initialize
|
||||
chunk.init(queue, X, Z);
|
||||
|
||||
IChunk newChunk = filter.applyChunk(chunk, region);
|
||||
if (newChunk != null) {
|
||||
chunk = newChunk;
|
||||
if (block == null) {
|
||||
block = queue.initFilterBlock();
|
||||
}
|
||||
chunk.filterBlocks(filter, block, region);
|
||||
}
|
||||
queue.submit(chunk);
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Filter> T apply(Region region, T filter) {
|
||||
// The chunks positions to iterate over
|
||||
final Set<BlockVector2> chunks = region.getChunks();
|
||||
@ -96,7 +81,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
|
||||
final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS);
|
||||
if (size <= 1) {
|
||||
BlockVector2 pos = chunksIter.next();
|
||||
apply(null, filter, getExtent(), region, pos.getX(), pos.getZ());
|
||||
getExtent().apply(null, filter, region, pos.getX(), pos.getZ());
|
||||
} else {
|
||||
final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> {
|
||||
try {
|
||||
@ -117,7 +102,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
|
||||
X = pos.getX();
|
||||
Z = pos.getZ();
|
||||
}
|
||||
block = apply(block, newFilter, queue, region, X, Z);
|
||||
block = queue.apply(block, newFilter, region, X, Z);
|
||||
}
|
||||
queue.flush();
|
||||
}
|
||||
@ -167,6 +152,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
|
||||
if (vset instanceof Region) {
|
||||
setBlocks((Region) vset, pattern);
|
||||
}
|
||||
// TODO optimize parallel
|
||||
for (BlockVector3 blockVector3 : vset) {
|
||||
pattern.apply(this, blockVector3, blockVector3);
|
||||
}
|
||||
@ -226,7 +212,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
|
||||
* returned by a given pattern.
|
||||
*
|
||||
* @param region the region to replace the blocks within
|
||||
* @param filter a list of block types to match, or null to use {@link ExistingBlockMask}
|
||||
* @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.function.mask.ExistingBlockMask}
|
||||
* @param replacement the replacement block
|
||||
* @return number of blocks affected
|
||||
* @throws MaxChangedBlocksException thrown if too many blocks are changed
|
||||
@ -241,7 +227,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
|
||||
* returned by a given pattern.
|
||||
*
|
||||
* @param region the region to replace the blocks within
|
||||
* @param filter a list of block types to match, or null to use {@link ExistingBlockMask}
|
||||
* @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.function.mask.ExistingBlockMask}
|
||||
* @param pattern the pattern that provides the new blocks
|
||||
* @return number of blocks affected
|
||||
* @throws MaxChangedBlocksException thrown if too many blocks are changed
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.queue;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
@ -8,6 +8,8 @@ import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
import com.boydti.fawe.beta.implementation.cache.ChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.CleanableThreadLocal;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
@ -19,6 +21,7 @@ import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@ -39,6 +42,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool();
|
||||
private ThreadPoolExecutor blockingExecutor = FaweCache.IMP.newBlockingExecutor();
|
||||
private ConcurrentLinkedQueue<FutureTask> syncTasks = new ConcurrentLinkedQueue<>();
|
||||
private ConcurrentLinkedQueue<FutureTask> syncWhenFree = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private Map<World, WeakReference<IChunkCache<IChunkGet>>> chunkGetCache = new HashMap<>();
|
||||
private CleanableThreadLocal<IQueueExtent> queuePool = new CleanableThreadLocal<>(QueueHandler.this::create);
|
||||
@ -60,53 +64,61 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
throw new IllegalStateException("Not main thread");
|
||||
}
|
||||
if (!syncTasks.isEmpty()) {
|
||||
long now = System.currentTimeMillis();
|
||||
targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0);
|
||||
long diff = 50 + this.last - (this.last = now);
|
||||
long absDiff = Math.abs(diff);
|
||||
if (diff == 0) {
|
||||
allocate = Math.min(50, allocate + 1);
|
||||
} else if (diff < 0) {
|
||||
allocate = Math.max(5, allocate + diff);
|
||||
} else if (!Fawe.get().getTimer().isAbove(targetTPS)) {
|
||||
allocate = Math.max(5, allocate - 1);
|
||||
}
|
||||
long currentAllocate = allocate - absDiff;
|
||||
long currentAllocate = getAllocate();
|
||||
|
||||
if (!MemUtil.isMemoryFree()) {
|
||||
// TODO reduce mem usage
|
||||
// FaweCache trim
|
||||
// Preloader trim
|
||||
}
|
||||
|
||||
boolean wait = false;
|
||||
do {
|
||||
Runnable task = syncTasks.poll();
|
||||
if (task == null) {
|
||||
if (wait) {
|
||||
synchronized (syncTasks) {
|
||||
try {
|
||||
syncTasks.wait(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
task = syncTasks.poll();
|
||||
wait = false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (task != null) {
|
||||
task.run();
|
||||
wait = true;
|
||||
}
|
||||
} while (System.currentTimeMillis() - now < currentAllocate);
|
||||
operate(syncTasks, last, currentAllocate);
|
||||
} else if (!syncWhenFree.isEmpty()) {
|
||||
operate(syncWhenFree, last, getAllocate());
|
||||
} else {
|
||||
// trim??
|
||||
}
|
||||
while (!syncTasks.isEmpty()) {
|
||||
final FutureTask task = syncTasks.poll();
|
||||
}
|
||||
|
||||
private long getAllocate() {
|
||||
long now = System.currentTimeMillis();
|
||||
targetTPS = 18 - Math.max(Settings.IMP.QUEUE.EXTRA_TIME_MS * 0.05, 0);
|
||||
long diff = 50 + this.last - (this.last = now);
|
||||
long absDiff = Math.abs(diff);
|
||||
if (diff == 0) {
|
||||
allocate = Math.min(50, allocate + 1);
|
||||
} else if (diff < 0) {
|
||||
allocate = Math.max(5, allocate + diff);
|
||||
} else if (!Fawe.get().getTimer().isAbove(targetTPS)) {
|
||||
allocate = Math.max(5, allocate - 1);
|
||||
}
|
||||
return allocate - absDiff;
|
||||
}
|
||||
|
||||
private void operate(Queue<FutureTask> queue, long start, long currentAllocate) {
|
||||
boolean wait = false;
|
||||
do {
|
||||
Runnable task = queue.poll();
|
||||
if (task == null) {
|
||||
if (wait) {
|
||||
synchronized (syncTasks) {
|
||||
try {
|
||||
queue.wait(1);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
task = queue.poll();
|
||||
wait = false;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (task != null) {
|
||||
task.run();
|
||||
wait = true;
|
||||
}
|
||||
}
|
||||
} while (System.currentTimeMillis() - start < currentAllocate);
|
||||
}
|
||||
|
||||
public <T extends Future<T>> void complete(Future<T> task) {
|
||||
@ -136,50 +148,83 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
}
|
||||
|
||||
public <T> Future<T> sync(Runnable run, T value) {
|
||||
return sync(run, value, syncTasks);
|
||||
}
|
||||
|
||||
public <T> Future<T> sync(Runnable run) {
|
||||
return sync(run, syncTasks);
|
||||
}
|
||||
|
||||
public <T> Future<T> sync(Callable<T> call) throws Exception {
|
||||
return sync(call, syncTasks);
|
||||
}
|
||||
|
||||
public <T> Future<T> sync(Supplier<T> call) {
|
||||
return sync(call, syncTasks);
|
||||
}
|
||||
|
||||
// Lower priorty sync task (runs only when there are no other tasks)
|
||||
public <T> Future<T> syncWhenFree(Runnable run, T value) {
|
||||
return sync(run, value, syncWhenFree);
|
||||
}
|
||||
|
||||
public <T> Future<T> syncWhenFree(Runnable run) {
|
||||
return sync(run, syncWhenFree);
|
||||
}
|
||||
|
||||
public <T> Future<T> syncWhenFree(Callable<T> call) throws Exception {
|
||||
return sync(call, syncWhenFree);
|
||||
}
|
||||
|
||||
public <T> Future<T> syncWhenFree(Supplier<T> call) {
|
||||
return sync(call, syncWhenFree);
|
||||
}
|
||||
|
||||
private <T> Future<T> sync(Runnable run, T value, Queue<FutureTask> queue) {
|
||||
if (Fawe.isMainThread()) {
|
||||
run.run();
|
||||
return Futures.immediateFuture(value);
|
||||
}
|
||||
final FutureTask<T> result = new FutureTask<>(run, value);
|
||||
syncTasks.add(result);
|
||||
notifySync();
|
||||
queue.add(result);
|
||||
notifySync(queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> Future<T> sync(Runnable run) {
|
||||
private <T> Future<T> sync(Runnable run, Queue<FutureTask> queue) {
|
||||
if (Fawe.isMainThread()) {
|
||||
run.run();
|
||||
return Futures.immediateCancelledFuture();
|
||||
}
|
||||
final FutureTask<T> result = new FutureTask<>(run, null);
|
||||
syncTasks.add(result);
|
||||
notifySync();
|
||||
queue.add(result);
|
||||
notifySync(queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> Future<T> sync(Callable<T> call) throws Exception {
|
||||
private <T> Future<T> sync(Callable<T> call, Queue<FutureTask> queue) throws Exception {
|
||||
if (Fawe.isMainThread()) {
|
||||
return Futures.immediateFuture(call.call());
|
||||
}
|
||||
final FutureTask<T> result = new FutureTask<>(call);
|
||||
syncTasks.add(result);
|
||||
notifySync();
|
||||
queue.add(result);
|
||||
notifySync(queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
public <T> Future<T> sync(Supplier<T> call) {
|
||||
private <T> Future<T> sync(Supplier<T> call, Queue<FutureTask> queue) {
|
||||
if (Fawe.isMainThread()) {
|
||||
return Futures.immediateFuture(call.get());
|
||||
}
|
||||
final FutureTask<T> result = new FutureTask<>(call::get);
|
||||
syncTasks.add(result);
|
||||
notifySync();
|
||||
queue.add(result);
|
||||
notifySync(queue);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void notifySync() {
|
||||
synchronized (syncTasks) {
|
||||
syncTasks.notifyAll();
|
||||
private void notifySync(Object object) {
|
||||
synchronized (object) {
|
||||
object.notifyAll();
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,28 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
package com.boydti.fawe.beta.implementation.queue;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.CharFilterBlock;
|
||||
import com.boydti.fawe.beta.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.CharFilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.IBatchProcessor;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.implementation.chunk.NullChunk;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.holder.ChunkHolder;
|
||||
import com.boydti.fawe.beta.implementation.holder.ReferenceChunk;
|
||||
import com.boydti.fawe.beta.implementation.chunk.ChunkHolder;
|
||||
import com.boydti.fawe.beta.implementation.chunk.ReferenceChunk;
|
||||
import com.boydti.fawe.beta.implementation.processors.BatchProcessorHolder;
|
||||
import com.boydti.fawe.beta.implementation.processors.EmptyBatchProcessor;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
@ -221,13 +220,15 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu
|
||||
|
||||
@Override
|
||||
public final IChunk getOrCreateChunk(int x, int z) {
|
||||
if (!processGet(x, z)) {
|
||||
throw FaweCache.CHUNK;
|
||||
}
|
||||
final long pair = (long) x << 32 | z & 0xffffffffL;
|
||||
if (pair == lastPair) {
|
||||
return lastChunk;
|
||||
}
|
||||
if (!processGet(x, z)) {
|
||||
lastPair = pair;
|
||||
lastChunk = NullChunk.INSTANCE;
|
||||
return NullChunk.INSTANCE;
|
||||
}
|
||||
|
||||
IChunk chunk = chunks.get(pair);
|
||||
if (chunk instanceof ReferenceChunk) {
|
||||
@ -276,11 +277,20 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu
|
||||
private void pollSubmissions(int targetSize, boolean aggressive) {
|
||||
final int overflow = submissions.size() - targetSize;
|
||||
if (aggressive) {
|
||||
if (targetSize == 0) {
|
||||
while (!submissions.isEmpty()) {
|
||||
Future future = submissions.poll();
|
||||
try {
|
||||
while (future != null) future = (Future) future.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < overflow; i++) {
|
||||
Future first = submissions.poll();
|
||||
try {
|
||||
while ((first = (Future) first.get()) != null) {
|
||||
}
|
||||
while (first != null) first = (Future) first.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -327,7 +337,6 @@ public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQu
|
||||
chunks.clear();
|
||||
}
|
||||
pollSubmissions(0, true);
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
@ -6,7 +6,7 @@ import static com.sk89q.worldedit.util.formatting.text.TextComponent.newline;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.beta.SingleFilterBlock;
|
||||
import com.boydti.fawe.beta.implementation.filter.block.SingleFilterBlock;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.object.brush.visualization.cfi.HeightMapMCAGenerator;
|
||||
@ -75,6 +75,7 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.IntStream;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import org.enginehub.piston.annotation.Command;
|
||||
import org.enginehub.piston.annotation.CommandContainer;
|
||||
import org.enginehub.piston.annotation.param.Arg;
|
||||
@ -431,7 +432,7 @@ public class CFICommands {
|
||||
Clipboard clipboard = holder.getClipboard();
|
||||
boolean[] ids = new boolean[BlockTypes.size()];
|
||||
for (BlockVector3 pt : clipboard.getRegion()) {
|
||||
ids[clipboard.getBlock(pt).getInternalBlockTypeId()] = true;
|
||||
ids[clipboard.getBlock(pt).getBlockType().getInternalId()] = true;
|
||||
}
|
||||
blocks = new HashSet<>();
|
||||
for (int combined = 0; combined < ids.length; combined++) {
|
||||
@ -605,7 +606,7 @@ public class CFICommands {
|
||||
@CommandPermissions("worldedit.anvil.cfi")
|
||||
public void waterId(Player player, BlockStateHolder block) throws WorldEditException {
|
||||
CFISettings settings = assertSettings(player);
|
||||
settings.getGenerator().setWaterId(block.getBlockType().getInternalId());
|
||||
settings.getGenerator().setWater(block.toImmutableState());
|
||||
|
||||
player.print("Set water id!");
|
||||
settings.resetComponent();
|
||||
@ -620,7 +621,7 @@ public class CFICommands {
|
||||
@CommandPermissions("worldedit.anvil.cfi")
|
||||
public void baseId(Player player, BlockStateHolder block) throws WorldEditException {
|
||||
CFISettings settings = assertSettings(player);
|
||||
settings.getGenerator().setBedrockId(block.getBlockType().getInternalId());
|
||||
settings.getGenerator().setBedrock(block.toImmutableState());
|
||||
player.print(TextComponent.of("Set base id!"));
|
||||
settings.resetComponent();
|
||||
component(player);
|
||||
|
@ -14,6 +14,8 @@ public class Settings extends Config {
|
||||
|
||||
@Ignore
|
||||
public boolean PROTOCOL_SUPPORT_FIX = false;
|
||||
@Ignore
|
||||
public boolean PLOTSQUARED_HOOK = false;
|
||||
|
||||
@Comment("These first 6 aren't configurable") // This is a comment
|
||||
@Final // Indicates that this value isn't configurable
|
||||
|
@ -4,17 +4,11 @@ import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.clipboard.CPUOptimizedClipboard;
|
||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||
import com.boydti.fawe.object.clipboard.FaweClipboard;
|
||||
import com.boydti.fawe.object.clipboard.LinearClipboard;
|
||||
import com.boydti.fawe.object.clipboard.MemoryOptimizedClipboard;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
@ -29,7 +23,7 @@ public class CorruptSchematicStreamer {
|
||||
|
||||
private final InputStream stream;
|
||||
private final UUID uuid;
|
||||
private FaweClipboard fc;
|
||||
private LinearClipboard fc;
|
||||
final AtomicInteger volume = new AtomicInteger();
|
||||
final AtomicInteger width = new AtomicInteger();
|
||||
final AtomicInteger height = new AtomicInteger();
|
||||
@ -78,7 +72,7 @@ public class CorruptSchematicStreamer {
|
||||
}
|
||||
}
|
||||
|
||||
public FaweClipboard setupClipboard() {
|
||||
public LinearClipboard setupClipboard() {
|
||||
if (fc != null) {
|
||||
return fc;
|
||||
}
|
||||
@ -87,11 +81,11 @@ public class CorruptSchematicStreamer {
|
||||
Fawe.debug("No dimensions found! Estimating based on factors:" + dimensions);
|
||||
}
|
||||
if (Settings.IMP.CLIPBOARD.USE_DISK) {
|
||||
fc = new DiskOptimizedClipboard(dimensions.getBlockX(), dimensions.getBlockY(), dimensions.getBlockZ(), uuid);
|
||||
fc = new DiskOptimizedClipboard(dimensions, uuid);
|
||||
} else if (Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL == 0) {
|
||||
fc = new CPUOptimizedClipboard(dimensions.getBlockX(), dimensions.getBlockY(), dimensions.getBlockZ());
|
||||
fc = new CPUOptimizedClipboard(dimensions);
|
||||
} else {
|
||||
fc = new MemoryOptimizedClipboard(dimensions.getBlockX(), dimensions.getBlockY(), dimensions.getBlockZ());
|
||||
fc = new MemoryOptimizedClipboard(dimensions);
|
||||
}
|
||||
return fc;
|
||||
}
|
||||
|
@ -1,90 +0,0 @@
|
||||
package com.boydti.fawe.jnbt;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.config.BBC;
|
||||
import com.boydti.fawe.object.exception.FaweException;
|
||||
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class NBTStreamer {
|
||||
private final NBTInputStream is;
|
||||
private final HashMap<String, BiConsumer> readers;
|
||||
|
||||
public NBTStreamer(NBTInputStream stream) {
|
||||
this.is = stream;
|
||||
readers = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the entire stream and runs the applicable readers
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void readFully() throws IOException {
|
||||
is.readNamedTagLazy(readers::get);
|
||||
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 {
|
||||
try {
|
||||
is.readNamedTagLazy(node -> {
|
||||
if (readers.isEmpty()) {
|
||||
throw FaweCache.MANUAL;
|
||||
}
|
||||
return readers.remove(node);
|
||||
});
|
||||
} catch (FaweException ignore) {}
|
||||
is.close();
|
||||
}
|
||||
|
||||
public <T, V> void addReader(String node, BiConsumer<T, V> run) {
|
||||
if (run instanceof NBTStreamReader) {
|
||||
((NBTStreamReader) run).init(node);
|
||||
}
|
||||
readers.put(node, run);
|
||||
}
|
||||
|
||||
public static abstract class NBTStreamReader<T, V> implements BiConsumer<T, V> {
|
||||
private String node;
|
||||
|
||||
public void init(String node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public String getNode() {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
public static abstract class ByteReader implements BiConsumer<Integer, Integer> {
|
||||
@Override
|
||||
public void accept(Integer index, Integer value) {
|
||||
run(index, value);
|
||||
}
|
||||
|
||||
public abstract void run(int index, int byteValue);
|
||||
}
|
||||
|
||||
public interface LazyReader extends BiConsumer<Integer, DataInputStream> {}
|
||||
|
||||
public static abstract class LongReader implements BiConsumer<Integer, Long> {
|
||||
@Override
|
||||
public void accept(Integer index, Long value) {
|
||||
run(index, value);
|
||||
}
|
||||
|
||||
public abstract void run(int index, long byteValue);
|
||||
}
|
||||
}
|
@ -1,420 +0,0 @@
|
||||
package com.boydti.fawe.jnbt;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.clipboard.CPUOptimizedClipboard;
|
||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||
import com.boydti.fawe.object.clipboard.FaweClipboard;
|
||||
import com.boydti.fawe.object.clipboard.MemoryOptimizedClipboard;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.boydti.fawe.object.io.FastByteArraysInputStream;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.registry.state.PropertyKey;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockCategories;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypeSwitch;
|
||||
import com.sk89q.worldedit.world.block.BlockTypeSwitchBuilder;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import com.sk89q.worldedit.world.registry.LegacyMapper;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import net.jpountz.lz4.LZ4BlockOutputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
// TODO FIXME
|
||||
public class SchematicStreamer extends NBTStreamer {
|
||||
private final UUID uuid;
|
||||
private FastByteArrayOutputStream idOut = new FastByteArrayOutputStream();
|
||||
private FastByteArrayOutputStream dataOut = new FastByteArrayOutputStream();
|
||||
private FastByteArrayOutputStream addOut;
|
||||
|
||||
private FaweOutputStream ids;
|
||||
private FaweOutputStream datas;
|
||||
private FaweOutputStream adds;
|
||||
|
||||
public SchematicStreamer(NBTInputStream stream, UUID uuid) {
|
||||
super(stream);
|
||||
this.uuid = uuid;
|
||||
clipboard = new BlockArrayClipboard(new CuboidRegion(BlockVector3.at(0, 0, 0), BlockVector3.at(0, 0, 0)), fc);
|
||||
}
|
||||
|
||||
public void addBlockReaders() throws IOException {
|
||||
NBTStreamReader<? extends Integer, ? extends Integer> idInit = new NBTStreamReader<Integer, Integer>() {
|
||||
@Override
|
||||
public void accept(Integer length, Integer type) {
|
||||
setupClipboard(length);
|
||||
ids = new FaweOutputStream(new LZ4BlockOutputStream(idOut));
|
||||
}
|
||||
};
|
||||
NBTStreamReader<? extends Integer, ? extends Integer> dataInit = new NBTStreamReader<Integer, Integer>() {
|
||||
@Override
|
||||
public void accept(Integer length, Integer type) {
|
||||
setupClipboard(length);
|
||||
datas = new FaweOutputStream(new LZ4BlockOutputStream(dataOut));
|
||||
}
|
||||
};
|
||||
NBTStreamReader<? extends Integer, ? extends Integer> addInit = new NBTStreamReader<Integer, Integer>() {
|
||||
@Override
|
||||
public void accept(Integer length, Integer type) {
|
||||
setupClipboard(length*2);
|
||||
addOut = new FastByteArrayOutputStream();
|
||||
adds = new FaweOutputStream(new LZ4BlockOutputStream(addOut));
|
||||
}
|
||||
};
|
||||
|
||||
addReader("Schematic.Blocks.?", idInit);
|
||||
addReader("Schematic.Data.?", dataInit);
|
||||
addReader("Schematic.AddBlocks.?", addInit);
|
||||
addReader("Schematic.Blocks.#", new ByteReader() {
|
||||
@Override
|
||||
public void run(int index, int value) {
|
||||
try {
|
||||
ids.write(value);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
addReader("Schematic.Data.#", new ByteReader() {
|
||||
@Override
|
||||
public void run(int index, int value) {
|
||||
try {
|
||||
datas.write(value);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
addReader("Schematic.AddBlocks.#", new ByteReader() {
|
||||
@Override
|
||||
public void run(int index, int value) {
|
||||
if (value != 0) {
|
||||
int first = value & 0x0F;
|
||||
int second = (value & 0xF0) >> 4;
|
||||
try {
|
||||
if (first != 0) adds.write(first);
|
||||
if (second != 0) adds.write(second);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
ByteReader biomeReader = new ByteReader() {
|
||||
@Override
|
||||
public void run(int index, int value) {
|
||||
BiomeType biome = BiomeTypes.getLegacy(value);
|
||||
if (biome != null) {
|
||||
fc.setBiome(index, biome);
|
||||
}
|
||||
}
|
||||
};
|
||||
NBTStreamReader<Integer, Integer> initializer23 = new NBTStreamReader<Integer, Integer>() {
|
||||
@Override
|
||||
public void accept(Integer value1, Integer value2) {
|
||||
if (fc == null) setupClipboard(length * width * height);
|
||||
}
|
||||
};
|
||||
addReader("Schematic.AWEBiomes.?", initializer23);
|
||||
addReader("Schematic.Biomes.?", initializer23);
|
||||
addReader("Schematic.AWEBiomes.#", biomeReader); // AWE stores as an int[]
|
||||
addReader("Schematic.Biomes.#", biomeReader); // FAWE stores as a byte[] (4x smaller)
|
||||
|
||||
// Tiles
|
||||
addReader("Schematic.TileEntities.#", (BiConsumer<Integer, CompoundTag>) (index, value) -> {
|
||||
if (fc == null) {
|
||||
setupClipboard(0);
|
||||
}
|
||||
int x = value.getInt("x");
|
||||
int y = value.getInt("y");
|
||||
int z = value.getInt("z");
|
||||
fc.setTile(x, y, z, value);
|
||||
});
|
||||
// Entities
|
||||
addReader("Schematic.Entities.#", (BiConsumer<Integer, CompoundTag>) (index, compound) -> {
|
||||
if (fc == null) {
|
||||
setupClipboard(0);
|
||||
}
|
||||
String id = compound.getString("id");
|
||||
if (id.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ListTag positionTag = compound.getListTag("Pos");
|
||||
ListTag directionTag = compound.getListTag("Rotation");
|
||||
EntityType type = EntityTypes.parse(id);
|
||||
if (type != null) {
|
||||
compound.getValue().put("Id", new StringTag(type.getId()));
|
||||
BaseEntity state = new BaseEntity(type, compound);
|
||||
fc.createEntity(clipboard, positionTag.asDouble(0), positionTag.asDouble(1), positionTag.asDouble(2), (float) directionTag.asDouble(0), (float) directionTag.asDouble(1), state);
|
||||
} else {
|
||||
Fawe.debug("Invalid entity: " + id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFully() throws IOException {
|
||||
super.readFully();
|
||||
if (ids != null) ids.close();
|
||||
if (datas != null) datas.close();
|
||||
if (adds != null) adds.close();
|
||||
FaweInputStream idIn = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(idOut.toByteArrays())));
|
||||
FaweInputStream dataIn = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(dataOut.toByteArrays())));
|
||||
|
||||
LegacyMapper remap = LegacyMapper.getInstance();
|
||||
BlockVector3 dimensions = fc.getDimensions();
|
||||
int length = dimensions.getBlockX() * dimensions.getBlockY() * dimensions.getBlockZ();
|
||||
if (adds == null) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
fc.setBlock(i, remap.getBlockFromLegacyCombinedId(((idIn.read() & 0xFF) << 4) + (dataIn.read() & 0xF)));
|
||||
}
|
||||
} else {
|
||||
FaweInputStream addIn = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(dataOut.toByteArrays())));
|
||||
for (int i = 0; i < length; i++) {
|
||||
fc.setBlock(i, remap.getBlockFromLegacyCombinedId(((addIn.read() & 0xFF) << 8) + ((idIn.read() & 0xFF) << 4) + (dataIn.read() & 0xF)));
|
||||
}
|
||||
addIn.close();
|
||||
}
|
||||
idIn.close();
|
||||
dataIn.close();
|
||||
}
|
||||
|
||||
private void fixStates() {
|
||||
fc.forEach(new FaweClipboard.BlockReader() {
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> void run(int x, int y, int z, B block) {
|
||||
BlockType type = block.getBlockType();
|
||||
if (BlockCategories.STAIRS.contains(type)) {
|
||||
Object half = block.getState(PropertyKey.HALF);
|
||||
Direction facing = block.getState(PropertyKey.FACING);
|
||||
|
||||
BlockVector3 forward = facing.toBlockVector();
|
||||
Direction left = facing.getLeft();
|
||||
Direction right = facing.getRight();
|
||||
|
||||
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> forwardBlock = fc.getBlock(x + forward.getBlockX(), y + forward.getBlockY(), z + forward.getBlockZ());
|
||||
BlockType forwardType = forwardBlock.getBlockType();
|
||||
if (forwardType.hasProperty(PropertyKey.SHAPE) && forwardType.hasProperty(PropertyKey.FACING)) {
|
||||
Direction forwardFacing = (Direction) forwardBlock.getState(PropertyKey.FACING);
|
||||
if (forwardFacing == left) {
|
||||
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ());
|
||||
BlockType rightType = rightBlock.getBlockType();
|
||||
if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) {
|
||||
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_left"));
|
||||
}
|
||||
return;
|
||||
} else if (forwardFacing == right) {
|
||||
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ());
|
||||
BlockType leftType = leftBlock.getBlockType();
|
||||
if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) {
|
||||
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_right"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> backwardsBlock = fc.getBlock(x - forward.getBlockX(), y - forward.getBlockY(), z - forward.getBlockZ());
|
||||
BlockType backwardsType = backwardsBlock.getBlockType();
|
||||
if (backwardsType.hasProperty(PropertyKey.SHAPE) && backwardsType.hasProperty(PropertyKey.FACING)) {
|
||||
Direction backwardsFacing = (Direction) backwardsBlock.getState(PropertyKey.FACING);
|
||||
if (backwardsFacing == left) {
|
||||
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ());
|
||||
BlockType rightType = rightBlock.getBlockType();
|
||||
if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) {
|
||||
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "outer_left"));
|
||||
}
|
||||
return;
|
||||
} else if (backwardsFacing == right) {
|
||||
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ());
|
||||
BlockType leftType = leftBlock.getBlockType();
|
||||
if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) {
|
||||
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "outer_right"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int group = group(type);
|
||||
if (group == -1) return;
|
||||
BlockStateHolder set = block;
|
||||
|
||||
if (set.getState(PropertyKey.NORTH) == Boolean.FALSE && merge(group, x, y, z - 1)) set = set.with(PropertyKey.NORTH, true);
|
||||
if (set.getState(PropertyKey.EAST) == Boolean.FALSE && merge(group, x + 1, y, z)) set = set.with(PropertyKey.EAST, true);
|
||||
if (set.getState(PropertyKey.SOUTH) == Boolean.FALSE && merge(group, x, y, z + 1)) set = set.with(PropertyKey.SOUTH, true);
|
||||
if (set.getState(PropertyKey.WEST) == Boolean.FALSE && merge(group, x - 1, y, z)) set = set.with(PropertyKey.WEST, true);
|
||||
|
||||
if (group == 2) {
|
||||
int ns = ((Boolean) set.getState(PropertyKey.NORTH) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.SOUTH) ? 1 : 0);
|
||||
int ew = ((Boolean) set.getState(PropertyKey.EAST) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.WEST) ? 1 : 0);
|
||||
if (Math.abs(ns - ew) != 2 || fc.getBlock(x, y + 1, z).getBlockType().getMaterial().isSolid()) {
|
||||
set = set.with(PropertyKey.UP, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (set != block) fc.setBlock(x, y, z, set);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
private BlockTypeSwitch<Boolean> fullCube = new BlockTypeSwitchBuilder<>(false).add(type -> {
|
||||
BlockMaterial mat = type.getMaterial();
|
||||
return (mat.isFullCube() && !mat.isFragileWhenPushed() && mat.getLightValue() == 0 && mat.isOpaque() && mat.isSolid() && !mat.isTranslucent());
|
||||
}, true).build();
|
||||
|
||||
private boolean merge(int group, int x, int y, int z) {
|
||||
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> block = fc.getBlock(x, y, z);
|
||||
BlockType type = block.getBlockType();
|
||||
return group(type) == group || fullCube.apply(type);
|
||||
}
|
||||
|
||||
private int group(BlockType type) {
|
||||
switch (type.getInternalId()) {
|
||||
case BlockID.ACACIA_FENCE:
|
||||
case BlockID.BIRCH_FENCE:
|
||||
case BlockID.DARK_OAK_FENCE:
|
||||
case BlockID.JUNGLE_FENCE:
|
||||
case BlockID.OAK_FENCE:
|
||||
case BlockID.SPRUCE_FENCE:
|
||||
return 0;
|
||||
case BlockID.NETHER_BRICK_FENCE:
|
||||
return 1;
|
||||
case BlockID.COBBLESTONE_WALL:
|
||||
case BlockID.MOSSY_COBBLESTONE_WALL:
|
||||
return 2;
|
||||
case BlockID.IRON_BARS:
|
||||
case BlockID.BLACK_STAINED_GLASS_PANE:
|
||||
case BlockID.BLUE_STAINED_GLASS_PANE:
|
||||
case BlockID.BROWN_MUSHROOM_BLOCK:
|
||||
case BlockID.BROWN_STAINED_GLASS_PANE:
|
||||
case BlockID.CYAN_STAINED_GLASS_PANE:
|
||||
case BlockID.GLASS_PANE:
|
||||
case BlockID.GRAY_STAINED_GLASS_PANE:
|
||||
case BlockID.GREEN_STAINED_GLASS_PANE:
|
||||
case BlockID.LIGHT_BLUE_STAINED_GLASS_PANE:
|
||||
case BlockID.LIGHT_GRAY_STAINED_GLASS_PANE:
|
||||
case BlockID.LIME_STAINED_GLASS_PANE:
|
||||
case BlockID.MAGENTA_STAINED_GLASS_PANE:
|
||||
case BlockID.ORANGE_STAINED_GLASS_PANE:
|
||||
case BlockID.PINK_STAINED_GLASS_PANE:
|
||||
case BlockID.PURPLE_STAINED_GLASS_PANE:
|
||||
case BlockID.RED_STAINED_GLASS_PANE:
|
||||
case BlockID.WHITE_STAINED_GLASS_PANE:
|
||||
case BlockID.YELLOW_STAINED_GLASS_PANE:
|
||||
return 3;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void addDimensionReaders() {
|
||||
addReader("Schematic.Height",
|
||||
(BiConsumer<Integer, Short>) (index, value) -> height = (value));
|
||||
addReader("Schematic.Width", (BiConsumer<Integer, Short>) (index, value) -> width = (value));
|
||||
addReader("Schematic.Length",
|
||||
(BiConsumer<Integer, Short>) (index, value) -> length = (value));
|
||||
addReader("Schematic.WEOriginX",
|
||||
(BiConsumer<Integer, Integer>) (index, value) -> originX = (value));
|
||||
addReader("Schematic.WEOriginY",
|
||||
(BiConsumer<Integer, Integer>) (index, value) -> originY = (value));
|
||||
addReader("Schematic.WEOriginZ",
|
||||
(BiConsumer<Integer, Integer>) (index, value) -> originZ = (value));
|
||||
addReader("Schematic.WEOffsetX",
|
||||
(BiConsumer<Integer, Integer>) (index, value) -> offsetX = (value));
|
||||
addReader("Schematic.WEOffsetY",
|
||||
(BiConsumer<Integer, Integer>) (index, value) -> offsetY = (value));
|
||||
addReader("Schematic.WEOffsetZ",
|
||||
(BiConsumer<Integer, Integer>) (index, value) -> offsetZ = (value));
|
||||
}
|
||||
|
||||
private int height;
|
||||
private int width;
|
||||
private int length;
|
||||
|
||||
private int originX;
|
||||
private int originY;
|
||||
private int originZ;
|
||||
|
||||
private int offsetX;
|
||||
private int offsetY;
|
||||
private int offsetZ;
|
||||
|
||||
private BlockArrayClipboard clipboard;
|
||||
private FaweClipboard fc;
|
||||
|
||||
private FaweClipboard setupClipboard(int size) {
|
||||
if (fc != null) {
|
||||
if (fc.getDimensions().getX() == 0) {
|
||||
fc.setDimensions(BlockVector3.at(size, 1, 1));
|
||||
}
|
||||
return fc;
|
||||
}
|
||||
if (Settings.IMP.CLIPBOARD.USE_DISK) {
|
||||
return fc = new DiskOptimizedClipboard(size, 1, 1, uuid);
|
||||
} else if (Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL == 0) {
|
||||
return fc = new CPUOptimizedClipboard(size, 1, 1);
|
||||
} else {
|
||||
return fc = new MemoryOptimizedClipboard(size, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockVector3 getOrigin() {
|
||||
return BlockVector3.at(originX, originY, originZ);
|
||||
}
|
||||
|
||||
public BlockVector3 getOffset() {
|
||||
return BlockVector3.at(offsetX, offsetY, offsetZ);
|
||||
}
|
||||
|
||||
public BlockVector3 getDimensions() {
|
||||
return BlockVector3.at(width, height, length);
|
||||
}
|
||||
|
||||
public void setClipboard(FaweClipboard clipboard) {
|
||||
this.fc = clipboard;
|
||||
}
|
||||
|
||||
public Clipboard getClipboard() throws IOException {
|
||||
try {
|
||||
setupClipboard(0);
|
||||
addDimensionReaders();
|
||||
addBlockReaders();
|
||||
readFully();
|
||||
BlockVector3 min = BlockVector3.at(originX, originY, originZ);
|
||||
BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ);
|
||||
BlockVector3 origin = min.subtract(offset);
|
||||
BlockVector3 dimensions = BlockVector3.at(width, height, length);
|
||||
fc.setDimensions(dimensions);
|
||||
fixStates();
|
||||
CuboidRegion region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE));
|
||||
clipboard.init(region, fc);
|
||||
clipboard.setOrigin(origin);
|
||||
return clipboard;
|
||||
} catch (Throwable e) {
|
||||
if (fc != null) {
|
||||
fc.close();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,49 +1,161 @@
|
||||
package com.boydti.fawe.object.brush.visualization.cfi;
|
||||
package com.boydti.fawe.jnbt.anvil;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.jnbt.streamer.StreamDelegate;
|
||||
import com.boydti.fawe.jnbt.streamer.ValueReader;
|
||||
import com.boydti.fawe.object.collection.BitArray4096;
|
||||
import com.boydti.fawe.object.collection.BlockVector3ChunkMap;
|
||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.NBTConstants;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class WritableMCAChunk {
|
||||
public class MCAChunk implements IChunkSet {
|
||||
public final boolean[] hasSections = new boolean[16];
|
||||
public final byte[] skyLight = new byte[65536];
|
||||
public final byte[] blockLight = new byte[65536];
|
||||
|
||||
public boolean hasBiomes = false;
|
||||
public final int[] biomes = new int[256];
|
||||
public final byte[] biomes = new byte[256];
|
||||
|
||||
public final int[] blocks = new int[65536];
|
||||
public final char[] blocks = new char[65536];
|
||||
|
||||
public Map<Short, CompoundTag> tiles = new HashMap<>();
|
||||
public Map<UUID, CompoundTag> entities = new HashMap<>();
|
||||
public final BlockVector3ChunkMap<CompoundTag> tiles = new BlockVector3ChunkMap<CompoundTag>();
|
||||
public final Map<UUID, CompoundTag> entities = new HashMap<>();
|
||||
public long inhabitedTime = System.currentTimeMillis();
|
||||
public long lastUpdate;
|
||||
|
||||
public int modified;
|
||||
public boolean deleted;
|
||||
|
||||
public int chunkX, chunkZ;
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
|
||||
protected WritableMCAChunk() {
|
||||
public MCAChunk() {}
|
||||
|
||||
private boolean readLayer(Section section) {
|
||||
if (section.palette == null || section.layer == -1 || section.blocksLength == -1 || section.palette[section.palette.length - 1] == null || section.blocks == null) {
|
||||
// not initialized
|
||||
return false;
|
||||
}
|
||||
|
||||
int bitsPerEntry = MathMan.log2nlz(section.palette.length - 1);
|
||||
BitArray4096 bitArray = new BitArray4096(section.blocks, bitsPerEntry);
|
||||
char[] buffer = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
|
||||
bitArray.toRaw(buffer);
|
||||
int offset = section.layer << 12;
|
||||
for (int i = 0; i < buffer.length; i++) {
|
||||
BlockState block = section.palette[buffer[i]];
|
||||
blocks[offset + i] = block.getOrdinalChar();
|
||||
}
|
||||
|
||||
section.layer = -1;
|
||||
section.blocksLength = -1;
|
||||
section.blocks = null;
|
||||
section.palette = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class Section {
|
||||
public int layer = -1;
|
||||
public long[] blocks;
|
||||
public int blocksLength = -1;
|
||||
public BlockState[] palette;
|
||||
}
|
||||
|
||||
public MCAChunk(NBTInputStream nis, int chunkX, int chunkZ, boolean readPos) throws IOException {
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
read(nis, readPos);
|
||||
}
|
||||
|
||||
public void read(NBTInputStream nis, boolean readPos) throws IOException {
|
||||
StreamDelegate root = createDelegate(nis, readPos);
|
||||
nis.readNamedTagLazy(root);
|
||||
}
|
||||
|
||||
public StreamDelegate createDelegate(NBTInputStream nis, boolean readPos) {
|
||||
StreamDelegate root = new StreamDelegate();
|
||||
StreamDelegate level = root.add("").add("Level");
|
||||
|
||||
level.add("InhabitedTime").withLong((i, v) -> inhabitedTime = v);
|
||||
level.add("LastUpdate").withLong((i, v) -> lastUpdate = v);
|
||||
|
||||
if (readPos) {
|
||||
level.add("xPos").withInt((i, v) -> MCAChunk.this.chunkX = v);
|
||||
level.add("zPos").withInt((i, v) -> MCAChunk.this.chunkZ = v);
|
||||
}
|
||||
|
||||
Section section = new Section();
|
||||
|
||||
StreamDelegate layers = level.add("Sections");
|
||||
StreamDelegate layer = layers.add();
|
||||
layer.withInfo((length, type) -> {
|
||||
section.layer = -1;
|
||||
section.blocksLength = -1;
|
||||
});
|
||||
layer.add("Y").withInt((i, y) -> section.layer = y);
|
||||
layer.add("Palette").withElem((ValueReader<Map<String, Object>>) (index, map) -> {
|
||||
String name = (String) map.get("Name");
|
||||
BlockType type = BlockTypes.get(name);
|
||||
BlockState state = type.getDefaultState();
|
||||
Map<String, String> properties = (Map<String, String>) map.get("Properties");
|
||||
if (properties != null) {
|
||||
for (Map.Entry<String, String> entry : properties.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
Property property = type.getProperty(key);
|
||||
state = state.with(property, property.getValueFor(value));
|
||||
}
|
||||
}
|
||||
section.palette[index] = state;
|
||||
readLayer(section);
|
||||
});
|
||||
StreamDelegate blockStates = layer.add("BlockStates");
|
||||
blockStates.withInfo((length, type) -> {
|
||||
if (section.blocks == null) {
|
||||
section.blocks = FaweCache.IMP.LONG_BUFFER_1024.get();
|
||||
}
|
||||
section.blocksLength = length;
|
||||
});
|
||||
blockStates.withLong((index, value) -> section.blocks[index] = value);
|
||||
level.add("TileEntities").withElem((ValueReader<Map<String, Object>>) (index, value) -> {
|
||||
CompoundTag tile = FaweCache.IMP.asTag(value);
|
||||
int x = tile.getInt("x") & 15;
|
||||
int y = tile.getInt("y");
|
||||
int z = tile.getInt("z") & 15;
|
||||
tiles.put(x, y, z, tile);
|
||||
});
|
||||
level.add("Entities").withElem((ValueReader<Map<String, Object>>) (index, value) -> {
|
||||
CompoundTag entity = FaweCache.IMP.asTag(value);
|
||||
entities.put(entity.getUUID(), entity);
|
||||
});
|
||||
level.add("Biomes").withInt((index, value) -> biomes[index] = (byte) value);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
@ -54,14 +166,22 @@ public class WritableMCAChunk {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
public void setLoc(int X, int Z) {
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return hasSections[layer];
|
||||
}
|
||||
|
||||
public void setPosition(int X, int Z) {
|
||||
this.chunkX = X;
|
||||
this.chunkZ = Z;
|
||||
}
|
||||
|
||||
public void clear(int X, int Z) {
|
||||
this.chunkX = X;
|
||||
this.chunkZ = Z;
|
||||
@Override
|
||||
public IChunkSet reset() {
|
||||
return this.reset(true);
|
||||
}
|
||||
|
||||
public IChunkSet reset(boolean full) {
|
||||
if (!tiles.isEmpty()) {
|
||||
tiles.clear();
|
||||
}
|
||||
@ -71,11 +191,13 @@ public class WritableMCAChunk {
|
||||
modified = 0;
|
||||
deleted = false;
|
||||
hasBiomes = false;
|
||||
// TODO optimize
|
||||
for (int i = 0; i < 65536; i++) {
|
||||
blocks[i] = BlockID.AIR;
|
||||
if (full) {
|
||||
for (int i = 0; i < 65536; i++) {
|
||||
blocks[i] = BlockID.AIR;
|
||||
}
|
||||
}
|
||||
Arrays.fill(hasSections, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void write(NBTOutputStream nbtOut) throws IOException {
|
||||
@ -127,11 +249,10 @@ public class WritableMCAChunk {
|
||||
int num_palette = 0;
|
||||
try {
|
||||
for (int i = blockIndexStart, j = 0; i < blockIndexEnd; i++, j++) {
|
||||
int stateId = blocks[i];
|
||||
int ordinal = BlockState.getFromInternalId(stateId).getOrdinal(); // TODO fixme Remove all use of BlockTypes.BIT_OFFSET so that this conversion isn't necessary
|
||||
int ordinal = blocks[i];
|
||||
int palette = blockToPalette[ordinal];
|
||||
if (palette == Integer.MAX_VALUE) {
|
||||
BlockState state = BlockTypes.states[ordinal];
|
||||
// BlockState state = BlockTypesCache.states[ordinal];
|
||||
blockToPalette[ordinal] = palette = num_palette;
|
||||
paletteToBlock[num_palette] = ordinal;
|
||||
num_palette++;
|
||||
@ -149,7 +270,7 @@ public class WritableMCAChunk {
|
||||
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int ordinal = paletteToBlock[i];
|
||||
BlockState state = BlockTypes.states[ordinal];
|
||||
BlockState state = BlockTypesCache.states[ordinal];
|
||||
BlockType type = state.getBlockType();
|
||||
out.writeNamedTag("Name", type.getId());
|
||||
|
||||
@ -192,13 +313,13 @@ public class WritableMCAChunk {
|
||||
}
|
||||
|
||||
|
||||
out.writeNamedTagName("BlockLight", NBTConstants.TYPE_BYTE_ARRAY);
|
||||
out.writeInt(2048);
|
||||
out.write(blockLight, layer << 11, 1 << 11);
|
||||
|
||||
out.writeNamedTagName("SkyLight", NBTConstants.TYPE_BYTE_ARRAY);
|
||||
out.writeInt(2048);
|
||||
out.write(skyLight, layer << 11, 1 << 11);
|
||||
// out.writeNamedTagName("BlockLight", NBTConstants.TYPE_BYTE_ARRAY);
|
||||
// out.writeInt(2048);
|
||||
// out.write(blockLight, layer << 11, 1 << 11);
|
||||
//
|
||||
// out.writeNamedTagName("SkyLight", NBTConstants.TYPE_BYTE_ARRAY);
|
||||
// out.writeInt(2048);
|
||||
// out.write(skyLight, layer << 11, 1 << 11);
|
||||
|
||||
|
||||
out.writeEndTag();
|
||||
@ -250,6 +371,15 @@ public class WritableMCAChunk {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
if (deleted) return true;
|
||||
for (boolean hasSection : hasSections) {
|
||||
if (hasSection) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
return modified != 0;
|
||||
}
|
||||
@ -272,14 +402,17 @@ public class WritableMCAChunk {
|
||||
return bitMask;
|
||||
}
|
||||
|
||||
public void setTile(int x, int y, int z, CompoundTag tile) {
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tile) {
|
||||
setModified();
|
||||
short pair = MathMan.tripleBlockCoord(x, y, z);
|
||||
if (tile != null) {
|
||||
tiles.put(pair, tile);
|
||||
tiles.put(x, y, z, tile);
|
||||
} else {
|
||||
tiles.remove(pair);
|
||||
if (tiles.remove(x, y, z) == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setEntity(CompoundTag entityTag) {
|
||||
@ -289,17 +422,39 @@ public class WritableMCAChunk {
|
||||
entities.put(new UUID(most, least), entityTag);
|
||||
}
|
||||
|
||||
public void setBiome(int x, int z, BiomeType biome) {
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
return BiomeTypes.get(this.biomes[(z << 4) | x] & 0xFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType[] getBiomes() {
|
||||
BiomeType[] tmp = new BiomeType[256];
|
||||
for (int i = 0; i < 256; i++) {
|
||||
tmp[i] = BiomeTypes.get(this.biomes[i] & 0xFF);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(BlockVector2 pos, BiomeType biome) {
|
||||
return this.setBiome(pos.getX(), 0, pos.getZ(), biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
setModified();
|
||||
biomes[x + (z << 4)] = biome.getInternalId();
|
||||
biomes[x + (z << 4)] = (byte) biome.getInternalId();
|
||||
return true;
|
||||
}
|
||||
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return new HashSet<>(entities.values());
|
||||
}
|
||||
|
||||
public Map<Short, CompoundTag> getTiles() {
|
||||
return tiles == null ? new HashMap<>() : tiles;
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
return tiles == null ? Collections.emptyMap() : tiles;
|
||||
}
|
||||
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
@ -310,94 +465,51 @@ public class WritableMCAChunk {
|
||||
return tiles.get(pair);
|
||||
}
|
||||
|
||||
public boolean doesSectionExist(int cy) {
|
||||
return hasSections[cy];
|
||||
}
|
||||
|
||||
private final int getIndex(int x, int y, int z) {
|
||||
return x | (z << 4) | (y << 8);
|
||||
}
|
||||
|
||||
public int getBlockCombinedId(int x, int y, int z) {
|
||||
public int getBlockOrdinal(int x, int y, int z) {
|
||||
return blocks[x | (z << 4) | (y << 8)];
|
||||
}
|
||||
|
||||
public BiomeType[] getBiomeArray() {
|
||||
return null;
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
int ordinal = getBlockOrdinal(x, y, z);
|
||||
return BlockState.getFromOrdinal(ordinal);
|
||||
}
|
||||
|
||||
public Set<UUID> getEntityRemoves() {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
public void setSkyLight(int x, int y, int z, int value) {
|
||||
setNibble(getIndex(x, y, z), skyLight, value);
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, BlockStateHolder holder) {
|
||||
setBlock(x, y, z, holder.getOrdinalChar());
|
||||
holder.applyTileEntity(this, x, y, z);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setBlockLight(int x, int y, int z, int value) {
|
||||
setNibble(getIndex(x, y, z), blockLight, value);
|
||||
}
|
||||
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
if (!hasSections[y >> 4]) {
|
||||
return 0;
|
||||
}
|
||||
return getNibble(getIndex(x, y, z), skyLight);
|
||||
}
|
||||
|
||||
public int getBlockLight(int x, int y, int z) {
|
||||
if (!hasSections[y >> 4]) {
|
||||
return 0;
|
||||
}
|
||||
return getNibble(getIndex(x, y, z), blockLight);
|
||||
}
|
||||
|
||||
public void setFullbright() {
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (hasSections[layer]) {
|
||||
Arrays.fill(skyLight, layer << 7, ((layer + 1) << 7), (byte) 255);
|
||||
}
|
||||
@Override
|
||||
public void setBlocks(int layer, char[] data) {
|
||||
int offset = layer << 12;
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
blocks[offset + i] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLight() {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
removeLight(i);
|
||||
@Override
|
||||
public char[] getArray(int layer) {
|
||||
char[] tmp = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
|
||||
int offset = layer << 12;
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
tmp[i] = blocks[offset + i];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public void removeLight(int i) {
|
||||
if (hasSections[i]) {
|
||||
Arrays.fill(skyLight, i << 7, ((i + 1) << 7), (byte) 0);
|
||||
Arrays.fill(blockLight, i << 7, ((i + 1) << 7), (byte) 0);
|
||||
}
|
||||
}
|
||||
|
||||
public int getNibble(int index, byte[] array) {
|
||||
int indexShift = index >> 1;
|
||||
if ((index & 1) == 0) {
|
||||
return array[indexShift] & 15;
|
||||
} else {
|
||||
return array[indexShift] >> 4 & 15;
|
||||
}
|
||||
}
|
||||
|
||||
public void setNibble(int index, byte[] array, int value) {
|
||||
int indexShift = index >> 1;
|
||||
byte existing = array[indexShift];
|
||||
int valueShift = value << 4;
|
||||
if (existing == value + valueShift) {
|
||||
return;
|
||||
}
|
||||
if ((index & 1) == 0) {
|
||||
array[indexShift] = (byte) (existing & 240 | value);
|
||||
} else {
|
||||
array[indexShift] = (byte) (existing & 15 | valueShift);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBlock(int x, int y, int z, int combinedId) {
|
||||
blocks[getIndex(x, y, z)] = combinedId;
|
||||
public void setBlock(int x, int y, int z, char ordinal) {
|
||||
blocks[getIndex(x, y, z)] = ordinal;
|
||||
}
|
||||
|
||||
public void setBiome(BiomeType biome) {
|
||||
@ -407,4 +519,9 @@ public class WritableMCAChunk {
|
||||
public void removeEntity(UUID uuid) {
|
||||
entities.remove(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return isEmpty();
|
||||
}
|
||||
}
|
708
worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java
Normale Datei
708
worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAFile.java
Normale Datei
@ -0,0 +1,708 @@
|
||||
package com.boydti.fawe.jnbt.anvil;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
import com.boydti.fawe.jnbt.streamer.StreamDelegate;
|
||||
import com.boydti.fawe.object.RunnableVal4;
|
||||
import com.boydti.fawe.object.collection.CleanableThreadLocal;
|
||||
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
||||
import com.boydti.fawe.object.io.FastByteArrayInputStream;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
/**
|
||||
* Chunk format: http://minecraft.gamepedia.com/Chunk_format#Entity_format
|
||||
* e.g.: `.Level.Entities.#` (Starts with a . as the root tag is unnamed)
|
||||
* Note: This class isn't thread safe. You can use it in an async thread, but not multiple at the same time
|
||||
*/
|
||||
public class MCAFile implements Trimable {
|
||||
|
||||
private static Field fieldBuf2;
|
||||
private static Field fieldBuf3;
|
||||
|
||||
static {
|
||||
try {
|
||||
fieldBuf2 = InflaterInputStream.class.getDeclaredField("buf");
|
||||
fieldBuf2.setAccessible(true);
|
||||
fieldBuf3 = NBTInputStream.class.getDeclaredField("buf");
|
||||
fieldBuf3.setAccessible(true);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private final ForkJoinPool pool;
|
||||
private final byte[] locations;
|
||||
private boolean readLocations;
|
||||
|
||||
private File file;
|
||||
private RandomAccessFile raf;
|
||||
|
||||
private boolean deleted;
|
||||
private int X, Z;
|
||||
private MCAChunk[] chunks;
|
||||
private boolean[] chunkInitialized;
|
||||
private Object[] locks;
|
||||
|
||||
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {
|
||||
return new byte[4096];
|
||||
}
|
||||
};
|
||||
final ThreadLocal<byte[]> byteStore2 = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {
|
||||
return new byte[4096];
|
||||
}
|
||||
};
|
||||
final ThreadLocal<byte[]> byteStore3 = new ThreadLocal<byte[]>() {
|
||||
@Override
|
||||
protected byte[] initialValue() {
|
||||
return new byte[1024];
|
||||
}
|
||||
};
|
||||
|
||||
public MCAFile(ForkJoinPool pool) {
|
||||
this.pool = pool;
|
||||
this.locations = new byte[4096];
|
||||
this.chunks = new MCAChunk[32 * 32];
|
||||
this.chunkInitialized = new boolean[this.chunks.length];
|
||||
this.locks = new Object[this.chunks.length];
|
||||
for (int i = 0; i < locks.length; i++) {
|
||||
locks[i] = new Object();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
boolean hasChunk = false;
|
||||
for (int i = 0; i < chunkInitialized.length; i++) {
|
||||
if (!chunkInitialized[i]) {
|
||||
chunks[i] = null;
|
||||
} else {
|
||||
hasChunk = true;
|
||||
}
|
||||
}
|
||||
CleanableThreadLocal.clean(byteStore1);
|
||||
CleanableThreadLocal.clean(byteStore2);
|
||||
CleanableThreadLocal.clean(byteStore3);
|
||||
return !hasChunk;
|
||||
}
|
||||
|
||||
public MCAFile init(File file) throws FileNotFoundException {
|
||||
String[] split = file.getName().split("\\.");
|
||||
int X = Integer.parseInt(split[1]);
|
||||
int Z = Integer.parseInt(split[2]);
|
||||
return init(file, X, Z);
|
||||
}
|
||||
|
||||
public MCAFile init(File file, int mcrX, int mcrZ) throws FileNotFoundException {
|
||||
if (raf != null) {
|
||||
flush(true);
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
locations[i] = 0;
|
||||
}
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
raf = null;
|
||||
}
|
||||
deleted = false;
|
||||
Arrays.fill(chunkInitialized, false);
|
||||
readLocations = false;
|
||||
this.X = mcrX;
|
||||
this.Z = mcrZ;
|
||||
this.file = file;
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException(file.getName());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public MCAFile init(World world, int mcrX, int mcrZ) throws FileNotFoundException {
|
||||
return init(new File(world.getStoragePath().toFile(), File.separator + "regions" + File.separator + "r." + mcrX + "." + mcrZ + ".mca"));
|
||||
}
|
||||
|
||||
public int getIndex(int chunkX, int chunkZ) {
|
||||
return ((chunkX & 31) << 2) + ((chunkZ & 31) << 7);
|
||||
}
|
||||
|
||||
|
||||
private RandomAccessFile getRaf() throws FileNotFoundException {
|
||||
if (this.raf == null) {
|
||||
this.raf = new RandomAccessFile(file, "rw");
|
||||
}
|
||||
return this.raf;
|
||||
}
|
||||
|
||||
private void readHeader() throws IOException {
|
||||
if (!readLocations) {
|
||||
readLocations = true;
|
||||
getRaf();
|
||||
if (raf.length() < 8192) {
|
||||
raf.setLength(8192);
|
||||
} else {
|
||||
raf.seek(0);
|
||||
raf.readFully(locations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
if (raf != null) {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
deleted = false;
|
||||
readLocations = false;
|
||||
Arrays.fill(chunkInitialized, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
CleanableThreadLocal.clean(byteStore1);
|
||||
CleanableThreadLocal.clean(byteStore2);
|
||||
CleanableThreadLocal.clean(byteStore3);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return X;
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return Z;
|
||||
}
|
||||
|
||||
public RandomAccessFile getRandomAccessFile() {
|
||||
return raf;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public MCAChunk getCachedChunk(int cx, int cz) {
|
||||
int pair = getIndex(cx, cz);
|
||||
MCAChunk chunk = chunks[pair];
|
||||
if (chunk != null && chunkInitialized[pair]) {
|
||||
return chunk;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setChunk(MCAChunk chunk) {
|
||||
int cx = chunk.getX();
|
||||
int cz = chunk.getZ();
|
||||
int pair = getIndex(cx, cz);
|
||||
chunks[pair] = chunk;
|
||||
}
|
||||
|
||||
public MCAChunk getChunk(int cx, int cz) throws IOException {
|
||||
int pair = getIndex(cx, cz);
|
||||
MCAChunk chunk = chunks[pair];
|
||||
if (chunk == null) {
|
||||
Object lock = locks[pair];
|
||||
synchronized (lock) {
|
||||
chunk = chunks[pair];
|
||||
if (chunk == null) {
|
||||
chunk = new MCAChunk();
|
||||
chunk.setPosition(cx, cz);
|
||||
chunks[pair] = chunk;
|
||||
}
|
||||
}
|
||||
} else if (chunkInitialized[pair]) {
|
||||
return chunk;
|
||||
}
|
||||
synchronized (chunk) {
|
||||
if (!chunkInitialized[pair]) {
|
||||
readChunk(chunk, pair);
|
||||
chunkInitialized[pair] = true;
|
||||
}
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private MCAChunk readChunk(MCAChunk chunk, int i) throws IOException {
|
||||
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i + 2] & 0xFF))) << 12;
|
||||
if (offset == 0) {
|
||||
return null;
|
||||
}
|
||||
int size = (locations[i + 3] & 0xFF) << 12;
|
||||
try (NBTInputStream nis = getChunkIS(offset)) {
|
||||
chunk.read(nis, false);
|
||||
}
|
||||
System.out.println("TODO multithreaded"); // TODO
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* CX, CZ, OFFSET, SIZE
|
||||
*
|
||||
* @param onEach
|
||||
* @throws IOException
|
||||
*/
|
||||
public void forEachSortedChunk(RunnableVal4<Integer, Integer, Integer, Integer> onEach) throws IOException {
|
||||
char[] offsets = new char[(int) (raf.length() / 4096) - 2];
|
||||
Arrays.fill(offsets, Character.MAX_VALUE);
|
||||
char i = 0;
|
||||
for (int z = 0; z < 32; z++) {
|
||||
for (int x = 0; x < 32; x++, i += 4) {
|
||||
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i + 2] & 0xFF))) - 2;
|
||||
int size = locations[i + 3] & 0xFF;
|
||||
if (size != 0) {
|
||||
if (offset < offsets.length) {
|
||||
offsets[offset] = i;
|
||||
} else {
|
||||
Fawe.debug("Ignoring invalid offset " + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < offsets.length; i++) {
|
||||
int index = offsets[i];
|
||||
if (index != Character.MAX_VALUE) {
|
||||
int offset = i + 2;
|
||||
int size = locations[index + 3] & 0xFF;
|
||||
int index2 = index >> 2;
|
||||
int x = (index2) & 31;
|
||||
int z = (index2) >> 5;
|
||||
onEach.run(x, z, offset << 12, size << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onEach cx, cz, offset, size
|
||||
*/
|
||||
public void forEachChunk(RunnableVal4<Integer, Integer, Integer, Integer> onEach) {
|
||||
int i = 0;
|
||||
for (int z = 0; z < 32; z++) {
|
||||
for (int x = 0; x < 32; x++, i += 4) {
|
||||
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i + 2] & 0xFF)));
|
||||
int size = locations[i + 3] & 0xFF;
|
||||
if (size != 0) {
|
||||
onEach.run(x, z, offset << 12, size << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void forEachChunk(Consumer<MCAChunk> onEach) {
|
||||
int i = 0;
|
||||
for (int z = 0; z < 32; z++) {
|
||||
for (int x = 0; x < 32; x++, i += 4) {
|
||||
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i + 2] & 0xFF)));
|
||||
int size = locations[i + 3] & 0xFF;
|
||||
if (size != 0) {
|
||||
try {
|
||||
onEach.accept(getChunk(x, z));
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getOffset(int cx, int cz) {
|
||||
int i = getIndex(cx, cz);
|
||||
int offset = (((locations[i] & 0xFF) << 16) + ((locations[i + 1] & 0xFF) << 8) + ((locations[i + 2] & 0xFF)));
|
||||
return offset << 12;
|
||||
}
|
||||
|
||||
public int getSize(int cx, int cz) {
|
||||
int i = getIndex(cx, cz);
|
||||
return (locations[i + 3] & 0xFF) << 12;
|
||||
}
|
||||
|
||||
public byte[] getChunkCompressedBytes(int offset) throws IOException {
|
||||
if (offset == 0) {
|
||||
return null;
|
||||
}
|
||||
synchronized (raf) {
|
||||
raf.seek(offset);
|
||||
int size = raf.readInt();
|
||||
int compression = raf.read();
|
||||
byte[] data = new byte[size];
|
||||
raf.readFully(data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
private NBTInputStream getChunkIS(int offset) throws IOException {
|
||||
try {
|
||||
byte[] data = getChunkCompressedBytes(offset);
|
||||
FastByteArrayInputStream bais = new FastByteArrayInputStream(data);
|
||||
InflaterInputStream iis = new InflaterInputStream(bais, new Inflater(), 1);
|
||||
fieldBuf2.set(iis, byteStore2.get());
|
||||
BufferedInputStream bis = new BufferedInputStream(iis);
|
||||
NBTInputStream nis = new NBTInputStream(bis);
|
||||
fieldBuf3.set(nis, byteStore3.get());
|
||||
return nis;
|
||||
} catch (IllegalAccessException unlikely) {
|
||||
unlikely.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void streamChunk(int cx, int cz, StreamDelegate delegate) throws IOException {
|
||||
streamChunk(getOffset(cx, cz), delegate);
|
||||
}
|
||||
|
||||
public void streamChunk(int offset, StreamDelegate delegate) throws IOException {
|
||||
byte[] data = getChunkCompressedBytes(offset);
|
||||
streamChunk(data, delegate);
|
||||
}
|
||||
|
||||
public void streamChunk(byte[] data, StreamDelegate delegate) throws IOException {
|
||||
if (data != null) {
|
||||
try {
|
||||
FastByteArrayInputStream bais = new FastByteArrayInputStream(data);
|
||||
InflaterInputStream iis = new InflaterInputStream(bais, new Inflater(), 1);
|
||||
fieldBuf2.set(iis, byteStore2.get());
|
||||
BufferedInputStream bis = new BufferedInputStream(iis);
|
||||
NBTInputStream nis = new NBTInputStream(bis);
|
||||
fieldBuf3.set(nis, byteStore3.get());
|
||||
nis.readNamedTagLazy(delegate);
|
||||
} catch (IllegalAccessException unlikely) {
|
||||
unlikely.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onEach chunk
|
||||
*/
|
||||
public void forEachCachedChunk(Consumer<MCAChunk> onEach) {
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
MCAChunk chunk = chunks[i];
|
||||
if (chunk != null && this.chunkInitialized[i]) {
|
||||
onEach.accept(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<MCAChunk> getCachedChunks() {
|
||||
int size = 0;
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
if (chunks[i] != null && this.chunkInitialized[i]) size++;
|
||||
}
|
||||
ArrayList<MCAChunk> list = new ArrayList<>(size);
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
MCAChunk chunk = chunks[i];
|
||||
if (chunk != null && this.chunkInitialized[i]) {
|
||||
list.add(chunk);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private byte[] toBytes(MCAChunk chunk) throws Exception {
|
||||
if (chunk.isDeleted()) {
|
||||
return null;
|
||||
}
|
||||
byte[] uncompressed = chunk.toBytes(byteStore3.get());
|
||||
byte[] compressed = MainUtil.compress(uncompressed, byteStore2.get(), null);
|
||||
return compressed;
|
||||
}
|
||||
|
||||
private byte[] getChunkBytes(int cx, int cz) throws Exception {
|
||||
MCAChunk mca = getCachedChunk(cx, cz);
|
||||
if (mca == null) {
|
||||
int offset = getOffset(cx, cz);
|
||||
if (offset == 0) {
|
||||
return null;
|
||||
}
|
||||
return getChunkCompressedBytes(offset);
|
||||
}
|
||||
return toBytes(mca);
|
||||
}
|
||||
|
||||
|
||||
private void writeSafe(RandomAccessFile raf, int offset, byte[] data) throws IOException {
|
||||
int len = data.length + 5;
|
||||
raf.seek(offset);
|
||||
if (raf.length() - offset < len) {
|
||||
raf.setLength(((offset + len + 4095) / 4096) * 4096);
|
||||
}
|
||||
// Length of remaining data
|
||||
raf.writeInt(data.length + 1);
|
||||
// Compression type
|
||||
raf.write(2);
|
||||
raf.write(data);
|
||||
}
|
||||
|
||||
private void writeHeader(RandomAccessFile raf, int cx, int cz, int offsetMedium, int sizeByte, boolean writeTime) throws IOException {
|
||||
int i = getIndex(cx, cz);
|
||||
locations[i] = (byte) (offsetMedium >> 16);
|
||||
locations[i + 1] = (byte) (offsetMedium >> 8);
|
||||
locations[i + 2] = (byte) (offsetMedium);
|
||||
locations[i + 3] = (byte) sizeByte;
|
||||
raf.seek(i);
|
||||
raf.write((offsetMedium >> 16));
|
||||
raf.write((offsetMedium >> 8));
|
||||
raf.write((offsetMedium >> 0));
|
||||
raf.write(sizeByte);
|
||||
raf.seek(i + 4096);
|
||||
if (offsetMedium == 0 && sizeByte == 0) {
|
||||
raf.writeInt(0);
|
||||
} else {
|
||||
raf.writeInt((int) (System.currentTimeMillis() / 1000L));
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (raf == null) return;
|
||||
synchronized (raf) {
|
||||
if (raf != null) {
|
||||
flush(true);
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
raf = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
if (isDeleted()) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < chunks.length; i++) {
|
||||
MCAChunk chunk = chunks[i];
|
||||
if (chunk != null && this.chunkInitialized[i]) {
|
||||
if (chunk.isModified() || chunk.isDeleted()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the chunk to the file
|
||||
* @param wait - If the flush method needs to wait for the pool
|
||||
*/
|
||||
public void flush(boolean wait) {
|
||||
synchronized (raf) {
|
||||
// If the file is marked as deleted, nothing is written
|
||||
if (isDeleted()) {
|
||||
clear();
|
||||
file.delete();
|
||||
return;
|
||||
}
|
||||
|
||||
// Chunks that need to be relocated
|
||||
Int2ObjectOpenHashMap<byte[]> relocate = new Int2ObjectOpenHashMap<>();
|
||||
// The position of each chunk
|
||||
final Int2ObjectOpenHashMap<Integer> offsetMap = new Int2ObjectOpenHashMap<>(); // Offset -> <byte cx, byte cz, short size>
|
||||
// The data of each modified chunk
|
||||
final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>();
|
||||
// The data of each chunk that needs to be moved
|
||||
final Int2ObjectOpenHashMap<byte[]> append = new Int2ObjectOpenHashMap<>();
|
||||
boolean[] modified = new boolean[1];
|
||||
// Get the current time for the chunk timestamp
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
// Load the chunks into the append or compressed map
|
||||
final ForkJoinPool finalPool = this.pool;
|
||||
forEachCachedChunk(chunk -> {
|
||||
if (chunk.isModified() || chunk.isDeleted()) {
|
||||
modified[0] = true;
|
||||
chunk.setLastUpdate(now);
|
||||
if (!chunk.isDeleted()) {
|
||||
MCAFile.this.pool.submit(() -> {
|
||||
try {
|
||||
byte[] compressed = toBytes(chunk);
|
||||
int pair = MathMan.pair((short) (chunk.getX() & 31), (short) (chunk.getZ() & 31));
|
||||
Int2ObjectOpenHashMap map;
|
||||
if (getOffset(chunk.getX(), chunk.getZ()) == 0) {
|
||||
map = append;
|
||||
} else {
|
||||
map = compressedMap;
|
||||
}
|
||||
synchronized (map) {
|
||||
map.put(pair, compressed);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// If any changes were detected
|
||||
if (modified[0]) {
|
||||
file.setLastModified(now);
|
||||
|
||||
// Load the offset data into the offset map
|
||||
forEachChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||
@Override
|
||||
public void run(Integer cx, Integer cz, Integer offset, Integer size) {
|
||||
short pair1 = MathMan.pairByte((byte) (cx & 31), (byte) (cz & 31));
|
||||
short pair2 = (short) (size >> 12);
|
||||
offsetMap.put((int) offset, (Integer) MathMan.pair(pair1, pair2));
|
||||
}
|
||||
});
|
||||
// Wait for previous tasks
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
|
||||
|
||||
int start = 8192;
|
||||
int written = start;
|
||||
int end = 8192;
|
||||
int nextOffset = 8192;
|
||||
try {
|
||||
for (int count = 0; count < offsetMap.size(); count++) {
|
||||
// Get the previous position of the next chunk
|
||||
Integer loc = offsetMap.get(nextOffset);
|
||||
while (loc == null) {
|
||||
nextOffset += 4096;
|
||||
loc = offsetMap.get(nextOffset);
|
||||
}
|
||||
int offset = nextOffset;
|
||||
|
||||
// Get the x/z from the paired location
|
||||
short cxz = MathMan.unpairX(loc);
|
||||
int cx = MathMan.unpairShortX(cxz);
|
||||
int cz = MathMan.unpairShortY(cxz);
|
||||
|
||||
// Get the size from the pair
|
||||
int size = MathMan.unpairY(loc) << 12;
|
||||
|
||||
nextOffset += size;
|
||||
end = Math.min(start + size, end);
|
||||
int pair = getIndex(cx, cz);
|
||||
byte[] newBytes = relocate.get(pair);
|
||||
|
||||
// newBytes is null if the chunk isn't modified or marked for moving
|
||||
if (newBytes == null) {
|
||||
MCAChunk cached = getCachedChunk(cx, cz);
|
||||
// If the previous offset marks the current write position (start) then we only write the header
|
||||
if (offset == start) {
|
||||
if (cached == null || !cached.isModified()) {
|
||||
writeHeader(raf, cx, cz, start >> 12, size >> 12, true);
|
||||
start += size;
|
||||
written = start + size;
|
||||
continue;
|
||||
} else {
|
||||
newBytes = compressedMap.get(pair);
|
||||
}
|
||||
} else {
|
||||
// The chunk needs to be moved, fetch the data if necessary
|
||||
newBytes = compressedMap.get(pair);
|
||||
if (newBytes == null) {
|
||||
if (cached == null || !cached.isDeleted()) {
|
||||
newBytes = getChunkCompressedBytes(getOffset(cx, cz));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newBytes == null) {
|
||||
writeHeader(raf, cx, cz, 0, 0, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
// The length to be written (compressed data + 5 byte chunk header)
|
||||
int len = newBytes.length + 5;
|
||||
int oldSize = (size + 4095) >> 12;
|
||||
int newSize = (len + 4095) >> 12;
|
||||
int nextOffset2 = end;
|
||||
|
||||
// If the current write position (start) + length of data to write (len) are longer than the position of the next chunk, we need to move the next chunks
|
||||
while (start + len > end) {
|
||||
Integer nextLoc = offsetMap.get(nextOffset2);
|
||||
if (nextLoc != null) {
|
||||
short nextCXZ = MathMan.unpairX(nextLoc);
|
||||
int nextCX = MathMan.unpairShortX(nextCXZ);
|
||||
int nextCZ = MathMan.unpairShortY(nextCXZ);
|
||||
MCAChunk cached = getCachedChunk(nextCX, nextCZ);
|
||||
if (cached == null || !cached.isModified()) {
|
||||
byte[] nextBytes = getChunkCompressedBytes(nextOffset2);
|
||||
relocate.put(MathMan.pair((short) (nextCX & 31), (short) (nextCZ & 31)), nextBytes);
|
||||
}
|
||||
int nextSize = MathMan.unpairY(nextLoc) << 12;
|
||||
end += nextSize;
|
||||
nextOffset2 += nextSize;
|
||||
} else {
|
||||
end += 4096;
|
||||
nextOffset2 += 4096;
|
||||
}
|
||||
}
|
||||
// Write the chunk + chunk header
|
||||
writeSafe(raf, start, newBytes);
|
||||
// Write the location data (beginning of file)
|
||||
writeHeader(raf, cx, cz, start >> 12, newSize, true);
|
||||
|
||||
written = start + newBytes.length + 5;
|
||||
start += newSize << 12;
|
||||
}
|
||||
|
||||
// Write all the chunks which need to be appended
|
||||
if (!append.isEmpty()) {
|
||||
for (Int2ObjectMap.Entry<byte[]> entry : append.int2ObjectEntrySet()) {
|
||||
int pair = entry.getIntKey();
|
||||
short cx = MathMan.unpairX(pair);
|
||||
short cz = MathMan.unpairY(pair);
|
||||
byte[] bytes = entry.getValue();
|
||||
int len = bytes.length + 5;
|
||||
int newSize = (len + 4095) >> 12;
|
||||
writeSafe(raf, start, bytes);
|
||||
writeHeader(raf, cx, cz, start >> 12, newSize, true);
|
||||
written = start + bytes.length + 5;
|
||||
start += newSize << 12;
|
||||
}
|
||||
}
|
||||
// Round the file length, since the vanilla server doesn't like it for some reason
|
||||
raf.setLength(4096 * ((written + 4095) / 4096));
|
||||
if (raf instanceof BufferedRandomAccessFile) {
|
||||
((BufferedRandomAccessFile) raf).flush();
|
||||
}
|
||||
raf.close();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (wait) {
|
||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren