wip on 1.14

This commit is contained in:
Jesse Boyd
2019-07-09 17:18:51 +10:00
229 changed files with 9489 additions and 3025 deletions

View File

@ -18,31 +18,39 @@ configurations.all { Configuration it ->
}
}
task downloadJarsToLibs(){
def f = new File('lib/spigot-1.14.jar')
if (!f.exists()) {
new URL('https://ci.athion.net/job/BuildTools/lastSuccessfulBuild/artifact/spigot-1.14.jar').withInputStream{ i -> f.withOutputStream{ it << i }}
}
}
dependencies {
api project(':worldedit-core')
api project(':worldedit-libs:bukkit')
compile 'net.milkbowl.vault:VaultAPI:1.7'
compile 'com.destroystokyo.paper:paper-api:1.14.3-R0.1-SNAPSHOT'
implementation 'io.papermc:paperlib:1.0.2'
compileOnly 'com.sk89q:dummypermscompat:1.10'
testCompile 'org.mockito:mockito-core:1.9.0-rc1'
implementation('org.apache.logging.log4j:log4j-slf4j-impl:2.8.1'){transitive = false}
compile 'com.destroystokyo.paper:paper-api:1.14.3-R0.1-SNAPSHOT'
implementation('io.papermc:paperlib:1.0.2'){transitive = false}
compile 'org.spigotmc:spigot:1.13.2-R0.1-SNAPSHOT'
compile name: 'spigot-1.14.3'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.8.1'
testCompile 'org.mockito:mockito-core:1.9.0-rc1'
compile 'com.massivecraft:factions:2.8.0'
compile 'com.drtshock:factions:1.6.9.5'
compile 'com.factionsone:FactionsOne:1.2.2'
compile 'me.ryanhamshire:GriefPrevention:11.5.2'
compile 'com.massivecraft:mcore:7.0.1'
compile 'net.sacredlabyrinth.Phaed:PreciousStones:10.0.4-SNAPSHOT'
compile 'net.jzx7:regios:5.9.9'
compile 'com.bekvon.bukkit.residence:Residence:4.5._13.1'
compile 'com.palmergames.bukkit:towny:0.84.0.9'
compile 'com.thevoxelbox.voxelsniper:voxelsniper:5.171.0'
compile 'com.comphenix.protocol:ProtocolLib-API:4.4.0-SNAPSHOT'
compile 'com.wasteofplastic:askyblock:3.0.8.2'
compileOnly 'com.sk89q.worldguard:worldguard-core:7.0.0-20190215.210421-39'
compileOnly 'com.sk89q.worldguard:worldguard-legacy:7.0.0-20190215.210421-39'
// compile([fileTree(dir: 'lib', include: ['*.jar']),'commons-validator:commons-validator:1.4.1'])
implementation('com.sk89q.worldguard:worldguard-core:7.0.0-20190215.210421-39'){transitive = false}
implementation('com.sk89q.worldguard:worldguard-legacy:7.0.0-20190215.210421-39'){transitive = false}
implementation('net.milkbowl.vault:VaultAPI:1.7'){transitive = false}
implementation('com.massivecraft:factions:2.8.0'){transitive = false}
implementation('com.drtshock:factions:1.6.9.5'){transitive = false}
implementation('com.factionsone:FactionsOne:1.2.2'){transitive = false}
implementation('me.ryanhamshire:GriefPrevention:11.5.2'){transitive = false}
implementation('com.massivecraft:mcore:7.0.1'){transitive = false}
implementation('net.sacredlabyrinth.Phaed:PreciousStones:10.0.4-SNAPSHOT'){transitive = false}
implementation('net.jzx7:regios:5.9.9'){transitive = false}
implementation('com.bekvon.bukkit.residence:Residence:4.5._13.1'){transitive = false}
implementation('com.palmergames.bukkit:towny:0.84.0.9'){transitive = false}
implementation('com.thevoxelbox.voxelsniper:voxelsniper:5.171.0'){transitive = false}
implementation('com.comphenix.protocol:ProtocolLib-API:4.4.0-SNAPSHOT'){transitive = false}
implementation('com.wasteofplastic:askyblock:3.0.8.2'){transitive = false}
}
processResources {

View File

@ -2,6 +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.bukkit.beta.BukkitQueue;
import com.boydti.fawe.bukkit.beta.BukkitQueueHandler;
import com.boydti.fawe.bukkit.chat.BukkitChatManager;
import com.boydti.fawe.bukkit.listener.AsyncTabCompleteListener;
import com.boydti.fawe.bukkit.listener.BrushListener;
@ -30,6 +33,7 @@ import com.boydti.fawe.bukkit.v0.BukkitQueue_All;
import com.boydti.fawe.bukkit.v0.ChunkListener_8;
import com.boydti.fawe.bukkit.v0.ChunkListener_9;
import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13;
import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweCommand;
@ -43,6 +47,7 @@ import com.boydti.fawe.util.image.ImageViewer;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.world.World;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
@ -50,9 +55,11 @@ 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;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileOutputStream;
@ -150,6 +157,11 @@ public class FaweBukkit implements IFawe, Listener {
// }
// }
@Override
public QueueHandler getQueueHandler() {
return new BukkitQueueHandler();
}
@Override
public synchronized ImageViewer getImageViewer(FawePlayer fp) {
if (listeningImages && imageListener == null) return null;
@ -575,6 +587,7 @@ public class FaweBukkit implements IFawe, Listener {
}
public enum Version {
v1_14_R1,
v1_13_R2,
NONE,
}
@ -583,6 +596,8 @@ public class FaweBukkit implements IFawe, Listener {
switch (getVersion()) {
case v1_13_R2:
return new BukkitQueue_1_13(world);
case v1_14_R1:
return new BukkitQueue_1_14(world);
default:
case NONE:
return new BukkitQueue_All(world);
@ -593,6 +608,8 @@ public class FaweBukkit implements IFawe, Listener {
switch (getVersion()) {
case v1_13_R2:
return new BukkitQueue_1_13(world);
case v1_14_R1:
return new BukkitQueue_1_14(world);
default:
case NONE:
return new BukkitQueue_All(world);

View File

@ -102,16 +102,16 @@ public final class Spigot_v1_13_R2 extends CachedBukkitAdapter implements Bukkit
nbtCreateTagMethod.setAccessible(true);
}
public int[] idbToStateOrdinal;
public char[] idbToStateOrdinal;
private boolean init() {
private synchronized boolean init() {
if (idbToStateOrdinal != null) return false;
idbToStateOrdinal = new int[Block.REGISTRY_ID.a()]; // size
idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
for (int i = 0; i < idbToStateOrdinal.length; i++) {
BlockState state = BlockTypes.states[i];
BlockMaterial_1_13 material = (BlockMaterial_1_13) state.getMaterial();
int id = Block.REGISTRY_ID.getId(material.getState());
idbToStateOrdinal[id] = state.getOrdinal();
idbToStateOrdinal[id] = state.getOrdinalChar();
}
return true;
}
@ -533,8 +533,18 @@ 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);
}
}
public char adaptToChar(IBlockData ibd) {
try {
int id = Block.REGISTRY_ID.getId(ibd);
return idbToStateOrdinal[id];
} catch (NullPointerException e) {
init();
return adaptToChar(ibd);
}
}

View File

@ -0,0 +1,352 @@
package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.beta.implementation.holder.ChunkHolder;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.bukkit.v1_13.BukkitQueue_1_13;
import com.boydti.fawe.util.MemUtil;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.LongTag;
import com.sk89q.jnbt.StringTag;
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 net.minecraft.server.v1_14_R1.BiomeBase;
import net.minecraft.server.v1_14_R1.BlockPosition;
import net.minecraft.server.v1_14_R1.Chunk;
import net.minecraft.server.v1_14_R1.ChunkSection;
import net.minecraft.server.v1_14_R1.Entity;
import net.minecraft.server.v1_14_R1.EntityTypes;
import net.minecraft.server.v1_14_R1.MinecraftKey;
import net.minecraft.server.v1_14_R1.NBTTagCompound;
import net.minecraft.server.v1_14_R1.NBTTagInt;
import net.minecraft.server.v1_14_R1.TileEntity;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
public class BukkitChunkHolder<T extends Future<T>> extends ChunkHolder {
@Override
public void init(final IQueueExtent extent, final int X, final int Z) {
super.init(extent, X, Z);
}
@Override
public IChunkGet get() {
BukkitQueue extent = (BukkitQueue) getExtent();
return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ(), MemUtil.isMemoryFree());
}
private void updateGet(BukkitGetBlocks get, Chunk nmsChunk, ChunkSection[] sections, ChunkSection section, char[] arr, int layer) {
synchronized (get) {
if (get.nmsChunk != nmsChunk) {
get.nmsChunk = nmsChunk;
get.sections = sections.clone();
get.reset();
}
if (get.sections == null) {
get.sections = sections.clone();
}
if (get.sections[layer] != section) {
get.sections[layer] = section;
}
get.blocks[layer] = arr;
}
}
@Override
public synchronized T call() {
try {
int X = getX();
int Z = getZ();
BukkitQueue extent = (BukkitQueue) getExtent();
BukkitGetBlocks get = (BukkitGetBlocks) getOrCreateGet();
IChunkSet set = getOrCreateSet();
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;
if (!set.hasSection(layer)) {
continue;
}
if (set.getBlock(lx, ly, lz).getOrdinal() != 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;
for (int layer = 0; layer < 16; layer++) {
if (!set.hasSection(layer)) continue;
bitMask |= 1 << layer;
char[] setArr = set.getArray(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 (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);
}
}
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);
}
}
}
}
// Biomes
BiomeType[] biomes = set.getBiomes();
if (biomes != null) {
// set biomes
final BiomeBase[] currentBiomes = nmsChunk.getBiomeIndex();
for (int i = 0; i < biomes.length; i++) {
final BiomeType biome = biomes[i];
if (biome != null) {
final Biome craftBiome = BukkitAdapter.adapt(biome);
currentBiomes[i] = CraftBlock.biomeToBiomeBase(craftBiome);
}
}
}
Runnable[] syncTasks = null;
net.minecraft.server.v1_14_R1.World nmsWorld = nmsChunk.getWorld();
int bx = X << 4;
int bz = Z << 4;
Set<UUID> entityRemoves = set.getEntityRemoves();
if (entityRemoves != null && !entityRemoves.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[3];
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 (entityRemoves.contains(entity.getUniqueID())) {
iter.remove();
entity.b(false);
entity.die();
entity.valid = false;
}
}
}
}
}
};
}
Set<CompoundTag> entities = set.getEntities();
if (entities != null && !entities.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[2];
syncTasks[1] = new Runnable() {
@Override
public void run() {
for (final CompoundTag nativeTag : entities) {
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
Map<Short, CompoundTag> tiles = set.getTiles();
if (tiles != null && !tiles.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[1];
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);
}
}
}
}
};
}
Runnable callback;
if (bitMask == 0) {
callback = null;
} else {
int finalMask = bitMask;
callback = () -> {
// 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;
// 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();
}
}
if (callback == null) {
extent.returnToPool(BukkitChunkHolder.this);
return null;
} else {
return queueHandler.async(callback, null);
}
}
};
return (T) (Future) queueHandler.sync(chain);
} else {
if (callback == null) {
extent.returnToPool(BukkitChunkHolder.this);
} else {
callback.run();
}
}
}
return null;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,208 @@
package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14;
import com.boydti.fawe.bukkit.v1_14.adapter.Spigot_v1_14_R1;
import com.boydti.fawe.jnbt.anvil.BitArray4096;
import com.boydti.fawe.util.MemUtil;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockTypes;
import net.minecraft.server.v1_14_R1.BiomeBase;
import net.minecraft.server.v1_14_R1.Chunk;
import net.minecraft.server.v1_14_R1.ChunkCoordIntPair;
import net.minecraft.server.v1_14_R1.ChunkProviderServer;
import net.minecraft.server.v1_14_R1.ChunkSection;
import net.minecraft.server.v1_14_R1.DataBits;
import net.minecraft.server.v1_14_R1.DataPalette;
import net.minecraft.server.v1_14_R1.DataPaletteBlock;
import net.minecraft.server.v1_14_R1.DataPaletteHash;
import net.minecraft.server.v1_14_R1.DataPaletteLinear;
import net.minecraft.server.v1_14_R1.IBlockData;
import net.minecraft.server.v1_14_R1.World;
import net.minecraft.server.v1_14_R1.WorldServer;
import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock;
import java.util.Arrays;
public class BukkitGetBlocks extends CharGetBlocks {
public ChunkSection[] sections;
public Chunk nmsChunk;
public World nmsWorld;
public int X, Z;
private boolean forceLoad;
public BukkitGetBlocks(World nmsWorld, int X, int Z, boolean forceLoad) {
this.nmsWorld = nmsWorld;
this.X = X;
this.Z = Z;
if (forceLoad) {
((WorldServer) nmsWorld).setForceLoaded(X, Z, this.forceLoad = true);
}
}
@Override
protected void finalize() {
if (forceLoad) {
((WorldServer) nmsWorld).setForceLoaded(X, Z, forceLoad = false);
}
}
@Override
public BiomeType getBiomeType(int x, int z) {
BiomeBase base = getChunk().getBiomeIndex()[(z << 4) + x];
return BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base));
}
@Override
public CompoundTag getTag(int x, int y, int z) {
// TODO
return null;
}
@Override
public char[] load(int layer) {
return load(layer, null);
}
@Override
public synchronized char[] load(int layer, char[] data) {
ChunkSection section = getSections()[layer];
// Section is null, return empty array
if (section == null) {
return FaweCache.EMPTY_CHAR_4096;
}
if (data == null || data == FaweCache.EMPTY_CHAR_4096) {
data = new char[4096];
}
DelegateLock lock = BukkitQueue.applyLock(section);
synchronized (lock) {
lock.untilFree();
lock.setModified(false);
// Efficiently convert ChunkSection to raw data
try {
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
final DataBits bits = (DataBits) BukkitQueue_1_14.fieldBits.get(blocks);
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitQueue_1_14.fieldPalette.get(blocks);
final int bitsPerEntry = bits.c();
final long[] blockStates = bits.a();
new BitArray4096(blockStates, bitsPerEntry).toRaw(data);
int num_palette;
if (palette instanceof DataPaletteLinear) {
num_palette = ((DataPaletteLinear<IBlockData>) palette).b();
} else if (palette instanceof DataPaletteHash) {
num_palette = ((DataPaletteHash<IBlockData>) palette).b();
} else {
num_palette = 0;
int[] paletteToBlockInts = FaweCache.PALETTE_TO_BLOCK.get();
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
try {
for (int i = 0; i < 4096; i++) {
char paletteVal = data[i];
char ordinal = paletteToBlockChars[paletteVal];
if (ordinal == Character.MAX_VALUE) {
paletteToBlockInts[num_palette++] = paletteVal;
IBlockData ibd = palette.a(data[i]);
if (ibd == null) {
ordinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
} else {
ordinal = ((Spigot_v1_14_R1) getAdapter()).adaptToChar(ibd);
}
paletteToBlockChars[paletteVal] = ordinal;
}
data[i] = ordinal;
}
} finally {
for (int i = 0; i < num_palette; i++) {
int paletteVal = paletteToBlockInts[i];
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
}
}
return data;
}
char[] paletteToBlockChars = FaweCache.PALETTE_TO_BLOCK_CHAR.get();
try {
final int size = num_palette;
if (size != 1) {
for (int i = 0; i < size; i++) {
char ordinal = ordinal(palette.a(i));
paletteToBlockChars[i] = ordinal;
}
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++) {
paletteToBlockChars[i] = Character.MAX_VALUE;
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return data;
}
}
private final char ordinal(IBlockData ibd) {
if (ibd == null) {
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
} else {
return ((Spigot_v1_14_R1) getAdapter()).adaptToChar(ibd);
}
}
public ChunkSection[] getSections() {
ChunkSection[] tmp = sections;
if (tmp == null) {
synchronized (this) {
tmp = sections;
if (tmp == null) {
Chunk chunk = getChunk();
sections = tmp = chunk.getSections().clone();
}
}
}
return tmp;
}
public Chunk getChunk() {
Chunk tmp = nmsChunk;
if (tmp == null) {
synchronized (this) {
tmp = nmsChunk;
if (tmp == null) {
nmsChunk = tmp = BukkitQueue.ensureLoaded(nmsWorld, X, Z);
}
}
}
return tmp;
}
@Override
public boolean hasSection(int layer) {
return getSections()[layer] != null;
}
@Override
public boolean trim(boolean aggressive) {
if (aggressive) {
sections = null;
nmsChunk = null;
}
return super.trim(aggressive);
}
}

View File

@ -0,0 +1,369 @@
package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.implementation.SimpleCharQueueExtent;
import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent;
import com.boydti.fawe.beta.implementation.WorldChunkCache;
import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.jnbt.anvil.BitArray4096;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import net.jpountz.util.UnsafeUtils;
import net.minecraft.server.v1_14_R1.Block;
import net.minecraft.server.v1_14_R1.Chunk;
import net.minecraft.server.v1_14_R1.ChunkCoordIntPair;
import net.minecraft.server.v1_14_R1.ChunkProviderServer;
import net.minecraft.server.v1_14_R1.ChunkSection;
import net.minecraft.server.v1_14_R1.ChunkStatus;
import net.minecraft.server.v1_14_R1.DataBits;
import net.minecraft.server.v1_14_R1.DataPalette;
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.PlayerChunk;
import net.minecraft.server.v1_14_R1.PlayerChunkMap;
import net.minecraft.server.v1_14_R1.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_14_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier;
import sun.misc.Unsafe;
import static com.google.common.base.Preconditions.checkNotNull;
public class BukkitQueue extends SimpleCharQueueExtent {
private org.bukkit.World bukkitWorld;
private WorldServer nmsWorld;
@Override
public synchronized void init(WorldChunkCache cache) {
World world = cache.getWorld();
if (world instanceof BukkitWorld) {
this.bukkitWorld = ((BukkitWorld) world).getWorld();
} else {
this.bukkitWorld = Bukkit.getWorld(world.getName());
}
checkNotNull(this.bukkitWorld);
CraftWorld craftWorld = ((CraftWorld) bukkitWorld);
this.nmsWorld = craftWorld.getHandle();
super.init(cache);
}
public WorldServer getNmsWorld() {
return nmsWorld;
}
public org.bukkit.World getBukkitWorld() {
return bukkitWorld;
}
@Override
protected synchronized void reset() {
super.reset();
}
// private static final IterableThreadLocal<BukkitFullChunk> FULL_CHUNKS = new IterableThreadLocal<BukkitFullChunk>() {
// @Override
// public BukkitFullChunk init() {
// return new BukkitFullChunk();
// }
// };
@Override
public IChunk create(boolean full) {
// if (full) {
// //TODO implement
// return FULL_CHUNKS.get();
// }
return new BukkitChunkHolder();
}
/*
NMS fields
*/
public final static Field fieldBits;
public final static Field fieldPalette;
public final static Field fieldSize;
public final static Field fieldFluidCount;
public final static Field fieldTickingBlockCount;
public final static Field fieldNonEmptyBlockCount;
private final static Field fieldDirtyCount;
private final static Field fieldDirtyBits;
private static final int CHUNKSECTION_BASE;
private static final int CHUNKSECTION_SHIFT;
private static final Field fieldLock;
static {
try {
fieldSize = DataPaletteBlock.class.getDeclaredField("i");
fieldSize.setAccessible(true);
fieldBits = DataPaletteBlock.class.getDeclaredField("a");
fieldBits.setAccessible(true);
fieldPalette = DataPaletteBlock.class.getDeclaredField("h");
fieldPalette.setAccessible(true);
fieldFluidCount = ChunkSection.class.getDeclaredField("e");
fieldFluidCount.setAccessible(true);
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
fieldNonEmptyBlockCount.setAccessible(true);
fieldDirtyCount = PlayerChunk.class.getDeclaredField("dirtyCount");
fieldDirtyCount.setAccessible(true);
fieldDirtyBits = PlayerChunk.class.getDeclaredField("h");
fieldDirtyBits.setAccessible(true);
{
Field tmp = null;
try {
tmp = DataPaletteBlock.class.getDeclaredField("j");
} catch (NoSuchFieldException paper) {
tmp = DataPaletteBlock.class.getDeclaredField("writeLock");
}
fieldLock = tmp;
fieldLock.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
int modifiers = modifiersField.getInt(fieldLock);
int newModifiers = modifiers & (~Modifier.FINAL);
if (newModifiers != modifiers) modifiersField.setInt(fieldLock, newModifiers);
}
Unsafe unsafe = UnsafeUtils.getUNSAFE();
CHUNKSECTION_BASE = unsafe.arrayBaseOffset(ChunkSection[].class);
int scale = unsafe.arrayIndexScale(ChunkSection[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale);
} catch (RuntimeException e) {
throw e;
} catch (Throwable rethrow) {
rethrow.printStackTrace();
throw new RuntimeException(rethrow);
}
}
protected static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) {
long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE;
if (layer >= 0 && layer < sections.length) {
return UnsafeUtils.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
}
return false;
}
protected static DelegateLock applyLock(ChunkSection section) {
try {
synchronized (section) {
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
Lock currentLock = (Lock) fieldLock.get(blocks);
if (currentLock instanceof DelegateLock) {
return (DelegateLock) currentLock;
}
DelegateLock newLock = new DelegateLock(currentLock);
fieldLock.set(blocks, newLock);
return newLock;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
private static boolean PAPER = true;
public Chunk ensureLoaded(int X, int Z) {
return ensureLoaded(nmsWorld, X, Z);
}
public static Chunk ensureLoaded(net.minecraft.server.v1_14_R1.World nmsWorld, int X, int Z) {
ChunkProviderServer provider = (ChunkProviderServer) nmsWorld.getChunkProvider();
Chunk nmsChunk = (Chunk) provider.getChunkAt(X, Z, ChunkStatus.FEATURES, false);;
if (nmsChunk != null) {
return nmsChunk;
}
if (Fawe.isMainThread()) {
return nmsWorld.getChunkAt(X, Z);
}
if (PAPER) {
CraftWorld craftWorld = nmsWorld.getWorld();
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(X, Z, true);
try {
CraftChunk chunk = (CraftChunk) future.get();
return chunk.getHandle();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (Throwable e) {
System.out.println("Error, cannot load chunk async (paper not installed?)");
PAPER = false;
}
}
// TODO optimize
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(X, Z));
}
private PlayerChunk getPlayerChunk(final int cx, final int cz) {
final PlayerChunkMap chunkMap = nmsWorld.getPlayerChunkMap();
final PlayerChunk playerChunk = chunkMap.getChunk(cx, cz);
if (playerChunk == null) {
return null;
}
if (playerChunk.players.isEmpty()) {
return null;
}
return playerChunk;
}
public boolean sendChunk(final int X, final int Z, final int mask) {
PlayerChunk playerChunk = getPlayerChunk(X, Z);
if (playerChunk == null) {
return false;
}
if (playerChunk.e()) {
TaskManager.IMP.sync(new Supplier<Object>() {
@Override
public Object get() {
try {
int dirtyBits = fieldDirtyBits.getInt(playerChunk);
if (dirtyBits == 0) {
nmsWorld.getPlayerChunkMap().a(playerChunk);
}
if (mask == 0) {
dirtyBits = 65535;
} else {
dirtyBits |= mask;
}
fieldDirtyBits.set(playerChunk, dirtyBits);
fieldDirtyCount.set(playerChunk, 64);
} catch (final IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
});
}
return true;
}
/*
NMS conversion
*/
public static ChunkSection newChunkSection(final int layer, final char[] blocks) {
ChunkSection section = new ChunkSection(layer << 4);
if (blocks == null) {
return section;
}
final int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get();
final long[] blockstates = FaweCache.BLOCK_STATES.get();
final int[] blocksCopy = FaweCache.SECTION_BLOCKS.get();
try {
int num_palette = 0;
int air = 0;
for (int i = 0; i < 4096; i++) {
char ordinal = blocks[i];
switch (ordinal) {
case 0:
case BlockID.AIR:
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
air++;
}
int palette = blockToPalette[ordinal];
if (palette == Integer.MAX_VALUE) {
blockToPalette[ordinal] = palette = num_palette;
paletteToBlock[num_palette] = ordinal;
num_palette++;
}
blocksCopy[i] = palette;
}
// BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
} else {
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
}
final int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6;
if (num_palette == 1) {
for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0;
} else {
final BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry);
bitArray.fromRaw(blocksCopy);
}
// set palette & data bits
final DataPaletteBlock<IBlockData> dataPaletteBlocks = section.getBlocks();
// private DataPalette<T> h;
// protected DataBits a;
final long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd);
final DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits);
final DataPalette<IBlockData> palette;
// palette = new DataPaletteHash<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d, GameProfileSerializer::a);
palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d);
// set palette
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 IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState();
palette.a(ibd);
}
try {
fieldBits.set(dataPaletteBlocks, nmsBits);
fieldPalette.set(dataPaletteBlocks, palette);
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
setCount(0, 4096 - air, section);
} catch (final IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
return section;
} catch (final Throwable e){
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
throw e;
}
}
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
fieldFluidCount.set(section, 0); // TODO FIXME
fieldTickingBlockCount.set(section, tickingBlockCount);
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
}
}

View File

@ -0,0 +1,11 @@
package com.boydti.fawe.bukkit.beta;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.QueueHandler;
public class BukkitQueueHandler extends QueueHandler {
@Override
public IQueueExtent create() {
return new BukkitQueue();
}
}

View File

@ -0,0 +1,123 @@
package com.boydti.fawe.bukkit.beta;
import org.apache.commons.lang.mutable.MutableInt;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DelegateLock extends ReentrantLock {
private final Lock parent;
private volatile boolean modified;
private final AtomicInteger count;
public DelegateLock(Lock parent) {
this.parent = parent;
if (!(parent instanceof ReentrantLock)) {
count = new AtomicInteger();
} else {
count = null;
}
}
public boolean isModified() {
return modified;
}
public void setModified(boolean modified) {
this.modified = modified;
}
@Override
public synchronized void lock() {
modified = true;
parent.lock();
if (count != null) {
count.incrementAndGet();
}
}
@Override
public synchronized void lockInterruptibly() throws InterruptedException {
parent.lockInterruptibly();
}
@Override
public synchronized boolean tryLock() {
return parent.tryLock();
}
@Override
public synchronized boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return parent.tryLock(timeout, unit);
}
@Override
public void unlock() {
modified = true;
parent.unlock();
if (count != null) {
if (count.getAndDecrement() <= 0) {
count.incrementAndGet();
}
}
}
public Lock getParent() {
return parent;
}
@Override
public synchronized Condition newCondition() {
return parent.newCondition();
}
@Override
public synchronized int getHoldCount() {
throw new UnsupportedOperationException();
}
@Override
public synchronized boolean isHeldByCurrentThread() {
throw new UnsupportedOperationException();
}
@Override
public synchronized boolean isLocked() {
if (parent instanceof ReentrantLock) {
return ((ReentrantLock) parent).isLocked();
}
return count.get() > 0;
}
public void untilFree() {
if (parent instanceof ReentrantLock) {
ReentrantLock rl = (ReentrantLock) parent;
if (rl.isLocked()) {
rl.lock();
rl.unlock();
}
return;
}
while (count.get() > 0);
}
@Override
public synchronized boolean hasWaiters(Condition condition) {
throw new UnsupportedOperationException();
}
@Override
public synchronized int getWaitQueueLength(Condition condition) {
throw new UnsupportedOperationException();
}
@Override
public synchronized String toString() {
return parent.toString();
}
}

View File

@ -220,34 +220,9 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
}
}
public static ConcurrentHashMap<Long, Long> keepLoaded = new ConcurrentHashMap<>(8, 0.9f, 1);
@EventHandler
public static void onChunkLoad(ChunkLoadEvent event) {
Chunk chunk = event.getChunk();
long pair = MathMan.pairInt(chunk.getX(), chunk.getZ());
keepLoaded.putIfAbsent(pair, Fawe.get().getTimer().getTickStart());
}
@EventHandler
public static void onChunkUnload(ChunkUnloadEvent event) {
Chunk chunk = event.getChunk();
long pair = MathMan.pairInt(chunk.getX(), chunk.getZ());
Long lastLoad = keepLoaded.get(pair);
if (lastLoad != null) {
if (Fawe.get().getTimer().getTickStart() - lastLoad < 10000) {
event.setCancelled(true);
} else {
keepLoaded.remove(pair);
}
}
}
@Override
public boolean queueChunkLoad(int cx, int cz) {
if (super.queueChunkLoad(cx, cz)) {
keepLoaded.put(MathMan.pairInt(cx, cz), System.currentTimeMillis());
return true;
}
return false;
@ -282,7 +257,6 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
@Override
public boolean regenerateChunk(World world, int x, int z, BiomeType biome, Long seed) {
if (!keepLoaded.isEmpty()) keepLoaded.remove(MathMan.pairInt(x, z));
return world.regenerateChunk(x, z);
}

View File

@ -233,19 +233,11 @@ public class BukkitQueue_All extends BukkitQueue_0<ChunkSnapshot, ChunkSnapshot,
ChunkSnapshot cached = chunkCache.get(pair);
if (cached != null) return cached;
if (world.isChunkLoaded(cx, cz)) {
Long originalKeep = keepLoaded.get(pair);
keepLoaded.put(pair, Long.MAX_VALUE);
if (world.isChunkLoaded(cx, cz)) {
Chunk chunk = world.getChunkAt(cx, cz);
ChunkSnapshot snapshot = getAndCacheChunk(chunk);
if (originalKeep != null) {
keepLoaded.put(pair, originalKeep);
} else {
keepLoaded.remove(pair);
}
return snapshot;
} else {
keepLoaded.remove(pair);
return null;
}
} else {

View File

@ -624,4 +624,4 @@ public class BukkitChunk_1_13 extends IntFaweChunk<Chunk, BukkitQueue_1_13> {
}
return this;
}
}
}

View File

@ -40,7 +40,7 @@ import java.util.concurrent.atomic.LongAdder;
public class BukkitQueue_1_13 extends BukkitQueue_0<net.minecraft.server.v1_13_R2.Chunk, ChunkSection[], ChunkSection> {
protected final static Field fieldBits;
final static Field fieldBits;
final static Field fieldPalette;
final static Field fieldSize;
@ -604,83 +604,82 @@ public class BukkitQueue_1_13 extends BukkitQueue_0<net.minecraft.server.v1_13_R
}
static ChunkSection newChunkSection(int y2, boolean flag, int[] blocks) {
ChunkSection section = new ChunkSection(y2 << 4, flag);
if (blocks == null) {
return new ChunkSection(y2 << 4, flag);
} else {
ChunkSection section = new ChunkSection(y2 << 4, flag);
int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get();
int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get();
long[] blockstates = FaweCache.BLOCK_STATES.get();
int[] blocksCopy = FaweCache.SECTION_BLOCKS.get();
try {
int num_palette = 0;
int air = 0;
for (int i = 0; i < 4096; i++) {
int stateId = blocks[i];
switch (stateId) {
case 0:
case BlockID.AIR:
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
stateId = BlockID.AIR;
air++;
}
int ordinal = BlockState.getFromInternalId(stateId).getOrdinal(); // TODO fixme Remove all use of BlockTypes.BIT_OFFSET so that this conversion isn't necessary
int palette = blockToPalette[ordinal];
if (palette == Integer.MAX_VALUE) {
blockToPalette[ordinal] = palette = num_palette;
paletteToBlock[num_palette] = ordinal;
num_palette++;
}
blocksCopy[i] = palette;
return section;
}
int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get();
int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get();
long[] blockstates = FaweCache.BLOCK_STATES.get();
int[] blocksCopy = FaweCache.SECTION_BLOCKS.get();
try {
int num_palette = 0;
int air = 0;
for (int i = 0; i < 4096; i++) {
int stateId = blocks[i];
switch (stateId) {
case 0:
case BlockID.AIR:
case BlockID.CAVE_AIR:
case BlockID.VOID_AIR:
stateId = BlockID.AIR;
air++;
}
// BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
} else {
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
int ordinal = BlockState.getFromInternalId(stateId).getOrdinal(); // TODO fixme Remove all use of BlockTypes.BIT_OFFSET so that this conversion isn't necessary
int palette = blockToPalette[ordinal];
if (palette == Integer.MAX_VALUE) {
blockToPalette[ordinal] = palette = num_palette;
paletteToBlock[num_palette] = ordinal;
num_palette++;
}
int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6;
if (num_palette == 1) {
for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0;
} else {
BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry);
bitArray.fromRaw(blocksCopy);
}
// set palette & data bits
DataPaletteBlock<IBlockData> dataPaletteBlocks = section.getBlocks();
// private DataPalette<T> h;
// protected DataBits a;
long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd);
DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits);
DataPalette<IBlockData> palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d);
// set palette
for (int i = 0; i < num_palette; i++) {
int ordinal = paletteToBlock[i];
blockToPalette[ordinal] = Integer.MAX_VALUE;
BlockState state = BlockTypes.states[ordinal];
IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState();
palette.a(ibd);
}
try {
fieldBits.set(dataPaletteBlocks, nmsBits);
fieldPalette.set(dataPaletteBlocks, palette);
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
setCount(0, 4096 - air, section);
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
return section;
} catch (Throwable e){
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
throw e;
blocksCopy[i] = palette;
}
// BlockStates
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
bitsPerEntry = Math.max(bitsPerEntry, 4); // Protocol support breaks <4 bits per entry
} else {
bitsPerEntry = Math.max(bitsPerEntry, 1); // For some reason minecraft needs 4096 bits to store 0 entries
}
int blockBitArrayEnd = (bitsPerEntry * 4096) >> 6;
if (num_palette == 1) {
for (int i = 0; i < blockBitArrayEnd; i++) blockstates[i] = 0;
} else {
BitArray4096 bitArray = new BitArray4096(blockstates, bitsPerEntry);
bitArray.fromRaw(blocksCopy);
}
// set palette & data bits
DataPaletteBlock<IBlockData> dataPaletteBlocks = section.getBlocks();
// private DataPalette<T> h;
// protected DataBits a;
long[] bits = Arrays.copyOfRange(blockstates, 0, blockBitArrayEnd);
DataBits nmsBits = new DataBits(bitsPerEntry, 4096, bits);
DataPalette<IBlockData> palette = new DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::d);
// set palette
for (int i = 0; i < num_palette; i++) {
int ordinal = paletteToBlock[i];
blockToPalette[ordinal] = Integer.MAX_VALUE;
BlockState state = BlockTypes.states[ordinal];
IBlockData ibd = ((BlockMaterial_1_13) state.getMaterial()).getState();
palette.a(ibd);
}
try {
fieldBits.set(dataPaletteBlocks, nmsBits);
fieldPalette.set(dataPaletteBlocks, palette);
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
setCount(0, 4096 - air, section);
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
return section;
} catch (Throwable e){
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
throw e;
}
}
@ -719,4 +718,4 @@ public class BukkitQueue_1_13 extends BukkitQueue_0<net.minecraft.server.v1_13_R
public BukkitChunk_1_13 getFaweChunk(int x, int z) {
return new BukkitChunk_1_13(this, x, z);
}
}
}

View File

@ -20,6 +20,7 @@
package com.boydti.fawe.bukkit.v1_14.adapter;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.bukkit.adapter.v1_13_1.BlockMaterial_1_13;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.ByteArrayTag;
@ -149,16 +150,16 @@ public final class Spigot_v1_14_R1 extends CachedBukkitAdapter implements Bukkit
nbtCreateTagMethod.setAccessible(true);
}
public int[] idbToStateOrdinal;
public char[] idbToStateOrdinal;
private boolean init() {
private synchronized boolean init() {
if (idbToStateOrdinal != null) return false;
idbToStateOrdinal = new int[Block.REGISTRY_ID.a()]; // size
idbToStateOrdinal = new char[Block.REGISTRY_ID.a()]; // size
for (int i = 0; i < idbToStateOrdinal.length; i++) {
BlockState state = BlockTypes.states[i];
BlockMaterial_1_14 material = (BlockMaterial_1_14) state.getMaterial();
int id = Block.REGISTRY_ID.getId(material.getState());
idbToStateOrdinal[id] = state.getOrdinal();
idbToStateOrdinal[id] = state.getOrdinalChar();
}
return true;
}
@ -580,8 +581,18 @@ public final class Spigot_v1_14_R1 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);
}
}
public char adaptToChar(IBlockData ibd) {
try {
int id = Block.REGISTRY_ID.getId(ibd);
return idbToStateOrdinal[id];
} catch (NullPointerException e) {
init();
return adaptToChar(ibd);
}
}

View File

@ -87,16 +87,8 @@ public class AsyncChunk implements Chunk {
if (queue instanceof BukkitQueue_0) {
BukkitQueue_0 bq = (BukkitQueue_0) queue;
if (world.isChunkLoaded(x, z)) {
long pair = MathMan.pairInt(x, z);
Long originalKeep = BukkitQueue_0.keepLoaded.get(pair);
BukkitQueue_0.keepLoaded.put(pair, Long.MAX_VALUE);
if (world.isChunkLoaded(x, z)) {
task.run();
if (originalKeep != null) {
BukkitQueue_0.keepLoaded.put(pair, originalKeep);
} else {
BukkitQueue_0.keepLoaded.remove(pair);
}
return task.value;
}
}

View File

@ -1,5 +1,6 @@
package com.boydti.fawe.bukkit.wrapper;
import com.bekvon.bukkit.residence.commands.material;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.object.FaweQueue;
@ -174,11 +175,6 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
});
}
@Override
public boolean unloadChunkRequest(int x, int z) {
return unloadChunk(x, z);
}
@Override
public void spawnParticle(Particle particle, Location location, int i) {
parent.spawnParticle(particle, location, i);
@ -397,6 +393,19 @@ public class AsyncWorld extends DelegateFaweQueue implements World, HasFaweQueue
return true;
}
@Override
public boolean unloadChunkRequest(int x, int z) {
if (isChunkLoaded(x, z)) {
return TaskManager.IMP.sync(new RunnableVal<Boolean>() {
@Override
public void run(Boolean value) {
this.value = parent.unloadChunkRequest(x, z);
}
});
}
return true;
}
@Override
public boolean regenerateChunk(final int x, final int z) {
return TaskManager.IMP.sync(new RunnableVal<Boolean>() {

View File

@ -0,0 +1,114 @@
package com.boydti.fawe.bukkit.wrapper.state;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Map.Entry;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.util.ReflectionUtils;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag;
import net.minecraft.server.v1_14_R1.NBTBase;
import net.minecraft.server.v1_14_R1.NBTTagCompound;
import org.apache.commons.lang.Validate;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.v1_14_R1.persistence.CraftPersistentDataAdapterContext;
import org.bukkit.craftbukkit.v1_14_R1.persistence.CraftPersistentDataTypeRegistry;
import org.bukkit.persistence.PersistentDataAdapterContext;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
public final class AsyncDataContainer implements PersistentDataContainer {
private final CompoundTag root;
public AsyncDataContainer(CompoundTag root) {
this.root = root;
}
private CompoundTag root() {
CompoundTag value = (CompoundTag) root.getValue().get("PublicBukkitValues");
return value;
}
private Map<String, Tag> get() {
return get(true);
}
private Map<String, Tag> get(boolean create) {
CompoundTag tag = root();
Map<String, Tag> raw;
if (tag == null) {
if (!create) return Collections.emptyMap();
Map<String, Tag> map = ReflectionUtils.getMap(root.getValue());
map.put("PublicBukkitValues", new CompoundTag(raw = new HashMap<>()));
} else {
raw = ReflectionUtils.getMap(tag.getValue());
}
return raw;
}
public <T, Z> void set(NamespacedKey key, PersistentDataType<T, Z> type, Z value) {
Validate.notNull(key, "The provided key for the custom value was null");
Validate.notNull(type, "The provided type for the custom value was null");
Validate.notNull(value, "The provided value for the custom value was null");
get().put(key.toString(), FaweCache.asTag(type.toPrimitive(value, null)));
}
public <T, Z> boolean has(NamespacedKey key, PersistentDataType<T, Z> type) {
Validate.notNull(key, "The provided key for the custom value was null");
Validate.notNull(type, "The provided type for the custom value was null");
Tag value = get(false).get(key.toString());
if (value == null) return type == null;
return type.getPrimitiveType() == value.getValue().getClass();
}
public <T, Z> Z get(NamespacedKey key, PersistentDataType<T, Z> type) {
Validate.notNull(key, "The provided key for the custom value was null");
Validate.notNull(type, "The provided type for the custom value was null");
Tag value = get(false).get(key.toString());
return (Z) value.toRaw();
}
public <T, Z> Z getOrDefault(NamespacedKey key, PersistentDataType<T, Z> type, Z defaultValue) {
Z z = this.get(key, type);
return z != null ? z : defaultValue;
}
public void remove(NamespacedKey key) {
Validate.notNull(key, "The provided key for the custom value was null");
get(false).remove(key.toString());
}
public boolean isEmpty() {
return get(false).isEmpty();
}
public PersistentDataAdapterContext getAdapterContext() {
return null;
}
public boolean equals(Object obj) {
if (!(obj instanceof AsyncDataContainer)) {
return false;
} else {
Map<String, Tag> myRawMap = this.getRaw();
Map<String, Tag> theirRawMap = ((AsyncDataContainer)obj).getRaw();
return Objects.equals(myRawMap, theirRawMap);
}
}
public Map<String, Tag> getRaw() {
return get(false);
}
public int hashCode() {
return get(false).hashCode();
}
public Map<String, Object> serialize() {
return new CompoundTag(get(false)).toRaw();
}
}

View File

@ -8,7 +8,13 @@ import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import java.util.Map;
import net.minecraft.server.v1_14_R1.TileEntitySign;
import org.bukkit.DyeColor;
import org.bukkit.block.Sign;
import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class AsyncSign extends AsyncBlockState implements Sign {
public AsyncSign(AsyncBlock block, int combined) {
@ -63,4 +69,28 @@ public class AsyncSign extends AsyncBlockState implements Sign {
public void setEditable(boolean arg0) {
this.isEditable = arg0;
}
@Override
public @NotNull PersistentDataContainer getPersistentDataContainer() {
return new AsyncDataContainer(getNbtData());
}
@Override
public @Nullable DyeColor getColor() {
CompoundTag nbt = getNbtData();
if (nbt != null) {
String color = nbt.getString("Color").toUpperCase();
if (color != null) return DyeColor.valueOf(color);
}
return DyeColor.BLACK;
}
@Override
public void setColor(DyeColor color) {
CompoundTag nbt = getNbtData();
if (nbt != null) {
Map<String, Tag> map = ReflectionUtils.getMap(nbt.getValue());
map.put("Color", new StringTag(color.name().toLowerCase()));
}
}
}

View File

@ -438,11 +438,6 @@ public class BukkitWorld extends AbstractWorld {
}
}
@Override
public com.sk89q.worldedit.world.block.BlockState getLazyBlock(BlockVector3 position) {
return getBlock(position);
}
@Override
public BaseBlock getFullBlock(BlockVector3 position) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();

View File

@ -23,7 +23,7 @@ import com.bekvon.bukkit.residence.commands.message;
import com.bekvon.bukkit.residence.containers.cmd;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.bukkit.FaweBukkit;
import com.boydti.fawe.bukkit.adapter.v1_13_1.Spigot_v1_13_R2;
import com.boydti.fawe.bukkit.v1_14.adapter.Spigot_v1_14_R1;
import com.boydti.fawe.util.MainUtil;
import com.google.common.base.Joiner;
@ -322,7 +322,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
// Attempt to load a Bukkit adapter
BukkitImplLoader adapterLoader = new BukkitImplLoader();
try {
adapterLoader.addClass(Spigot_v1_13_R2.class);
adapterLoader.addClass(Spigot_v1_14_R1.class);
} catch (Throwable throwable) {
throwable.printStackTrace();
}