filter set

This commit is contained in:
Jesse Boyd
2019-05-03 00:45:03 +10:00
parent 8dcc005ec1
commit f5944fbcaf
26 changed files with 617 additions and 480 deletions

View File

@ -56,6 +56,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
@ -147,6 +148,11 @@ public class FaweBukkit implements IFawe, Listener {
});
}
@EventHandler
public static void onChunkUnload(ChunkUnloadEvent event) {
event.setCancelled(true);
}
@Override
public QueueHandler getQueueHandler() {
return new BukkitQueueHandler();

View File

@ -94,7 +94,7 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit
public char[] idbToStateOrdinal;
private boolean init() {
private synchronized boolean init() {
if (idbToStateOrdinal != null) return false;
idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
for (int i = 0; i < idbToStateOrdinal.length; i++) {
@ -527,8 +527,8 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit
int id = Block.REGISTRY_ID.getId(ibd);
return idbToStateOrdinal[id];
} catch (NullPointerException e) {
if (init()) return adaptToInt(ibd);
throw e;
init();
return adaptToInt(ibd);
}
}
@ -537,8 +537,8 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit
int id = Block.REGISTRY_ID.getId(ibd);
return idbToStateOrdinal[id];
} catch (NullPointerException e) {
if (init()) return adaptToChar(ibd);
throw e;
init();
return adaptToChar(ibd);
}
}

View File

@ -20,6 +20,7 @@ import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.Constants;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockTypes;
import net.jpountz.util.UnsafeUtils;
import net.minecraft.server.v1_13_R2.BiomeBase;
import net.minecraft.server.v1_13_R2.BlockPosition;
@ -69,7 +70,7 @@ public class BukkitChunkHolder<T extends Future<T>> extends ChunkHolder {
get.reset();
}
if (get.sections == null) {
get.sections = sections;
get.sections = sections.clone();
}
if (get.sections[layer] != section) {
get.sections[layer] = section;
@ -79,271 +80,274 @@ public class BukkitChunkHolder<T extends Future<T>> extends ChunkHolder {
}
@Override
public T call() {
BukkitQueue extent = (BukkitQueue) getExtent();
BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet();
CharSetBlocks set = (CharSetBlocks) getOrCreateSet();
int X = getX();
int Z = getZ();
public synchronized T call() {
try {
int X = getX();
int Z = getZ();
BukkitQueue extent = (BukkitQueue) getExtent();
BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet();
CharSetBlocks set = (CharSetBlocks) getOrCreateSet();
Chunk nmsChunk = extent.ensureLoaded(X, Z);
Chunk nmsChunk = extent.ensureLoaded(X, Z);
// Remove existing tiles
{
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
if (!tiles.isEmpty()) {
final Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = tiles.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry<BlockPosition, TileEntity> entry = iterator.next();
final BlockPosition pos = entry.getKey();
final int lx = pos.getX() & 15;
final int ly = pos.getY();
final int lz = pos.getZ() & 15;
final int layer = ly >> 4;
final char[] array = set.blocks[layer];
if (array == null) {
continue;
}
final int index = (((ly & 0xF) << 8) | (lz << 4) | lx);
if (array[index] != 0) {
TileEntity tile = entry.getValue();
tile.z();
tile.invalidateBlockCache();
// Remove existing tiles
{
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
if (!tiles.isEmpty()) {
final Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = tiles.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry<BlockPosition, TileEntity> entry = iterator.next();
final BlockPosition pos = entry.getKey();
final int lx = pos.getX() & 15;
final int ly = pos.getY();
final int lz = pos.getZ() & 15;
final int layer = ly >> 4;
final char[] array = set.blocks[layer];
if (array == null) {
continue;
}
final int index = (((ly & 0xF) << 8) | (lz << 4) | lx);
if (array[index] != 0) {
TileEntity tile = entry.getValue();
tile.z();
tile.invalidateBlockCache();
}
}
}
}
}
int bitMask = 0;
synchronized (nmsChunk) {
ChunkSection[] sections = nmsChunk.getSections();
World world = extent.getBukkitWorld();
boolean hasSky = world.getEnvironment() == World.Environment.NORMAL;
int bitMask = 0;
synchronized (nmsChunk) {
ChunkSection[] sections = nmsChunk.getSections();
World world = extent.getBukkitWorld();
boolean hasSky = world.getEnvironment() == World.Environment.NORMAL;
for (int layer = 0; layer < 16; layer++) {
if (!set.hasSection(layer)) continue;
for (int layer = 0; layer < 16; layer++) {
if (!set.hasSection(layer)) continue;
bitMask |= 1 << layer;
bitMask |= 1 << layer;
char[] setArr = set.blocks[layer];
ChunkSection newSection;
ChunkSection existingSection = sections[layer];
if (existingSection == null) {
newSection = extent.newChunkSection(layer, hasSky, setArr);
if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) {
updateGet(get, nmsChunk, sections, newSection, setArr, layer);
continue;
} else {
existingSection = sections[layer];
if (existingSection == null) {
System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer);
continue;
}
}
}
DelegateLock lock = BukkitQueue.applyLock(existingSection);
synchronized (lock) {
lock.untilFree();
synchronized (get) {
ChunkSection getSection;
if (get.nmsChunk != nmsChunk) {
if (get.nmsChunk != null) System.out.println("chunk doesn't match");
get.nmsChunk = nmsChunk;
get.sections = null;
get.reset();
} else {
getSection = get.getSections()[layer];
if (getSection != existingSection) {
get.sections[layer] = existingSection;
get.reset();
System.out.println("Section doesn't match");
} else if (lock.isModified()) {
System.out.println("lock is outdated");
get.reset(layer);
}
}
char[] getArr = get.load(layer);
for (int i = 0; i < 4096; i++) {
char value = setArr[i];
if (value != 0) {
getArr[i] = value;
}
}
newSection = extent.newChunkSection(layer, hasSky, getArr);
if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) {
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
continue;
} else {
char[] setArr = set.blocks[layer];
ChunkSection newSection;
ChunkSection existingSection = sections[layer];
if (existingSection == null) {
newSection = extent.newChunkSection(layer, hasSky, setArr);
if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) {
updateGet(get, nmsChunk, sections, newSection, setArr, layer);
}
}
}
}
// Biomes
if (set.biomes != null) {
// set biomes
final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex();
for (int i = 0; i < set.biomes.length; i++) {
final BiomeType biome = set.biomes[i];
if (biome != null) {
final Biome craftBiome = BukkitAdapter.adapt(biome);
currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome);
}
}
}
Runnable[] syncTasks = null;
net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.getWorld();
int bx = X << 4;
int bz = Z << 4;
if (set.entityRemoves != null && !set.entityRemoves.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[3];
HashSet<UUID> entsToRemove = set.entityRemoves;
syncTasks[2] = new Runnable() {
@Override
public void run() {
final List<Entity>[] entities = nmsChunk.getEntitySlices();
for (int i = 0; i < entities.length; i++) {
final Collection<Entity> ents = entities[i];
if (!ents.isEmpty()) {
final Iterator<Entity> iter = ents.iterator();
while (iter.hasNext()) {
final Entity entity = iter.next();
if (entsToRemove.contains(entity.getUniqueID())) {
iter.remove();
entity.b(false);
entity.die();
entity.valid = false;
}
}
}
}
}
};
}
if (set.entities != null && !set.entities.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[2];
HashSet<CompoundTag> entitiesToSpawn = set.entities;
syncTasks[1] = new Runnable() {
@Override
public void run() {
for (final CompoundTag nativeTag : entitiesToSpawn) {
final Map<String, Tag> entityTagMap = ReflectionUtils.getMap(nativeTag.getValue());
final StringTag idTag = (StringTag) entityTagMap.get("Id");
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
if (idTag == null || posTag == null || rotTag == null) {
Fawe.debug("Unknown entity tag: " + nativeTag);
continue;
} else {
existingSection = sections[layer];
if (existingSection == null) {
System.out.println("Skipping invalid null section. chunk:" + X + "," + Z + " layer: " + layer);
continue;
}
final double x = posTag.getDouble(0);
final double y = posTag.getDouble(1);
final double z = posTag.getDouble(2);
final float yaw = rotTag.getFloat(0);
final float pitch = rotTag.getFloat(1);
final String id = idTag.getValue();
final Entity entity = EntityTypes.a(nmsWorld, new MinecraftKey(id));
if (entity != null) {
final UUID uuid = entity.getUniqueID();
entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits()));
entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits()));
if (nativeTag != null) {
final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag);
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name);
}
entity.f(tag);
}
}
DelegateLock lock = BukkitQueue.applyLock(existingSection);
synchronized (get) {
synchronized (lock) {
lock.untilFree();
ChunkSection getSection;
if (get.nmsChunk != nmsChunk) {
get.nmsChunk = nmsChunk;
get.sections = null;
get.reset();
} else {
getSection = get.getSections()[layer];
if (getSection != existingSection) {
get.sections[layer] = existingSection;
get.reset();
} else if (lock.isModified()) {
get.reset(layer);
}
entity.setLocation(x, y, z, yaw, pitch);
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
}
char[] getArr = get.load(layer);
for (int i = 0; i < 4096; i++) {
char value = setArr[i];
if (value != 0) {
getArr[i] = value;
}
}
newSection = extent.newChunkSection(layer, hasSky, getArr);
if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) {
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
continue;
} else {
updateGet(get, nmsChunk, sections, newSection, setArr, layer);
}
}
}
};
}
// set tiles
if (set.tiles != null && !set.tiles.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[1];
HashMap<Short, CompoundTag> tiles = set.tiles;
syncTasks[0] = new Runnable() {
@Override
public void run() {
for (final Map.Entry<Short, CompoundTag> entry : tiles.entrySet()) {
final CompoundTag nativeTag = entry.getValue();
final short blockHash = entry.getKey();
final int x = (blockHash >> 12 & 0xF) + bx;
final int y = (blockHash & 0xFF);
final int z = (blockHash >> 8 & 0xF) + bz;
final BlockPosition pos = new BlockPosition(x, y, z);
synchronized (BukkitQueue_0.class) {
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
if (tileEntity == null || tileEntity.x()) {
nmsWorld.n(pos);
tileEntity = nmsWorld.getTileEntity(pos);
}
if (tileEntity != null) {
final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag);
tag.set("x", new NBTTagInt(x));
tag.set("y", new NBTTagInt(y));
tag.set("z", new NBTTagInt(z));
tileEntity.load(tag);
}
}
}
}
};
}
int finalMask = bitMask;
Runnable callback = () -> {
if (finalMask != 0) {
// Set Modified
nmsChunk.f(true);
nmsChunk.mustSave = true;
nmsChunk.markDirty();
// send to player
extent.sendChunk(X, Z, finalMask);
}
extent.returnToPool(BukkitChunkHolder.this);
};
if (syncTasks != null) {
QueueHandler queueHandler = Fawe.get().getQueueHandler();
Runnable[] finalSyncTasks = syncTasks;
// Biomes
if (set.biomes != null) {
// set biomes
final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex();
for (int i = 0; i < set.biomes.length; i++) {
final BiomeType biome = set.biomes[i];
if (biome != null) {
final Biome craftBiome = BukkitAdapter.adapt(biome);
currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome);
}
}
}
// Chain the sync tasks and the callback
Callable<Future> chain = new Callable<Future>() {
@Override
public Future call() {
// Run the sync tasks
for (int i = 1; i < finalSyncTasks.length; i++) {
Runnable task = finalSyncTasks[i];
if (task != null) {
task.run();
Runnable[] syncTasks = null;
net.minecraft.server.v1_13_R2.World nmsWorld = nmsChunk.getWorld();
int bx = X << 4;
int bz = Z << 4;
if (set.entityRemoves != null && !set.entityRemoves.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[3];
HashSet<UUID> entsToRemove = set.entityRemoves;
syncTasks[2] = new Runnable() {
@Override
public void run() {
final List<Entity>[] entities = nmsChunk.getEntitySlices();
for (int i = 0; i < entities.length; i++) {
final Collection<Entity> ents = entities[i];
if (!ents.isEmpty()) {
final Iterator<Entity> iter = ents.iterator();
while (iter.hasNext()) {
final Entity entity = iter.next();
if (entsToRemove.contains(entity.getUniqueID())) {
iter.remove();
entity.b(false);
entity.die();
entity.valid = false;
}
}
}
}
}
return queueHandler.async(callback, null);
};
}
if (set.entities != null && !set.entities.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[2];
HashSet<CompoundTag> entitiesToSpawn = set.entities;
syncTasks[1] = new Runnable() {
@Override
public void run() {
for (final CompoundTag nativeTag : entitiesToSpawn) {
final Map<String, Tag> entityTagMap = ReflectionUtils.getMap(nativeTag.getValue());
final StringTag idTag = (StringTag) entityTagMap.get("Id");
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
if (idTag == null || posTag == null || rotTag == null) {
Fawe.debug("Unknown entity tag: " + nativeTag);
continue;
}
final double x = posTag.getDouble(0);
final double y = posTag.getDouble(1);
final double z = posTag.getDouble(2);
final float yaw = rotTag.getFloat(0);
final float pitch = rotTag.getFloat(1);
final String id = idTag.getValue();
final Entity entity = EntityTypes.a(nmsWorld, new MinecraftKey(id));
if (entity != null) {
final UUID uuid = entity.getUniqueID();
entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits()));
entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits()));
if (nativeTag != null) {
final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag);
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
tag.remove(name);
}
entity.f(tag);
}
entity.setLocation(x, y, z, yaw, pitch);
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
}
}
}
};
}
// set tiles
if (set.tiles != null && !set.tiles.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[1];
HashMap<Short, CompoundTag> tiles = set.tiles;
syncTasks[0] = new Runnable() {
@Override
public void run() {
for (final Map.Entry<Short, CompoundTag> entry : tiles.entrySet()) {
final CompoundTag nativeTag = entry.getValue();
final short blockHash = entry.getKey();
final int x = (blockHash >> 12 & 0xF) + bx;
final int y = (blockHash & 0xFF);
final int z = (blockHash >> 8 & 0xF) + bz;
final BlockPosition pos = new BlockPosition(x, y, z);
synchronized (BukkitQueue_0.class) {
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
if (tileEntity == null || tileEntity.x()) {
nmsWorld.n(pos);
tileEntity = nmsWorld.getTileEntity(pos);
}
if (tileEntity != null) {
final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_13.fromNative(nativeTag);
tag.set("x", new NBTTagInt(x));
tag.set("y", new NBTTagInt(y));
tag.set("z", new NBTTagInt(z));
tileEntity.load(tag);
}
}
}
}
};
}
int finalMask = bitMask;
Runnable callback = () -> {
if (finalMask != 0) {
// Set Modified
nmsChunk.f(true);
nmsChunk.mustSave = true;
nmsChunk.markDirty();
// send to player
extent.sendChunk(X, Z, finalMask);
}
extent.returnToPool(BukkitChunkHolder.this);
};
return (T) queueHandler.sync(chain);
} else {
callback.run();
if (syncTasks != null) {
QueueHandler queueHandler = Fawe.get().getQueueHandler();
Runnable[] finalSyncTasks = syncTasks;
// Chain the sync tasks and the callback
Callable<Future> chain = new Callable<Future>() {
@Override
public Future call() {
// Run the sync tasks
for (int i = 1; i < finalSyncTasks.length; i++) {
Runnable task = finalSyncTasks[i];
if (task != null) {
task.run();
}
}
return queueHandler.async(callback, null);
}
};
return (T) (Future) queueHandler.sync(chain);
} else {
callback.run();
}
}
return null;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
return null;
}
@Override

View File

@ -21,6 +21,8 @@ import net.minecraft.server.v1_13_R2.DataPaletteLinear;
import net.minecraft.server.v1_13_R2.IBlockData;
import net.minecraft.server.v1_13_R2.World;
import java.util.Arrays;
import static com.boydti.fawe.bukkit.v0.BukkitQueue_0.getAdapter;
public class BukkitGetBlocks extends CharGetBlocks {
@ -29,7 +31,7 @@ public class BukkitGetBlocks extends CharGetBlocks {
public World nmsWorld;
public int X, Z;
public BukkitGetBlocks(World nmsWorld, int X, int Z) {/*d*/
public BukkitGetBlocks(World nmsWorld, int X, int Z) {
this.nmsWorld = nmsWorld;
this.X = X;
this.Z = Z;
@ -71,9 +73,10 @@ public class BukkitGetBlocks extends CharGetBlocks {
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
final DataBits bits = (DataBits) BukkitQueue_1_13.fieldBits.get(blocks);
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitQueue_1_13.fieldPalette.get(blocks);
final int bitsPerEntry = bits.c();
final int bitsPerEntry = bits.c();
final long[] blockStates = bits.a();
new BitArray4096(blockStates, bitsPerEntry).toRaw(data);
int num_palette;
@ -112,23 +115,20 @@ public class BukkitGetBlocks extends CharGetBlocks {
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
try {
for (int i = 0; i < num_palette; i++) {
IBlockData ibd = palette.a(i);
char ordinal;
if (ibd == null) {
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
System.out.println("Invalid palette");
} else {
ordinal = ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd);
final int size = num_palette;
if (size != 1) {
for (int i = 0; i < size; i++) {
char ordinal = ordinal(palette.a(i));
paletteToBlockChars[i] = ordinal;
}
paletteToBlockChars[i] = ordinal;
}
for (int i = 0; i < 4096; i++) {
char paletteVal = data[i];
data[i] = paletteToBlockChars[paletteVal];
if (data[i] == Character.MAX_VALUE) {
System.out.println("Invalid " + paletteVal + " | " + num_palette);
for (int i = 0; i < 4096; i++) {
char paletteVal = data[i];
char val = paletteToBlockChars[paletteVal];
data[i] = val;
}
} else {
char ordinal = ordinal(palette.a(0));
Arrays.fill(data, ordinal);
}
} finally {
for (int i = 0; i < num_palette; i++) {
@ -143,6 +143,14 @@ public class BukkitGetBlocks extends CharGetBlocks {
}
}
private final char ordinal(IBlockData ibd) {
if (ibd == null) {
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
} else {
return ((Spigot_v1_13_R2) getAdapter()).adaptToChar(ibd);
}
}
public ChunkSection[] getSections() {
ChunkSection[] tmp = sections;
if (tmp == null) {