mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-06-11 20:13:55 +00:00
Feature/1.17 (#1120)
* start v6 * Update classes to v6 method signatures * change rootVersion to signify p2v6 compat * Use 16 as toolchain version but target 11 for build output * add minimessage as api * Require v6 and don't attempt to "setup" hook from FAWE * Address comments * *address /all/ comments * FAWE classes should only act as a delegate * Uppercase logger * Settings for v6-hook have moved to P2-v6, remove unneeded if statements * Rename classes to Delegate * add whenDone task to setCuboids * Remove bad spaces * Fix plot swap * Initial work on 1.17 support * Remove data versions from the Bukkit adapters (#1507) * Remove data versions from the Bukkit adapters * Don't allow saving schematics without an adapter in place on Bukkit. * Removed confusing line (cherry picked from commit 2056218b4a8644836b1d127105dfa289e9cdbc1c) * More progress * Fix chunk sending * Repackage from com.boydti to com.fastasyncworldedit.<module> (#1119) * Preliminary work on repackaging * Rename build artifacts matching our pattern * Finish up repackaging * Fix a few field accesses and old imports * Dirty fix for chunks container ChunkSections outside of 0-15 * Correctly read from NibbleArrays for lighting * Fix getSections and BlockMaterial for 1.17 * Fix writing blocks to the world. - The issue isn't the presence of a "-1" chunk, it's the constructor for ChunkSection requiring the layer (0 to 15) rather than the y chord * Fix more field accesses * More work towards 1.17 * Update Upstream a57f66f Fix watchdog, add negative y support. (1782) * Add azalea tree to `/tool tree` * Don't define toolchain twice * Repackage GriefDefender * Relocate under new namespace * Bye bye ecma left overs * Add 1.17 to issue templates and instructions * Move to adventure-nbt (#918) * Initial work for adventure-nbt * Some more FAWE specific stuff * Fix erroneous deprecation check * Workflow change * Continued merging all adventure NBT related changes * Continued merging all adventure NBT related changes * Made a constructor public again This needs to be public for BlockTransformExtent.java * Finished converting all NBT data to adventure. * Make this compile * Fix conflicts Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com> * Update adapters to 1.17 * Change build prefix to 1.17 * Move more nms classes to adapters * Move left over nms classes * Move Spigot 1.17 class * Remove unneeded adapter loader code The loader will find the appropriate class now itself * Update adapters * Update adapters * Lazy fix tests * Update adapters * Update Upstream 43da91a Remove method reflection for getMinHeight in BukkitWorld. (1796) * Relocate adventure-nbt under proper namespace * Add LazyCompoundTag as a non-version-specific class to be used by adapters * Better integration between old NBT and Adventure NBT - begin fixing the issues seen recently * Correctly NBT conversion method * LazyCompoundTags should actually be overriding and correctly returning a CompoundBinaryTag. * Update worldedit-adapters Fixes #1141 * Remove unnecessary massive lag machine * Refactor apply to applyBlock in subclasses * applyBlock should be overriden by all subclasses. Default apply to applyBlock * Closes #1130 Closes #1132 * Squashed commit of the following: commit a9bfa1a07c77083c844a0c3ba62f4bd94bed107c Author: NotMyFault <mc.cache@web.de> Date: Sun Jun 27 21:53:21 2021 +0200 [ci skip] Update gradle wrapper validation commit aa7471f95317d28a16f62e4b200de8d0fea2fa95 Author: Matthew Miller <mnmiller1@me.com> Date: Sat Oct 10 15:49:13 2020 +1000 Add ^x,y,z relative offset support to the offset parser (#1545) * Add ^x,y,z relative offset support to the offset parser * Wrap in a try-catch (cherry picked from commit 28bdf7ff9254bbc85bb4f5f792b303943a3930a8) * Add `fawe.error.schematic.not.found` translation key * Update Upstream 728a152 Skip notify if chunk section doesn't exist (1794) * Fixed #1157 * Add a null check to prevent NPE in nbt code * Update adapters * Update Upstream fbb047a Optimize legacy schematic loading (1808) * Hurr durr I don't want to update Java * Update Upstream 0790e6e Fix CLI Mess (1811) * Fixes #1160 * Expose minimessage transitively thru PlotSquared Touches #32 * [ci skip] Remove unneeded maven repository * Steal tab completion from PlotSquared for P2 related commands * Don't error on startup when building locally Co-Authored-By: goldfishapp <8278196+goldfishapp@users.noreply.github.com> * [ci skip] Update gh actions to Java 16 * Update textures to grab 1.17 jar Co-authored-by: NotMyFault <mc.cache@web.de> Co-authored-by: SirYwell <hannesgreule@outlook.de> Co-authored-by: Matthew Miller <mnmiller1@me.com> Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com> Co-authored-by: goldfishapp <8278196+goldfishapp@users.noreply.github.com>
This commit is contained in:
@ -1,19 +0,0 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.lighting.NMSRelighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.Relighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.RelighterFactory;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NMSRelighterFactory implements RelighterFactory {
|
||||
@Override
|
||||
public @NotNull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
|
||||
return new NMSRelighter(queue,
|
||||
relightMode != null ? relightMode : RelightMode.valueOf(Settings.IMP.LIGHTING.MODE));
|
||||
}
|
||||
}
|
@ -1,175 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_15_R1.Block;
|
||||
import net.minecraft.server.v1_15_R1.BlockAccessAir;
|
||||
import net.minecraft.server.v1_15_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_15_R1.EnumPistonReaction;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.ITileEntity;
|
||||
import net.minecraft.server.v1_15_R1.Material;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData;
|
||||
|
||||
public class BlockMaterial_1_15_2 implements BlockMaterial {
|
||||
private final Block block;
|
||||
private final IBlockData defaultState;
|
||||
private final Material material;
|
||||
private final boolean isTranslucent;
|
||||
private final CraftBlockData craftBlockData;
|
||||
private final org.bukkit.Material craftMaterial;
|
||||
private final int opacity;
|
||||
private final CompoundTag tile;
|
||||
|
||||
public BlockMaterial_1_15_2(Block block) {
|
||||
this(block, block.getBlockData());
|
||||
}
|
||||
|
||||
public BlockMaterial_1_15_2(Block block, IBlockData defaultState) {
|
||||
this.block = block;
|
||||
this.defaultState = defaultState;
|
||||
this.material = defaultState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(defaultState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
this.isTranslucent = !(boolean) ReflectionUtil.getField(Block.class, block, "v");
|
||||
opacity = defaultState.b(BlockAccessAir.INSTANCE, BlockPosition.ZERO);
|
||||
TileEntity tileEntity = !block.isTileEntity() ? null : ((ITileEntity)block).createTile(null);
|
||||
tile = tileEntity == null ? null : new LazyCompoundTag_1_15_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public IBlockData getState() {
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return defaultState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return craftMaterial.isOccluding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return defaultState.isPowerSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isBuildable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return block.strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.m();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return defaultState.h();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == EnumPistonReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == EnumPistonReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isTicking(defaultState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
return !material.isAlwaysDestroyable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof ITileEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTile() {
|
||||
return block.isTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
return material.i().rgb;
|
||||
}
|
||||
}
|
@ -1,308 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArray;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.UnsafeUtility;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_15_R1.Block;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_15_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_15_R1.DataBits;
|
||||
import net.minecraft.server.v1_15_R1.DataPalette;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_15_R1.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.LightEngineStorage;
|
||||
import net.minecraft.server.v1_15_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitAdapter_1_15_2 extends NMSAdapter {
|
||||
/*
|
||||
NMS fields
|
||||
*/
|
||||
public static final Field fieldBits;
|
||||
public static final Field fieldPalette;
|
||||
public static final Field fieldSize;
|
||||
|
||||
public static final Field fieldFluidCount;
|
||||
public static final Field fieldTickingBlockCount;
|
||||
public static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final Field fieldBiomeArray;
|
||||
|
||||
private final static MethodHandle methodGetVisibleChunk;
|
||||
|
||||
public static final MethodHandle methodSetLightNibbleArray;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldLock;
|
||||
private static final long fieldLockOffset;
|
||||
|
||||
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);
|
||||
|
||||
fieldBiomeArray = BiomeStorage.class.getDeclaredField("g");
|
||||
fieldBiomeArray.setAccessible(true);
|
||||
|
||||
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
|
||||
Method declaredSetLightNibbleArray = LightEngineStorage.class.getDeclaredMethod("a", long.class, NibbleArray.class);
|
||||
declaredSetLightNibbleArray.setAccessible(true);
|
||||
methodSetLightNibbleArray = MethodHandles.lookup().unreflect(declaredSetLightNibbleArray);
|
||||
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
fieldLock = DataPaletteBlock.class.getDeclaredField("j");
|
||||
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
|
||||
|
||||
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 UnsafeUtility.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static DelegateLock applyLock(ChunkSection section) {
|
||||
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
|
||||
try {
|
||||
synchronized (section) {
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
ReentrantLock currentLock = (ReentrantLock) unsafe.getObject(blocks, fieldLockOffset);
|
||||
if (currentLock instanceof DelegateLock) {
|
||||
return (DelegateLock) currentLock;
|
||||
}
|
||||
DelegateLock newLock = new DelegateLock(currentLock);
|
||||
unsafe.putObject(blocks, fieldLockOffset, newLock);
|
||||
return newLock;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Chunk ensureLoaded(World nmsWorld, int chunkX, int chunkZ) {
|
||||
Chunk nmsChunk = nmsWorld.getChunkIfLoaded(chunkX, chunkZ);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
if (Fawe.isMainThread()) {
|
||||
return nmsWorld.getChunkAt(chunkX, chunkZ);
|
||||
}
|
||||
if (PaperLib.isPaper()) {
|
||||
CraftWorld craftWorld = nmsWorld.getWorld();
|
||||
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(chunkX, chunkZ, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO optimize
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int cx, final int cz) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
try {
|
||||
return (PlayerChunk) methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(cx, cz));
|
||||
} catch (Throwable thr) {
|
||||
throw new RuntimeException(thr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(WorldServer nmsWorld, int chunkX, int chunkZ, int mask, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
|
||||
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
|
||||
Chunk chunk = optional.orElseGet(() ->
|
||||
nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ));
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
PacketPlayOutMapChunk chunkPacket = new PacketPlayOutMapChunk(chunk, 65535);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(chunkPacket);
|
||||
});
|
||||
if (lighting) {
|
||||
PacketPlayOutLightUpdate packet =
|
||||
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine());
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NMS conversion
|
||||
*/
|
||||
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
|
||||
return newChunkSection(layer, null, blocks, fastmode);
|
||||
}
|
||||
|
||||
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int[] num_palette_buffer = new int[1];
|
||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
||||
int air;
|
||||
if (get == null) {
|
||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
||||
set, ticking_blocks, fastmode);
|
||||
} else {
|
||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
||||
num_palette_buffer, get, set, ticking_blocks, fastmode);
|
||||
}
|
||||
int num_palette = num_palette_buffer[0];
|
||||
// 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 BitArray bitArray = new BitArray(bitsPerEntry, 4096, blockStates);
|
||||
bitArray.fromRaw(blocksCopy);
|
||||
}
|
||||
|
||||
ChunkSection section = newChunkSection(layer);
|
||||
// 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 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 = BlockTypesCache.states[ordinal];
|
||||
final IBlockData ibd = ((BlockMaterial_1_15_2) state.getMaterial()).getState();
|
||||
palette.a(ibd);
|
||||
}
|
||||
try {
|
||||
fieldBits.set(dataPaletteBlocks, nmsBits);
|
||||
fieldPalette.set(dataPaletteBlocks, palette);
|
||||
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
|
||||
setCount(ticking_blocks.size(), 4096 - air, section);
|
||||
if (!fastmode) {
|
||||
ticking_blocks.forEach((pos, ordinal) -> section
|
||||
.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
|
||||
Block.getByCombinedId(ordinal)));
|
||||
}
|
||||
} catch (final IllegalAccessException | NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return section;
|
||||
} catch (final Throwable e) {
|
||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static ChunkSection newChunkSection(int layer) {
|
||||
return new ChunkSection(layer << 4);
|
||||
}
|
||||
|
||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
|
||||
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
||||
}
|
||||
|
||||
public static BiomeBase[] getBiomeArray(BiomeStorage storage) {
|
||||
try {
|
||||
return (BiomeBase[]) fieldBiomeArray.get(storage);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,916 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitGetBlocks;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.AdaptedMap;
|
||||
import com.boydti.fawe.object.collection.BitArray;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R2;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_15_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_15_R1.DataBits;
|
||||
import net.minecraft.server.v1_15_R1.DataPalette;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteHash;
|
||||
import net.minecraft.server.v1_15_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_15_R1.Entity;
|
||||
import net.minecraft.server.v1_15_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_15_R1.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_15_R1.HeightMap;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.LightEngine;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_15_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_15_R1.SectionPosition;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBlocks {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||
private static final Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_15_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
private boolean createCopy = false;
|
||||
private BukkitGetBlocks_1_15_2_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
|
||||
public BukkitGetBlocks_1_15_2(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public BukkitGetBlocks_1_15_2(WorldServer world, int chunkX, int chunkZ) {
|
||||
this.world = world;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
this.createCopy = createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
BitArray bitArray = new BitArray(9, 256);
|
||||
bitArray.fromRaw(data);
|
||||
getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a(bitArray.getData());
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeStorage index = getChunk().getBiomeIndex();
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
if (nibble != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibble) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibble.getIfSet() : nibble.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sky) {
|
||||
SectionPosition sectionPositionSky = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleSky = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPositionSky);
|
||||
if (nibbleSky != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibbleSky) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibbleSky.getIfSet() : nibbleSky.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
TileEntity tileEntity = getChunk().getTileEntity(new BlockPosition((x & 15) + (
|
||||
chunkX << 4), y, (z & 15) + (chunkZ << 4)));
|
||||
if (tileEntity == null) {
|
||||
return null;
|
||||
}
|
||||
return new LazyCompoundTag_1_15_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
Map<BlockPosition, TileEntity> nmsTiles = getChunk().getTileEntities();
|
||||
if (nmsTiles.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray);
|
||||
}
|
||||
skyLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's not got any emitted light. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 0);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray);
|
||||
}
|
||||
blockLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override public int[] getHeightMap(HeightMapType type) {
|
||||
long[] longArray = getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a();
|
||||
BitArray bitArray = new BitArray(9, 256, longArray);
|
||||
return bitArray.toRaw(new int[256]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
if (entity != null) {
|
||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||
if (entry != null) {
|
||||
for (Entity ent : entry) {
|
||||
if (uuid.equals(ent.getUniqueID())) {
|
||||
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
List<Entity>[] slices = getChunk().getEntitySlices();
|
||||
int size = 0;
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
size += slice.size();
|
||||
}
|
||||
}
|
||||
if (slices.length == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
int finalSize = size;
|
||||
return new AbstractSet<CompoundTag>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object get) {
|
||||
if (!(get instanceof CompoundTag)) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag getTag = (CompoundTag) get;
|
||||
Map<String, Tag> value = getTag.getValue();
|
||||
CompoundTag getParts = (CompoundTag) value.get("UUID");
|
||||
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
for (Entity entity : slice) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
if (uuid.equals(getUUID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<CompoundTag> iterator() {
|
||||
Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundTag apply(@Nullable Entity input) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
return (CompoundTag) adapter.toNative(input.save(tag));
|
||||
}
|
||||
});
|
||||
return result.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks_1_15_2 get, Chunk nmsChunk, ChunkSection[] chunkSections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
this.reset();
|
||||
}
|
||||
if (this.sections == null) {
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
}
|
||||
if (this.sections[layer] != section) {
|
||||
// Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords
|
||||
this.sections[layer] = new ChunkSection[]{section}.clone()[0];
|
||||
}
|
||||
this.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
}
|
||||
|
||||
public Chunk ensureLoaded(net.minecraft.server.v1_15_R1.World nmsWorld, int chunkX, int chunkZ) {
|
||||
return BukkitAdapter_1_15_2.ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new BukkitGetBlocks_1_15_2_Copy(world) : null;
|
||||
try {
|
||||
WorldServer nmsWorld = world;
|
||||
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
|
||||
|
||||
// Remove existing tiles
|
||||
{
|
||||
// Create a copy so that we can remove blocks
|
||||
Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities());
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
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;
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
nmsChunk.removeTileEntity(tile.getPosition());
|
||||
if (createCopy) {
|
||||
copy.storeTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] tmp = set.load(layer);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
if (createCopy) {
|
||||
char[] tmpLoad = loadPrivately(layer);
|
||||
char[] copyArr = new char[4096];
|
||||
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
||||
copy.storeSection(layer, copyArr);
|
||||
}
|
||||
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, setArr, fastmode);
|
||||
if (BukkitAdapter_1_15_2.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
LOGGER.error("Skipping invalid null section. chunk:" + chunkX + ","
|
||||
+ chunkZ + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
BukkitAdapter_1_15_2.fieldTickingBlockCount.set(existingSection, (short) 0);
|
||||
|
||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
||||
DelegateLock lock = BukkitAdapter_1_15_2.applyLock(existingSection);
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = null;
|
||||
this.reset();
|
||||
} else if (existingSection != getSections(false)[layer]) {
|
||||
this.sections[layer] = existingSection;
|
||||
this.reset();
|
||||
} else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layer))) {
|
||||
this.reset(layer);
|
||||
} else if (lock.isModified()) {
|
||||
this.reset(layer);
|
||||
}
|
||||
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
|
||||
if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
LOGGER.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
BiomeStorage currentBiomes = nmsChunk.getBiomeIndex();
|
||||
if (createCopy) {
|
||||
copy.storeBiomes(currentBiomes);
|
||||
}
|
||||
for (int y = 0, i = 0; y < 64; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
BiomeBase nmsBiome = CraftBlock.biomeToBiomeBase(craftBiome);
|
||||
currentBiomes.setBiome(x, y, z, nmsBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
||||
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
||||
BukkitGetBlocks_1_15_2.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
||||
}
|
||||
BukkitGetBlocks_1_15_2.this.setLightingToGet(set.getLight());
|
||||
BukkitGetBlocks_1_15_2.this.setSkyLightingToGet(set.getSkyLight());
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = () -> {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (final Collection<Entity> ents : entities) {
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
if (createCopy) {
|
||||
copy.storeEntity(entity);
|
||||
}
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[2];
|
||||
}
|
||||
|
||||
syncTasks[1] = () -> {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = 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) {
|
||||
LOGGER.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();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.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<BlockVector3, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[1];
|
||||
}
|
||||
|
||||
syncTasks[0] = () -> {
|
||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final BlockVector3 blockHash = entry.getKey();
|
||||
final int x = blockHash.getX() + bx;
|
||||
final int y = blockHash.getY();
|
||||
final int z = blockHash.getZ() + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) {
|
||||
this.send(finalMask, finalLightUpdate);
|
||||
}
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = () -> {
|
||||
try {
|
||||
// Run the sync tasks
|
||||
for (Runnable task : finalSyncTasks) {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
forceLoadSections = true;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized char[] loadPrivately(int layer) {
|
||||
if (super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
} else {
|
||||
return BukkitGetBlocks_1_15_2.this.update(layer, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void send(int mask, boolean lighting) {
|
||||
BukkitAdapter_1_15_2.sendChunk(world, chunkX, chunkZ, mask, lighting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] update(int layer, char[] data, boolean aggressive) {
|
||||
ChunkSection section = getSections(aggressive)[layer];
|
||||
// Section is null, return empty array
|
||||
if (section == null) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
return data;
|
||||
}
|
||||
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
}
|
||||
DelegateLock lock = BukkitAdapter_1_15_2.applyLock(section);
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
lock.setModified(false);
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
FAWE_Spigot_v1_15_R2 adapter = ((FAWE_Spigot_v1_15_R2) WorldEditPlugin.getInstance().getBukkitImplAdapter());
|
||||
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitAdapter_1_15_2.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_15_2.fieldPalette.get(blocks);
|
||||
|
||||
final int bitsPerEntry = bits.c();
|
||||
final long[] blockStates = bits.a();
|
||||
|
||||
new BitArray(bitsPerEntry, 4096, blockStates).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.IMP.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.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 = adapter.adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
if (num_palette != 1) {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
char ordinal = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char val = paletteToOrdinal[paletteVal];
|
||||
if (val == Character.MAX_VALUE) {
|
||||
val = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = val;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (val == 0) {
|
||||
val = 1;
|
||||
}
|
||||
data[i] = val;
|
||||
}
|
||||
} else {
|
||||
char ordinal = ordinal(palette.a(0), adapter);
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
Arrays.fill(data, ordinal);
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
paletteToOrdinal[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_15_R2 adapter) {
|
||||
if (ibd == null) {
|
||||
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
return adapter.adaptToChar(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
ChunkSection[] tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
synchronized (this) {
|
||||
tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
ChunkSection[] chunkSections = getChunk().getSections();
|
||||
tmp = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length);
|
||||
sections = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public Chunk getChunk() {
|
||||
Chunk tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = ensureLoaded(this.world, chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
|
||||
if (nibble == null) {
|
||||
byte[] a = new byte[2048];
|
||||
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
|
||||
nibble = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble);
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections(false)[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
skyLight = new NibbleArray[16];
|
||||
blockLight = new NibbleArray[16];
|
||||
if (aggressive) {
|
||||
sections = null;
|
||||
nmsChunk = null;
|
||||
return super.trim(true);
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!hasSection(i) || !super.sections[i].isFull()) {
|
||||
continue;
|
||||
}
|
||||
ChunkSection existing = getSections(true)[i];
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
|
||||
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_15_2.fieldPalette.get(blocksExisting);
|
||||
int paletteSize;
|
||||
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
super.trim(false, i);
|
||||
continue;
|
||||
}
|
||||
if (paletteSize == 1) {
|
||||
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
|
||||
continue;
|
||||
}
|
||||
super.trim(false, i);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
super.trim(false, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
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.BlockTypesCache;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_15_R1.Entity;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class BukkitGetBlocks_1_15_2_Copy implements IChunkGet {
|
||||
|
||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
||||
private final Set<CompoundTag> entities = new HashSet<>();
|
||||
private BiomeStorage biomeStorage;
|
||||
private final char[][] blocks = new char[16][];
|
||||
private final WorldServer world;
|
||||
|
||||
protected BukkitGetBlocks_1_15_2_Copy(WorldServer world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
protected void storeTile(TileEntity tile) {
|
||||
tiles.put(BlockVector3.at(tile.getPosition().getX(), tile.getPosition().getY(), tile.getPosition().getZ()),
|
||||
new LazyCompoundTag_1_15_2(Suppliers.memoize(() -> tile.save(new NBTTagCompound()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
return tiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
return tiles.get(BlockVector3.at(x, y, z));
|
||||
}
|
||||
|
||||
protected void storeEntity(Entity entity) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
entities.add((CompoundTag) adapter.toNative(entity.save(tag)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
for (CompoundTag tag : entities) {
|
||||
UUID tagUUID;
|
||||
if (tag.containsKey("UUID")) {
|
||||
int[] arr = tag.getIntArray("UUID");
|
||||
tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL));
|
||||
} else if (tag.containsKey("UUIDMost")) {
|
||||
tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast"));
|
||||
} else if (tag.containsKey("PersistentIDMSB")) {
|
||||
tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (uuid.equals(tagUUID)) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {}
|
||||
|
||||
protected void storeBiomes(BiomeStorage biomeStorage) {
|
||||
this.biomeStorage = new BiomeStorage(BukkitAdapter_1_15_2.getBiomeArray(biomeStorage).clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) break;
|
||||
}
|
||||
} else {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive, int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void storeSection(int layer, char[] data) {
|
||||
blocks[layer] = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||
return state.toBaseBlock(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
|
||||
return blocks[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
return blocks[layer];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypesCache.states[get(x, y, z)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHeightMap(HeightMapType type) {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char get(int x, int y, int z) {
|
||||
final int layer = y >> 4;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
return blocks[layer][index];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.IntPair;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R2;
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import net.minecraft.server.v1_15_R1.Block;
|
||||
import net.minecraft.server.v1_15_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_15_R1.EnumDirection;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_15_R1.NBTBase;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FAWEWorldNativeAccess_1_15_2 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
|
||||
private final FAWE_Spigot_v1_15_R2 adapter;
|
||||
private final WeakReference<World> world;
|
||||
private SideEffectSet sideEffectSet;
|
||||
private final AtomicInteger lastTick;
|
||||
private final Set<CachedChange> cachedChanges = new HashSet<>();
|
||||
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
|
||||
|
||||
public FAWEWorldNativeAccess_1_15_2(FAWE_Spigot_v1_15_R2 adapter, WeakReference<World> world) {
|
||||
this.adapter = adapter;
|
||||
this.world = world;
|
||||
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
|
||||
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
|
||||
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
|
||||
}
|
||||
|
||||
private World getWorld() {
|
||||
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int x, int z) {
|
||||
return getWorld().getChunkAt(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData toNative(com.sk89q.worldedit.world.block.BlockState state) {
|
||||
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.getByCombinedId(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
|
||||
return chunk.getType(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
|
||||
int currentTick = MinecraftServer.currentTick;
|
||||
if (Fawe.isMainThread()) {
|
||||
return chunk.setType(position, state,
|
||||
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE));
|
||||
}
|
||||
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
|
||||
cachedChanges.add(new CachedChange(chunk, position, state));
|
||||
cachedChunksToSend.add(new IntPair(chunk.bukkitChunk.getX(), chunk.bukkitChunk.getZ()));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
lastTick.set(currentTick);
|
||||
}
|
||||
flushAsync(nextTick);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
|
||||
return Block.b(block, getWorld(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPosition getPosition(int x, int y, int z) {
|
||||
return new BlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPosition position) {
|
||||
getWorld().getChunkProvider().getLightEngine().a(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the other versions
|
||||
TileEntity tileEntity = getWorld().getTileEntity(position);
|
||||
if (tileEntity == null) {
|
||||
return false;
|
||||
}
|
||||
NBTBase nativeTag = adapter.fromNative(tag);
|
||||
tileEntity.load((NBTTagCompound) nativeTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(Chunk chunk) {
|
||||
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(BlockPosition position) {
|
||||
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
|
||||
}
|
||||
|
||||
private static final EnumDirection[] NEIGHBOUR_ORDER = {
|
||||
EnumDirection.WEST, EnumDirection.EAST,
|
||||
EnumDirection.DOWN, EnumDirection.UP,
|
||||
EnumDirection.NORTH, EnumDirection.SOUTH
|
||||
};
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
World world = getWorld();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
world.update(pos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
// Un-nest neighbour updating
|
||||
for (EnumDirection direction : NEIGHBOUR_ORDER) {
|
||||
BlockPosition shifted = pos.shift(direction);
|
||||
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
|
||||
}
|
||||
}
|
||||
if (newState.isComplexRedstone()) {
|
||||
world.updateAdjacentComparators(pos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
|
||||
World world = getWorld();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.b(world, pos, NOTIFY);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = world.getWorld();
|
||||
if (craftWorld != null) {
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newState.a(world, pos, NOTIFY);
|
||||
newState.b(world, pos, NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().a(pos, oldState, newState);
|
||||
}
|
||||
|
||||
private synchronized void flushAsync(final boolean sendChunks) {
|
||||
final Set<CachedChange> changes = Collections.unmodifiableSet(new HashSet<>(cachedChanges));
|
||||
cachedChanges.clear();
|
||||
final Set<IntPair> toSend;
|
||||
if (sendChunks) {
|
||||
toSend = Collections.unmodifiableSet(new HashSet<>(cachedChunksToSend));
|
||||
cachedChunksToSend.clear();
|
||||
} else {
|
||||
toSend = Collections.emptySet();
|
||||
}
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
changes.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
if (!sendChunks) {
|
||||
return;
|
||||
}
|
||||
for (IntPair chunk : toSend) {
|
||||
BukkitAdapter_1_15_2.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
TaskManager.IMP.async(() -> TaskManager.IMP.sync(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
cachedChanges.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
for (IntPair chunk : cachedChunksToSend) {
|
||||
BukkitAdapter_1_15_2.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
TaskManager.IMP.sync(r);
|
||||
}
|
||||
cachedChanges.clear();
|
||||
cachedChunksToSend.clear();
|
||||
}
|
||||
|
||||
private static final class CachedChange {
|
||||
|
||||
private final Chunk chunk;
|
||||
private final BlockPosition position;
|
||||
private final IBlockData blockData;
|
||||
|
||||
private CachedChange(Chunk chunk, BlockPosition position, IBlockData blockData) {
|
||||
this.chunk = chunk;
|
||||
this.position = position;
|
||||
this.blockData = blockData;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.MapChunkUtil;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutMapChunk;
|
||||
|
||||
public class MapChunkUtil_1_15_2 extends MapChunkUtil<PacketPlayOutMapChunk> {
|
||||
public MapChunkUtil_1_15_2() throws NoSuchFieldException {
|
||||
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
|
||||
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
|
||||
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
|
||||
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
|
||||
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("f");
|
||||
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("g");
|
||||
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("h");
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldChunkData.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketPlayOutMapChunk createPacket() {
|
||||
return new PacketPlayOutMapChunk();
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import net.minecraft.server.v1_15_R1.NBTBase;
|
||||
import net.minecraft.server.v1_15_R1.NBTNumber;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LazyCompoundTag_1_15_2 extends CompoundTag {
|
||||
|
||||
private final Supplier<NBTTagCompound> nmsTag;
|
||||
private CompoundTag cachedValue;
|
||||
|
||||
public LazyCompoundTag_1_15_2(Supplier<NBTTagCompound> tag) {
|
||||
super(new HashMap<>());
|
||||
this.nmsTag = tag;
|
||||
}
|
||||
|
||||
public LazyCompoundTag_1_15_2(NBTTagCompound tag) {
|
||||
this(() -> tag);
|
||||
}
|
||||
|
||||
public NBTTagCompound get() {
|
||||
return nmsTag.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
if (cachedValue == null) {
|
||||
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
|
||||
}
|
||||
return cachedValue.getValue();
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return nmsTag.get().hasKey(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(String key) {
|
||||
return nmsTag.get().getByteArray(key);
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
return nmsTag.get().getByte(key);
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
return nmsTag.get().getDouble(key);
|
||||
}
|
||||
|
||||
public double asDouble(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
return nmsTag.get().getFloat(key);
|
||||
}
|
||||
|
||||
public int[] getIntArray(String key) {
|
||||
return nmsTag.get().getIntArray(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return nmsTag.get().getInt(key);
|
||||
}
|
||||
|
||||
public int asInt(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<Tag> getList(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
ArrayList<Tag> list = new ArrayList<>();
|
||||
NBTTagList nbtList = (NBTTagList) tag;
|
||||
for (NBTBase elem : nbtList) {
|
||||
if (elem instanceof NBTTagCompound) {
|
||||
list.add(new LazyCompoundTag_1_15_2((NBTTagCompound) elem));
|
||||
} else {
|
||||
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public ListTag getListTag(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag);
|
||||
}
|
||||
return new ListTag(StringTag.class, Collections.emptyList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
|
||||
ListTag listTag = getListTag(key);
|
||||
if (listTag.getType().equals(listType)) {
|
||||
return (List<T>) listTag.getValue();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public long[] getLongArray(String key) {
|
||||
return nmsTag.get().getLongArray(key);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return nmsTag.get().getLong(key);
|
||||
}
|
||||
|
||||
public long asLong(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
return nmsTag.get().getShort(key);
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return nmsTag.get().getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nmsTag.get().toString();
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R1.Block;
|
||||
import net.minecraft.server.v1_16_R1.BlockAccessAir;
|
||||
import net.minecraft.server.v1_16_R1.BlockBase;
|
||||
import net.minecraft.server.v1_16_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R1.EnumPistonReaction;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.ITileEntity;
|
||||
import net.minecraft.server.v1_16_R1.Material;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData;
|
||||
|
||||
public class BlockMaterial_1_16_1 implements BlockMaterial {
|
||||
private final Block block;
|
||||
private final IBlockData defaultState;
|
||||
private final Material material;
|
||||
private final boolean isTranslucent;
|
||||
private final CraftBlockData craftBlockData;
|
||||
private final org.bukkit.Material craftMaterial;
|
||||
private final int opacity;
|
||||
private final CompoundTag tile;
|
||||
|
||||
public BlockMaterial_1_16_1(Block block) {
|
||||
this(block, block.getBlockData());
|
||||
}
|
||||
|
||||
public BlockMaterial_1_16_1(Block block, IBlockData defaultState) {
|
||||
this.block = block;
|
||||
this.defaultState = defaultState;
|
||||
this.material = defaultState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(defaultState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
BlockBase.Info blockInfo = ReflectionUtil.getField(BlockBase.class, block, "aB");
|
||||
this.isTranslucent = !(boolean)ReflectionUtil.getField(BlockBase.Info.class, blockInfo, "n");
|
||||
opacity = defaultState.b(BlockAccessAir.INSTANCE, BlockPosition.ZERO);
|
||||
TileEntity tileEntity = !block.isTileEntity() ? null : ((ITileEntity)block).createTile(null);
|
||||
tile = tileEntity == null ? null : new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public IBlockData getState() {
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return defaultState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return craftMaterial.isOccluding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return defaultState.isPowerSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isBuildable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return craftBlockData.getState().strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.getFrictionFactor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return defaultState.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == EnumPistonReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == EnumPistonReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isTicking(defaultState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
//TODO Removed in 1.16.1 Replacement not found.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof ITileEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTile() {
|
||||
return block.isTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
return material.h().rgb;
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.UnsafeUtility;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R1.Block;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R1.DataBits;
|
||||
import net.minecraft.server.v1_16_R1.DataPalette;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R1.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_16_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R1.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_16_R1.World;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitAdapter_1_16_1 extends NMSAdapter {
|
||||
/*
|
||||
NMS fields
|
||||
*/
|
||||
public static final Field fieldBits;
|
||||
public static final Field fieldPalette;
|
||||
public static final Field fieldSize;
|
||||
|
||||
public static final Field fieldBitsPerEntry;
|
||||
|
||||
public static final Field fieldFluidCount;
|
||||
public static final Field fieldTickingBlockCount;
|
||||
public static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final Field fieldBiomeArray;
|
||||
|
||||
private final static MethodHandle methodGetVisibleChunk;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldLock;
|
||||
private static final long fieldLockOffset;
|
||||
|
||||
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);
|
||||
|
||||
fieldBitsPerEntry = DataBits.class.getDeclaredField("c");
|
||||
fieldBitsPerEntry.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);
|
||||
|
||||
fieldBiomeArray = BiomeStorage.class.getDeclaredField("g");
|
||||
fieldBiomeArray.setAccessible(true);
|
||||
|
||||
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
fieldLock = DataPaletteBlock.class.getDeclaredField("j");
|
||||
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
|
||||
|
||||
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 UnsafeUtility.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static DelegateLock applyLock(ChunkSection section) {
|
||||
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
|
||||
try {
|
||||
synchronized (section) {
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
ReentrantLock currentLock = (ReentrantLock) unsafe.getObject(blocks, fieldLockOffset);
|
||||
if (currentLock instanceof DelegateLock) {
|
||||
return (DelegateLock) currentLock;
|
||||
}
|
||||
DelegateLock newLock = new DelegateLock(currentLock);
|
||||
unsafe.putObject(blocks, fieldLockOffset, newLock);
|
||||
return newLock;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Chunk ensureLoaded(World nmsWorld, int chunkX, int chunkZ) {
|
||||
Chunk nmsChunk = nmsWorld.getChunkProvider().getChunkAt(chunkX, chunkZ, false);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
if (Fawe.isMainThread()) {
|
||||
return nmsWorld.getChunkAt(chunkX, chunkZ);
|
||||
}
|
||||
if (PaperLib.isPaper()) {
|
||||
CraftWorld craftWorld = nmsWorld.getWorld();
|
||||
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(chunkX, chunkZ, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO optimize
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int cx, final int cz) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
try {
|
||||
return (PlayerChunk) methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(cx, cz));
|
||||
} catch (Throwable thr) {
|
||||
throw new RuntimeException(thr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(WorldServer nmsWorld, int chunkX, int chunkZ, int mask, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
|
||||
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
|
||||
Chunk chunk = optional.orElseGet(() ->
|
||||
nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ));
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
PacketPlayOutMapChunk chunkPacket = new PacketPlayOutMapChunk(chunk, 65535, true);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(chunkPacket);
|
||||
});
|
||||
if (lighting) {
|
||||
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
|
||||
boolean trustEdges = true;
|
||||
PacketPlayOutLightUpdate packet =
|
||||
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(),
|
||||
trustEdges);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NMS conversion
|
||||
*/
|
||||
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
|
||||
return newChunkSection(layer, null, blocks, fastmode);
|
||||
}
|
||||
|
||||
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int[] num_palette_buffer = new int[1];
|
||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
||||
int air;
|
||||
if (get == null) {
|
||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
||||
set, ticking_blocks, fastmode);
|
||||
} else {
|
||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
||||
num_palette_buffer, get, set, ticking_blocks, fastmode);
|
||||
}
|
||||
int num_palette = num_palette_buffer[0];
|
||||
// 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 blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry);
|
||||
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
|
||||
|
||||
if (num_palette == 1) {
|
||||
for (int i = 0; i < blockBitArrayEnd; i++) {
|
||||
blockStates[i] = 0;
|
||||
}
|
||||
} else {
|
||||
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntry, 4096, blockStates);
|
||||
bitArray.fromRaw(blocksCopy);
|
||||
}
|
||||
|
||||
ChunkSection section = newChunkSection(layer);
|
||||
// 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 DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::c);
|
||||
|
||||
// set palette
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
final int ordinal = paletteToBlock[i];
|
||||
blockToPalette[ordinal] = Integer.MAX_VALUE;
|
||||
final BlockState state = BlockTypesCache.states[ordinal];
|
||||
final IBlockData ibd = ((BlockMaterial_1_16_1) state.getMaterial()).getState();
|
||||
palette.a(ibd);
|
||||
}
|
||||
try {
|
||||
fieldBits.set(dataPaletteBlocks, nmsBits);
|
||||
fieldPalette.set(dataPaletteBlocks, palette);
|
||||
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
|
||||
setCount(ticking_blocks.size(), 4096 - air, section);
|
||||
if (!fastmode) {
|
||||
ticking_blocks.forEach((pos, ordinal) -> section
|
||||
.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
|
||||
Block.getByCombinedId(ordinal)));
|
||||
}
|
||||
} catch (final IllegalAccessException | NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return section;
|
||||
} catch (final Throwable e) {
|
||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static ChunkSection newChunkSection(int layer) {
|
||||
return new ChunkSection(layer << 4);
|
||||
}
|
||||
|
||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
|
||||
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
||||
}
|
||||
|
||||
public static BiomeBase[] getBiomeArray(BiomeStorage storage) {
|
||||
try {
|
||||
return (BiomeBase[]) fieldBiomeArray.get(storage);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,917 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitGetBlocks;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.AdaptedMap;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R1;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R1.DataBits;
|
||||
import net.minecraft.server.v1_16_R1.DataPalette;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteHash;
|
||||
import net.minecraft.server.v1_16_R1.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R1.Entity;
|
||||
import net.minecraft.server.v1_16_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R1.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_16_R1.HeightMap;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.LightEngine;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_16_R1.SectionPosition;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBlocks {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||
private static final Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
private boolean createCopy = false;
|
||||
private BukkitGetBlocks_1_16_1_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
|
||||
public BukkitGetBlocks_1_16_1(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public BukkitGetBlocks_1_16_1(WorldServer world, int chunkX, int chunkZ) {
|
||||
this.world = world;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
|
||||
public int getChunkX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
this.createCopy = createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256);
|
||||
bitArray.fromRaw(data);
|
||||
getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a(bitArray.getData());
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeStorage index = getChunk().getBiomeIndex();
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
if (nibble != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibble) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibble.getIfSet() : nibble.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sky) {
|
||||
SectionPosition sectionPositionSky = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleSky = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPositionSky);
|
||||
if (nibbleSky != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibbleSky) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibbleSky.getIfSet() : nibbleSky.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
TileEntity tileEntity = getChunk().getTileEntity(new BlockPosition((x & 15) + (
|
||||
chunkX << 4), y, (z & 15) + (
|
||||
chunkZ << 4)));
|
||||
if (tileEntity == null) {
|
||||
return null;
|
||||
}
|
||||
return new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
Map<BlockPosition, TileEntity> nmsTiles = getChunk().getTileEntities();
|
||||
if (nmsTiles.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
skyLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
blockLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override public int[] getHeightMap(HeightMapType type) {
|
||||
long[] longArray = getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a();
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray);
|
||||
return bitArray.toRaw(new int[256]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
if (entity != null) {
|
||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||
if (entry != null) {
|
||||
for (Entity ent : entry) {
|
||||
if (uuid.equals(ent.getUniqueID())) {
|
||||
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
List<Entity>[] slices = getChunk().getEntitySlices();
|
||||
int size = 0;
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
size += slice.size();
|
||||
}
|
||||
}
|
||||
if (slices.length == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
int finalSize = size;
|
||||
return new AbstractSet<CompoundTag>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object get) {
|
||||
if (!(get instanceof CompoundTag)) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag getTag = (CompoundTag) get;
|
||||
Map<String, Tag> value = getTag.getValue();
|
||||
CompoundTag getParts = (CompoundTag) value.get("UUID");
|
||||
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
for (Entity entity : slice) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
if (uuid.equals(getUUID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<CompoundTag> iterator() {
|
||||
Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundTag apply(@Nullable Entity input) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
return (CompoundTag) adapter.toNative(input.save(tag));
|
||||
}
|
||||
});
|
||||
return result.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks_1_16_1 get, Chunk nmsChunk, ChunkSection[] chunkSections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
this.reset();
|
||||
}
|
||||
if (this.sections == null) {
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
}
|
||||
if (this.sections[layer] != section) {
|
||||
// Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords
|
||||
this.sections[layer] = new ChunkSection[]{section}.clone()[0];
|
||||
}
|
||||
this.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
}
|
||||
|
||||
public Chunk ensureLoaded(net.minecraft.server.v1_16_R1.World nmsWorld, int chunkX, int chunkZ) {
|
||||
return BukkitAdapter_1_16_1.ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new BukkitGetBlocks_1_16_1_Copy(world) : null;
|
||||
try {
|
||||
WorldServer nmsWorld = world;
|
||||
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
|
||||
|
||||
// Remove existing tiles
|
||||
{
|
||||
// Create a copy so that we can remove blocks
|
||||
Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities());
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
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;
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
nmsChunk.removeTileEntity(tile.getPosition());
|
||||
if (createCopy) {
|
||||
copy.storeTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] tmp = set.load(layer);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
if (createCopy) {
|
||||
char[] tmpLoad = loadPrivately(layer);
|
||||
char[] copyArr = new char[4096];
|
||||
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
||||
copy.storeSection(layer, copyArr);
|
||||
}
|
||||
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = BukkitAdapter_1_16_1.newChunkSection(layer, setArr, fastmode);
|
||||
if (BukkitAdapter_1_16_1.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
LOGGER.error("Skipping invalid null section. chunk:" + chunkX + "," +
|
||||
chunkZ + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
BukkitAdapter_1_16_1.fieldTickingBlockCount.set(existingSection, (short) 0);
|
||||
|
||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
||||
DelegateLock lock = BukkitAdapter_1_16_1.applyLock(existingSection);
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = null;
|
||||
this.reset();
|
||||
} else if (existingSection != getSections(false)[layer]) {
|
||||
this.sections[layer] = existingSection;
|
||||
this.reset();
|
||||
} else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layer))) {
|
||||
this.reset(layer);
|
||||
} else if (lock.isModified()) {
|
||||
this.reset(layer);
|
||||
}
|
||||
newSection = BukkitAdapter_1_16_1
|
||||
.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
|
||||
if (!BukkitAdapter_1_16_1
|
||||
.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
LOGGER.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
BiomeStorage currentBiomes = nmsChunk.getBiomeIndex();
|
||||
if (createCopy) {
|
||||
copy.storeBiomes(currentBiomes);
|
||||
}
|
||||
for (int y = 0, i = 0; y < 64; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
BiomeBase nmsBiome = CraftBlock.biomeToBiomeBase(craftBiome);
|
||||
currentBiomes.setBiome(x, y, z, nmsBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
||||
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
||||
BukkitGetBlocks_1_16_1.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
||||
}
|
||||
BukkitGetBlocks_1_16_1.this.setLightingToGet(set.getLight());
|
||||
BukkitGetBlocks_1_16_1.this.setSkyLightingToGet(set.getSkyLight());
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = () -> {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (final Collection<Entity> ents : entities) {
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
if (createCopy) {
|
||||
copy.storeEntity(entity);
|
||||
}
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[2];
|
||||
}
|
||||
|
||||
syncTasks[1] = () -> {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = 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) {
|
||||
LOGGER.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();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
entity.load(tag);
|
||||
entity.setLocation(x, y, z, yaw, pitch);
|
||||
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// set tiles
|
||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[1];
|
||||
}
|
||||
|
||||
syncTasks[0] = () -> {
|
||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final BlockVector3 blockHash = entry.getKey();
|
||||
final int x = blockHash.getX() + bx;
|
||||
final int y = blockHash.getY();
|
||||
final int z = blockHash.getZ() + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) {
|
||||
this.send(finalMask, finalLightUpdate);
|
||||
}
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = () -> {
|
||||
try {
|
||||
// Run the sync tasks
|
||||
for (Runnable task : finalSyncTasks) {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
forceLoadSections = true;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized char[] loadPrivately(int layer) {
|
||||
if (super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
} else {
|
||||
return BukkitGetBlocks_1_16_1.this.update(layer, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void send(int mask, boolean lighting) {
|
||||
BukkitAdapter_1_16_1.sendChunk(world, chunkX, chunkZ, mask, lighting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] update(int layer, char[] data, boolean aggressive) {
|
||||
ChunkSection section = getSections(aggressive)[layer];
|
||||
// Section is null, return empty array
|
||||
if (section == null) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
return data;
|
||||
}
|
||||
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
}
|
||||
DelegateLock lock = BukkitAdapter_1_16_1.applyLock(section);
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
lock.setModified(false);
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
FAWE_Spigot_v1_16_R1 adapter = ((FAWE_Spigot_v1_16_R1) WorldEditPlugin.getInstance().getBukkitImplAdapter());
|
||||
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitAdapter_1_16_1.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_1.fieldPalette.get(blocks);
|
||||
|
||||
final int bitsPerEntry = (int) BukkitAdapter_1_16_1.fieldBitsPerEntry.get(bits);
|
||||
final long[] blockStates = bits.a();
|
||||
|
||||
new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).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.IMP.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.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 = adapter.adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
if (num_palette != 1) {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
char ordinal = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char val = paletteToOrdinal[paletteVal];
|
||||
if (val == Character.MAX_VALUE) {
|
||||
val = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = val;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (val == 0) {
|
||||
val = 1;
|
||||
}
|
||||
data[i] = val;
|
||||
}
|
||||
} else {
|
||||
char ordinal = ordinal(palette.a(0), adapter);
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
Arrays.fill(data, ordinal);
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
paletteToOrdinal[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_16_R1 adapter) {
|
||||
if (ibd == null) {
|
||||
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
return adapter.adaptToChar(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
ChunkSection[] tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
synchronized (this) {
|
||||
tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
ChunkSection[] chunkSections = getChunk().getSections();
|
||||
tmp = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length);
|
||||
sections = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public Chunk getChunk() {
|
||||
Chunk tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = ensureLoaded(this.world, chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
|
||||
if (nibble == null) {
|
||||
byte[] a = new byte[2048];
|
||||
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
|
||||
nibble = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble, true);
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections(false)[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
skyLight = new NibbleArray[16];
|
||||
blockLight = new NibbleArray[16];
|
||||
if (aggressive) {
|
||||
sections = null;
|
||||
nmsChunk = null;
|
||||
return super.trim(true);
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!hasSection(i) || !super.sections[i].isFull()) {
|
||||
continue;
|
||||
}
|
||||
ChunkSection existing = getSections(true)[i];
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
|
||||
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_1.fieldPalette.get(blocksExisting);
|
||||
int paletteSize;
|
||||
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
super.trim(false, i);
|
||||
continue;
|
||||
}
|
||||
if (paletteSize == 1) {
|
||||
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
|
||||
continue;
|
||||
}
|
||||
super.trim(false, i);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
super.trim(false, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
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.BlockTypesCache;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R1.Entity;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class BukkitGetBlocks_1_16_1_Copy implements IChunkGet {
|
||||
|
||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
||||
private final Set<CompoundTag> entities = new HashSet<>();
|
||||
private BiomeStorage biomeStorage;
|
||||
private final char[][] blocks = new char[16][];
|
||||
private final WorldServer world;
|
||||
|
||||
protected BukkitGetBlocks_1_16_1_Copy(WorldServer world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
protected void storeTile(TileEntity tile) {
|
||||
tiles.put(BlockVector3.at(tile.getPosition().getX(), tile.getPosition().getY(), tile.getPosition().getZ()),
|
||||
new LazyCompoundTag_1_16_1(Suppliers.memoize(() -> tile.save(new NBTTagCompound()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
return tiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
return tiles.get(BlockVector3.at(x, y, z));
|
||||
}
|
||||
|
||||
protected void storeEntity(Entity entity) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
entities.add((CompoundTag) adapter.toNative(entity.save(tag)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
for (CompoundTag tag : entities) {
|
||||
UUID tagUUID;
|
||||
if (tag.containsKey("UUID")) {
|
||||
int[] arr = tag.getIntArray("UUID");
|
||||
tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL));
|
||||
} else if (tag.containsKey("UUIDMost")) {
|
||||
tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast"));
|
||||
} else if (tag.containsKey("PersistentIDMSB")) {
|
||||
tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (uuid.equals(tagUUID)) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {}
|
||||
|
||||
protected void storeBiomes(BiomeStorage biomeStorage) {
|
||||
this.biomeStorage = new BiomeStorage(BukkitAdapter_1_16_1.getBiomeArray(biomeStorage).clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) break;
|
||||
}
|
||||
} else {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive, int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void storeSection(int layer, char[] data) {
|
||||
blocks[layer] = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||
return state.toBaseBlock(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
|
||||
return blocks[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
return blocks[layer];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypesCache.states[get(x, y, z)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHeightMap(HeightMapType type) {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char get(int x, int y, int z) {
|
||||
final int layer = y >> 4;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
return blocks[layer][index];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.IntPair;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R1;
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import net.minecraft.server.v1_16_R1.Block;
|
||||
import net.minecraft.server.v1_16_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R1.EnumDirection;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R1.NBTBase;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import net.minecraft.server.v1_16_R1.World;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FAWEWorldNativeAccess_1_16_R1 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
|
||||
private final FAWE_Spigot_v1_16_R1 adapter;
|
||||
private final WeakReference<World> world;
|
||||
private SideEffectSet sideEffectSet;
|
||||
private final AtomicInteger lastTick;
|
||||
private final Set<CachedChange> cachedChanges = new HashSet<>();
|
||||
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
|
||||
|
||||
public FAWEWorldNativeAccess_1_16_R1(FAWE_Spigot_v1_16_R1 adapter, WeakReference<World> world) {
|
||||
this.adapter = adapter;
|
||||
this.world = world;
|
||||
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
|
||||
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
|
||||
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
|
||||
}
|
||||
|
||||
private World getWorld() {
|
||||
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int x, int z) {
|
||||
return getWorld().getChunkAt(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData toNative(BlockState state) {
|
||||
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.getByCombinedId(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
|
||||
return chunk.getType(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
|
||||
int currentTick = MinecraftServer.currentTick;
|
||||
if (Fawe.isMainThread()) {
|
||||
return chunk.setType(position, state,
|
||||
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE));
|
||||
}
|
||||
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
|
||||
cachedChanges.add(new CachedChange(chunk, position, state));
|
||||
cachedChunksToSend.add(new IntPair(chunk.bukkitChunk.getX(), chunk.bukkitChunk.getZ()));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
lastTick.set(currentTick);
|
||||
}
|
||||
flushAsync(nextTick);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
|
||||
return Block.b(block, getWorld(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPosition getPosition(int x, int y, int z) {
|
||||
return new BlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPosition position) {
|
||||
getWorld().getChunkProvider().getLightEngine().a(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the other versions
|
||||
TileEntity tileEntity = getWorld().getTileEntity(position);
|
||||
if (tileEntity == null) {
|
||||
return false;
|
||||
}
|
||||
NBTBase nativeTag = adapter.fromNative(tag);
|
||||
tileEntity.load(tileEntity.getBlock(), (NBTTagCompound) nativeTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(Chunk chunk) {
|
||||
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(BlockPosition position) {
|
||||
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
|
||||
}
|
||||
|
||||
private static final EnumDirection[] NEIGHBOUR_ORDER = {
|
||||
EnumDirection.WEST, EnumDirection.EAST,
|
||||
EnumDirection.DOWN, EnumDirection.UP,
|
||||
EnumDirection.NORTH, EnumDirection.SOUTH
|
||||
};
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
World world = getWorld();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
world.update(pos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
// Un-nest neighbour updating
|
||||
for (EnumDirection direction : NEIGHBOUR_ORDER) {
|
||||
BlockPosition shifted = pos.shift(direction);
|
||||
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
|
||||
}
|
||||
}
|
||||
if (newState.isComplexRedstone()) {
|
||||
world.updateAdjacentComparators(pos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
|
||||
World world = getWorld();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.b(world, pos, NOTIFY, recursionLimit);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = world.getWorld();
|
||||
if (craftWorld != null) {
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newState.a(world, pos, NOTIFY, recursionLimit);
|
||||
newState.b(world, pos, NOTIFY, recursionLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().a(pos, oldState, newState);
|
||||
}
|
||||
|
||||
private synchronized void flushAsync(final boolean sendChunks) {
|
||||
final Set<CachedChange> changes = Collections.unmodifiableSet(new HashSet<>(cachedChanges));
|
||||
cachedChanges.clear();
|
||||
final Set<IntPair> toSend;
|
||||
if (sendChunks) {
|
||||
toSend = Collections.unmodifiableSet(new HashSet<>(cachedChunksToSend));
|
||||
cachedChunksToSend.clear();
|
||||
} else {
|
||||
toSend = Collections.emptySet();
|
||||
}
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
changes.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
if (!sendChunks) {
|
||||
return;
|
||||
}
|
||||
for (IntPair chunk : toSend) {
|
||||
BukkitAdapter_1_16_1.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
TaskManager.IMP.async(() -> TaskManager.IMP.sync(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
cachedChanges.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
for (IntPair chunk : cachedChunksToSend) {
|
||||
BukkitAdapter_1_16_1.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
TaskManager.IMP.sync(r);
|
||||
}
|
||||
cachedChanges.clear();
|
||||
cachedChunksToSend.clear();
|
||||
}
|
||||
|
||||
private static final class CachedChange {
|
||||
|
||||
private final Chunk chunk;
|
||||
private final BlockPosition position;
|
||||
private final IBlockData blockData;
|
||||
|
||||
private CachedChange(Chunk chunk, BlockPosition position, IBlockData blockData) {
|
||||
this.chunk = chunk;
|
||||
this.position = position;
|
||||
this.blockData = blockData;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.MapChunkUtil;
|
||||
import net.minecraft.server.v1_16_R1.PacketPlayOutMapChunk;
|
||||
|
||||
public class MapChunkUtil_1_16_1 extends MapChunkUtil<PacketPlayOutMapChunk> {
|
||||
public MapChunkUtil_1_16_1() throws NoSuchFieldException {
|
||||
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
|
||||
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
|
||||
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
|
||||
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
|
||||
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("f");
|
||||
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("g");
|
||||
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("h");
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldChunkData.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketPlayOutMapChunk createPacket() {
|
||||
return new PacketPlayOutMapChunk();
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import net.minecraft.server.v1_16_R1.NBTBase;
|
||||
import net.minecraft.server.v1_16_R1.NBTNumber;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LazyCompoundTag_1_16_1 extends CompoundTag {
|
||||
|
||||
private final Supplier<NBTTagCompound> nmsTag;
|
||||
private CompoundTag cachedValue;
|
||||
|
||||
public LazyCompoundTag_1_16_1(Supplier<NBTTagCompound> tag) {
|
||||
super(new HashMap<>());
|
||||
this.nmsTag = tag;
|
||||
}
|
||||
|
||||
public LazyCompoundTag_1_16_1(NBTTagCompound tag) {
|
||||
this(() -> tag);
|
||||
}
|
||||
|
||||
public NBTTagCompound get() {
|
||||
return nmsTag.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
if (cachedValue == null) {
|
||||
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
|
||||
}
|
||||
return cachedValue.getValue();
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return nmsTag.get().hasKey(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(String key) {
|
||||
return nmsTag.get().getByteArray(key);
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
return nmsTag.get().getByte(key);
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
return nmsTag.get().getDouble(key);
|
||||
}
|
||||
|
||||
public double asDouble(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
return nmsTag.get().getFloat(key);
|
||||
}
|
||||
|
||||
public int[] getIntArray(String key) {
|
||||
return nmsTag.get().getIntArray(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return nmsTag.get().getInt(key);
|
||||
}
|
||||
|
||||
public int asInt(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<Tag> getList(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
ArrayList<Tag> list = new ArrayList<>();
|
||||
NBTTagList nbtList = (NBTTagList) tag;
|
||||
for (NBTBase elem : nbtList) {
|
||||
if (elem instanceof NBTTagCompound) {
|
||||
list.add(new LazyCompoundTag_1_16_1((NBTTagCompound) elem));
|
||||
} else {
|
||||
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public ListTag getListTag(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag);
|
||||
}
|
||||
return new ListTag(StringTag.class, Collections.emptyList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
|
||||
ListTag listTag = getListTag(key);
|
||||
if (listTag.getType().equals(listType)) {
|
||||
return (List<T>) listTag.getValue();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public long[] getLongArray(String key) {
|
||||
return nmsTag.get().getLongArray(key);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return nmsTag.get().getLong(key);
|
||||
}
|
||||
|
||||
public long asLong(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
return nmsTag.get().getShort(key);
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return nmsTag.get().getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nmsTag.get().toString();
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R2.Block;
|
||||
import net.minecraft.server.v1_16_R2.BlockAccessAir;
|
||||
import net.minecraft.server.v1_16_R2.BlockBase;
|
||||
import net.minecraft.server.v1_16_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R2.EnumPistonReaction;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.ITileEntity;
|
||||
import net.minecraft.server.v1_16_R2.Material;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.data.CraftBlockData;
|
||||
|
||||
public class BlockMaterial_1_16_2 implements BlockMaterial {
|
||||
private final Block block;
|
||||
private final IBlockData defaultState;
|
||||
private final Material material;
|
||||
private final boolean isTranslucent;
|
||||
private final CraftBlockData craftBlockData;
|
||||
private final org.bukkit.Material craftMaterial;
|
||||
private final int opacity;
|
||||
private final CompoundTag tile;
|
||||
|
||||
public BlockMaterial_1_16_2(Block block) {
|
||||
this(block, block.getBlockData());
|
||||
}
|
||||
|
||||
public BlockMaterial_1_16_2(Block block, IBlockData defaultState) {
|
||||
this.block = block;
|
||||
this.defaultState = defaultState;
|
||||
this.material = defaultState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(defaultState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
BlockBase.Info blockInfo = ReflectionUtil.getField(BlockBase.class, block, "aB");
|
||||
this.isTranslucent = !(boolean)ReflectionUtil.getField(BlockBase.Info.class, blockInfo, "n");
|
||||
opacity = defaultState.b(BlockAccessAir.INSTANCE, BlockPosition.ZERO);
|
||||
TileEntity tileEntity = !block.isTileEntity() ? null : ((ITileEntity)block).createTile(null);
|
||||
tile = tileEntity == null ? null : new LazyCompoundTag_1_16_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public IBlockData getState() {
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return defaultState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return craftMaterial.isOccluding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return defaultState.isPowerSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isBuildable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return craftBlockData.getState().strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.getFrictionFactor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return defaultState.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == EnumPistonReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == EnumPistonReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isTicking(defaultState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
//TODO Removed in 1.16.1 Replacement not found.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof ITileEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTile() {
|
||||
return block.isTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
return material.h().rgb;
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.UnsafeUtility;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R2.Block;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R2.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R2.DataBits;
|
||||
import net.minecraft.server.v1_16_R2.DataPalette;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R2.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_16_R2.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R2.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R2.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_16_R2.World;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitAdapter_1_16_2 extends NMSAdapter {
|
||||
/*
|
||||
NMS fields
|
||||
*/
|
||||
public static final Field fieldBits;
|
||||
public static final Field fieldPalette;
|
||||
public static final Field fieldSize;
|
||||
|
||||
public static final Field fieldBitsPerEntry;
|
||||
|
||||
public static final Field fieldFluidCount;
|
||||
public static final Field fieldTickingBlockCount;
|
||||
public static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final Field fieldBiomeArray;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldLock;
|
||||
private static final long fieldLockOffset;
|
||||
|
||||
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);
|
||||
|
||||
fieldBitsPerEntry = DataBits.class.getDeclaredField("c");
|
||||
fieldBitsPerEntry.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);
|
||||
|
||||
fieldBiomeArray = BiomeStorage.class.getDeclaredField("h");
|
||||
fieldBiomeArray.setAccessible(true);
|
||||
|
||||
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
fieldLock = DataPaletteBlock.class.getDeclaredField("j");
|
||||
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
|
||||
|
||||
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 UnsafeUtility.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static DelegateLock applyLock(ChunkSection section) {
|
||||
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
|
||||
try {
|
||||
synchronized (section) {
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
ReentrantLock currentLock = (ReentrantLock) unsafe.getObject(blocks, fieldLockOffset);
|
||||
if (currentLock instanceof DelegateLock) {
|
||||
return (DelegateLock) currentLock;
|
||||
}
|
||||
DelegateLock newLock = new DelegateLock(currentLock);
|
||||
unsafe.putObject(blocks, fieldLockOffset, newLock);
|
||||
return newLock;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Chunk ensureLoaded(World nmsWorld, int chunkX, int chunkZ) {
|
||||
Chunk nmsChunk = nmsWorld.getChunkProvider().getChunkAt(chunkX, chunkZ, false);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
if (Fawe.isMainThread()) {
|
||||
return nmsWorld.getChunkAt(chunkX, chunkZ);
|
||||
}
|
||||
if (PaperLib.isPaper()) {
|
||||
CraftWorld craftWorld = nmsWorld.getWorld();
|
||||
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(chunkX, chunkZ, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO optimize
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int chunkX, final int chunkZ) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
try {
|
||||
return (PlayerChunk) methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(chunkX, chunkZ));
|
||||
} catch (Throwable thr) {
|
||||
throw new RuntimeException(thr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(WorldServer nmsWorld, int chunkX, int chunkZ, int mask, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
|
||||
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
|
||||
Chunk chunk = optional.orElseGet(() ->
|
||||
nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ));
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
PacketPlayOutMapChunk chunkPacket = new PacketPlayOutMapChunk(chunk, 65535);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(chunkPacket);
|
||||
});
|
||||
if (lighting) {
|
||||
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
|
||||
boolean trustEdges = true;
|
||||
PacketPlayOutLightUpdate packet =
|
||||
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(),
|
||||
trustEdges);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NMS conversion
|
||||
*/
|
||||
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
|
||||
return newChunkSection(layer, null, blocks, fastmode);
|
||||
}
|
||||
|
||||
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int[] num_palette_buffer = new int[1];
|
||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
||||
int air;
|
||||
if (get == null) {
|
||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
||||
set, ticking_blocks, fastmode);
|
||||
} else {
|
||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
||||
num_palette_buffer, get, set, ticking_blocks, fastmode);
|
||||
}
|
||||
int num_palette = num_palette_buffer[0];
|
||||
// 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 blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry);
|
||||
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
|
||||
|
||||
if (num_palette == 1) {
|
||||
for (int i = 0; i < blockBitArrayEnd; i++) {
|
||||
blockStates[i] = 0;
|
||||
}
|
||||
} else {
|
||||
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntry, 4096, blockStates);
|
||||
bitArray.fromRaw(blocksCopy);
|
||||
}
|
||||
|
||||
ChunkSection section = newChunkSection(layer);
|
||||
// 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 DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::c);
|
||||
|
||||
// set palette
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
final int ordinal = paletteToBlock[i];
|
||||
blockToPalette[ordinal] = Integer.MAX_VALUE;
|
||||
final BlockState state = BlockTypesCache.states[ordinal];
|
||||
final IBlockData ibd = ((BlockMaterial_1_16_2) state.getMaterial()).getState();
|
||||
palette.a(ibd);
|
||||
}
|
||||
try {
|
||||
fieldBits.set(dataPaletteBlocks, nmsBits);
|
||||
fieldPalette.set(dataPaletteBlocks, palette);
|
||||
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
|
||||
setCount(ticking_blocks.size(), 4096 - air, section);
|
||||
if (!fastmode) {
|
||||
ticking_blocks.forEach((pos, ordinal) -> section
|
||||
.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
|
||||
Block.getByCombinedId(ordinal)));
|
||||
}
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return section;
|
||||
} catch (final Throwable e) {
|
||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static ChunkSection newChunkSection(int layer) {
|
||||
return new ChunkSection(layer << 4);
|
||||
}
|
||||
|
||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws IllegalAccessException {
|
||||
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
||||
}
|
||||
|
||||
public static BiomeBase[] getBiomeArray(BiomeStorage storage) {
|
||||
try {
|
||||
return (BiomeBase[]) fieldBiomeArray.get(storage);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,920 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitGetBlocks;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.AdaptedMap;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R2;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R2.DataBits;
|
||||
import net.minecraft.server.v1_16_R2.DataPalette;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteHash;
|
||||
import net.minecraft.server.v1_16_R2.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R2.Entity;
|
||||
import net.minecraft.server.v1_16_R2.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R2.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_16_R2.HeightMap;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.IRegistry;
|
||||
import net.minecraft.server.v1_16_R2.LightEngine;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R2.NibbleArray;
|
||||
import net.minecraft.server.v1_16_R2.SectionPosition;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBlocks {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||
private static final Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_16_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
private boolean createCopy = false;
|
||||
private BukkitGetBlocks_1_16_2_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
|
||||
public BukkitGetBlocks_1_16_2(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public BukkitGetBlocks_1_16_2(WorldServer world, int chunkX, int chunkZ) {
|
||||
this.world = world;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
this.createCopy = createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256);
|
||||
bitArray.fromRaw(data);
|
||||
getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a(bitArray.getData());
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeStorage index = getChunk().getBiomeIndex();
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
if (nibble != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibble) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibble.getIfSet() : nibble.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sky) {
|
||||
SectionPosition sectionPositionSky = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleSky = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPositionSky);
|
||||
if (nibbleSky != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibbleSky) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibbleSky.getIfSet() : nibbleSky.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
TileEntity tileEntity = getChunk().getTileEntity(new BlockPosition((x & 15) + (
|
||||
chunkX << 4), y, (z & 15) + (
|
||||
chunkZ << 4)));
|
||||
if (tileEntity == null) {
|
||||
return null;
|
||||
}
|
||||
return new LazyCompoundTag_1_16_2(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
Map<BlockPosition, TileEntity> nmsTiles = getChunk().getTileEntities();
|
||||
if (nmsTiles.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
skyLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
blockLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHeightMap(HeightMapType type) {
|
||||
long[] longArray = getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a();
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray);
|
||||
return bitArray.toRaw(new int[256]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
if (entity != null) {
|
||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||
if (entry != null) {
|
||||
for (Entity ent : entry) {
|
||||
if (uuid.equals(ent.getUniqueID())) {
|
||||
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
List<Entity>[] slices = getChunk().getEntitySlices();
|
||||
int size = 0;
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
size += slice.size();
|
||||
}
|
||||
}
|
||||
if (slices.length == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
int finalSize = size;
|
||||
return new AbstractSet<CompoundTag>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object get) {
|
||||
if (!(get instanceof CompoundTag)) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag getTag = (CompoundTag) get;
|
||||
Map<String, Tag> value = getTag.getValue();
|
||||
CompoundTag getParts = (CompoundTag) value.get("UUID");
|
||||
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
for (Entity entity : slice) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
if (uuid.equals(getUUID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<CompoundTag> iterator() {
|
||||
Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundTag apply(@Nullable Entity input) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
return (CompoundTag) adapter.toNative(input.save(tag));
|
||||
}
|
||||
});
|
||||
return result.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks_1_16_2 get, Chunk nmsChunk, ChunkSection[] chunkSections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
this.reset();
|
||||
}
|
||||
if (this.sections == null) {
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
}
|
||||
if (this.sections[layer] != section) {
|
||||
// Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords
|
||||
this.sections[layer] = new ChunkSection[]{section}.clone()[0];
|
||||
}
|
||||
this.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
}
|
||||
|
||||
public Chunk ensureLoaded(net.minecraft.server.v1_16_R2.World nmsWorld, int chunkX, int chunkZ) {
|
||||
return BukkitAdapter_1_16_2.ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new BukkitGetBlocks_1_16_2_Copy(world) : null;
|
||||
try {
|
||||
WorldServer nmsWorld = world;
|
||||
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
|
||||
|
||||
// Remove existing tiles
|
||||
{
|
||||
// Create a copy so that we can remove blocks
|
||||
Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities());
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
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;
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
nmsChunk.removeTileEntity(tile.getPosition());
|
||||
if (createCopy) {
|
||||
copy.storeTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] tmp = set.load(layer);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
if (createCopy) {
|
||||
char[] tmpLoad = loadPrivately(layer);
|
||||
char[] copyArr = new char[4096];
|
||||
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
||||
copy.storeSection(layer, copyArr);
|
||||
}
|
||||
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = BukkitAdapter_1_16_2.newChunkSection(layer, setArr, fastmode);
|
||||
if (BukkitAdapter_1_16_2.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
LOGGER.error("Skipping invalid null section. chunk:" + chunkX + ","
|
||||
+ chunkZ + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
BukkitAdapter_1_16_2.fieldTickingBlockCount.set(existingSection, (short) 0);
|
||||
|
||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
||||
DelegateLock lock = BukkitAdapter_1_16_2.applyLock(existingSection);
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = null;
|
||||
this.reset();
|
||||
} else if (existingSection != getSections(false)[layer]) {
|
||||
this.sections[layer] = existingSection;
|
||||
this.reset();
|
||||
} else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layer))) {
|
||||
this.reset(layer);
|
||||
} else if (lock.isModified()) {
|
||||
this.reset(layer);
|
||||
}
|
||||
newSection = BukkitAdapter_1_16_2
|
||||
.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
|
||||
if (!BukkitAdapter_1_16_2
|
||||
.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
LOGGER.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
BiomeStorage currentBiomes = nmsChunk.getBiomeIndex();
|
||||
if (createCopy) {
|
||||
copy.storeBiomes(currentBiomes);
|
||||
}
|
||||
for (int y = 0, i = 0; y < 64; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
BiomeBase nmsBiome = CraftBlock.biomeToBiomeBase(nmsWorld.r().b(IRegistry.ay), craftBiome);
|
||||
currentBiomes.setBiome(x, y, z, nmsBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
||||
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
||||
BukkitGetBlocks_1_16_2.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
||||
}
|
||||
BukkitGetBlocks_1_16_2.this.setLightingToGet(set.getLight());
|
||||
BukkitGetBlocks_1_16_2.this.setSkyLightingToGet(set.getSkyLight());
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = () -> {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (final Collection<Entity> ents : entities) {
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
if (createCopy) {
|
||||
copy.storeEntity(entity);
|
||||
}
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[2];
|
||||
}
|
||||
|
||||
syncTasks[1] = () -> {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = 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) {
|
||||
LOGGER.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();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
entity.load(tag);
|
||||
entity.setLocation(x, y, z, yaw, pitch);
|
||||
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// set tiles
|
||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[1];
|
||||
}
|
||||
|
||||
syncTasks[0] = () -> {
|
||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final BlockVector3 blockHash = entry.getKey();
|
||||
final int x = blockHash.getX() + bx;
|
||||
final int y = blockHash.getY();
|
||||
final int z = blockHash.getZ() + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) {
|
||||
this.send(finalMask, finalLightUpdate);
|
||||
}
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = () -> {
|
||||
try {
|
||||
// Run the sync tasks
|
||||
for (Runnable task : finalSyncTasks) {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
forceLoadSections = true;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized char[] loadPrivately(int layer) {
|
||||
if (super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
} else {
|
||||
return BukkitGetBlocks_1_16_2.this.update(layer, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void send(int mask, boolean lighting) {
|
||||
BukkitAdapter_1_16_2.sendChunk(world, chunkX, chunkZ, mask, lighting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] update(int layer, char[] data, boolean aggressive) {
|
||||
ChunkSection section = getSections(aggressive)[layer];
|
||||
// Section is null, return empty array
|
||||
if (section == null) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
return data;
|
||||
}
|
||||
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
}
|
||||
DelegateLock lock = BukkitAdapter_1_16_2.applyLock(section);
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
lock.setModified(false);
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
FAWE_Spigot_v1_16_R2 adapter = ((FAWE_Spigot_v1_16_R2) WorldEditPlugin.getInstance().getBukkitImplAdapter());
|
||||
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitAdapter_1_16_2.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_2.fieldPalette.get(blocks);
|
||||
|
||||
final int bitsPerEntry = (int) BukkitAdapter_1_16_2.fieldBitsPerEntry.get(bits);
|
||||
final long[] blockStates = bits.a();
|
||||
|
||||
new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).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.IMP.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.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 = adapter.adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
if (num_palette != 1) {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
char ordinal = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char val = paletteToOrdinal[paletteVal];
|
||||
if (val == Character.MAX_VALUE) {
|
||||
val = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = val;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (val == 0) {
|
||||
val = 1;
|
||||
}
|
||||
data[i] = val;
|
||||
}
|
||||
} else {
|
||||
char ordinal = ordinal(palette.a(0), adapter);
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
Arrays.fill(data, ordinal);
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
paletteToOrdinal[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_16_R2 adapter) {
|
||||
if (ibd == null) {
|
||||
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
return adapter.adaptToChar(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
ChunkSection[] tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
synchronized (this) {
|
||||
tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
ChunkSection[] chunkSections = getChunk().getSections();
|
||||
tmp = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length);
|
||||
sections = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public Chunk getChunk() {
|
||||
Chunk tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = ensureLoaded(this.world, chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
|
||||
if (nibble == null) {
|
||||
byte[] a = new byte[2048];
|
||||
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
|
||||
nibble = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble, true);
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections(false)[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
skyLight = new NibbleArray[16];
|
||||
blockLight = new NibbleArray[16];
|
||||
if (aggressive) {
|
||||
sections = null;
|
||||
nmsChunk = null;
|
||||
return super.trim(true);
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!hasSection(i) || !super.sections[i].isFull()) {
|
||||
continue;
|
||||
}
|
||||
ChunkSection existing = getSections(true)[i];
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
|
||||
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_2.fieldPalette.get(blocksExisting);
|
||||
int paletteSize;
|
||||
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
super.trim(false, i);
|
||||
continue;
|
||||
}
|
||||
if (paletteSize == 1) {
|
||||
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
|
||||
continue;
|
||||
}
|
||||
super.trim(false, i);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
super.trim(false, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
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.BlockTypesCache;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R2.Entity;
|
||||
import net.minecraft.server.v1_16_R2.IRegistry;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class BukkitGetBlocks_1_16_2_Copy implements IChunkGet {
|
||||
|
||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
||||
private final Set<CompoundTag> entities = new HashSet<>();
|
||||
private BiomeStorage biomeStorage;
|
||||
private final char[][] blocks = new char[16][];
|
||||
private final WorldServer world;
|
||||
|
||||
protected BukkitGetBlocks_1_16_2_Copy(WorldServer world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
protected void storeTile(TileEntity tile) {
|
||||
tiles.put(BlockVector3.at(tile.getPosition().getX(), tile.getPosition().getY(), tile.getPosition().getZ()),
|
||||
new LazyCompoundTag_1_16_2(Suppliers.memoize(() -> tile.save(new NBTTagCompound()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
return tiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
return tiles.get(BlockVector3.at(x, y, z));
|
||||
}
|
||||
|
||||
protected void storeEntity(Entity entity) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
entities.add((CompoundTag) adapter.toNative(entity.save(tag)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
for (CompoundTag tag : entities) {
|
||||
UUID tagUUID;
|
||||
if (tag.containsKey("UUID")) {
|
||||
int[] arr = tag.getIntArray("UUID");
|
||||
tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL));
|
||||
} else if (tag.containsKey("UUIDMost")) {
|
||||
tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast"));
|
||||
} else if (tag.containsKey("PersistentIDMSB")) {
|
||||
tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (uuid.equals(tagUUID)) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {}
|
||||
|
||||
protected void storeBiomes(BiomeStorage biomeStorage) {
|
||||
this.biomeStorage = new BiomeStorage(biomeStorage.g, BukkitAdapter_1_16_2.getBiomeArray(biomeStorage).clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) break;
|
||||
}
|
||||
} else {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive, int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void storeSection(int layer, char[] data) {
|
||||
blocks[layer] = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||
return state.toBaseBlock(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
|
||||
return blocks[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
return blocks[layer];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypesCache.states[get(x, y, z)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHeightMap(HeightMapType type) {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char get(int x, int y, int z) {
|
||||
final int layer = y >> 4;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
return blocks[layer][index];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.IntPair;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R2;
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import net.minecraft.server.v1_16_R2.Block;
|
||||
import net.minecraft.server.v1_16_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R2.EnumDirection;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R2.NBTBase;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import net.minecraft.server.v1_16_R2.World;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FAWEWorldNativeAccess_1_16_R2 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
|
||||
private final FAWE_Spigot_v1_16_R2 adapter;
|
||||
private final WeakReference<World> world;
|
||||
private SideEffectSet sideEffectSet;
|
||||
private final AtomicInteger lastTick;
|
||||
private final Set<CachedChange> cachedChanges = new HashSet<>();
|
||||
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
|
||||
|
||||
public FAWEWorldNativeAccess_1_16_R2(FAWE_Spigot_v1_16_R2 adapter, WeakReference<World> world) {
|
||||
this.adapter = adapter;
|
||||
this.world = world;
|
||||
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
|
||||
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
|
||||
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
|
||||
}
|
||||
|
||||
private World getWorld() {
|
||||
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int x, int z) {
|
||||
return getWorld().getChunkAt(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData toNative(BlockState state) {
|
||||
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.getByCombinedId(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
|
||||
return chunk.getType(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
|
||||
int currentTick = MinecraftServer.currentTick;
|
||||
if (Fawe.isMainThread()) {
|
||||
return chunk.setType(position, state,
|
||||
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE));
|
||||
}
|
||||
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
|
||||
cachedChanges.add(new CachedChange(chunk, position, state));
|
||||
cachedChunksToSend.add(new IntPair(chunk.bukkitChunk.getX(), chunk.bukkitChunk.getZ()));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
lastTick.set(currentTick);
|
||||
}
|
||||
flushAsync(nextTick);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
|
||||
return Block.b(block, getWorld(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPosition getPosition(int x, int y, int z) {
|
||||
return new BlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPosition position) {
|
||||
getWorld().getChunkProvider().getLightEngine().a(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the other versions
|
||||
TileEntity tileEntity = getWorld().getTileEntity(position);
|
||||
if (tileEntity == null) {
|
||||
return false;
|
||||
}
|
||||
NBTBase nativeTag = adapter.fromNative(tag);
|
||||
tileEntity.load(tileEntity.getBlock(), (NBTTagCompound) nativeTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(Chunk chunk) {
|
||||
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(BlockPosition position) {
|
||||
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
|
||||
}
|
||||
|
||||
private static final EnumDirection[] NEIGHBOUR_ORDER = {
|
||||
EnumDirection.WEST, EnumDirection.EAST,
|
||||
EnumDirection.DOWN, EnumDirection.UP,
|
||||
EnumDirection.NORTH, EnumDirection.SOUTH
|
||||
};
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
World world = getWorld();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
world.update(pos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
// Un-nest neighbour updating
|
||||
for (EnumDirection direction : NEIGHBOUR_ORDER) {
|
||||
BlockPosition shifted = pos.shift(direction);
|
||||
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
|
||||
}
|
||||
}
|
||||
if (newState.isComplexRedstone()) {
|
||||
world.updateAdjacentComparators(pos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
|
||||
World world = getWorld();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.b(world, pos, NOTIFY, recursionLimit);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = world.getWorld();
|
||||
if (craftWorld != null) {
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newState.a(world, pos, NOTIFY, recursionLimit);
|
||||
newState.b(world, pos, NOTIFY, recursionLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().a(pos, oldState, newState);
|
||||
}
|
||||
|
||||
private synchronized void flushAsync(final boolean sendChunks) {
|
||||
final Set<CachedChange> changes = Collections.unmodifiableSet(new HashSet<>(cachedChanges));
|
||||
cachedChanges.clear();
|
||||
final Set<IntPair> toSend;
|
||||
if (sendChunks) {
|
||||
toSend = Collections.unmodifiableSet(new HashSet<>(cachedChunksToSend));
|
||||
cachedChunksToSend.clear();
|
||||
} else {
|
||||
toSend = Collections.emptySet();
|
||||
}
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
changes.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
if (!sendChunks) {
|
||||
return;
|
||||
}
|
||||
for (IntPair chunk : toSend) {
|
||||
BukkitAdapter_1_16_2.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
TaskManager.IMP.async(() -> TaskManager.IMP.sync(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
cachedChanges.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
for (IntPair chunk : cachedChunksToSend) {
|
||||
BukkitAdapter_1_16_2.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, 0, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
TaskManager.IMP.sync(r);
|
||||
}
|
||||
cachedChanges.clear();
|
||||
cachedChunksToSend.clear();
|
||||
}
|
||||
|
||||
private static final class CachedChange {
|
||||
|
||||
private final Chunk chunk;
|
||||
private final BlockPosition position;
|
||||
private final IBlockData blockData;
|
||||
|
||||
private CachedChange(Chunk chunk, BlockPosition position, IBlockData blockData) {
|
||||
this.chunk = chunk;
|
||||
this.position = position;
|
||||
this.blockData = blockData;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.MapChunkUtil;
|
||||
import net.minecraft.server.v1_16_R2.PacketPlayOutMapChunk;
|
||||
|
||||
public class MapChunkUtil_1_16_2 extends MapChunkUtil<PacketPlayOutMapChunk> {
|
||||
public MapChunkUtil_1_16_2() throws NoSuchFieldException {
|
||||
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
|
||||
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
|
||||
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
|
||||
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
|
||||
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("f");
|
||||
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("g");
|
||||
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("h");
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldChunkData.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketPlayOutMapChunk createPacket() {
|
||||
return new PacketPlayOutMapChunk();
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import net.minecraft.server.v1_16_R2.NBTBase;
|
||||
import net.minecraft.server.v1_16_R2.NBTNumber;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LazyCompoundTag_1_16_2 extends CompoundTag {
|
||||
|
||||
private final Supplier<NBTTagCompound> nmsTag;
|
||||
private CompoundTag cachedValue;
|
||||
|
||||
public LazyCompoundTag_1_16_2(Supplier<NBTTagCompound> tag) {
|
||||
super(new HashMap<>());
|
||||
this.nmsTag = tag;
|
||||
}
|
||||
|
||||
public LazyCompoundTag_1_16_2(NBTTagCompound tag) {
|
||||
this(() -> tag);
|
||||
}
|
||||
|
||||
public NBTTagCompound get() {
|
||||
return nmsTag.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
if (cachedValue == null) {
|
||||
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
|
||||
}
|
||||
return cachedValue.getValue();
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return nmsTag.get().hasKey(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(String key) {
|
||||
return nmsTag.get().getByteArray(key);
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
return nmsTag.get().getByte(key);
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
return nmsTag.get().getDouble(key);
|
||||
}
|
||||
|
||||
public double asDouble(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
return nmsTag.get().getFloat(key);
|
||||
}
|
||||
|
||||
public int[] getIntArray(String key) {
|
||||
return nmsTag.get().getIntArray(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return nmsTag.get().getInt(key);
|
||||
}
|
||||
|
||||
public int asInt(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<Tag> getList(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
ArrayList<Tag> list = new ArrayList<>();
|
||||
NBTTagList nbtList = (NBTTagList) tag;
|
||||
for (NBTBase elem : nbtList) {
|
||||
if (elem instanceof NBTTagCompound) {
|
||||
list.add(new LazyCompoundTag_1_16_2((NBTTagCompound) elem));
|
||||
} else {
|
||||
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public ListTag getListTag(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag);
|
||||
}
|
||||
return new ListTag(StringTag.class, Collections.emptyList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
|
||||
ListTag listTag = getListTag(key);
|
||||
if (listTag.getType().equals(listType)) {
|
||||
return (List<T>) listTag.getValue();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public long[] getLongArray(String key) {
|
||||
return nmsTag.get().getLongArray(key);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return nmsTag.get().getLong(key);
|
||||
}
|
||||
|
||||
public long asLong(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
return nmsTag.get().getShort(key);
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return nmsTag.get().getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nmsTag.get().toString();
|
||||
}
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt.LazyCompoundTag_1_16_5;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.util.ReflectionUtil;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R3.Block;
|
||||
import net.minecraft.server.v1_16_R3.BlockAccessAir;
|
||||
import net.minecraft.server.v1_16_R3.BlockBase;
|
||||
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R3.EnumPistonReaction;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.ITileEntity;
|
||||
import net.minecraft.server.v1_16_R3.Material;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData;
|
||||
|
||||
public class BlockMaterial_1_16_5 implements BlockMaterial {
|
||||
private final Block block;
|
||||
private final IBlockData defaultState;
|
||||
private final Material material;
|
||||
private final boolean isTranslucent;
|
||||
private final CraftBlockData craftBlockData;
|
||||
private final org.bukkit.Material craftMaterial;
|
||||
private final int opacity;
|
||||
private final CompoundTag tile;
|
||||
|
||||
public BlockMaterial_1_16_5(Block block) {
|
||||
this(block, block.getBlockData());
|
||||
}
|
||||
|
||||
public BlockMaterial_1_16_5(Block block, IBlockData defaultState) {
|
||||
this.block = block;
|
||||
this.defaultState = defaultState;
|
||||
this.material = defaultState.getMaterial();
|
||||
this.craftBlockData = CraftBlockData.fromData(defaultState);
|
||||
this.craftMaterial = craftBlockData.getMaterial();
|
||||
BlockBase.Info blockInfo = ReflectionUtil.getField(BlockBase.class, block, "aB");
|
||||
this.isTranslucent = !(boolean)ReflectionUtil.getField(BlockBase.Info.class, blockInfo, "n");
|
||||
opacity = defaultState.b(BlockAccessAir.INSTANCE, BlockPosition.ZERO);
|
||||
TileEntity tileEntity = !block.isTileEntity() ? null : ((ITileEntity)block).createTile(null);
|
||||
tile = tileEntity == null ? null : new LazyCompoundTag_1_16_5(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
public Block getBlock() {
|
||||
return block;
|
||||
}
|
||||
|
||||
public IBlockData getState() {
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
public CraftBlockData getCraftBlockData() {
|
||||
return craftBlockData;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return defaultState.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFullCube() {
|
||||
return craftMaterial.isOccluding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return material.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPowerSource() {
|
||||
return defaultState.isPowerSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid() {
|
||||
return material.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return material.isBuildable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getHardness() {
|
||||
return craftBlockData.getState().strength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getResistance() {
|
||||
return block.getDurability();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSlipperiness() {
|
||||
return block.getFrictionFactor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue() {
|
||||
return defaultState.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightOpacity() {
|
||||
return opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFragileWhenPushed() {
|
||||
return material.getPushReaction() == EnumPistonReaction.DESTROY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnpushable() {
|
||||
return material.getPushReaction() == EnumPistonReaction.BLOCK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTicksRandomly() {
|
||||
return block.isTicking(defaultState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMovementBlocker() {
|
||||
return material.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBurnable() {
|
||||
return material.isBurnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isToolRequired() {
|
||||
//TODO Removed in 1.16.1 Replacement not found.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacedDuringPlacement() {
|
||||
return material.isReplaceable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTranslucent() {
|
||||
return isTranslucent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasContainer() {
|
||||
return block instanceof ITileEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTile() {
|
||||
return block.isTileEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getDefaultTile() {
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMapColor() {
|
||||
return material.h().rgb;
|
||||
}
|
||||
}
|
@ -1,310 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.UnsafeUtility;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R3.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R3.Block;
|
||||
import net.minecraft.server.v1_16_R3.Chunk;
|
||||
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R3.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R3.DataBits;
|
||||
import net.minecraft.server.v1_16_R3.DataPalette;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R3.GameProfileSerializer;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutLightUpdate;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_16_R3.World;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public final class BukkitAdapter_1_16_5 extends NMSAdapter {
|
||||
/*
|
||||
NMS fields
|
||||
*/
|
||||
public static final Field fieldBits;
|
||||
public static final Field fieldPalette;
|
||||
public static final Field fieldSize;
|
||||
|
||||
public static final Field fieldBitsPerEntry;
|
||||
|
||||
public static final Field fieldFluidCount;
|
||||
public static final Field fieldTickingBlockCount;
|
||||
public static final Field fieldNonEmptyBlockCount;
|
||||
|
||||
private static final Field fieldBiomeArray;
|
||||
|
||||
private static final MethodHandle methodGetVisibleChunk;
|
||||
|
||||
private static final int CHUNKSECTION_BASE;
|
||||
private static final int CHUNKSECTION_SHIFT;
|
||||
|
||||
private static final Field fieldLock;
|
||||
private static final long fieldLockOffset;
|
||||
|
||||
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);
|
||||
|
||||
fieldBitsPerEntry = DataBits.class.getDeclaredField("c");
|
||||
fieldBitsPerEntry.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);
|
||||
|
||||
fieldBiomeArray = BiomeStorage.class.getDeclaredField("h");
|
||||
fieldBiomeArray.setAccessible(true);
|
||||
|
||||
Method declaredGetVisibleChunk = PlayerChunkMap.class.getDeclaredMethod("getVisibleChunk", long.class);
|
||||
declaredGetVisibleChunk.setAccessible(true);
|
||||
methodGetVisibleChunk = MethodHandles.lookup().unreflect(declaredGetVisibleChunk);
|
||||
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
fieldLock = DataPaletteBlock.class.getDeclaredField("j");
|
||||
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
|
||||
|
||||
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 UnsafeUtility.getUNSAFE().compareAndSwapObject(sections, offset, expected, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static DelegateLock applyLock(ChunkSection section) {
|
||||
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
|
||||
try {
|
||||
synchronized (section) {
|
||||
Unsafe unsafe = UnsafeUtility.getUNSAFE();
|
||||
DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
ReentrantLock currentLock = (ReentrantLock) unsafe.getObject(blocks, fieldLockOffset);
|
||||
if (currentLock instanceof DelegateLock) {
|
||||
return (DelegateLock) currentLock;
|
||||
}
|
||||
DelegateLock newLock = new DelegateLock(currentLock);
|
||||
unsafe.putObject(blocks, fieldLockOffset, newLock);
|
||||
return newLock;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Chunk ensureLoaded(World nmsWorld, int chunkX, int chunkZ) {
|
||||
Chunk nmsChunk = nmsWorld.getChunkProvider().getChunkAt(chunkX, chunkZ, false);
|
||||
if (nmsChunk != null) {
|
||||
return nmsChunk;
|
||||
}
|
||||
if (Fawe.isMainThread()) {
|
||||
return nmsWorld.getChunkAt(chunkX, chunkZ);
|
||||
}
|
||||
if (PaperLib.isPaper()) {
|
||||
CraftWorld craftWorld = nmsWorld.getWorld();
|
||||
CompletableFuture<org.bukkit.Chunk> future = craftWorld.getChunkAtAsync(chunkX, chunkZ, true);
|
||||
try {
|
||||
CraftChunk chunk = (CraftChunk) future.get();
|
||||
return chunk.getHandle();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
// TODO optimize
|
||||
return TaskManager.IMP.sync(() -> nmsWorld.getChunkAt(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
public static PlayerChunk getPlayerChunk(WorldServer nmsWorld, final int chunkX, final int chunkZ) {
|
||||
PlayerChunkMap chunkMap = nmsWorld.getChunkProvider().playerChunkMap;
|
||||
try {
|
||||
return (PlayerChunk) methodGetVisibleChunk.invoke(chunkMap, ChunkCoordIntPair.pair(chunkX, chunkZ));
|
||||
} catch (Throwable thr) {
|
||||
throw new RuntimeException(thr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(WorldServer nmsWorld, int chunkX, int chunkZ, boolean lighting) {
|
||||
PlayerChunk playerChunk = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||
if (playerChunk == null) {
|
||||
return;
|
||||
}
|
||||
ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ);
|
||||
Optional<Chunk> optional = ((Either) playerChunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left();
|
||||
Chunk chunk = optional.orElseGet(() ->
|
||||
nmsWorld.getChunkProvider().getChunkAtIfLoadedImmediately(chunkX, chunkZ));
|
||||
if (chunk == null) {
|
||||
return;
|
||||
}
|
||||
PacketPlayOutMapChunk chunkPacket = new PacketPlayOutMapChunk(chunk, 65535);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(chunkPacket);
|
||||
});
|
||||
if (lighting) {
|
||||
//This needs to be true otherwise Minecraft will update lighting from/at the chunk edges (bad)
|
||||
boolean trustEdges = true;
|
||||
PacketPlayOutLightUpdate packet =
|
||||
new PacketPlayOutLightUpdate(chunkCoordIntPair, nmsWorld.getChunkProvider().getLightEngine(),
|
||||
trustEdges);
|
||||
playerChunk.players.a(chunkCoordIntPair, false).forEach(p -> {
|
||||
p.playerConnection.sendPacket(packet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NMS conversion
|
||||
*/
|
||||
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
|
||||
return newChunkSection(layer, null, blocks, fastmode);
|
||||
}
|
||||
|
||||
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
|
||||
if (set == null) {
|
||||
return newChunkSection(layer);
|
||||
}
|
||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
try {
|
||||
int[] num_palette_buffer = new int[1];
|
||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
||||
int air;
|
||||
if (get == null) {
|
||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
||||
set, ticking_blocks, fastmode);
|
||||
} else {
|
||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
||||
num_palette_buffer, get, set, ticking_blocks, fastmode);
|
||||
}
|
||||
int num_palette = num_palette_buffer[0];
|
||||
// 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 blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntry);
|
||||
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
|
||||
|
||||
if (num_palette == 1) {
|
||||
for (int i = 0; i < blockBitArrayEnd; i++) {
|
||||
blockStates[i] = 0;
|
||||
}
|
||||
} else {
|
||||
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntry, 4096, blockStates);
|
||||
bitArray.fromRaw(blocksCopy);
|
||||
}
|
||||
|
||||
ChunkSection section = newChunkSection(layer);
|
||||
// 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 DataPaletteLinear<>(Block.REGISTRY_ID, bitsPerEntry, dataPaletteBlocks, GameProfileSerializer::c);
|
||||
|
||||
// set palette
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
final int ordinal = paletteToBlock[i];
|
||||
blockToPalette[ordinal] = Integer.MAX_VALUE;
|
||||
final BlockState state = BlockTypesCache.states[ordinal];
|
||||
final IBlockData ibd = ((BlockMaterial_1_16_5) state.getMaterial()).getState();
|
||||
palette.a(ibd);
|
||||
}
|
||||
try {
|
||||
fieldBits.set(dataPaletteBlocks, nmsBits);
|
||||
fieldPalette.set(dataPaletteBlocks, palette);
|
||||
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
|
||||
setCount(ticking_blocks.size(), 4096 - air, section);
|
||||
if (!fastmode) {
|
||||
ticking_blocks.forEach((pos, ordinal) -> section
|
||||
.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
|
||||
Block.getByCombinedId(ordinal)));
|
||||
}
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return section;
|
||||
} catch (final Throwable e) {
|
||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static ChunkSection newChunkSection(int layer) {
|
||||
return new ChunkSection(layer << 4);
|
||||
}
|
||||
|
||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws IllegalAccessException {
|
||||
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
||||
}
|
||||
|
||||
public static BiomeBase[] getBiomeArray(BiomeStorage storage) {
|
||||
try {
|
||||
return (BiomeBase[]) fieldBiomeArray.get(storage);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,920 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitGetBlocks;
|
||||
import com.boydti.fawe.bukkit.adapter.DelegateLock;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt.LazyCompoundTag_1_16_5;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.AdaptedMap;
|
||||
import com.boydti.fawe.object.collection.BitArrayUnstretched;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R3;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import io.papermc.lib.PaperLib;
|
||||
import net.minecraft.server.v1_16_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R3.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R3.Chunk;
|
||||
import net.minecraft.server.v1_16_R3.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R3.DataBits;
|
||||
import net.minecraft.server.v1_16_R3.DataPalette;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteHash;
|
||||
import net.minecraft.server.v1_16_R3.DataPaletteLinear;
|
||||
import net.minecraft.server.v1_16_R3.Entity;
|
||||
import net.minecraft.server.v1_16_R3.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R3.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_16_R3.HeightMap;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.IRegistry;
|
||||
import net.minecraft.server.v1_16_R3.LightEngine;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R3.NibbleArray;
|
||||
import net.minecraft.server.v1_16_R3.SectionPosition;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;
|
||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
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;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class BukkitGetBlocks_1_16_5 extends CharGetBlocks implements BukkitGetBlocks {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final Function<BlockPosition, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||
private static final Function<TileEntity, CompoundTag> nmsTile2We = tileEntity -> new LazyCompoundTag_1_16_5(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
public ChunkSection[] sections;
|
||||
public Chunk nmsChunk;
|
||||
public WorldServer world;
|
||||
public int chunkX;
|
||||
public int chunkZ;
|
||||
public NibbleArray[] blockLight = new NibbleArray[16];
|
||||
public NibbleArray[] skyLight = new NibbleArray[16];
|
||||
private boolean createCopy = false;
|
||||
private BukkitGetBlocks_1_16_5_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
|
||||
public BukkitGetBlocks_1_16_5(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public BukkitGetBlocks_1_16_5(WorldServer world, int chunkX, int chunkZ) {
|
||||
this.world = world;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
this.createCopy = createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return createCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.BLOCK);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] light) {
|
||||
if (light != null) {
|
||||
lightUpdate = true;
|
||||
try {
|
||||
fillLightNibble(light, EnumSkyBlock.SKY);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256);
|
||||
bitArray.fromRaw(data);
|
||||
getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a(bitArray.getData());
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeStorage index = getChunk().getBiomeIndex();
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
base = index.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
if (nibble != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibble) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibble.getIfSet() : nibble.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sky) {
|
||||
SectionPosition sectionPositionSky = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleSky = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPositionSky);
|
||||
if (nibbleSky != null) {
|
||||
lightUpdate = true;
|
||||
synchronized (nibbleSky) {
|
||||
byte[] bytes = PaperLib.isPaper() ? nibbleSky.getIfSet() : nibbleSky.asBytes();
|
||||
if (!PaperLib.isPaper() || bytes != NibbleArray.EMPTY_NIBBLE) {
|
||||
Arrays.fill(bytes, (byte) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
TileEntity tileEntity = getChunk().getTileEntity(new BlockPosition((x & 15) + (
|
||||
chunkX << 4), y, (z & 15) + (
|
||||
chunkZ << 4)));
|
||||
if (tileEntity == null) {
|
||||
return null;
|
||||
}
|
||||
return new LazyCompoundTag_1_16_5(Suppliers.memoize(() -> tileEntity.save(new NBTTagCompound())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
Map<BlockPosition, TileEntity> nmsTiles = getChunk().getTileEntities();
|
||||
if (nmsTiles.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (skyLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.SKY).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.SKY, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
skyLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return skyLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
int layer = y >> 4;
|
||||
if (blockLight[layer] == null) {
|
||||
SectionPosition sectionPosition = SectionPosition.a(getChunk().getPos(), layer);
|
||||
NibbleArray nibbleArray = world.getChunkProvider().getLightEngine().a(EnumSkyBlock.BLOCK).a(sectionPosition);
|
||||
// If the server hasn't generated the section's NibbleArray yet, it will be null
|
||||
if (nibbleArray == null) {
|
||||
byte[] a = new byte[2048];
|
||||
// Safe enough to assume if it's not created, it's under the sky. Unlikely to be created before lighting is fixed anyway.
|
||||
Arrays.fill(a, (byte) 15);
|
||||
nibbleArray = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(EnumSkyBlock.BLOCK, sectionPosition, nibbleArray, true);
|
||||
}
|
||||
blockLight[layer] = nibbleArray;
|
||||
}
|
||||
long l = BlockPosition.a(x, y, z);
|
||||
return blockLight[layer].a(SectionPosition.b(BlockPosition.b(l)), SectionPosition.b(BlockPosition.c(l)), SectionPosition.b(BlockPosition.d(l)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHeightMap(HeightMapType type) {
|
||||
long[] longArray = getChunk().heightMap.get(HeightMap.Type.valueOf(type.name())).a();
|
||||
BitArrayUnstretched bitArray = new BitArrayUnstretched(9, 256, longArray);
|
||||
return bitArray.toRaw(new int[256]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
Entity entity = world.getEntity(uuid);
|
||||
if (entity != null) {
|
||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
for (List<Entity> entry : getChunk().getEntitySlices()) {
|
||||
if (entry != null) {
|
||||
for (Entity ent : entry) {
|
||||
if (uuid.equals(ent.getUniqueID())) {
|
||||
org.bukkit.entity.Entity bukkitEnt = ent.getBukkitEntity();
|
||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
List<Entity>[] slices = getChunk().getEntitySlices();
|
||||
int size = 0;
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
size += slice.size();
|
||||
}
|
||||
}
|
||||
if (slices.length == 0) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
int finalSize = size;
|
||||
return new AbstractSet<CompoundTag>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return finalSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object get) {
|
||||
if (!(get instanceof CompoundTag)) {
|
||||
return false;
|
||||
}
|
||||
CompoundTag getTag = (CompoundTag) get;
|
||||
Map<String, Tag> value = getTag.getValue();
|
||||
CompoundTag getParts = (CompoundTag) value.get("UUID");
|
||||
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
|
||||
for (List<Entity> slice : slices) {
|
||||
if (slice != null) {
|
||||
for (Entity entity : slice) {
|
||||
UUID uuid = entity.getUniqueID();
|
||||
if (uuid.equals(getUUID)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<CompoundTag> iterator() {
|
||||
Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public CompoundTag apply(@Nullable Entity input) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
return (CompoundTag) adapter.toNative(input.save(tag));
|
||||
}
|
||||
});
|
||||
return result.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateGet(BukkitGetBlocks_1_16_5 get, Chunk nmsChunk, ChunkSection[] chunkSections, ChunkSection section, char[] arr, int layer) {
|
||||
synchronized (get) {
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
this.reset();
|
||||
}
|
||||
if (this.sections == null) {
|
||||
this.sections = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, this.sections, 0, chunkSections.length);
|
||||
}
|
||||
if (this.sections[layer] != section) {
|
||||
// Not sure why it's funky, but it's what I did in commit fda7d00747abe97d7891b80ed8bb88d97e1c70d1 and I don't want to touch it >dords
|
||||
this.sections[layer] = new ChunkSection[]{section}.clone()[0];
|
||||
}
|
||||
this.blocks[layer] = arr;
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEntity(Entity entity) {
|
||||
entity.die();
|
||||
}
|
||||
|
||||
public Chunk ensureLoaded(net.minecraft.server.v1_16_R3.World nmsWorld, int chunkX, int chunkZ) {
|
||||
return BukkitAdapter_1_16_5.ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new BukkitGetBlocks_1_16_5_Copy(world) : null;
|
||||
try {
|
||||
WorldServer nmsWorld = world;
|
||||
Chunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
|
||||
|
||||
// Remove existing tiles
|
||||
{
|
||||
// Create a copy so that we can remove blocks
|
||||
Map<BlockPosition, TileEntity> tiles = new HashMap<>(nmsChunk.getTileEntities());
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||
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;
|
||||
}
|
||||
|
||||
int ordinal = set.getBlock(lx, ly, lz).getOrdinal();
|
||||
if (ordinal != 0) {
|
||||
TileEntity tile = entry.getValue();
|
||||
nmsChunk.removeTileEntity(tile.getPosition());
|
||||
if (createCopy) {
|
||||
copy.storeTile(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bitMask = 0;
|
||||
synchronized (nmsChunk) {
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (!set.hasSection(layer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitMask |= 1 << layer;
|
||||
|
||||
char[] tmp = set.load(layer);
|
||||
char[] setArr = new char[4096];
|
||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||
if (createCopy) {
|
||||
char[] tmpLoad = loadPrivately(layer);
|
||||
char[] copyArr = new char[4096];
|
||||
System.arraycopy(tmpLoad, 0, copyArr, 0, 4096);
|
||||
copy.storeSection(layer, copyArr);
|
||||
}
|
||||
|
||||
ChunkSection newSection;
|
||||
ChunkSection existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
newSection = BukkitAdapter_1_16_5.newChunkSection(layer, setArr, fastmode);
|
||||
if (BukkitAdapter_1_16_5.setSectionAtomic(sections, null, newSection, layer)) {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
continue;
|
||||
} else {
|
||||
existingSection = sections[layer];
|
||||
if (existingSection == null) {
|
||||
LOGGER.error("Skipping invalid null section. chunk:" + chunkX + ","
|
||||
+ chunkZ + " layer: " + layer);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
BukkitAdapter_1_16_5.fieldTickingBlockCount.set(existingSection, (short) 0);
|
||||
|
||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
||||
DelegateLock lock = BukkitAdapter_1_16_5.applyLock(existingSection);
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
if (this.getChunk() != nmsChunk) {
|
||||
this.nmsChunk = nmsChunk;
|
||||
this.sections = null;
|
||||
this.reset();
|
||||
} else if (existingSection != getSections(false)[layer]) {
|
||||
this.sections[layer] = existingSection;
|
||||
this.reset();
|
||||
} else if (!Arrays.equals(update(layer, new char[4096], true), loadPrivately(layer))) {
|
||||
this.reset(layer);
|
||||
} else if (lock.isModified()) {
|
||||
this.reset(layer);
|
||||
}
|
||||
newSection = BukkitAdapter_1_16_5
|
||||
.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
|
||||
if (!BukkitAdapter_1_16_5
|
||||
.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||
LOGGER.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
|
||||
} else {
|
||||
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Biomes
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
// set biomes
|
||||
BiomeStorage currentBiomes = nmsChunk.getBiomeIndex();
|
||||
if (createCopy) {
|
||||
copy.storeBiomes(currentBiomes);
|
||||
}
|
||||
for (int y = 0, i = 0; y < 64; y++) {
|
||||
for (int z = 0; z < 4; z++) {
|
||||
for (int x = 0; x < 4; x++, i++) {
|
||||
final BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
final Biome craftBiome = BukkitAdapter.adapt(biome);
|
||||
BiomeBase nmsBiome = CraftBlock.biomeToBiomeBase(nmsWorld.r().b(IRegistry.ay), craftBiome);
|
||||
currentBiomes.setBiome(x, y, z, nmsBiome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<HeightMapType, int[]> heightMaps = set.getHeightMaps();
|
||||
for (Map.Entry<HeightMapType, int[]> entry : heightMaps.entrySet()) {
|
||||
BukkitGetBlocks_1_16_5.this.setHeightmapToGet(entry.getKey(), entry.getValue());
|
||||
}
|
||||
BukkitGetBlocks_1_16_5.this.setLightingToGet(set.getLight());
|
||||
BukkitGetBlocks_1_16_5.this.setSkyLightingToGet(set.getSkyLight());
|
||||
|
||||
Runnable[] syncTasks = null;
|
||||
|
||||
int bx = chunkX << 4;
|
||||
int bz = chunkZ << 4;
|
||||
|
||||
Set<UUID> entityRemoves = set.getEntityRemoves();
|
||||
if (entityRemoves != null && !entityRemoves.isEmpty()) {
|
||||
syncTasks = new Runnable[3];
|
||||
|
||||
syncTasks[2] = () -> {
|
||||
final List<Entity>[] entities = nmsChunk.getEntitySlices();
|
||||
|
||||
for (final Collection<Entity> ents : entities) {
|
||||
if (!ents.isEmpty()) {
|
||||
final Iterator<Entity> iter = ents.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Entity entity = iter.next();
|
||||
if (entityRemoves.contains(entity.getUniqueID())) {
|
||||
if (createCopy) {
|
||||
copy.storeEntity(entity);
|
||||
}
|
||||
iter.remove();
|
||||
removeEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Set<CompoundTag> entities = set.getEntities();
|
||||
if (entities != null && !entities.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[2];
|
||||
}
|
||||
|
||||
syncTasks[1] = () -> {
|
||||
for (final CompoundTag nativeTag : entities) {
|
||||
final Map<String, Tag> entityTagMap = 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) {
|
||||
LOGGER.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();
|
||||
|
||||
EntityTypes<?> type = EntityTypes.a(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.a(nmsWorld);
|
||||
if (entity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
tag.remove(name);
|
||||
}
|
||||
entity.load(tag);
|
||||
entity.setLocation(x, y, z, yaw, pitch);
|
||||
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// set tiles
|
||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
||||
if (tiles != null && !tiles.isEmpty()) {
|
||||
if (syncTasks == null) {
|
||||
syncTasks = new Runnable[1];
|
||||
}
|
||||
|
||||
syncTasks[0] = () -> {
|
||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
||||
final CompoundTag nativeTag = entry.getValue();
|
||||
final BlockVector3 blockHash = entry.getKey();
|
||||
final int x = blockHash.getX() + bx;
|
||||
final int y = blockHash.getY();
|
||||
final int z = blockHash.getZ() + bz;
|
||||
final BlockPosition pos = new BlockPosition(x, y, z);
|
||||
|
||||
synchronized (nmsWorld) {
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
nmsWorld.removeTileEntity(pos);
|
||||
tileEntity = nmsWorld.getTileEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
final NBTTagCompound tag = (NBTTagCompound) adapter.fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Runnable callback;
|
||||
if (bitMask == 0 && biomes == null && !lightUpdate) {
|
||||
callback = null;
|
||||
} else {
|
||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||
boolean finalLightUpdate = lightUpdate;
|
||||
callback = () -> {
|
||||
// Set Modified
|
||||
nmsChunk.d(true); // Set Modified
|
||||
nmsChunk.mustNotSave = false;
|
||||
nmsChunk.markDirty();
|
||||
// send to player
|
||||
if (Settings.IMP.LIGHTING.MODE == 0 || !Settings.IMP.LIGHTING.DELAY_PACKET_SENDING) {
|
||||
this.send(finalMask, finalLightUpdate);
|
||||
}
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
};
|
||||
}
|
||||
if (syncTasks != null) {
|
||||
QueueHandler queueHandler = Fawe.get().getQueueHandler();
|
||||
Runnable[] finalSyncTasks = syncTasks;
|
||||
|
||||
// Chain the sync tasks and the callback
|
||||
Callable<Future> chain = () -> {
|
||||
try {
|
||||
// Run the sync tasks
|
||||
for (Runnable task : finalSyncTasks) {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
return (T) (Future) queueHandler.sync(chain);
|
||||
} else {
|
||||
if (callback == null) {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
} else {
|
||||
callback.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
forceLoadSections = true;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized char[] loadPrivately(int layer) {
|
||||
if (super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
} else {
|
||||
return BukkitGetBlocks_1_16_5.this.update(layer, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void send(int mask, boolean lighting) {
|
||||
BukkitAdapter_1_16_5.sendChunk(world, chunkX, chunkZ, lighting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized char[] update(int layer, char[] data, boolean aggressive) {
|
||||
ChunkSection section = getSections(aggressive)[layer];
|
||||
// Section is null, return empty array
|
||||
if (section == null) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
return data;
|
||||
}
|
||||
if (data == null || data == FaweCache.IMP.EMPTY_CHAR_4096) {
|
||||
data = new char[4096];
|
||||
Arrays.fill(data, (char) 1);
|
||||
}
|
||||
DelegateLock lock = BukkitAdapter_1_16_5.applyLock(section);
|
||||
synchronized (lock) {
|
||||
lock.untilFree();
|
||||
lock.setModified(false);
|
||||
// Efficiently convert ChunkSection to raw data
|
||||
try {
|
||||
FAWE_Spigot_v1_16_R3 adapter = ((FAWE_Spigot_v1_16_R3) WorldEditPlugin.getInstance().getBukkitImplAdapter());
|
||||
|
||||
final DataPaletteBlock<IBlockData> blocks = section.getBlocks();
|
||||
final DataBits bits = (DataBits) BukkitAdapter_1_16_5.fieldBits.get(blocks);
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_5.fieldPalette.get(blocks);
|
||||
|
||||
final int bitsPerEntry = (int) BukkitAdapter_1_16_5.fieldBitsPerEntry.get(bits);
|
||||
final long[] blockStates = bits.a();
|
||||
|
||||
new BitArrayUnstretched(bitsPerEntry, 4096, blockStates).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.IMP.PALETTE_TO_BLOCK.get();
|
||||
char[] paletteToBlockChars = FaweCache.IMP.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 = adapter.adaptToChar(ibd);
|
||||
}
|
||||
paletteToBlockChars[paletteVal] = ordinal;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
data[i] = ordinal;
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
int paletteVal = paletteToBlockInts[i];
|
||||
paletteToBlockChars[paletteVal] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
char[] paletteToOrdinal = FaweCache.IMP.PALETTE_TO_BLOCK_CHAR.get();
|
||||
try {
|
||||
if (num_palette != 1) {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
char ordinal = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = ordinal;
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
char paletteVal = data[i];
|
||||
char val = paletteToOrdinal[paletteVal];
|
||||
if (val == Character.MAX_VALUE) {
|
||||
val = ordinal(palette.a(i), adapter);
|
||||
paletteToOrdinal[i] = val;
|
||||
}
|
||||
// Don't read "empty".
|
||||
if (val == 0) {
|
||||
val = 1;
|
||||
}
|
||||
data[i] = val;
|
||||
}
|
||||
} else {
|
||||
char ordinal = ordinal(palette.a(0), adapter);
|
||||
// Don't read "empty".
|
||||
if (ordinal == 0) {
|
||||
ordinal = 1;
|
||||
}
|
||||
Arrays.fill(data, ordinal);
|
||||
}
|
||||
} finally {
|
||||
for (int i = 0; i < num_palette; i++) {
|
||||
paletteToOrdinal[i] = Character.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final char ordinal(IBlockData ibd, FAWE_Spigot_v1_16_R3 adapter) {
|
||||
if (ibd == null) {
|
||||
return BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||
} else {
|
||||
return adapter.adaptToChar(ibd);
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
ChunkSection[] tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
synchronized (this) {
|
||||
tmp = sections;
|
||||
if (tmp == null || force) {
|
||||
ChunkSection[] chunkSections = getChunk().getSections();
|
||||
tmp = new ChunkSection[chunkSections.length];
|
||||
System.arraycopy(chunkSections, 0, tmp, 0, chunkSections.length);
|
||||
sections = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public Chunk getChunk() {
|
||||
Chunk tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
synchronized (this) {
|
||||
tmp = nmsChunk;
|
||||
if (tmp == null) {
|
||||
nmsChunk = tmp = ensureLoaded(this.world, chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private void fillLightNibble(char[][] light, EnumSkyBlock skyBlock) {
|
||||
for (int Y = 0; Y < 16; Y++) {
|
||||
if (light[Y] == null) {
|
||||
continue;
|
||||
}
|
||||
SectionPosition sectionPosition = SectionPosition.a(nmsChunk.getPos(), Y);
|
||||
NibbleArray nibble = world.getChunkProvider().getLightEngine().a(skyBlock).a(sectionPosition);
|
||||
if (nibble == null) {
|
||||
byte[] a = new byte[2048];
|
||||
Arrays.fill(a, skyBlock == EnumSkyBlock.SKY ? (byte) 15 : (byte) 0);
|
||||
nibble = new NibbleArray(a);
|
||||
((LightEngine) world.getChunkProvider().getLightEngine()).a(skyBlock, sectionPosition, nibble, true);
|
||||
}
|
||||
synchronized (nibble) {
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
if (light[Y][i] < 16) {
|
||||
nibble.a(i, light[Y][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return getSections(false)[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
skyLight = new NibbleArray[16];
|
||||
blockLight = new NibbleArray[16];
|
||||
if (aggressive) {
|
||||
sections = null;
|
||||
nmsChunk = null;
|
||||
return super.trim(true);
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!hasSection(i) || !super.sections[i].isFull()) {
|
||||
continue;
|
||||
}
|
||||
ChunkSection existing = getSections(true)[i];
|
||||
try {
|
||||
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
|
||||
|
||||
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_16_5.fieldPalette.get(blocksExisting);
|
||||
int paletteSize;
|
||||
|
||||
if (palette instanceof DataPaletteLinear) {
|
||||
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
|
||||
} else if (palette instanceof DataPaletteHash) {
|
||||
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
|
||||
} else {
|
||||
super.trim(false, i);
|
||||
continue;
|
||||
}
|
||||
if (paletteSize == 1) {
|
||||
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
|
||||
continue;
|
||||
}
|
||||
super.trim(false, i);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
super.trim(false, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,204 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.implementation.lighting.HeightMapType;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt.LazyCompoundTag_1_16_5;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
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.BlockTypesCache;
|
||||
import net.minecraft.server.v1_16_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R3.BiomeStorage;
|
||||
import net.minecraft.server.v1_16_R3.Entity;
|
||||
import net.minecraft.server.v1_16_R3.IRegistry;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class BukkitGetBlocks_1_16_5_Copy implements IChunkGet {
|
||||
|
||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
||||
private final Set<CompoundTag> entities = new HashSet<>();
|
||||
private BiomeStorage biomeStorage;
|
||||
private final char[][] blocks = new char[16][];
|
||||
private final WorldServer world;
|
||||
|
||||
protected BukkitGetBlocks_1_16_5_Copy(WorldServer world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
protected void storeTile(TileEntity tile) {
|
||||
tiles.put(BlockVector3.at(tile.getPosition().getX(), tile.getPosition().getY(), tile.getPosition().getZ()),
|
||||
new LazyCompoundTag_1_16_5(Suppliers.memoize(() -> tile.save(new NBTTagCompound()))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||
return tiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public CompoundTag getTile(int x, int y, int z) {
|
||||
return tiles.get(BlockVector3.at(x, y, z));
|
||||
}
|
||||
|
||||
protected void storeEntity(Entity entity) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
entities.add((CompoundTag) adapter.toNative(entity.save(tag)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<CompoundTag> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getEntity(UUID uuid) {
|
||||
for (CompoundTag tag : entities) {
|
||||
UUID tagUUID;
|
||||
if (tag.containsKey("UUID")) {
|
||||
int[] arr = tag.getIntArray("UUID");
|
||||
tagUUID = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL));
|
||||
} else if (tag.containsKey("UUIDMost")) {
|
||||
tagUUID = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast"));
|
||||
} else if (tag.containsKey("PersistentIDMSB")) {
|
||||
tagUUID = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
if (uuid.equals(tagUUID)) {
|
||||
return tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setSkyLightingToGet(char[][] lighting) {}
|
||||
|
||||
@Override
|
||||
public void setHeightmapToGet(HeightMapType type, int[] data) {}
|
||||
|
||||
protected void storeBiomes(BiomeStorage biomeStorage) {
|
||||
this.biomeStorage = new BiomeStorage(biomeStorage.registry, BukkitAdapter_1_16_5.getBiomeArray(biomeStorage).clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int y, int z) {
|
||||
BiomeBase base = null;
|
||||
if (y == -1) {
|
||||
for (y = 0; y < FaweCache.IMP.WORLD_HEIGHT; y++) {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
if (base != null) break;
|
||||
}
|
||||
} else {
|
||||
base = biomeStorage.getBiome(x >> 2, y >> 2, z >> 2);
|
||||
}
|
||||
return base != null ? BukkitAdapter.adapt(CraftBlock.biomeBaseToBiome(world.r().b(IRegistry.ay), base)) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSectionLighting(int layer, boolean sky) {}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive, int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void storeSection(int layer, char[] data) {
|
||||
blocks[layer] = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||
return state.toBaseBlock(this, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(@Range(from = 0, to = 15) int layer) {
|
||||
return blocks[layer] != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
return blocks[layer];
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypesCache.states[get(x, y, z)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEmmittedLight(int x, int y, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getHeightMap(HeightMapType type) {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char get(int x, int y, int z) {
|
||||
final int layer = y >> 4;
|
||||
final int index = (y & 15) << 8 | z << 4 | x;
|
||||
return blocks[layer][index];
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.object.IntPair;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R3;
|
||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import net.minecraft.server.v1_16_R3.Block;
|
||||
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R3.Chunk;
|
||||
import net.minecraft.server.v1_16_R3.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R3.EnumDirection;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R3.NBTBase;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import net.minecraft.server.v1_16_R3.World;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData;
|
||||
import org.bukkit.event.block.BlockPhysicsEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class FAWEWorldNativeAccess_1_16_R3 implements WorldNativeAccess<Chunk, IBlockData, BlockPosition> {
|
||||
private static final int UPDATE = 1;
|
||||
private static final int NOTIFY = 2;
|
||||
|
||||
private final FAWE_Spigot_v1_16_R3 adapter;
|
||||
private final WeakReference<World> world;
|
||||
private SideEffectSet sideEffectSet;
|
||||
private final AtomicInteger lastTick;
|
||||
private final Set<CachedChange> cachedChanges = new HashSet<>();
|
||||
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
|
||||
|
||||
public FAWEWorldNativeAccess_1_16_R3(FAWE_Spigot_v1_16_R3 adapter, WeakReference<World> world) {
|
||||
this.adapter = adapter;
|
||||
this.world = world;
|
||||
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
|
||||
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
|
||||
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
|
||||
}
|
||||
|
||||
private World getWorld() {
|
||||
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
|
||||
this.sideEffectSet = sideEffectSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunk(int x, int z) {
|
||||
return getWorld().getChunkAt(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData toNative(BlockState state) {
|
||||
int stateId = adapter.ordinalToIbdID(state.getOrdinalChar());
|
||||
return BlockStateIdAccess.isValidInternalId(stateId)
|
||||
? Block.getByCombinedId(stateId)
|
||||
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getBlockState(Chunk chunk, BlockPosition position) {
|
||||
return chunk.getType(position);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public synchronized IBlockData setBlockState(Chunk chunk, BlockPosition position, IBlockData state) {
|
||||
int currentTick = MinecraftServer.currentTick;
|
||||
if (Fawe.isMainThread()) {
|
||||
return chunk.setType(position, state,
|
||||
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE));
|
||||
}
|
||||
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
|
||||
cachedChanges.add(new CachedChange(chunk, position, state));
|
||||
cachedChunksToSend.add(new IntPair(chunk.bukkitChunk.getX(), chunk.bukkitChunk.getZ()));
|
||||
boolean nextTick = lastTick.get() > currentTick;
|
||||
if (nextTick || cachedChanges.size() >= 1024) {
|
||||
if (nextTick) {
|
||||
lastTick.set(currentTick);
|
||||
}
|
||||
flushAsync(nextTick);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockData getValidBlockForPosition(IBlockData block, BlockPosition position) {
|
||||
return Block.b(block, getWorld(), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPosition getPosition(int x, int y, int z) {
|
||||
return new BlockPosition(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLightingForBlock(BlockPosition position) {
|
||||
getWorld().getChunkProvider().getLightEngine().a(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateTileEntity(BlockPosition position, CompoundTag tag) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the other versions
|
||||
TileEntity tileEntity = getWorld().getTileEntity(position);
|
||||
if (tileEntity == null) {
|
||||
return false;
|
||||
}
|
||||
NBTBase nativeTag = adapter.fromNative(tag);
|
||||
tileEntity.load(tileEntity.getBlock(), (NBTTagCompound) nativeTag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyBlockUpdate(BlockPosition position, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().notify(position, oldState, newState, UPDATE | NOTIFY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChunkTicking(Chunk chunk) {
|
||||
return chunk.getState().isAtLeast(PlayerChunk.State.TICKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markBlockChanged(BlockPosition position) {
|
||||
((ChunkProviderServer) getWorld().getChunkProvider()).flagDirty(position);
|
||||
}
|
||||
|
||||
private static final EnumDirection[] NEIGHBOUR_ORDER = {
|
||||
EnumDirection.WEST, EnumDirection.EAST,
|
||||
EnumDirection.DOWN, EnumDirection.UP,
|
||||
EnumDirection.NORTH, EnumDirection.SOUTH
|
||||
};
|
||||
|
||||
@Override
|
||||
public void notifyNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
World world = getWorld();
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
world.update(pos, oldState.getBlock());
|
||||
} else {
|
||||
// When we don't want events, manually run the physics without them.
|
||||
// Un-nest neighbour updating
|
||||
for (EnumDirection direction : NEIGHBOUR_ORDER) {
|
||||
BlockPosition shifted = pos.shift(direction);
|
||||
world.getType(shifted).doPhysics(world, shifted, oldState.getBlock(), pos, false);
|
||||
}
|
||||
}
|
||||
if (newState.isComplexRedstone()) {
|
||||
world.updateAdjacentComparators(pos, newState.getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNeighbors(BlockPosition pos, IBlockData oldState, IBlockData newState, int recursionLimit) {
|
||||
World world = getWorld();
|
||||
// a == updateNeighbors
|
||||
// b == updateDiagonalNeighbors
|
||||
oldState.b(world, pos, NOTIFY, recursionLimit);
|
||||
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
|
||||
CraftWorld craftWorld = world.getWorld();
|
||||
if (craftWorld != null) {
|
||||
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
|
||||
world.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
newState.a(world, pos, NOTIFY, recursionLimit);
|
||||
newState.b(world, pos, NOTIFY, recursionLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockStateChange(BlockPosition pos, IBlockData oldState, IBlockData newState) {
|
||||
getWorld().a(pos, oldState, newState);
|
||||
}
|
||||
|
||||
private synchronized void flushAsync(final boolean sendChunks) {
|
||||
final Set<CachedChange> changes = Collections.unmodifiableSet(new HashSet<>(cachedChanges));
|
||||
cachedChanges.clear();
|
||||
final Set<IntPair> toSend;
|
||||
if (sendChunks) {
|
||||
toSend = Collections.unmodifiableSet(new HashSet<>(cachedChunksToSend));
|
||||
cachedChunksToSend.clear();
|
||||
} else {
|
||||
toSend = Collections.emptySet();
|
||||
}
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
changes.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
if (!sendChunks) {
|
||||
return;
|
||||
}
|
||||
for (IntPair chunk : toSend) {
|
||||
BukkitAdapter_1_16_5.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
TaskManager.IMP.async(() -> TaskManager.IMP.sync(r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
RunnableVal<Object> r = new RunnableVal<Object>() {
|
||||
@Override
|
||||
public void run(Object value) {
|
||||
cachedChanges.forEach(cc -> cc.chunk.setType(cc.position, cc.blockData,
|
||||
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)));
|
||||
for (IntPair chunk : cachedChunksToSend) {
|
||||
BukkitAdapter_1_16_5.sendChunk(getWorld().getWorld().getHandle(), chunk.x, chunk.z, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
TaskManager.IMP.sync(r);
|
||||
}
|
||||
cachedChanges.clear();
|
||||
cachedChunksToSend.clear();
|
||||
}
|
||||
|
||||
private static final class CachedChange {
|
||||
|
||||
private final Chunk chunk;
|
||||
private final BlockPosition position;
|
||||
private final IBlockData blockData;
|
||||
|
||||
private CachedChange(Chunk chunk, BlockPosition position, IBlockData blockData) {
|
||||
this.chunk = chunk;
|
||||
this.position = position;
|
||||
this.blockData = blockData;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.bukkit.adapter.MapChunkUtil;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutMapChunk;
|
||||
|
||||
public class MapChunkUtil_1_16_5 extends MapChunkUtil<PacketPlayOutMapChunk> {
|
||||
public MapChunkUtil_1_16_5() throws NoSuchFieldException {
|
||||
fieldX = PacketPlayOutMapChunk.class.getDeclaredField("a");
|
||||
fieldZ = PacketPlayOutMapChunk.class.getDeclaredField("b");
|
||||
fieldBitMask = PacketPlayOutMapChunk.class.getDeclaredField("c");
|
||||
fieldHeightMap = PacketPlayOutMapChunk.class.getDeclaredField("d");
|
||||
fieldChunkData = PacketPlayOutMapChunk.class.getDeclaredField("f");
|
||||
fieldBlockEntities = PacketPlayOutMapChunk.class.getDeclaredField("g");
|
||||
fieldFull = PacketPlayOutMapChunk.class.getDeclaredField("h");
|
||||
fieldX.setAccessible(true);
|
||||
fieldZ.setAccessible(true);
|
||||
fieldBitMask.setAccessible(true);
|
||||
fieldHeightMap.setAccessible(true);
|
||||
fieldChunkData.setAccessible(true);
|
||||
fieldBlockEntities.setAccessible(true);
|
||||
fieldFull.setAccessible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketPlayOutMapChunk createPacket() {
|
||||
return new PacketPlayOutMapChunk();
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.lighting.NullRelighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.Relighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.RelighterFactory;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class TuinityRelighterFactory_1_16_5 implements RelighterFactory {
|
||||
@Override
|
||||
public @NotNull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
|
||||
org.bukkit.World w = Bukkit.getWorld(world.getName());
|
||||
if (w == null) return NullRelighter.INSTANCE;
|
||||
return new TuinityRelighter_1_16_5(((CraftWorld) w).getHandle(), queue);
|
||||
}
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5;
|
||||
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.lighting.NMSRelighter;
|
||||
import com.boydti.fawe.beta.implementation.lighting.Relighter;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongArraySet;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R3.ChunkStatus;
|
||||
import net.minecraft.server.v1_16_R3.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_16_R3.MCUtil;
|
||||
import net.minecraft.server.v1_16_R3.TicketType;
|
||||
import net.minecraft.server.v1_16_R3.Unit;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
public class TuinityRelighter_1_16_5 implements Relighter {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final MethodHandle RELIGHT;
|
||||
|
||||
private static final int CHUNKS_PER_BATCH = 1024; // 32 * 32
|
||||
private static final int CHUNKS_PER_BATCH_SQRT_LOG2 = 5; // for shifting
|
||||
|
||||
private static final TicketType<Unit> FAWE_TICKET = TicketType.a("fawe_ticket", (a, b) -> 0);
|
||||
private static final int LIGHT_LEVEL = MCUtil.getTicketLevelFor(ChunkStatus.LIGHT);
|
||||
|
||||
private final WorldServer world;
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final Long2ObjectLinkedOpenHashMap<LongSet> regions = new Long2ObjectLinkedOpenHashMap<>();
|
||||
|
||||
private final ReentrantLock areaLock = new ReentrantLock();
|
||||
private final NMSRelighter delegate;
|
||||
|
||||
static {
|
||||
MethodHandle tmp = null;
|
||||
try {
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
tmp = lookup.findVirtual(LightEngineThreaded.class,
|
||||
"relight",
|
||||
MethodType.methodType(
|
||||
int.class, // return type
|
||||
// params
|
||||
Set.class,
|
||||
Consumer.class,
|
||||
IntConsumer.class
|
||||
)
|
||||
);
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
LOGGER.error("Failed to locate relight method in LightEngineThreaded on Tuinity. " +
|
||||
"Is everything up to date?", e);
|
||||
}
|
||||
RELIGHT = tmp;
|
||||
}
|
||||
|
||||
public TuinityRelighter_1_16_5(WorldServer world, IQueueExtent<IQueueChunk> queue) {
|
||||
this.world = world;
|
||||
this.delegate = new NMSRelighter(queue, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addChunk(int cx, int cz, byte[] skipReason, int bitmask) {
|
||||
areaLock.lock();
|
||||
try {
|
||||
long key = MathMan.pairInt(cx >> CHUNKS_PER_BATCH_SQRT_LOG2, cz >> CHUNKS_PER_BATCH_SQRT_LOG2);
|
||||
// TODO probably submit here already if chunks.size == CHUNKS_PER_BATCH?
|
||||
LongSet chunks = this.regions.computeIfAbsent(key, k -> new LongArraySet(CHUNKS_PER_BATCH >> 2));
|
||||
chunks.add(ChunkCoordIntPair.pair(cx, cz));
|
||||
} finally {
|
||||
areaLock.unlock();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLightUpdate(int x, int y, int z) {
|
||||
delegate.addLightUpdate(x, y, z);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is called "recursively", iterating and removing elements
|
||||
* from the regions linked map. This way, chunks are loaded in batches to avoid
|
||||
* OOMEs.
|
||||
*/
|
||||
@Override
|
||||
public void fixLightingSafe(boolean sky) {
|
||||
this.areaLock.lock();
|
||||
try {
|
||||
if (regions.isEmpty()) return;
|
||||
LongSet first = regions.removeFirst();
|
||||
fixLighting(first, () -> fixLightingSafe(true));
|
||||
} finally {
|
||||
this.areaLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Processes a set of chunks and runs an action afterwards.
|
||||
* The action is run async, the chunks are partly processed on the main thread
|
||||
* (as required by the server).
|
||||
*/
|
||||
private void fixLighting(LongSet chunks, Runnable andThen) {
|
||||
// convert from long keys to ChunkCoordIntPairs
|
||||
Set<ChunkCoordIntPair> coords = new HashSet<>();
|
||||
LongIterator iterator = chunks.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
coords.add(new ChunkCoordIntPair(iterator.nextLong()));
|
||||
}
|
||||
TaskManager.IMP.task(() -> {
|
||||
// trigger chunk load and apply ticket on main thread
|
||||
List<CompletableFuture<?>> futures = new ArrayList<>();
|
||||
for (ChunkCoordIntPair pos : coords) {
|
||||
futures.add(world.getWorld().getChunkAtAsync(pos.x, pos.z)
|
||||
.thenAccept(c -> world.getChunkProvider().addTicketAtLevel(
|
||||
FAWE_TICKET,
|
||||
pos,
|
||||
LIGHT_LEVEL,
|
||||
Unit.INSTANCE))
|
||||
);
|
||||
}
|
||||
// collect futures and trigger relight once all chunks are loaded
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(v ->
|
||||
invokeRelight(coords,
|
||||
c -> { }, // no callback for single chunks required
|
||||
i -> {
|
||||
if (i != coords.size()) {
|
||||
LOGGER.warn("Processed " + i + " chunks instead of " + coords.size());
|
||||
}
|
||||
// post process chunks on main thread
|
||||
TaskManager.IMP.task(() -> postProcessChunks(coords));
|
||||
// call callback on our own threads
|
||||
TaskManager.IMP.async(andThen);
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private void invokeRelight(Set<ChunkCoordIntPair> coords,
|
||||
Consumer<ChunkCoordIntPair> chunkCallback,
|
||||
IntConsumer processCallback) {
|
||||
try {
|
||||
int unused = (int) RELIGHT.invokeExact(world.getChunkProvider().getLightEngine(),
|
||||
coords,
|
||||
chunkCallback, // callback per chunk
|
||||
processCallback // callback for all chunks
|
||||
);
|
||||
} catch (Throwable throwable) {
|
||||
LOGGER.error("Error occurred on relighting", throwable);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the server to unload the chunks again.
|
||||
* Also, if chunk packets are sent delayed, we need to do that here
|
||||
*/
|
||||
private void postProcessChunks(Set<ChunkCoordIntPair> coords) {
|
||||
boolean delay = Settings.IMP.LIGHTING.DELAY_PACKET_SENDING;
|
||||
for (ChunkCoordIntPair pos : coords) {
|
||||
int x = pos.x;
|
||||
int z = pos.z;
|
||||
if (delay) { // we still need to send the block changes of that chunk
|
||||
BukkitAdapter_1_16_5.sendChunk(world, x, z, false);
|
||||
}
|
||||
world.getChunkProvider().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeLighting() {
|
||||
this.delegate.removeLighting();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixBlockLighting() {
|
||||
fixLightingSafe(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixSkyLighting() {
|
||||
fixLightingSafe(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReentrantLock getLock() {
|
||||
return this.lock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
fixLightingSafe(true);
|
||||
}
|
||||
}
|
@ -1,153 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import net.minecraft.server.v1_16_R3.NBTBase;
|
||||
import net.minecraft.server.v1_16_R3.NBTNumber;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagList;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LazyCompoundTag_1_16_5 extends CompoundTag {
|
||||
|
||||
private final Supplier<NBTTagCompound> nmsTag;
|
||||
private CompoundTag cachedValue;
|
||||
|
||||
public LazyCompoundTag_1_16_5(Supplier<NBTTagCompound> tag) {
|
||||
super(new HashMap<>());
|
||||
this.nmsTag = tag;
|
||||
}
|
||||
|
||||
public LazyCompoundTag_1_16_5(NBTTagCompound tag) {
|
||||
this(() -> tag);
|
||||
}
|
||||
|
||||
public NBTTagCompound get() {
|
||||
return nmsTag.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Tag> getValue() {
|
||||
if (cachedValue == null) {
|
||||
cachedValue = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag.get());
|
||||
}
|
||||
return cachedValue.getValue();
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return nmsTag.get().hasKey(key);
|
||||
}
|
||||
|
||||
public byte[] getByteArray(String key) {
|
||||
return nmsTag.get().getByteArray(key);
|
||||
}
|
||||
|
||||
public byte getByte(String key) {
|
||||
return nmsTag.get().getByte(key);
|
||||
}
|
||||
|
||||
public double getDouble(String key) {
|
||||
return nmsTag.get().getDouble(key);
|
||||
}
|
||||
|
||||
public double asDouble(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asDouble();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public float getFloat(String key) {
|
||||
return nmsTag.get().getFloat(key);
|
||||
}
|
||||
|
||||
public int[] getIntArray(String key) {
|
||||
return nmsTag.get().getIntArray(key);
|
||||
}
|
||||
|
||||
public int getInt(String key) {
|
||||
return nmsTag.get().getInt(key);
|
||||
}
|
||||
|
||||
public int asInt(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asInt();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<Tag> getList(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
ArrayList<Tag> list = new ArrayList<>();
|
||||
NBTTagList nbtList = (NBTTagList) tag;
|
||||
for (NBTBase elem : nbtList) {
|
||||
if (elem instanceof NBTTagCompound) {
|
||||
list.add(new LazyCompoundTag_1_16_5((NBTTagCompound) elem));
|
||||
} else {
|
||||
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public ListTag getListTag(String key) {
|
||||
NBTBase tag = nmsTag.get().get(key);
|
||||
if (tag instanceof NBTTagList) {
|
||||
return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag);
|
||||
}
|
||||
return new ListTag(StringTag.class, Collections.emptyList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
|
||||
ListTag listTag = getListTag(key);
|
||||
if (listTag.getType().equals(listType)) {
|
||||
return (List<T>) listTag.getValue();
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public long[] getLongArray(String key) {
|
||||
return nmsTag.get().getLongArray(key);
|
||||
}
|
||||
|
||||
public long getLong(String key) {
|
||||
return nmsTag.get().getLong(key);
|
||||
}
|
||||
|
||||
public long asLong(String key) {
|
||||
NBTBase value = nmsTag.get().get(key);
|
||||
if (value instanceof NBTNumber) {
|
||||
return ((NBTNumber) value).asLong();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public short getShort(String key) {
|
||||
return nmsTag.get().getShort(key);
|
||||
}
|
||||
|
||||
public String getString(String key) {
|
||||
return nmsTag.get().getString(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return nmsTag.get().toString();
|
||||
}
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.plotsquared.core.queue.LocalBlockQueue;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.MutableBlockVector3;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
// TODO FIXME
|
||||
public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
public final IQueueExtent<IQueueChunk> instance;
|
||||
private final World world;
|
||||
private BlockVector3 mutable = new MutableBlockVector3();
|
||||
private boolean setbiome = false;
|
||||
|
||||
public FaweLocalBlockQueue(String worldName) {
|
||||
super(worldName);
|
||||
this.world = FaweAPI.getWorld(worldName);
|
||||
instance = Fawe.get().getQueueHandler().getQueue(world);
|
||||
Fawe.get().getQueueHandler().unCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean next() {
|
||||
if (!instance.isEmpty()) {
|
||||
instance.flush();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSet(boolean parallel) {
|
||||
Fawe.get().getQueueHandler().startSet(parallel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endSet(boolean parallel) {
|
||||
Fawe.get().getQueueHandler().endSet(parallel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return instance.isEmpty() ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void optimize() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified(long l) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getModified() {
|
||||
return instance.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BlockState id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, Pattern pattern) {
|
||||
mutable.setComponents(x, y, z);
|
||||
return pattern.apply(instance, mutable, mutable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BaseBlock id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return instance.getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int z, BiomeType biomeType) {
|
||||
setbiome = true;
|
||||
return instance.setBiome(x, 0, z, biomeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome() {
|
||||
return setbiome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWorld() {
|
||||
return world.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
instance.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enqueue() {
|
||||
boolean val = super.enqueue();
|
||||
instance.enableQueue();
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshChunk(int x, int z) {
|
||||
world.refreshChunk(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixChunkLighting(int x, int z) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void regenChunk(int x, int z) {
|
||||
instance.regenerateChunk(x, z, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.plotsquared.core.command.CommandCategory;
|
||||
import com.plotsquared.core.command.CommandDeclaration;
|
||||
import com.plotsquared.core.command.RequiredType;
|
||||
import com.plotsquared.core.command.SubCommand;
|
||||
import com.plotsquared.core.configuration.Captions;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.util.WorldUtil;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "trimchunks",
|
||||
permission = "plots.admin",
|
||||
description = "Delete unmodified portions of your plotworld",
|
||||
requiredType = RequiredType.PLAYER,
|
||||
category = CommandCategory.ADMINISTRATION)
|
||||
public class FaweTrim extends SubCommand {
|
||||
|
||||
private boolean ran = false;
|
||||
|
||||
@Override
|
||||
public boolean onCommand(final PlotPlayer plotPlayer, final String[] strings) {
|
||||
if (ran) {
|
||||
plotPlayer.sendMessage("Already running!");
|
||||
return false;
|
||||
}
|
||||
if (strings.length != 2) {
|
||||
plotPlayer.sendMessage("First make a backup of your world called <world-copy> then stand in the middle of an empty plot");
|
||||
plotPlayer.sendMessage("use /plot trimall <world> <boolean-delete-unowned>");
|
||||
return false;
|
||||
}
|
||||
if (!WorldUtil.IMP.isWorld(strings[0])) {
|
||||
Captions.NOT_VALID_PLOT_WORLD.send(plotPlayer, strings[0]);
|
||||
return false;
|
||||
}
|
||||
ran = true;
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// TODO NOT IMPLEMENTED
|
||||
// PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1]));
|
||||
// Location loc = plotPlayer.getLocation();
|
||||
// trim.setChunk(loc.getX() >> 4, loc.getZ() >> 4);
|
||||
// trim.run();
|
||||
// plotPlayer.sendMessage("Done!");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ran = false;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.plotsquared.core.command.Command;
|
||||
import com.plotsquared.core.command.CommandCategory;
|
||||
import com.plotsquared.core.command.CommandDeclaration;
|
||||
import com.plotsquared.core.command.MainCommand;
|
||||
import com.plotsquared.core.command.RequiredType;
|
||||
import com.plotsquared.core.configuration.Captions;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.util.MainUtil;
|
||||
import com.plotsquared.core.util.Permissions;
|
||||
import com.plotsquared.core.util.StringMan;
|
||||
import com.plotsquared.core.util.task.RunnableVal2;
|
||||
import com.plotsquared.core.util.task.RunnableVal3;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "generatebiome",
|
||||
permission = "plots.generatebiome",
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.NONE,
|
||||
description = "Generate a biome in your plot",
|
||||
aliases = {"bg", "gb"},
|
||||
usage = "/plots generatebiome <biome>"
|
||||
)
|
||||
public class PlotSetBiome extends Command {
|
||||
public PlotSetBiome() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> execute(final PlotPlayer<?> player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT);
|
||||
checkTrue(plot.isOwner(player.getUUID()) || Permissions
|
||||
.hasPermission(player, "plots.admin.command.generatebiome"), Captions.NO_PLOT_PERMS);
|
||||
if (plot.getRunning() != 0) {
|
||||
Captions.WAIT_FOR_TIMER.send(player);
|
||||
return null;
|
||||
}
|
||||
checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage());
|
||||
final Set<CuboidRegion> regions = plot.getRegions();
|
||||
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
|
||||
Collection<BiomeType> knownBiomes = BiomeTypes.values();
|
||||
final BiomeType biome = Biomes.findBiomeByName(knownBiomes, args[0], biomeRegistry);
|
||||
if (biome == null) {
|
||||
String biomes = StringMan
|
||||
.join(BiomeType.REGISTRY.values(), Captions.BLOCK_LIST_SEPARATOR.getTranslated());
|
||||
Captions.NEED_BIOME.send(player);
|
||||
MainUtil.sendMessage(player, Captions.SUBCOMMAND_SET_OPTIONS_HEADER.toString() + biomes);
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
confirm.run(this, () -> {
|
||||
if (plot.getRunning() != 0) {
|
||||
Captions.WAIT_FOR_TIMER.send(player);
|
||||
return;
|
||||
}
|
||||
plot.addRunning();
|
||||
TaskManager.IMP.async(() -> {
|
||||
EditSession session = new EditSessionBuilder(BukkitAdapter.adapt(Bukkit.getWorld(plot.getArea().getWorldName())))
|
||||
.autoQueue(false)
|
||||
.checkMemory(false)
|
||||
.allowedRegionsEverywhere()
|
||||
.player(BukkitAdapter.adapt(Bukkit.getPlayer(player.getUUID())))
|
||||
.limitUnlimited()
|
||||
.build();
|
||||
long seed = ThreadLocalRandom.current().nextLong();
|
||||
for (CuboidRegion region : regions) {
|
||||
session.regenerate(region, biome, seed);
|
||||
}
|
||||
session.flushQueue();
|
||||
plot.removeRunning();
|
||||
});
|
||||
}, null);
|
||||
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
package com.fastasyncworldedit.bukkit;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.PermissionAttachment;
|
||||
|
@ -1,31 +1,32 @@
|
||||
package com.boydti.fawe.bukkit;
|
||||
package com.fastasyncworldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.FAWEPlatformAdapterImpl;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.IFawe;
|
||||
import com.boydti.fawe.beta.implementation.cache.preloader.AsyncPreloader;
|
||||
import com.boydti.fawe.beta.implementation.cache.preloader.Preloader;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.BukkitQueueHandler;
|
||||
import com.boydti.fawe.bukkit.adapter.NMSAdapter;
|
||||
import com.boydti.fawe.bukkit.listener.BrushListener;
|
||||
import com.boydti.fawe.bukkit.listener.ChunkListener9;
|
||||
import com.boydti.fawe.bukkit.listener.RenderListener;
|
||||
import com.boydti.fawe.bukkit.regions.GriefPreventionFeature;
|
||||
import com.boydti.fawe.bukkit.regions.GriefDefenderFeature;
|
||||
import com.boydti.fawe.bukkit.regions.ResidenceFeature;
|
||||
import com.boydti.fawe.bukkit.regions.TownyFeature;
|
||||
import com.boydti.fawe.bukkit.regions.Worldguard;
|
||||
import com.boydti.fawe.bukkit.util.BukkitTaskManager;
|
||||
import com.boydti.fawe.bukkit.util.ItemUtil;
|
||||
import com.boydti.fawe.bukkit.util.MinecraftVersion;
|
||||
import com.boydti.fawe.bukkit.util.image.BukkitImageViewer;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.util.ThirdPartyManager;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.util.WEManager;
|
||||
import com.boydti.fawe.util.image.ImageViewer;
|
||||
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.IFawe;
|
||||
import com.fastasyncworldedit.core.beta.implementation.preloader.AsyncPreloader;
|
||||
import com.fastasyncworldedit.core.beta.implementation.preloader.Preloader;
|
||||
import com.fastasyncworldedit.core.beta.implementation.queue.QueueHandler;
|
||||
import com.fastasyncworldedit.bukkit.adapter.BukkitQueueHandler;
|
||||
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
||||
import com.fastasyncworldedit.bukkit.listener.BrushListener;
|
||||
import com.fastasyncworldedit.bukkit.listener.ChunkListener9;
|
||||
import com.fastasyncworldedit.bukkit.listener.RenderListener;
|
||||
import com.fastasyncworldedit.bukkit.regions.GriefPreventionFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.GriefDefenderFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.ResidenceFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.TownyFeature;
|
||||
import com.fastasyncworldedit.bukkit.regions.Worldguard;
|
||||
import com.fastasyncworldedit.bukkit.util.BukkitTaskManager;
|
||||
import com.fastasyncworldedit.bukkit.util.ItemUtil;
|
||||
import com.fastasyncworldedit.bukkit.util.MinecraftVersion;
|
||||
import com.fastasyncworldedit.bukkit.util.image.BukkitImageViewer;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.util.ThirdPartyManager;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.WEManager;
|
||||
import com.fastasyncworldedit.core.util.image.ImageViewer;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
@ -291,12 +292,13 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
return;
|
||||
}
|
||||
if (plotSquared.getClass().getPackage().toString().contains("intellectualsites")) {
|
||||
WEManager.IMP.managers
|
||||
.add(new com.boydti.fawe.bukkit.regions.plotsquaredv4.PlotSquaredFeature());
|
||||
WEManager.IMP.managers.add(new com.fastasyncworldedit.bukkit.regions.plotsquaredv4.PlotSquaredFeature());
|
||||
LOGGER.info("Plugin 'PlotSquared' found. Using it now.");
|
||||
} else if (PlotSquared.get().getVersion().version[0] == 6){
|
||||
WEManager.IMP.managers.add(new com.fastasyncworldedit.bukkit.regions.plotsquared.PlotSquaredFeature());
|
||||
LOGGER.info("Plugin 'PlotSquared' found. Using it now.");
|
||||
} else {
|
||||
WEManager.IMP.managers
|
||||
.add(new com.boydti.fawe.bukkit.regions.plotsquared.PlotSquaredFeature());
|
||||
LOGGER.error("Incompatible version of PlotSquared found. Please use PlotSquared v6.");
|
||||
}
|
||||
LOGGER.info("Plugin 'PlotSquared' found. Using it now.");
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
public interface BukkitGetBlocks {
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import co.aikar.timings.Timings;
|
||||
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
|
||||
import com.boydti.fawe.bukkit.listener.ChunkListener;
|
||||
import com.fastasyncworldedit.core.beta.implementation.queue.QueueHandler;
|
||||
import com.fastasyncworldedit.bukkit.listener.ChunkListener;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.spigotmc.AsyncCatcher;
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.destroystokyo.paper.util.ReentrantLockWithGetOwner;
|
||||
|
@ -0,0 +1,33 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public class DelegateSemaphore extends Semaphore {
|
||||
private final Semaphore delegate;
|
||||
|
||||
public DelegateSemaphore(int permits, Semaphore delegate) {
|
||||
super(permits);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
// this is bad
|
||||
@Override
|
||||
public synchronized boolean tryAcquire() {
|
||||
try {
|
||||
this.delegate.acquire();
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void acquire() throws InterruptedException {
|
||||
this.delegate.acquire();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void release() {
|
||||
this.delegate.release();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
@ -1,12 +1,13 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.Vector3;
|
||||
@ -21,6 +22,7 @@ import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.gamemode.GameMode;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
@ -39,11 +41,6 @@ import java.util.OptionalInt;
|
||||
public interface IDelegateBukkitImplAdapter<T> extends BukkitImplAdapter<T> {
|
||||
BukkitImplAdapter<T> getParent();
|
||||
|
||||
@Override
|
||||
default int getDataVersion() {
|
||||
return getParent().getDataVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default DataFixer getDataFixer() {
|
||||
@ -83,7 +80,7 @@ public interface IDelegateBukkitImplAdapter<T> extends BukkitImplAdapter<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData) {
|
||||
default void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) {
|
||||
getParent().sendFakeNBT(player, pos, nbtData);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -18,7 +18,7 @@ public abstract class MapChunkUtil<T> {
|
||||
protected Field fieldBlockEntities;
|
||||
protected Field fieldFull;
|
||||
|
||||
public abstract T createPacket();
|
||||
protected abstract T createPacket();
|
||||
|
||||
public T create(BukkitImplAdapter adapter, ChunkPacket packet) {
|
||||
try {
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.FAWEPlatformAdapterImpl;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
@ -0,0 +1,19 @@
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.core.beta.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.beta.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.NMSRelighter;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.Relighter;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.RelighterFactory;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.object.RelightMode;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NMSRelighterFactory implements RelighterFactory {
|
||||
@Override
|
||||
public @NotNull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<IQueueChunk> queue) {
|
||||
return new NMSRelighter(queue,
|
||||
relightMode != null ? relightMode : RelightMode.valueOf(Settings.IMP.LIGHTING.MODE));
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.queue.SingleThreadQueueExtent;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.fastasyncworldedit.core.beta.IChunkCache;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.beta.implementation.queue.SingleThreadQueueExtent;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
@ -1,5 +1,6 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
package com.fastasyncworldedit.bukkit.adapter;
|
||||
|
||||
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.bukkit.filter;
|
||||
package com.fastasyncworldedit.bukkit.filter;
|
||||
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.griefdefender.api.claim.Claim;
|
||||
import com.griefdefender.api.GriefDefender;
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.bukkit.filter;
|
||||
package com.fastasyncworldedit.bukkit.filter;
|
||||
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import me.ryanhamshire.GriefPrevention.Claim;
|
||||
import me.ryanhamshire.GriefPrevention.GriefPrevention;
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.bukkit.filter;
|
||||
package com.fastasyncworldedit.bukkit.filter;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.object.brush.MovableTool;
|
||||
import com.boydti.fawe.object.brush.ResettableTool;
|
||||
import com.boydti.fawe.object.brush.scroll.ScrollTool;
|
||||
import com.fastasyncworldedit.core.object.brush.MovableTool;
|
||||
import com.fastasyncworldedit.core.object.brush.ResettableTool;
|
||||
import com.fastasyncworldedit.core.object.brush.scroll.ScrollTool;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitPlayer;
|
@ -1,11 +1,11 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.FaweTimer;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.FaweTimer;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
@ -1,9 +1,9 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.FaweTimer;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.FaweTimer;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.listener;
|
||||
package com.fastasyncworldedit.bukkit.listener;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.preloader;
|
||||
package com.fastasyncworldedit.bukkit.preloader;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.regions.Region;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
|
||||
public abstract class BukkitMaskManager extends FaweMaskManager {
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.bukkit.filter.GriefDefenderFilter;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.bukkit.filter.GriefDefenderFilter;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.griefdefender.api.GriefDefender;
|
||||
import com.griefdefender.api.claim.Claim;
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.bukkit.filter.GriefPreventionFilter;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.bukkit.filter.GriefPreventionFilter;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
@ -1,10 +1,10 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.bekvon.bukkit.residence.Residence;
|
||||
import com.bekvon.bukkit.residence.protection.ClaimedResidence;
|
||||
import com.bekvon.bukkit.residence.protection.CuboidArea;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.palmergames.bukkit.towny.Towny;
|
||||
import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
|
||||
import com.palmergames.bukkit.towny.object.PlayerCache;
|
@ -1,9 +1,9 @@
|
||||
package com.boydti.fawe.bukkit.regions;
|
||||
package com.fastasyncworldedit.bukkit.regions;
|
||||
|
||||
import com.boydti.fawe.bukkit.filter.WorldGuardFilter;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.bukkit.filter.WorldGuardFilter;
|
||||
import com.fastasyncworldedit.core.object.RegionWrapper;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
@ -1,9 +1,9 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.object.RelightMode;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.object.RelightMode;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.generator.HybridPlotManager;
|
||||
import com.plotsquared.core.generator.HybridPlotWorld;
|
||||
@ -13,7 +13,6 @@ import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.PlotAreaTerrainType;
|
||||
import com.plotsquared.core.plot.PlotAreaType;
|
||||
import com.plotsquared.core.plot.PlotManager;
|
||||
import com.plotsquared.core.util.RegionManager;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
@ -33,41 +32,32 @@ import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.bukkit.Bukkit.getWorld;
|
||||
|
||||
public class FaweRegionManager extends RegionManager {
|
||||
public class FaweDelegateRegionManager {
|
||||
|
||||
private final RegionManager parent;
|
||||
|
||||
public FaweRegionManager(RegionManager parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] countEntities(Plot plot) {
|
||||
return parent.countEntities(plot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllEntities(Location pos1, Location pos2) {
|
||||
parent.clearAllEntities(pos1, pos2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setCuboids(final PlotArea area, final Set<CuboidRegion> regions, final Pattern blocks, final int minY, final int maxY) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.CUBOIDS) {
|
||||
return parent.setCuboids(area, regions, blocks, minY, maxY);
|
||||
}
|
||||
public boolean setCuboids(final @NonNull PlotArea area,
|
||||
final @NonNull Set<CuboidRegion> regions,
|
||||
final @NonNull Pattern blocks,
|
||||
int minY,
|
||||
int maxY,
|
||||
Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
World world = BukkitAdapter.adapt(getWorld(area.getWorldName()));
|
||||
EditSession session = new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession session =
|
||||
new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull()
|
||||
.autoQueue(false).build();
|
||||
for (CuboidRegion region : regions) {
|
||||
region.setPos1(region.getPos1().withY(minY));
|
||||
region.setPos2(region.getPos2().withY(maxY));
|
||||
@ -77,32 +67,28 @@ public class FaweRegionManager extends RegionManager {
|
||||
session.flushQueue();
|
||||
for (CuboidRegion region : regions) {
|
||||
FaweAPI.fixLighting(world, region, null,
|
||||
RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
}
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notifyClear(PlotManager manager) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.CLEAR || !(manager instanceof HybridPlotManager)) {
|
||||
return false;
|
||||
}
|
||||
final HybridPlotWorld hpw = ((HybridPlotManager) manager).getHybridPlotWorld();
|
||||
return hpw.getType() != PlotAreaType.AUGMENTED || hpw.getTerrain() == PlotAreaTerrainType.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleClear(final Plot plot, final Runnable whenDone, final PlotManager manager) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.CLEAR || !(manager instanceof HybridPlotManager)) {
|
||||
return false;
|
||||
}
|
||||
public boolean handleClear(@NotNull Plot plot,
|
||||
@Nullable Runnable whenDone,
|
||||
@NotNull PlotManager manager) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
final HybridPlotWorld hybridPlotWorld = ((HybridPlotManager) manager).getHybridPlotWorld();
|
||||
World world = BukkitAdapter.adapt(getWorld(hybridPlotWorld.getWorldName()));
|
||||
EditSession editSession = new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
@ -157,56 +143,58 @@ public class FaweRegionManager extends RegionManager {
|
||||
// Be verbose in editsession flushing
|
||||
editSession.flushQueue();
|
||||
FaweAPI.fixLighting(world, new CuboidRegion(plot.getBottomAbs().getBlockVector3(), plot.getTopAbs().getBlockVector3()), null,
|
||||
RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swap(final Location pos1, final Location pos2, final Location pos3, final Location pos4, final Runnable whenDone) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) {
|
||||
parent.swap(pos1, pos2, pos3, pos4, whenDone);
|
||||
}
|
||||
public void swap(Location pos1,
|
||||
Location pos2,
|
||||
Location swapPos,
|
||||
final Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
//todo because of the following code this should proably be in the Bukkit module
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorld()));
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(swapPos.getWorldName()));
|
||||
WorldEdit.getInstance().getEditSessionFactory().getEditSession(pos1World, -1);
|
||||
EditSession sessionA = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession sessionB = new EditSessionBuilder(pos3World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion regionA = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
CuboidRegion regionB = new CuboidRegion(BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ()), BlockVector3.at(pos4.getX(), pos4.getY(), pos4.getZ()));
|
||||
ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, sessionB, regionB.getMinimumPoint());
|
||||
ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, sessionA, regionA.getMinimumPoint());
|
||||
CuboidRegion regionA = new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3());
|
||||
CuboidRegion regionB = new CuboidRegion(swapPos.getBlockVector3(), swapPos.getBlockVector3().add(pos2.getBlockVector3()).subtract(pos1.getBlockVector3()));
|
||||
regionA.setWorld(pos1World);
|
||||
regionB.setWorld(pos3World);
|
||||
Clipboard clipA = Clipboard.create(regionA, UUID.randomUUID());
|
||||
Clipboard clipB = Clipboard.create(regionB, UUID.randomUUID());
|
||||
ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, clipA, clipA.getMinimumPoint());
|
||||
ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, clipB, clipB.getMinimumPoint());
|
||||
try {
|
||||
Operations.completeLegacy(copyA);
|
||||
Operations.completeLegacy(copyB);
|
||||
clipA.paste(sessionB, swapPos.getBlockVector3(), true);
|
||||
clipB.paste(sessionA, pos1.getBlockVector3(), true);
|
||||
sessionA.flushQueue();
|
||||
sessionB.flushQueue();
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
FaweAPI.fixLighting(pos1World, new CuboidRegion(pos1.getBlockVector3(), pos2.getBlockVector3()), null,
|
||||
RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
FaweAPI.fixLighting(pos1World, new CuboidRegion(pos3.getBlockVector3(), pos4.getBlockVector3()), null,
|
||||
RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
FaweAPI.fixLighting(pos1World, new CuboidRegion(swapPos.getBlockVector3(),
|
||||
BlockVector3.at(swapPos.getX() + pos2.getX() - pos1.getX(), 0, swapPos.getZ() + pos2.getZ() - pos1.getZ())), null,
|
||||
RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
TaskManager.IMP.task(whenDone);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBiome(CuboidRegion region, int extendBiome, BiomeType biome, String world, Runnable whenDone) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.SET_BIOME) {
|
||||
parent.setBiome(region, extendBiome, biome, world, whenDone);
|
||||
}
|
||||
region.expand(BlockVector3.at(extendBiome, 0, extendBiome));
|
||||
region.expand(BlockVector3.at(-extendBiome, 0, -extendBiome));
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
EditSession editSession = new EditSessionBuilder(BukkitAdapter.adapt(getWorld(world))).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
FlatRegionFunction replace = new BiomeReplace(editSession, biome);
|
||||
FlatRegionVisitor visitor = new FlatRegionVisitor(region, replace);
|
||||
@ -221,15 +209,14 @@ public class FaweRegionManager extends RegionManager {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean copyRegion(final Location pos1, final Location pos2, final Location pos3, final Runnable whenDone) {
|
||||
if (!com.boydti.fawe.config.Settings.IMP.PLOTSQUARED_INTEGRATION.COPY_AND_SWAP) {
|
||||
return parent.copyRegion(pos1, pos2, pos3, whenDone);
|
||||
}
|
||||
public boolean copyRegion(final @NonNull Location pos1,
|
||||
final @NonNull Location pos2,
|
||||
final @NonNull Location pos3,
|
||||
final @NonNull Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorld()));
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
World pos3World = BukkitAdapter.adapt(getWorld(pos3.getWorldName()));
|
||||
EditSession from = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
EditSession to = new EditSessionBuilder(pos3World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
@ -239,7 +226,7 @@ public class FaweRegionManager extends RegionManager {
|
||||
to.flushQueue();
|
||||
FaweAPI.fixLighting(pos1World,
|
||||
new CuboidRegion(pos3.getBlockVector3(), pos3.getBlockVector3().add(pos2.getBlockVector3().subtract(pos1.getBlockVector3()))),
|
||||
null, RelightMode.valueOf(com.boydti.fawe.config.Settings.IMP.LIGHTING.MODE));
|
||||
null, RelightMode.valueOf(com.fastasyncworldedit.core.configuration.Settings.IMP.LIGHTING.MODE));
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -249,11 +236,10 @@ public class FaweRegionManager extends RegionManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
synchronized (FaweRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorld()));
|
||||
synchronized (FaweDelegateRegionManager.class) {
|
||||
World pos1World = BukkitAdapter.adapt(getWorld(pos1.getWorldName()));
|
||||
try (EditSession editSession = new EditSessionBuilder(pos1World).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build()) {
|
||||
CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
editSession.regenerate(region);
|
@ -1,18 +1,20 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
|
||||
import com.boydti.fawe.object.io.PGZIPOutputStream;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.IOUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.object.io.PGZIPOutputStream;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.IOUtil;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.location.Location;
|
||||
import com.plotsquared.core.generator.ClassicPlotWorld;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.schematic.Schematic;
|
||||
import com.plotsquared.core.queue.LocalBlockQueue;
|
||||
import com.plotsquared.core.util.MainUtil;
|
||||
import com.plotsquared.core.util.FileUtils;
|
||||
import com.plotsquared.core.util.SchematicHandler;
|
||||
import com.plotsquared.core.util.task.RunnableVal;
|
||||
import com.plotsquared.core.util.task.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.CompressedCompoundTag;
|
||||
import com.sk89q.jnbt.NBTInputStream;
|
||||
@ -20,18 +22,17 @@ import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.jnbt.fawe.CompressedSchematicTag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.FastSchematicWriter;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.MCEditSchematicReader;
|
||||
import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicReader;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import net.jpountz.lz4.LZ4BlockInputStream;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
@ -45,64 +46,109 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import static org.bukkit.Bukkit.getWorld;
|
||||
public class FaweDelegateSchematicHandler {
|
||||
|
||||
public class FaweSchematicHandler extends SchematicHandler {
|
||||
@Override
|
||||
public boolean restoreTile(LocalBlockQueue queue, CompoundTag compoundTag, int x, int y, int z) {
|
||||
if (queue instanceof FaweLocalBlockQueue) {
|
||||
queue.setTile(x, y, z, compoundTag);
|
||||
return true;
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final AtomicBoolean exportingAll = new AtomicBoolean();
|
||||
|
||||
public void paste(final Schematic schematic,
|
||||
final Plot plot,
|
||||
final int xOffset,
|
||||
final int yOffset,
|
||||
final int zOffset,
|
||||
final boolean autoHeight,
|
||||
final RunnableVal<Boolean> whenDone) {
|
||||
Runnable r = () -> {
|
||||
if (whenDone != null) {
|
||||
whenDone.value = false;
|
||||
}
|
||||
if (schematic == null) {
|
||||
TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
BlockVector3 dimension = schematic.getClipboard().getDimensions();
|
||||
final int WIDTH = dimension.getX();
|
||||
final int LENGTH = dimension.getZ();
|
||||
final int HEIGHT = dimension.getY();
|
||||
// Validate dimensions
|
||||
CuboidRegion region = plot.getLargestRegion();
|
||||
if (((region.getMaximumPoint().getX() - region.getMinimumPoint().getX() + xOffset + 1) < WIDTH) || (
|
||||
(region.getMaximumPoint().getZ() - region.getMinimumPoint().getZ() + zOffset + 1) < LENGTH) || (HEIGHT
|
||||
> 256)) {
|
||||
TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
// Calculate the optimal height to paste the schematic at
|
||||
final int y_offset_actual;
|
||||
if (autoHeight) {
|
||||
if (HEIGHT >= 256) {
|
||||
y_offset_actual = yOffset;
|
||||
} else {
|
||||
PlotArea pw = plot.getArea();
|
||||
if (pw instanceof ClassicPlotWorld) {
|
||||
y_offset_actual = yOffset + ((ClassicPlotWorld) pw).PLOT_HEIGHT;
|
||||
} else {
|
||||
y_offset_actual = yOffset + 1 + PlotSquared.platform().worldUtil()
|
||||
.getHighestBlockSynchronous(plot.getWorldName(), region.getMinimumPoint().getX() + 1,
|
||||
region.getMinimumPoint().getZ() + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
y_offset_actual = yOffset;
|
||||
}
|
||||
|
||||
final BlockVector3 to = BlockVector3
|
||||
.at(region.getMinimumPoint().getX() + xOffset, y_offset_actual, region.getMinimumPoint().getZ() + zOffset);
|
||||
|
||||
try (EditSession editSession = new EditSessionBuilder(FaweAPI.getWorld(plot.getWorldName())).checkMemory(false)
|
||||
.fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build()) {
|
||||
final Clipboard clipboard = schematic.getClipboard();
|
||||
clipboard.paste(editSession, to, true, false, true);
|
||||
if (whenDone != null) {
|
||||
whenDone.value = true;
|
||||
TaskManager.runTask(whenDone);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Fawe.isMainThread()) {
|
||||
com.fastasyncworldedit.core.util.TaskManager.IMP.async(r);
|
||||
} else {
|
||||
r.run();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCompoundTag(final String world, final Set<CuboidRegion> regions, final RunnableVal<CompoundTag> whenDone) {
|
||||
TaskManager.IMP.async(() -> {
|
||||
Location[] corners = MainUtil.getCorners(world, regions);
|
||||
Location pos1 = corners[0];
|
||||
Location pos2 = corners[1];
|
||||
World adaptedWorld = BukkitAdapter.adapt(getWorld(world));
|
||||
final CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
|
||||
final EditSession editSession = new EditSessionBuilder(adaptedWorld).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
|
||||
|
||||
ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region, false, true);
|
||||
|
||||
Clipboard holder = new BlockArrayClipboard(region, clipboard);
|
||||
CompressedSchematicTag tag = new CompressedSchematicTag(holder);
|
||||
whenDone.run(tag);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean save(CompoundTag tag, String path) {
|
||||
if (tag == null) {
|
||||
PlotSquared.debug("&cCannot save empty tag");
|
||||
LOGGER.warn("Cannot save empty tag");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
File tmp = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), path);
|
||||
File tmp = FileUtils.getFile(PlotSquared.platform().getDirectory(), path);
|
||||
tmp.getParentFile().mkdirs();
|
||||
if (tag instanceof CompressedCompoundTag) {
|
||||
CompressedCompoundTag cTag = (CompressedCompoundTag) tag;
|
||||
if (cTag instanceof CompressedSchematicTag) {
|
||||
Clipboard clipboard = (Clipboard) cTag.getSource();
|
||||
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new BufferedOutputStream(new PGZIPOutputStream(stream)))) {
|
||||
try (OutputStream stream = new FileOutputStream(tmp);
|
||||
NBTOutputStream output = new NBTOutputStream(
|
||||
new BufferedOutputStream(new PGZIPOutputStream(stream)))) {
|
||||
new FastSchematicWriter(output).write(clipboard);
|
||||
}
|
||||
} else {
|
||||
try (OutputStream stream = new FileOutputStream(tmp); BufferedOutputStream output = new BufferedOutputStream(new PGZIPOutputStream(stream))) {
|
||||
try (OutputStream stream = new FileOutputStream(tmp);
|
||||
BufferedOutputStream output = new BufferedOutputStream(new PGZIPOutputStream(stream))) {
|
||||
LZ4BlockInputStream is = cTag.adapt(cTag.getSource());
|
||||
IOUtil.copy(is, stream);
|
||||
IOUtil.copy(is, output);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new PGZIPOutputStream(stream))) {
|
||||
try (OutputStream stream = new FileOutputStream(tmp);
|
||||
NBTOutputStream output = new NBTOutputStream(new PGZIPOutputStream(stream))) {
|
||||
Map<String, Tag> map = tag.getValue();
|
||||
output.writeNamedTag("Schematic", map.getOrDefault("Schematic", tag));
|
||||
}
|
||||
@ -116,15 +162,14 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(final CompoundTag tag, final UUID uuid, final String file, final RunnableVal<URL> whenDone) {
|
||||
if (tag == null) {
|
||||
PlotSquared.debug("&cCannot save empty tag");
|
||||
LOGGER.warn("Cannot save empty tag");
|
||||
com.plotsquared.core.util.task.TaskManager.runTask(whenDone);
|
||||
return;
|
||||
}
|
||||
final CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
|
||||
MainUtil.upload(uuid, file, "schem", new RunnableVal<OutputStream>() {
|
||||
SchematicHandler.upload(uuid, file, "schem", new RunnableVal<>() {
|
||||
@Override
|
||||
public void run(OutputStream output) {
|
||||
if (weTag instanceof CompressedSchematicTag) {
|
||||
@ -145,7 +190,6 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
}, whenDone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Schematic getSchematic(@NotNull InputStream is) {
|
||||
try {
|
||||
FastSchematicReader schematicReader = new FastSchematicReader(
|
||||
@ -174,8 +218,8 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
return new Schematic(clip);
|
||||
} catch (IOException e3) {
|
||||
e.printStackTrace();
|
||||
PlotSquared.debug(
|
||||
is.toString() + " | " + is.getClass().getCanonicalName() + " is not in GZIP format : " + e
|
||||
LOGGER.warn(
|
||||
is + " | " + is.getClass().getCanonicalName() + " is not in GZIP format : " + e
|
||||
.getMessage());
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.beta.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.beta.IQueueExtent;
|
||||
import com.plotsquared.core.queue.LightingMode;
|
||||
import com.plotsquared.core.queue.QueueCoordinator;
|
||||
import com.plotsquared.core.queue.subscriber.ProgressSubscriber;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.math.MutableBlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class FaweQueueCoordinator extends QueueCoordinator {
|
||||
|
||||
public final IQueueExtent<IQueueChunk> instance;
|
||||
private final World world;
|
||||
private BlockVector3 mutable = new MutableBlockVector3();
|
||||
private boolean setbiome = false;
|
||||
|
||||
public FaweQueueCoordinator(World world) {
|
||||
super(world);
|
||||
this.world = world;
|
||||
instance = Fawe.get().getQueueHandler().getQueue(world);
|
||||
Fawe.get().getQueueHandler().unCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return instance.isEmpty() ? 0 : 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setModified(long l) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BlockState id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(int x, int y, int z, Pattern pattern) {
|
||||
mutable.setComponents(x, y, z);
|
||||
return pattern.apply(instance, mutable, mutable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(final int x, final int y, final int z, final BaseBlock id) {
|
||||
return instance.setBlock(x, y, z, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return instance.getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int z, BiomeType biomeType) {
|
||||
setbiome = true;
|
||||
return instance.setBiome(x, 0, z, biomeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(int x, int y, int z, @NotNull BiomeType biome) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSettingBiomes() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setEntity(@NotNull Entity entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<BlockVector2> getReadChunks() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReadChunks(@NotNull Set<BlockVector2> readChunks) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReadChunk(@NotNull BlockVector2 chunk) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnloadAfter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnloadAfter(boolean unloadAfter) {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CuboidRegion getRegenRegion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRegenRegion(@NotNull CuboidRegion regenRegion) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enqueue() {
|
||||
boolean val = super.enqueue();
|
||||
instance.enableQueue();
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable getCompleteTask() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCompleteTask(@Nullable Runnable whenDone) {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Consumer<BlockVector2> getChunkConsumer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkConsumer(@NotNull Consumer<BlockVector2> consumer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addProgressSubscriber(@NotNull ProgressSubscriber progressSubscriber) {
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightingMode getLightingMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLightingMode(@Nullable LightingMode mode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void regenChunk(int x, int z) {
|
||||
instance.regenerateChunk(x, z, null, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
instance.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSettingTiles() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.command.CommandCategory;
|
||||
import com.plotsquared.core.command.CommandDeclaration;
|
||||
import com.plotsquared.core.command.RequiredType;
|
||||
import com.plotsquared.core.command.SubCommand;
|
||||
import com.plotsquared.core.configuration.caption.StaticCaption;
|
||||
import com.plotsquared.core.configuration.caption.Templates;
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
|
||||
@CommandDeclaration(command = "trimchunks",
|
||||
permission = "plots.admin",
|
||||
description = "Delete unmodified portions of your plotworld",
|
||||
requiredType = RequiredType.PLAYER,
|
||||
category = CommandCategory.ADMINISTRATION)
|
||||
public class FaweTrim extends SubCommand {
|
||||
|
||||
private boolean ran = false;
|
||||
|
||||
@Override
|
||||
public boolean onCommand(final PlotPlayer plotPlayer, final String[] strings) {
|
||||
if (ran) {
|
||||
plotPlayer.sendMessage(TranslatableCaption.of("error.task_in_process"));
|
||||
return false;
|
||||
}
|
||||
if (strings.length != 2) {
|
||||
plotPlayer.sendMessage(StaticCaption
|
||||
.of("First make a backup of your world called <world-copy> then stand in the middle of an empty plot"));
|
||||
plotPlayer.sendMessage(StaticCaption.of("use /plot trimall <world> <boolean-delete-unowned>"));
|
||||
return false;
|
||||
}
|
||||
if (!PlotSquared.platform().worldUtil().isWorld(strings[0])) {
|
||||
plotPlayer.sendMessage(TranslatableCaption.of("errors.not_valid_plot_world"), Templates.of("value", strings[0]));
|
||||
return false;
|
||||
}
|
||||
ran = true;
|
||||
TaskManager.IMP.async(() -> {
|
||||
try {
|
||||
// TODO NOT IMPLEMENTED
|
||||
//PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1]));
|
||||
//Location loc = plotPlayer.getLocation();
|
||||
//trim.setChunk(loc.getX() >> 4, loc.getZ() >> 4);
|
||||
//trim.run();
|
||||
//plotPlayer.sendMessage("Done!");
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ran = false;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
|
||||
import com.plotsquared.core.command.CommandCategory;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.plotsquared.core.location.Location;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
@ -0,0 +1,108 @@
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.plotsquared.core.command.Command;
|
||||
import com.plotsquared.core.command.CommandCategory;
|
||||
import com.plotsquared.core.command.CommandDeclaration;
|
||||
import com.plotsquared.core.command.MainCommand;
|
||||
import com.plotsquared.core.command.RequiredType;
|
||||
import com.plotsquared.core.configuration.caption.Templates;
|
||||
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.util.Permissions;
|
||||
import com.plotsquared.core.util.StringMan;
|
||||
import com.plotsquared.core.util.task.RunnableVal2;
|
||||
import com.plotsquared.core.util.task.RunnableVal3;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.command.util.SuggestionHelper;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@CommandDeclaration(command = "generatebiome",
|
||||
permission = "plots.generatebiome",
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.PLAYER,
|
||||
description = "Generate a biome in your plot",
|
||||
aliases = {"bg", "gb"},
|
||||
usage = "/plots generatebiome <biome>")
|
||||
public class PlotSetBiome extends Command {
|
||||
public PlotSetBiome() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> execute(final PlotPlayer<?> player,
|
||||
String[] args,
|
||||
RunnableVal3<Command, Runnable, Runnable> confirm,
|
||||
RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
final Plot plot = check(player.getCurrentPlot(), TranslatableCaption.of("errors.not_in_plot"));
|
||||
checkTrue(plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.admin.command.generatebiome"),
|
||||
TranslatableCaption.of("permission.no_plot_perms"));
|
||||
if (plot.getRunning() != 0) {
|
||||
player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));
|
||||
return null;
|
||||
}
|
||||
checkTrue(args.length == 1, TranslatableCaption.of("commandconfig.command_syntax"),
|
||||
Templates.of("value", getUsage()));
|
||||
final Set<CuboidRegion> regions = plot.getRegions();
|
||||
BiomeRegistry biomeRegistry =
|
||||
WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries()
|
||||
.getBiomeRegistry();
|
||||
Collection<BiomeType> knownBiomes = BiomeTypes.values();
|
||||
final BiomeType biome = Biomes.findBiomeByName(knownBiomes, args[0], biomeRegistry);
|
||||
if (biome == null) {
|
||||
String biomes = StringMan.join(BiomeType.REGISTRY.values(),
|
||||
TranslatableCaption.of("blocklist.block_list_separator").getComponent(player));
|
||||
player.sendMessage(TranslatableCaption.of("biome.need_biome"));
|
||||
player.sendMessage(TranslatableCaption.of("commandconfig.subcommand_set_options_header"),
|
||||
Templates.of("values", biomes));
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
confirm.run(this, () -> {
|
||||
if (plot.getRunning() != 0) {
|
||||
player.sendMessage(TranslatableCaption.of("errors.wait_for_timer"));
|
||||
return;
|
||||
}
|
||||
plot.addRunning();
|
||||
TaskManager.IMP.async(() -> {
|
||||
EditSession session =
|
||||
new EditSessionBuilder(BukkitAdapter.adapt(Bukkit.getWorld(plot.getArea().getWorldName())))
|
||||
.autoQueue(false).checkMemory(false).allowedRegionsEverywhere()
|
||||
.player(BukkitAdapter.adapt(Bukkit.getPlayer(player.getUUID()))).limitUnlimited().build();
|
||||
long seed = ThreadLocalRandom.current().nextLong();
|
||||
for (CuboidRegion region : regions) {
|
||||
session.regenerate(region, biome, seed);
|
||||
}
|
||||
session.flushQueue();
|
||||
plot.removeRunning();
|
||||
});
|
||||
}, null);
|
||||
|
||||
return CompletableFuture.completedFuture(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) {
|
||||
return SuggestionHelper.getNamespacedRegistrySuggestions(BiomeType.REGISTRY, args[0])
|
||||
.map(value -> value.toLowerCase(Locale.ENGLISH).replace("minecraft:", ""))
|
||||
.filter(value -> value.startsWith(args[0].toLowerCase(Locale.ENGLISH)))
|
||||
.map(value -> new Command(null, false, value, "", RequiredType.PLAYER, null) {
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquared;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquared;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler;
|
||||
import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.command.MainCommand;
|
||||
@ -14,9 +14,8 @@ import com.plotsquared.core.plot.Plot;
|
||||
import com.plotsquared.core.plot.PlotArea;
|
||||
import com.plotsquared.core.plot.flag.implementations.DoneFlag;
|
||||
import com.plotsquared.core.plot.flag.implementations.NoWorldeditFlag;
|
||||
import com.plotsquared.core.util.RegionManager;
|
||||
import com.plotsquared.core.util.SchematicHandler;
|
||||
import com.plotsquared.core.util.WEManager;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -39,15 +38,8 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
public PlotSquaredFeature() {
|
||||
super("PlotSquared");
|
||||
LOGGER.debug("Optimizing PlotSquared");
|
||||
if (com.boydti.fawe.config.Settings.IMP.ENABLED_COMPONENTS.PLOTSQUARED_HOOK) {
|
||||
if (Settings.FAWE_Components.FAWE_HOOK) {
|
||||
Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS = false;
|
||||
try {
|
||||
setupBlockQueue();
|
||||
setupSchematicHandler();
|
||||
setupRegionManager();
|
||||
} catch (Throwable ignored) {
|
||||
LOGGER.debug("Please update PlotSquared: https://www.spigotmc.org/resources/77506/");
|
||||
}
|
||||
if (Settings.PLATFORM.toLowerCase(Locale.ROOT).startsWith("bukkit")) {
|
||||
new FaweTrim();
|
||||
}
|
||||
@ -71,38 +63,20 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
return UUIDHandler.getName(uuid);
|
||||
}
|
||||
|
||||
private void setupBlockQueue() throws RuntimeException {
|
||||
// If it's going to fail, throw an error now rather than later
|
||||
//QueueProvider provider = QueueProvider.of(FaweLocalBlockQueue.class, null);
|
||||
//GlobalBlockQueue.IMP.setProvider(provider);
|
||||
//HybridPlotManager.REGENERATIVE_CLEAR = false;
|
||||
//log.debug(" - QueueProvider: " + FaweLocalBlockQueue.class);
|
||||
//log.debug(" - HybridPlotManager.REGENERATIVE_CLEAR: " + HybridPlotManager.REGENERATIVE_CLEAR);
|
||||
}
|
||||
|
||||
private void setupRegionManager() throws RuntimeException {
|
||||
RegionManager.manager = new FaweRegionManager(RegionManager.manager);
|
||||
LOGGER.debug(" - RegionManager: " + RegionManager.manager);
|
||||
}
|
||||
|
||||
private void setupSchematicHandler() throws RuntimeException {
|
||||
SchematicHandler.manager = new FaweSchematicHandler();
|
||||
LOGGER.debug(" - SchematicHandler: " + SchematicHandler.manager);
|
||||
}
|
||||
|
||||
public boolean isAllowed(Player player, Plot plot, MaskType type) {
|
||||
if (plot == null) {
|
||||
return false;
|
||||
}
|
||||
UUID uid = player.getUniqueId();
|
||||
return !plot.getFlag(NoWorldeditFlag.class) && (plot.isOwner(uid) || type == MaskType.MEMBER && (plot.getTrusted().contains(uid) || plot
|
||||
.getTrusted().contains(DBFunc.EVERYONE) || (plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE)) && player
|
||||
.hasPermission("fawe.plotsquared.member")) || player.hasPermission("fawe.plotsquared.admin"));
|
||||
return !plot.getFlag(NoWorldeditFlag.class) && (plot.isOwner(uid) || type == MaskType.MEMBER && (
|
||||
plot.getTrusted().contains(uid) || plot.getTrusted().contains(DBFunc.EVERYONE)
|
||||
|| (plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE)) && player
|
||||
.hasPermission("fawe.plotsquared.member")) || player.hasPermission("fawe.plotsquared.admin"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaweMask getMask(Player player, MaskType type) {
|
||||
final PlotPlayer pp = PlotPlayer.wrap(player.getUniqueId());
|
||||
final PlotPlayer<org.bukkit.entity.Player> pp = PlotPlayer.from(BukkitAdapter.adapt(player));
|
||||
if (pp == null) {
|
||||
return null;
|
||||
}
|
||||
@ -115,7 +89,8 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
regions = WEManager.getMask(pp);
|
||||
if (regions.size() == 1) {
|
||||
CuboidRegion region = regions.iterator().next();
|
||||
if (region.getMinimumPoint().getX() == Integer.MIN_VALUE && region.getMaximumPoint().getX() == Integer.MAX_VALUE) {
|
||||
if (region.getMinimumPoint().getX() == Integer.MIN_VALUE
|
||||
&& region.getMaximumPoint().getX() == Integer.MAX_VALUE) {
|
||||
regions.clear();
|
||||
}
|
||||
}
|
||||
@ -159,7 +134,7 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
|
||||
@Override
|
||||
public RegionFilter getFilter(String world) {
|
||||
PlotArea area = PlotSquared.get().getPlotArea(world, null);
|
||||
PlotArea area = PlotSquared.get().getPlotAreaManager().getPlotArea(world, null);
|
||||
if (area != null) {
|
||||
return new PlotRegionFilter(area);
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Location;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Plot;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.ChunkManager;
|
@ -1,10 +1,10 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IQueueChunk;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.beta.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.beta.IQueueExtent;
|
||||
import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
@ -1,12 +1,12 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
|
||||
import com.boydti.fawe.object.io.PGZIPOutputStream;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.IOUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.object.clipboard.ReadOnlyClipboard;
|
||||
import com.fastasyncworldedit.core.object.io.PGZIPOutputStream;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.IOUtil;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Location;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.regions.general.CuboidRegionFilter;
|
||||
import com.fastasyncworldedit.core.regions.general.CuboidRegionFilter;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Location;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.Plot;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
|
@ -1,7 +1,7 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.EditSessionBuilder;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.github.intellectualsites.plotsquared.commands.Command;
|
||||
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
|
@ -1,10 +1,10 @@
|
||||
package com.boydti.fawe.bukkit.regions.plotsquaredv4;
|
||||
package com.fastasyncworldedit.bukkit.regions.plotsquaredv4;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.object.RegionWrapper;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.boydti.fawe.regions.general.RegionFilter;
|
||||
import com.fastasyncworldedit.core.FaweAPI;
|
||||
import com.fastasyncworldedit.core.object.RegionWrapper;
|
||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||
import com.fastasyncworldedit.core.regions.general.RegionFilter;
|
||||
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
|
||||
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
|
||||
import com.github.intellectualsites.plotsquared.plot.config.Settings;
|
||||
@ -40,7 +40,7 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
public PlotSquaredFeature() {
|
||||
super("PlotSquared");
|
||||
LOGGER.debug("Optimizing PlotSquared");
|
||||
if (com.boydti.fawe.config.Settings.IMP.ENABLED_COMPONENTS.PLOTSQUARED_HOOK) {
|
||||
if (com.fastasyncworldedit.core.configuration.Settings.IMP.ENABLED_COMPONENTS.PLOTSQUARED_v4_HOOK) {
|
||||
Settings.Enabled_Components.WORLDEDIT_RESTRICTIONS = false;
|
||||
try {
|
||||
setupBlockQueue();
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import org.apache.commons.lang.mutable.MutableInt;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
@ -1,6 +1,6 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.Tag;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import org.bukkit.Bukkit;
|
@ -1,4 +1,4 @@
|
||||
package com.boydti.fawe.bukkit.util;
|
||||
package com.fastasyncworldedit.bukkit.util;
|
||||
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
import org.bukkit.Bukkit;
|
@ -1,8 +1,8 @@
|
||||
package com.boydti.fawe.bukkit.util.image;
|
||||
package com.fastasyncworldedit.bukkit.util.image;
|
||||
|
||||
import com.boydti.fawe.util.image.Drawable;
|
||||
import com.boydti.fawe.util.image.ImageUtil;
|
||||
import com.boydti.fawe.util.image.ImageViewer;
|
||||
import com.fastasyncworldedit.core.util.image.Drawable;
|
||||
import com.fastasyncworldedit.core.util.image.ImageUtil;
|
||||
import com.fastasyncworldedit.core.util.image.ImageViewer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
@ -22,8 +22,8 @@ package com.sk89q.worldedit.bukkit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.SimpleBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.IBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.SimpleBukkitAdapter;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.boydti.fawe.bukkit.util.ItemUtil;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.bukkit.util.ItemUtil;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.world.item.ItemType;
|
||||
|
@ -19,10 +19,10 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.object.RunnableVal;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.sk89q.util.StringUtil;
|
||||
import com.sk89q.wepif.VaultResolver;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
@ -46,6 +46,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
|
||||
import com.sk89q.worldedit.util.formatting.text.adapter.bukkit.TextAdapter;
|
||||
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
|
||||
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
@ -392,11 +393,12 @@ public class BukkitPlayer extends AbstractPlayerActor {
|
||||
player.sendBlockChange(loc, player.getWorld().getBlockAt(loc).getBlockData());
|
||||
} else {
|
||||
player.sendBlockChange(loc, BukkitAdapter.adapt(block));
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).hasNbtData()) {
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK) {
|
||||
adapter.sendFakeNBT(player, pos, ((BaseBlock) block).getNbtData());
|
||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||
if (adapter != null) {
|
||||
if (block.getBlockType() == BlockTypes.STRUCTURE_BLOCK && block instanceof BaseBlock) {
|
||||
CompoundBinaryTag nbt = ((BaseBlock) block).getNbt();
|
||||
if (nbt != null) {
|
||||
adapter.sendFakeNBT(player, pos, nbt);
|
||||
adapter.sendFakeOP(player);
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.lighting.RelighterFactory;
|
||||
import com.boydti.fawe.bukkit.NMSRelighterFactory;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.TuinityRelighterFactory_1_16_5;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.RelighterFactory;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.bukkit.util.CommandInfo;
|
||||
import com.sk89q.bukkit.util.CommandRegistration;
|
||||
@ -38,7 +36,6 @@ import com.sk89q.worldedit.extension.platform.Preference;
|
||||
import com.sk89q.worldedit.extension.platform.Watchdog;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.concurrency.LazyReference;
|
||||
import com.sk89q.worldedit.util.lifecycle.Lifecycled;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.registry.Registries;
|
||||
@ -70,7 +67,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
public final WorldEditPlugin plugin;
|
||||
private final CommandRegistration dynamicCommands;
|
||||
private final Lifecycled<Watchdog> watchdog;
|
||||
private final RelighterFactory relighterFactory;
|
||||
private RelighterFactory relighterFactory;
|
||||
private boolean hookingEvents;
|
||||
|
||||
public BukkitServerInterface(WorldEditPlugin plugin, Server server) {
|
||||
@ -80,16 +77,6 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
this.watchdog = plugin.getLifecycledBukkitImplAdapter()
|
||||
.filter(BukkitImplAdapter::supportsWatchdog)
|
||||
.map(BukkitWatchdog::new);
|
||||
RelighterFactory tempFactory;
|
||||
try {
|
||||
Class.forName("com.tuinity.tuinity.config.TuinityConfig");
|
||||
tempFactory = new TuinityRelighterFactory_1_16_5();
|
||||
LOGGER.info("Using Tuinity internals for relighting");
|
||||
} catch (ClassNotFoundException e) {
|
||||
tempFactory = new NMSRelighterFactory();
|
||||
LOGGER.info("Using FAWE for relighting");
|
||||
}
|
||||
this.relighterFactory = tempFactory;
|
||||
}
|
||||
|
||||
CommandRegistration getDynamicCommands() {
|
||||
@ -144,7 +131,7 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
|
||||
@Override
|
||||
public Watchdog getWatchdog() {
|
||||
return watchdog.valueOrThrow();
|
||||
return watchdog.value().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -262,6 +249,10 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
||||
|
||||
@Override
|
||||
public @NotNull RelighterFactory getRelighterFactory() {
|
||||
if (this.relighterFactory == null) {
|
||||
this.relighterFactory = this.plugin.getBukkitImplAdapter().getRelighterFactory();
|
||||
LOGGER.info("Using " + this.relighterFactory.getClass().getCanonicalName() + " as relighter factory.");
|
||||
}
|
||||
return this.relighterFactory;
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
@ -80,6 +80,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private static final boolean HAS_3D_BIOMES;
|
||||
private static final boolean HAS_MIN_Y;
|
||||
|
||||
private static final Map<Integer, Effect> effects = new HashMap<>();
|
||||
|
||||
@ -98,6 +99,13 @@ public class BukkitWorld extends AbstractWorld {
|
||||
temp = false;
|
||||
}
|
||||
HAS_3D_BIOMES = temp;
|
||||
try {
|
||||
World.class.getMethod("getMinHeight");
|
||||
temp = true;
|
||||
} catch (NoSuchMethodException e) {
|
||||
temp = false;
|
||||
}
|
||||
HAS_MIN_Y = temp;
|
||||
}
|
||||
|
||||
private WeakReference<World> worldRef;
|
||||
@ -143,7 +151,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
return list;
|
||||
}
|
||||
|
||||
//createEntity was moved to IChunkExtent to prevent issues with Async Entitiy Add.
|
||||
//createEntity was moved to IChunkExtent to prevent issues with Async Entity Add.
|
||||
|
||||
/**
|
||||
* Get the world handle.
|
||||
@ -252,6 +260,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
if (!getBlock(pt).getBlockType().getMaterial().hasContainer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Block block = getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ());
|
||||
BlockState state = PaperLib.getBlockState(block, false).getState();
|
||||
if (!(state instanceof InventoryHolder)) {
|
||||
@ -360,6 +369,14 @@ public class BukkitWorld extends AbstractWorld {
|
||||
return getWorld().getMaxHeight() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
if (HAS_MIN_Y) {
|
||||
return getWorld().getMinHeight();
|
||||
}
|
||||
return super.getMinY();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void fixAfterFastMode(Iterable<BlockVector2> chunks) {
|
||||
@ -463,9 +480,9 @@ public class BukkitWorld extends AbstractWorld {
|
||||
try {
|
||||
return worldNativeAccess.setBlock(position, block, sideEffects);
|
||||
} catch (Exception e) {
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).getNbtData() != null) {
|
||||
if (block instanceof BaseBlock && ((BaseBlock) block).getNbt() != null) {
|
||||
LOGGER.warn("Tried to set a corrupt tile entity at " + position.toString()
|
||||
+ ": " + ((BaseBlock) block).getNbtData(), e);
|
||||
+ ": " + ((BaseBlock) block).getNbt(), e);
|
||||
} else {
|
||||
LOGGER.warn("Failed to set block via adapter, falling back to generic", e);
|
||||
}
|
||||
|
@ -19,8 +19,9 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.bukkit.BukkitPermissionAttachmentManager;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.sk89q.util.yaml.YAMLProcessor;
|
||||
import com.sk89q.wepif.PermissionsResolverManager;
|
||||
@ -30,10 +31,6 @@ import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.bukkit.adapter.AdapterLoadException;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplLoader;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_15_R2;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R1;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R2;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.FAWE_Spigot_v1_16_R3;
|
||||
import com.sk89q.worldedit.event.platform.CommandEvent;
|
||||
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
|
||||
import com.sk89q.worldedit.event.platform.PlatformReadyEvent;
|
||||
@ -72,7 +69,6 @@ import org.bukkit.event.world.WorldInitEvent;
|
||||
import org.bukkit.metadata.FixedMetadataValue;
|
||||
import org.bukkit.metadata.MetadataValue;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.incendo.serverlib.ServerLib;
|
||||
|
||||
@ -299,15 +295,6 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
|
||||
|
||||
// Attempt to load a Bukkit adapter
|
||||
BukkitImplLoader adapterLoader = new BukkitImplLoader();
|
||||
try {
|
||||
adapterLoader.addClass(FAWE_Spigot_v1_15_R2.class);
|
||||
adapterLoader.addClass(FAWE_Spigot_v1_16_R1.class);
|
||||
adapterLoader.addClass(FAWE_Spigot_v1_16_R2.class);
|
||||
adapterLoader.addClass(FAWE_Spigot_v1_16_R3.class);
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
adapterLoader.addFromPath(getClass().getClassLoader());
|
||||
} catch (IOException e) {
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit;
|
||||
|
||||
import com.boydti.fawe.config.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
|
||||
/**
|
||||
|
@ -19,11 +19,14 @@
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter;
|
||||
|
||||
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.sk89q.jnbt.CompoundTag;
|
||||
import com.fastasyncworldedit.bukkit.FaweBukkit;
|
||||
import com.fastasyncworldedit.bukkit.adapter.IBukkitAdapter;
|
||||
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.beta.IChunkGet;
|
||||
import com.fastasyncworldedit.core.beta.implementation.lighting.RelighterFactory;
|
||||
import com.fastasyncworldedit.core.beta.implementation.packet.ChunkPacket;
|
||||
import com.sk89q.jnbt.AdventureNBTConverter;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItem;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
@ -37,6 +40,8 @@ import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.util.nbt.BinaryTag;
|
||||
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
|
||||
import com.sk89q.worldedit.world.DataFixer;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
@ -54,23 +59,16 @@ import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An interface for adapters of various Bukkit implementations.
|
||||
*/
|
||||
public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
|
||||
/**
|
||||
* Get the Minecraft data version for the current world data.
|
||||
*
|
||||
* @return the data version
|
||||
*/
|
||||
int getDataVersion();
|
||||
|
||||
/**
|
||||
* Get a data fixer, or null if not supported.
|
||||
*
|
||||
@ -168,7 +166,7 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
* @param pos The position
|
||||
* @param nbtData The NBT Data
|
||||
*/
|
||||
void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData);
|
||||
void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData);
|
||||
|
||||
/**
|
||||
* Make the client think it has operator status.
|
||||
@ -239,11 +237,24 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
default Tag toNative(T foreign) {
|
||||
return AdventureNBTConverter.fromAdventure(toNativeBinary(foreign));
|
||||
}
|
||||
|
||||
default BinaryTag toNativeBinary(T foreign) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
default T fromNative(Tag foreign) {
|
||||
if (foreign == null) {
|
||||
return null;
|
||||
}
|
||||
return fromNativeBinary(foreign.asBinaryTag());
|
||||
}
|
||||
|
||||
default T fromNativeBinary(BinaryTag foreign) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -278,4 +289,8 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
||||
default int getInternalBiomeId(BiomeType biome) {
|
||||
return Biome.BADLANDS.ordinal();
|
||||
}
|
||||
|
||||
default RelighterFactory getRelighterFactory() {
|
||||
return new NMSRelighterFactory(); // TODO implement in adapters instead
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class BukkitImplLoader {
|
||||
private final List<String> adapterCandidates = new ArrayList<>();
|
||||
private String customCandidate;
|
||||
|
||||
private static final String SEARCH_PACKAGE = "com.sk89q.worldedit.bukkit.adapter.impl";
|
||||
private static final String SEARCH_PACKAGE = "com.sk89q.worldedit.bukkit.adapter.impl.fawe";
|
||||
private static final String SEARCH_PACKAGE_DOT = SEARCH_PACKAGE + ".";
|
||||
private static final String SEARCH_PATH = SEARCH_PACKAGE.replace(".", "/");
|
||||
private static final String CLASS_SUFFIX = ".class";
|
||||
@ -76,10 +76,6 @@ public class BukkitImplLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public void addClass(Class<?> cls) {
|
||||
adapterCandidates.add(0, cls.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the given JAR for candidate implementations.
|
||||
*
|
||||
|
@ -1,450 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BlockMaterial_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BukkitAdapter_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BukkitGetBlocks_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.FAWEWorldNativeAccess_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.MapChunkUtil_1_15_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.regen.Regen_v1_15_R2;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
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.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.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.Block;
|
||||
import net.minecraft.server.v1_15_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_15_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_15_R1.Entity;
|
||||
import net.minecraft.server.v1_15_R1.EntityPlayer;
|
||||
import net.minecraft.server.v1_15_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_15_R1.IBlockData;
|
||||
import net.minecraft.server.v1_15_R1.IRegistry;
|
||||
import net.minecraft.server.v1_15_R1.ItemStack;
|
||||
import net.minecraft.server.v1_15_R1.MinecraftKey;
|
||||
import net.minecraft.server.v1_15_R1.NBTBase;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_15_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_15_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_15_R1.TileEntity;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class FAWE_Spigot_v1_15_R2 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Spigot_v1_15_R2 parent;
|
||||
private char[] ibdToStateOrdinal;
|
||||
private int[] ordinalToIbdID;
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that may break between versions of Minecraft
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public FAWE_Spigot_v1_15_R2() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.parent = new Spigot_v1_15_R2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitImplAdapter<NBTBase> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
|
||||
return false;
|
||||
}
|
||||
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
|
||||
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
|
||||
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
BlockMaterial_1_15_2 material = (BlockMaterial_1_15_2) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
char ordinal = state.getOrdinalChar();
|
||||
ibdToStateOrdinal[id] = ordinal;
|
||||
ordinalToIbdID[ordinal] = id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
Block block = getBlock(blockType);
|
||||
return new BlockMaterial_1_15_2(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BlockMaterial getMaterial(BlockState state) {
|
||||
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new BlockMaterial_1_15_2(bs.getBlock(), bs);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
final WorldServer handle = craftWorld.getHandle();
|
||||
Chunk chunk = handle.getChunkAt(x >> 4, z >> 4);
|
||||
final BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
|
||||
// Read the NBT data
|
||||
TileEntity te = chunk.a(blockPos, Chunk.EnumTileEntityState.CHECK);
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
te.save(tag); // readTileEntityIntoTag - load data
|
||||
return state.toBaseBlock((CompoundTag) toNative(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> getSupportedSideEffects() {
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
Chunk nmsChunk = craftChunk.getHandle();
|
||||
World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
IBlockData blockData = ((BlockMaterial_1_15_2) state.getMaterial()).getState();
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
ChunkSection section = sections[y4];
|
||||
|
||||
IBlockData existing;
|
||||
if (section == null) {
|
||||
existing = ((BlockMaterial_1_15_2) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getType(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
|
||||
nmsChunk.removeTileEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundTag nativeTag = state instanceof BaseBlock ? ((BaseBlock)state).getNbtData() : null;
|
||||
if (nativeTag != null || existing instanceof TileEntityBlock) {
|
||||
nmsWorld.setTypeAndData(blockPos, blockData, 0);
|
||||
// remove tile
|
||||
if (nativeTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(blockPos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockData) {
|
||||
return true;
|
||||
}
|
||||
if (section == null) {
|
||||
if (blockData.isAir()) {
|
||||
return true;
|
||||
}
|
||||
sections[y4] = section = new ChunkSection(y4 << 4);
|
||||
}
|
||||
nmsChunk.setType(blockPos, blockData, false);
|
||||
}
|
||||
if (update) {
|
||||
nmsWorld.getMinecraftWorld().notify(blockPos, existing, blockData, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new FAWEWorldNativeAccess_1_15_2(this,
|
||||
new WeakReference<>(((CraftWorld) world).getHandle()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
|
||||
return minecraftkey == null ? null : minecraftkey.toString();
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) {
|
||||
entity.save(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundTag> saveTag = () -> {
|
||||
final NBTTagCompound minecraftTag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, minecraftTag);
|
||||
//add Id for AbstractChangeSet to work
|
||||
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
|
||||
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
|
||||
tags.put("Id", new StringTag(id));
|
||||
return new CompoundTag(tags);
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichBlockName(BlockType blockType) {
|
||||
return parent.getRichBlockName(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(ItemType itemType) {
|
||||
return parent.getRichItemName(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(BaseItemStack itemStack) {
|
||||
return parent.getRichItemName(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
BlockMaterial_1_15_2 material = (BlockMaterial_1_15_2) 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);
|
||||
IBlockData ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypesCache.states[adaptToChar(ibd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Method unused. Use #adaptToChar(IBlockData).
|
||||
*/
|
||||
@Deprecated
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToInt(ibd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char adaptToChar(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToChar(ibd);
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
|
||||
ibd.getBlock(), Block.REGISTRY_ID.getId(ibd), ibdToStateOrdinal.length, e1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
public int ordinalToIbdID(char ordinal) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
return ordinalToIbdID[ordinal];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return ordinalToIbdID(ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
|
||||
BlockMaterial_1_15_2 material = (BlockMaterial_1_15_2) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
private MapChunkUtil_1_15_2 mapUtil = new MapChunkUtil_1_15_2();
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||
PlayerChunk map = BukkitAdapter_1_15_2.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 = mapUtil.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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
|
||||
ItemStack stack = new ItemStack(IRegistry.ITEM.get(MinecraftKey.a(item.getType().getId())), item.getAmount());
|
||||
stack.setTag(((NBTTagCompound) fromNative(item.getNbtData())));
|
||||
return CraftItemStack.asCraftMirror(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
|
||||
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
|
||||
weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
|
||||
return weStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toNative(NBTBase foreign) {
|
||||
return parent.toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase fromNative(Tag foreign) {
|
||||
if (foreign instanceof LazyCompoundTag_1_15_2) {
|
||||
return ((LazyCompoundTag_1_15_2) foreign).get();
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
@Override
|
||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||
return new Regen_v1_15_R2(bukkitWorld, region, target, options).regenerate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_15_2(world, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalBiomeId(BiomeType biome) {
|
||||
BiomeBase base = CraftBlock.biomeToBiomeBase(BukkitAdapter.adapt(biome));
|
||||
return IRegistry.BIOME.a(base);
|
||||
}
|
||||
}
|
@ -1,452 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.BlockMaterial_1_16_1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.BukkitAdapter_1_16_1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.BukkitGetBlocks_1_16_1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.FAWEWorldNativeAccess_1_16_R1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.MapChunkUtil_1_16_1;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.nbt.LazyCompoundTag_1_16_1;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.regen.Regen_v1_16_R1;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
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.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.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.Block;
|
||||
import net.minecraft.server.v1_16_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R1.Entity;
|
||||
import net.minecraft.server.v1_16_R1.EntityPlayer;
|
||||
import net.minecraft.server.v1_16_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R1.IBlockData;
|
||||
import net.minecraft.server.v1_16_R1.IRegistry;
|
||||
import net.minecraft.server.v1_16_R1.ItemStack;
|
||||
import net.minecraft.server.v1_16_R1.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R1.NBTBase;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R1.TileEntity;
|
||||
import net.minecraft.server.v1_16_R1.World;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class FAWE_Spigot_v1_16_R1 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Spigot_v1_16_R1 parent;
|
||||
private char[] ibdToStateOrdinal;
|
||||
private int[] ordinalToIbdID;
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that may break between versions of Minecraft
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public FAWE_Spigot_v1_16_R1() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.parent = new Spigot_v1_16_R1();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitImplAdapter<NBTBase> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
|
||||
return false;
|
||||
}
|
||||
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
|
||||
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
|
||||
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
char ordinal = state.getOrdinalChar();
|
||||
ibdToStateOrdinal[id] = ordinal;
|
||||
ordinalToIbdID[ordinal] = id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
Block block = getBlock(blockType);
|
||||
return new BlockMaterial_1_16_1(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BlockMaterial getMaterial(BlockState state) {
|
||||
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new BlockMaterial_1_16_1(bs.getBlock(), bs);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
final WorldServer handle = craftWorld.getHandle();
|
||||
Chunk chunk = handle.getChunkAt(x >> 4, z >> 4);
|
||||
final BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
|
||||
// Read the NBT data
|
||||
TileEntity te = chunk.a(blockPos, Chunk.EnumTileEntityState.CHECK);
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
te.save(tag); // readTileEntityIntoTag - load data
|
||||
return state.toBaseBlock((CompoundTag) toNative(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> getSupportedSideEffects() {
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
Chunk nmsChunk = craftChunk.getHandle();
|
||||
World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
IBlockData blockData = ((BlockMaterial_1_16_1) state.getMaterial()).getState();
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
ChunkSection section = sections[y4];
|
||||
|
||||
IBlockData existing;
|
||||
if (section == null) {
|
||||
existing = ((BlockMaterial_1_16_1) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getType(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
|
||||
nmsChunk.removeTileEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundTag nativeTag = state instanceof BaseBlock ? ((BaseBlock)state).getNbtData() : null;
|
||||
if (nativeTag != null || existing instanceof TileEntityBlock) {
|
||||
nmsWorld.setTypeAndData(blockPos, blockData, 0);
|
||||
// remove tile
|
||||
if (nativeTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(blockPos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockData) {
|
||||
return true;
|
||||
}
|
||||
if (section == null) {
|
||||
if (blockData.isAir()) {
|
||||
return true;
|
||||
}
|
||||
sections[y4] = section = new ChunkSection(y4 << 4);
|
||||
}
|
||||
nmsChunk.setType(blockPos, blockData, false);
|
||||
}
|
||||
if (update) {
|
||||
nmsWorld.getMinecraftWorld().notify(blockPos, existing, blockData, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new FAWEWorldNativeAccess_1_16_R1(this,
|
||||
new WeakReference<>(((CraftWorld)world).getHandle()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
|
||||
return minecraftkey == null ? null : minecraftkey.toString();
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) {
|
||||
entity.save(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundTag> saveTag = () -> {
|
||||
final NBTTagCompound minecraftTag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, minecraftTag);
|
||||
//add Id for AbstractChangeSet to work
|
||||
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
|
||||
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
|
||||
tags.put("Id", new StringTag(id));
|
||||
return new CompoundTag(tags);
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichBlockName(BlockType blockType) {
|
||||
return parent.getRichBlockName(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(ItemType itemType) {
|
||||
return parent.getRichItemName(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(BaseItemStack itemStack) {
|
||||
return parent.getRichItemName(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) 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);
|
||||
IBlockData ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypesCache.states[adaptToChar(ibd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Method unused. Use #adaptToChar(IBlockData).
|
||||
*/
|
||||
@Deprecated
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToInt(ibd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char adaptToChar(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToChar(ibd);
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
|
||||
ibd.getBlock(), Block.REGISTRY_ID.getId(ibd), ibdToStateOrdinal.length, e1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int ordinalToIbdID(char ordinal) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
return ordinalToIbdID[ordinal];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return ordinalToIbdID(ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
|
||||
BlockMaterial_1_16_1 material = (BlockMaterial_1_16_1) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
private MapChunkUtil_1_16_1 mapUtil = new MapChunkUtil_1_16_1();
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||
PlayerChunk map = BukkitAdapter_1_16_1.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 = mapUtil.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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
|
||||
ItemStack stack = new ItemStack(IRegistry.ITEM.get(MinecraftKey.a(item.getType().getId())), item.getAmount());
|
||||
stack.setTag(((NBTTagCompound) fromNative(item.getNbtData())));
|
||||
return CraftItemStack.asCraftMirror(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
|
||||
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
|
||||
weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
|
||||
return weStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toNative(NBTBase foreign) {
|
||||
return parent.toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase fromNative(Tag foreign) {
|
||||
if (foreign instanceof LazyCompoundTag_1_16_1) {
|
||||
return ((LazyCompoundTag_1_16_1) foreign).get();
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||
return new Regen_v1_16_R1(bukkitWorld, region, target, options).regenerate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_16_1(world, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalBiomeId(BiomeType biome) {
|
||||
BiomeBase base = CraftBlock.biomeToBiomeBase(BukkitAdapter.adapt(biome));
|
||||
return IRegistry.BIOME.a(base);
|
||||
}
|
||||
}
|
@ -1,453 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.BlockMaterial_1_16_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.BukkitAdapter_1_16_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.BukkitGetBlocks_1_16_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.FAWEWorldNativeAccess_1_16_R2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.MapChunkUtil_1_16_2;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.nbt.LazyCompoundTag_1_16_2;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.regen.Regen_v1_16_R2;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
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.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.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.Block;
|
||||
import net.minecraft.server.v1_16_R2.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R2.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R2.Entity;
|
||||
import net.minecraft.server.v1_16_R2.EntityPlayer;
|
||||
import net.minecraft.server.v1_16_R2.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R2.IBlockData;
|
||||
import net.minecraft.server.v1_16_R2.IRegistry;
|
||||
import net.minecraft.server.v1_16_R2.ItemStack;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R2.NBTBase;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R2.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R2.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R2.TileEntity;
|
||||
import net.minecraft.server.v1_16_R2.World;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class FAWE_Spigot_v1_16_R2 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Spigot_v1_16_R2 parent;
|
||||
private char[] ibdToStateOrdinal;
|
||||
private int[] ordinalToIbdID;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that may break between versions of Minecraft
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public FAWE_Spigot_v1_16_R2() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.parent = new Spigot_v1_16_R2();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitImplAdapter<NBTBase> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
|
||||
return false;
|
||||
}
|
||||
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
|
||||
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
|
||||
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
BlockMaterial_1_16_2 material = (BlockMaterial_1_16_2) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
char ordinal = state.getOrdinalChar();
|
||||
ibdToStateOrdinal[id] = ordinal;
|
||||
ordinalToIbdID[ordinal] = id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
Block block = getBlock(blockType);
|
||||
return new BlockMaterial_1_16_2(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BlockMaterial getMaterial(BlockState state) {
|
||||
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new BlockMaterial_1_16_2(bs.getBlock(), bs);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
final WorldServer handle = craftWorld.getHandle();
|
||||
Chunk chunk = handle.getChunkAt(x >> 4, z >> 4);
|
||||
final BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
|
||||
// Read the NBT data
|
||||
TileEntity te = chunk.a(blockPos, Chunk.EnumTileEntityState.CHECK);
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
te.save(tag); // readTileEntityIntoTag - load data
|
||||
return state.toBaseBlock((CompoundTag) toNative(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> getSupportedSideEffects() {
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
Chunk nmsChunk = craftChunk.getHandle();
|
||||
World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
IBlockData blockData = ((BlockMaterial_1_16_2) state.getMaterial()).getState();
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
ChunkSection section = sections[y4];
|
||||
|
||||
IBlockData existing;
|
||||
if (section == null) {
|
||||
existing = ((BlockMaterial_1_16_2) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getType(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
|
||||
nmsChunk.removeTileEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundTag nativeTag = state instanceof BaseBlock ? ((BaseBlock)state).getNbtData() : null;
|
||||
if (nativeTag != null || existing instanceof TileEntityBlock) {
|
||||
nmsWorld.setTypeAndData(blockPos, blockData, 0);
|
||||
// remove tile
|
||||
if (nativeTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(blockPos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockData) {
|
||||
return true;
|
||||
}
|
||||
if (section == null) {
|
||||
if (blockData.isAir()) {
|
||||
return true;
|
||||
}
|
||||
sections[y4] = section = new ChunkSection(y4 << 4);
|
||||
}
|
||||
nmsChunk.setType(blockPos, blockData, false);
|
||||
}
|
||||
if (update) {
|
||||
nmsWorld.getMinecraftWorld().notify(blockPos, existing, blockData, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new FAWEWorldNativeAccess_1_16_R2(this,
|
||||
new WeakReference<>(((CraftWorld)world).getHandle()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
|
||||
return minecraftkey == null ? null : minecraftkey.toString();
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) {
|
||||
entity.save(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundTag> saveTag = () -> {
|
||||
final NBTTagCompound minecraftTag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, minecraftTag);
|
||||
//add Id for AbstractChangeSet to work
|
||||
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
|
||||
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
|
||||
tags.put("Id", new StringTag(id));
|
||||
return new CompoundTag(tags);
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichBlockName(BlockType blockType) {
|
||||
return parent.getRichBlockName(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(ItemType itemType) {
|
||||
return parent.getRichItemName(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(BaseItemStack itemStack) {
|
||||
return parent.getRichItemName(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
BlockMaterial_1_16_2 material = (BlockMaterial_1_16_2) 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);
|
||||
IBlockData ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypesCache.states[adaptToChar(ibd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Method unused. Use #adaptToChar(IBlockData).
|
||||
*/
|
||||
@Deprecated
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToInt(ibd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char adaptToChar(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToChar(ibd);
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
|
||||
ibd.getBlock(), Block.REGISTRY_ID.getId(ibd), ibdToStateOrdinal.length, e1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
public int ordinalToIbdID(char ordinal) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
return ordinalToIbdID[ordinal];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return ordinalToIbdID(ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
|
||||
BlockMaterial_1_16_2 material = (BlockMaterial_1_16_2) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
private MapChunkUtil_1_16_2 mapUtil = new MapChunkUtil_1_16_2();
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||
PlayerChunk map = BukkitAdapter_1_16_2.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 = mapUtil.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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
|
||||
ItemStack stack = new ItemStack(IRegistry.ITEM.get(MinecraftKey.a(item.getType().getId())), item.getAmount());
|
||||
stack.setTag(((NBTTagCompound) fromNative(item.getNbtData())));
|
||||
return CraftItemStack.asCraftMirror(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
|
||||
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
|
||||
weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
|
||||
return weStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toNative(NBTBase foreign) {
|
||||
return parent.toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase fromNative(Tag foreign) {
|
||||
if (foreign instanceof LazyCompoundTag_1_16_2) {
|
||||
return ((LazyCompoundTag_1_16_2) foreign).get();
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||
return new Regen_v1_16_R2(bukkitWorld, region, target, options).regenerate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_16_2(world, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalBiomeId(BiomeType biome) {
|
||||
BiomeBase base = CraftBlock.biomeToBiomeBase(MinecraftServer.getServer().getCustomRegistry().b(IRegistry.ay), BukkitAdapter.adapt(biome));
|
||||
return MinecraftServer.getServer().getCustomRegistry().b(IRegistry.ay).a(base);
|
||||
}
|
||||
}
|
@ -1,454 +0,0 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.BlockMaterial_1_16_5;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.BukkitAdapter_1_16_5;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.BukkitGetBlocks_1_16_5;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.FAWEWorldNativeAccess_1_16_R3;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.MapChunkUtil_1_16_5;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_5.nbt.LazyCompoundTag_1_16_5;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.blocks.TileEntityBlock;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.CachedBukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.IDelegateBukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.regen.Regen_v1_16_R3;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.LazyBaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.util.SideEffect;
|
||||
import com.sk89q.worldedit.util.SideEffectSet;
|
||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
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.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.item.ItemType;
|
||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||
import net.minecraft.server.v1_16_R3.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R3.Block;
|
||||
import net.minecraft.server.v1_16_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_16_R3.Chunk;
|
||||
import net.minecraft.server.v1_16_R3.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R3.ChunkSection;
|
||||
import net.minecraft.server.v1_16_R3.Entity;
|
||||
import net.minecraft.server.v1_16_R3.EntityPlayer;
|
||||
import net.minecraft.server.v1_16_R3.EntityTypes;
|
||||
import net.minecraft.server.v1_16_R3.IBlockData;
|
||||
import net.minecraft.server.v1_16_R3.IRegistry;
|
||||
import net.minecraft.server.v1_16_R3.ItemStack;
|
||||
import net.minecraft.server.v1_16_R3.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R3.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R3.NBTBase;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R3.NBTTagInt;
|
||||
import net.minecraft.server.v1_16_R3.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_16_R3.PlayerChunk;
|
||||
import net.minecraft.server.v1_16_R3.TileEntity;
|
||||
import net.minecraft.server.v1_16_R3.World;
|
||||
import net.minecraft.server.v1_16_R3.WorldServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public final class FAWE_Spigot_v1_16_R3 extends CachedBukkitAdapter implements IDelegateBukkitImplAdapter<NBTBase> {
|
||||
|
||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||
|
||||
private final Spigot_v1_16_R3 parent;
|
||||
private char[] ibdToStateOrdinal;
|
||||
private int[] ordinalToIbdID;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Code that may break between versions of Minecraft
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
public FAWE_Spigot_v1_16_R3() throws NoSuchFieldException, NoSuchMethodException {
|
||||
this.parent = new Spigot_v1_16_R3();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitImplAdapter<NBTBase> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
private synchronized boolean init() {
|
||||
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
|
||||
return false;
|
||||
}
|
||||
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
|
||||
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
|
||||
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
|
||||
BlockState state = BlockTypesCache.states[i];
|
||||
BlockMaterial_1_16_5 material = (BlockMaterial_1_16_5) state.getMaterial();
|
||||
int id = Block.REGISTRY_ID.getId(material.getState());
|
||||
char ordinal = state.getOrdinalChar();
|
||||
ibdToStateOrdinal[id] = ordinal;
|
||||
ordinalToIbdID[ordinal] = id;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockMaterial getMaterial(BlockType blockType) {
|
||||
Block block = getBlock(blockType);
|
||||
return new BlockMaterial_1_16_5(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized BlockMaterial getMaterial(BlockState state) {
|
||||
IBlockData bs = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
|
||||
return new BlockMaterial_1_16_5(bs.getBlock(), bs);
|
||||
}
|
||||
|
||||
public Block getBlock(BlockType blockType) {
|
||||
return IRegistry.BLOCK.get(new MinecraftKey(blockType.getNamespace(), blockType.getResource()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public BaseBlock getBlock(Location location) {
|
||||
Preconditions.checkNotNull(location);
|
||||
|
||||
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
|
||||
int x = location.getBlockX();
|
||||
int y = location.getBlockY();
|
||||
int z = location.getBlockZ();
|
||||
|
||||
final WorldServer handle = craftWorld.getHandle();
|
||||
Chunk chunk = handle.getChunkAt(x >> 4, z >> 4);
|
||||
final BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
org.bukkit.block.Block bukkitBlock = location.getBlock();
|
||||
BlockState state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
|
||||
if (state.getBlockType().getMaterial().hasContainer()) {
|
||||
|
||||
// Read the NBT data
|
||||
TileEntity te = chunk.a(blockPos, Chunk.EnumTileEntityState.CHECK);
|
||||
if (te != null) {
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
te.save(tag); // readTileEntityIntoTag - load data
|
||||
return state.toBaseBlock((CompoundTag) toNative(tag));
|
||||
}
|
||||
}
|
||||
|
||||
return state.toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SideEffect> getSupportedSideEffects() {
|
||||
return SideEffectSet.defaults().getSideEffectsToApply();
|
||||
}
|
||||
|
||||
public boolean setBlock(org.bukkit.Chunk chunk, int x, int y, int z, BlockStateHolder state, boolean update) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk;
|
||||
Chunk nmsChunk = craftChunk.getHandle();
|
||||
World nmsWorld = nmsChunk.getWorld();
|
||||
|
||||
BlockPosition blockPos = new BlockPosition(x, y, z);
|
||||
IBlockData blockData = ((BlockMaterial_1_16_5) state.getMaterial()).getState();
|
||||
ChunkSection[] sections = nmsChunk.getSections();
|
||||
int y4 = y >> 4;
|
||||
ChunkSection section = sections[y4];
|
||||
|
||||
IBlockData existing;
|
||||
if (section == null) {
|
||||
existing = ((BlockMaterial_1_16_5) BlockTypes.AIR.getDefaultState().getMaterial()).getState();
|
||||
} else {
|
||||
existing = section.getType(x & 15, y & 15, z & 15);
|
||||
}
|
||||
|
||||
|
||||
nmsChunk.removeTileEntity(blockPos); // Force delete the old tile entity
|
||||
|
||||
CompoundTag nativeTag = state instanceof BaseBlock ? ((BaseBlock)state).getNbtData() : null;
|
||||
if (nativeTag != null || existing instanceof TileEntityBlock) {
|
||||
nmsWorld.setTypeAndData(blockPos, blockData, 0);
|
||||
// remove tile
|
||||
if (nativeTag != null) {
|
||||
// We will assume that the tile entity was created for us,
|
||||
// though we do not do this on the Forge version
|
||||
TileEntity tileEntity = nmsWorld.getTileEntity(blockPos);
|
||||
if (tileEntity != null) {
|
||||
NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag);
|
||||
tag.set("x", NBTTagInt.a(x));
|
||||
tag.set("y", NBTTagInt.a(y));
|
||||
tag.set("z", NBTTagInt.a(z));
|
||||
tileEntity.load(tileEntity.getBlock(), tag); // readTagIntoTileEntity - load data
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (existing == blockData) {
|
||||
return true;
|
||||
}
|
||||
if (section == null) {
|
||||
if (blockData.isAir()) {
|
||||
return true;
|
||||
}
|
||||
sections[y4] = section = new ChunkSection(y4 << 4);
|
||||
}
|
||||
nmsChunk.setType(blockPos, blockData, false);
|
||||
}
|
||||
if (update) {
|
||||
nmsWorld.getMinecraftWorld().notify(blockPos, existing, blockData, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
|
||||
return new FAWEWorldNativeAccess_1_16_R3(this,
|
||||
new WeakReference<>(((CraftWorld)world).getHandle()));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getEntityId(Entity entity) {
|
||||
MinecraftKey minecraftkey = EntityTypes.getName(entity.getEntityType());
|
||||
return minecraftkey == null ? null : minecraftkey.toString();
|
||||
}
|
||||
|
||||
private static void readEntityIntoTag(Entity entity, NBTTagCompound tag) {
|
||||
entity.save(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
|
||||
Preconditions.checkNotNull(entity);
|
||||
|
||||
CraftEntity craftEntity = ((CraftEntity) entity);
|
||||
Entity mcEntity = craftEntity.getHandle();
|
||||
|
||||
String id = getEntityId(mcEntity);
|
||||
|
||||
if (id != null) {
|
||||
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
|
||||
Supplier<CompoundTag> saveTag = () -> {
|
||||
final NBTTagCompound minecraftTag = new NBTTagCompound();
|
||||
readEntityIntoTag(mcEntity, minecraftTag);
|
||||
//add Id for AbstractChangeSet to work
|
||||
final CompoundTag tag = (CompoundTag) toNative(minecraftTag);
|
||||
final Map<String, Tag> tags = new HashMap<>(tag.getValue());
|
||||
tags.put("Id", new StringTag(id));
|
||||
return new CompoundTag(tags);
|
||||
};
|
||||
return new LazyBaseEntity(type, saveTag);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichBlockName(BlockType blockType) {
|
||||
return parent.getRichBlockName(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(ItemType itemType) {
|
||||
return parent.getRichItemName(itemType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getRichItemName(BaseItemStack itemStack) {
|
||||
return parent.getRichItemName(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OptionalInt getInternalBlockStateId(BlockState state) {
|
||||
BlockMaterial_1_16_5 material = (BlockMaterial_1_16_5) 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);
|
||||
IBlockData ibd = cbd.getState();
|
||||
return adapt(ibd);
|
||||
}
|
||||
|
||||
public BlockState adapt(IBlockData ibd) {
|
||||
return BlockTypesCache.states[adaptToChar(ibd)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Method unused. Use #adaptToChar(IBlockData).
|
||||
*/
|
||||
@Deprecated
|
||||
public int adaptToInt(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToInt(ibd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public char adaptToChar(IBlockData ibd) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
int id = Block.REGISTRY_ID.getId(ibd);
|
||||
return ibdToStateOrdinal[id];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return adaptToChar(ibd);
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
|
||||
ibd.getBlock(), Block.REGISTRY_ID.getId(ibd), ibdToStateOrdinal.length, e1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int ordinalToIbdID(char ordinal) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
return ordinalToIbdID[ordinal];
|
||||
} catch (NullPointerException e) {
|
||||
init();
|
||||
return ordinalToIbdID(ordinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
|
||||
BlockMaterial_1_16_5 material = (BlockMaterial_1_16_5) state.getMaterial();
|
||||
return material.getCraftBlockData();
|
||||
}
|
||||
|
||||
private MapChunkUtil_1_16_5 mapUtil = new MapChunkUtil_1_16_5();
|
||||
|
||||
@Override
|
||||
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket packet) {
|
||||
WorldServer nmsWorld = ((CraftWorld) world).getHandle();
|
||||
PlayerChunk map = BukkitAdapter_1_16_5.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 = mapUtil.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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
|
||||
return getParent().getProperties(blockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
|
||||
ItemStack stack = new ItemStack(IRegistry.ITEM.get(MinecraftKey.a(item.getType().getId())), item.getAmount());
|
||||
stack.setTag(((NBTTagCompound) fromNative(item.getNbtData())));
|
||||
return CraftItemStack.asCraftMirror(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
|
||||
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
|
||||
final BaseItemStack weStack = new BaseItemStack(BukkitAdapter.asItemType(itemStack.getType()), itemStack.getAmount());
|
||||
weStack.setNbtData(((CompoundTag) toNative(nmsStack.getTag())));
|
||||
return weStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag toNative(NBTBase foreign) {
|
||||
return parent.toNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase fromNative(Tag foreign) {
|
||||
if (foreign instanceof LazyCompoundTag_1_16_5) {
|
||||
return ((LazyCompoundTag_1_16_5) foreign).get();
|
||||
}
|
||||
return parent.fromNative(foreign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||
return new Regen_v1_16_R3(bukkitWorld, region, target, options).regenerate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
|
||||
return new BukkitGetBlocks_1_16_5(world, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInternalBiomeId(BiomeType biome) {
|
||||
BiomeBase base = CraftBlock.biomeToBiomeBase(MinecraftServer.getServer().getCustomRegistry().b(IRegistry.ay), BukkitAdapter.adapt(biome));
|
||||
return MinecraftServer.getServer().getCustomRegistry().b(IRegistry.ay).a(base);
|
||||
}
|
||||
}
|
@ -1,513 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.regen;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_15_2.BukkitGetBlocks_1_15_2;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Regenerator;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.server.v1_15_R1.Area;
|
||||
import net.minecraft.server.v1_15_R1.AreaContextTransformed;
|
||||
import net.minecraft.server.v1_15_R1.AreaFactory;
|
||||
import net.minecraft.server.v1_15_R1.AreaTransformer8;
|
||||
import net.minecraft.server.v1_15_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_15_R1.BiomeLayoutOverworldConfiguration;
|
||||
import net.minecraft.server.v1_15_R1.Biomes;
|
||||
import net.minecraft.server.v1_15_R1.Chunk;
|
||||
import net.minecraft.server.v1_15_R1.ChunkConverter;
|
||||
import net.minecraft.server.v1_15_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_15_R1.ChunkGenerator;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderFlat;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderGenerate;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderHell;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_15_R1.ChunkProviderTheEnd;
|
||||
import net.minecraft.server.v1_15_R1.ChunkStatus;
|
||||
import net.minecraft.server.v1_15_R1.DefinedStructureManager;
|
||||
import net.minecraft.server.v1_15_R1.GenLayer;
|
||||
import net.minecraft.server.v1_15_R1.GenLayers;
|
||||
import net.minecraft.server.v1_15_R1.GeneratorSettingsEnd;
|
||||
import net.minecraft.server.v1_15_R1.GeneratorSettingsFlat;
|
||||
import net.minecraft.server.v1_15_R1.GeneratorSettingsNether;
|
||||
import net.minecraft.server.v1_15_R1.GeneratorSettingsOverworld;
|
||||
import net.minecraft.server.v1_15_R1.IChunkAccess;
|
||||
import net.minecraft.server.v1_15_R1.IRegistry;
|
||||
import net.minecraft.server.v1_15_R1.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_15_R1.LinearCongruentialGenerator;
|
||||
import net.minecraft.server.v1_15_R1.MinecraftKey;
|
||||
import net.minecraft.server.v1_15_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_15_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_15_R1.NoiseGeneratorPerlin;
|
||||
import net.minecraft.server.v1_15_R1.ProtoChunk;
|
||||
import net.minecraft.server.v1_15_R1.World;
|
||||
import net.minecraft.server.v1_15_R1.WorldChunkManager;
|
||||
import net.minecraft.server.v1_15_R1.WorldChunkManagerOverworld;
|
||||
import net.minecraft.server.v1_15_R1.WorldData;
|
||||
import net.minecraft.server.v1_15_R1.WorldLoadListener;
|
||||
import net.minecraft.server.v1_15_R1.WorldNBTStorage;
|
||||
import net.minecraft.server.v1_15_R1.WorldServer;
|
||||
import net.minecraft.server.v1_15_R1.WorldType;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.generator.CustomChunkGenerator;
|
||||
import org.bukkit.craftbukkit.v1_15_R1.util.CraftMagicNumbers;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
public class Regen_v1_15_R2 extends Regenerator<IChunkAccess, ProtoChunk, Chunk, Regen_v1_15_R2.ChunkStatusWrap> {
|
||||
|
||||
private static final Field serverWorldsField;
|
||||
private static final Field worldPaperConfigField;
|
||||
private static final Field flatBedrockField;
|
||||
private static final Field delegateField;
|
||||
private static final Field chunkProviderField;
|
||||
|
||||
//list of chunk stati in correct order without FULL
|
||||
private static final Map<ChunkStatus, Regenerator.Concurrency> chunkStati = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
chunkStati.put(ChunkStatus.EMPTY, Regenerator.Concurrency.FULL); // radius -1, does nothing
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_REFERENCES, Regenerator.Concurrency.FULL); // radius 8, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.BIOMES, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.NOISE, Regenerator.Concurrency.RADIUS); // radius 8
|
||||
chunkStati.put(ChunkStatus.SURFACE, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.LIQUID_CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.FEATURES, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.LIGHT, Regenerator.Concurrency.FULL); // radius 1, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.SPAWN, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.HEIGHTMAPS, Regenerator.Concurrency.FULL); // radius 0
|
||||
|
||||
try {
|
||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||
serverWorldsField.setAccessible(true);
|
||||
|
||||
Field tmpPaperConfigField = null;
|
||||
Field tmpFlatBedrockField = null;
|
||||
try { //only present on paper
|
||||
tmpPaperConfigField = World.class.getDeclaredField("paperConfig");
|
||||
tmpPaperConfigField.setAccessible(true);
|
||||
|
||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
||||
tmpFlatBedrockField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
tmpPaperConfigField = null;
|
||||
tmpFlatBedrockField = null;
|
||||
}
|
||||
worldPaperConfigField = tmpPaperConfigField;
|
||||
flatBedrockField = tmpFlatBedrockField;
|
||||
|
||||
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
|
||||
chunkProviderField = World.class.getDeclaredField("chunkProvider");
|
||||
chunkProviderField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//runtime
|
||||
private WorldServer originalNMSWorld;
|
||||
private ChunkProviderServer originalChunkProvider;
|
||||
private WorldServer freshNMSWorld;
|
||||
private ChunkProviderServer freshChunkProvider;
|
||||
private DefinedStructureManager structureManager;
|
||||
private LightEngineThreaded lightEngine;
|
||||
private ChunkGenerator generator;
|
||||
|
||||
private Path tempDir;
|
||||
|
||||
private boolean generateFlatBedrock = false;
|
||||
|
||||
public Regen_v1_15_R2(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
||||
super(originalBukkitWorld, region, target, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean prepare() {
|
||||
this.originalNMSWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
||||
originalChunkProvider = originalNMSWorld.getChunkProvider();
|
||||
if (!(originalChunkProvider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//flat bedrock? (only on paper)
|
||||
try {
|
||||
generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalNMSWorld));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
seed = options.getSeed().orElse(originalNMSWorld.getSeed());
|
||||
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initNewWorld() throws Exception {
|
||||
//world folder
|
||||
tempDir = java.nio.file.Files.createTempDirectory("WorldEditWorldGen");
|
||||
|
||||
//prepare for world init (see upstream implementation for reference)
|
||||
org.bukkit.World.Environment env = originalBukkitWorld.getEnvironment();
|
||||
org.bukkit.generator.ChunkGenerator gen = originalBukkitWorld.getGenerator();
|
||||
|
||||
MinecraftServer server = originalNMSWorld.getServer().getServer();
|
||||
WorldData newWorldData = new WorldData(originalNMSWorld.worldData.a((NBTTagCompound) null), server.dataConverterManager, CraftMagicNumbers.INSTANCE.getDataVersion(), (NBTTagCompound) null);
|
||||
newWorldData.setName("worldeditregentempworld");
|
||||
WorldNBTStorage saveHandler = new WorldNBTStorage(new File(tempDir.toUri()), originalNMSWorld.getDataManager().getDirectory().getName(), server, server.dataConverterManager);
|
||||
|
||||
//init world
|
||||
freshNMSWorld = Fawe.get().getQueueHandler().sync((Supplier<WorldServer>) () -> new WorldServer(server, server.executorService, saveHandler, newWorldData, originalNMSWorld.worldProvider.getDimensionManager(), originalNMSWorld.getMethodProfiler(), new RegenNoOpWorldLoadListener(), env, gen) {
|
||||
@Override
|
||||
public void doTick(BooleanSupplier booleansupplier) { //no ticking
|
||||
}
|
||||
|
||||
private final BiomeBase singleBiome = options.hasBiomeType() ? IRegistry.BIOME.get(MinecraftKey.a(options.getBiomeType().getId())) : null;
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int i, int k, int j) {
|
||||
if (options.hasBiomeType()) {
|
||||
return singleBiome;
|
||||
}
|
||||
return this.getChunkProvider().getChunkGenerator().getWorldChunkManager().getBiome(i, j, k);
|
||||
}
|
||||
}).get();
|
||||
freshNMSWorld.savingDisabled = true;
|
||||
removeWorldFromWorldsMap();
|
||||
newWorldData.checkName(originalNMSWorld.getWorldData().getName()); //rename to original world name
|
||||
|
||||
try { //flat bedrock (paper only)
|
||||
Object paperconf = worldPaperConfigField.get(freshNMSWorld);
|
||||
flatBedrockField.setBoolean(paperconf, generateFlatBedrock);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
DefinedStructureManager tmpStructureManager = saveHandler.f();
|
||||
freshChunkProvider = new ChunkProviderServer(freshNMSWorld, saveHandler.getDirectory(), server.aC(), tmpStructureManager, server.executorService, originalChunkProvider.chunkGenerator, freshNMSWorld.spigotConfig.viewDistance, new RegenNoOpWorldLoadListener(), () -> freshNMSWorld.getWorldPersistentData()) {
|
||||
// redirect to our protoChunks list
|
||||
@Override
|
||||
public IChunkAccess getChunkAt(int x, int z, ChunkStatus chunkstatus, boolean flag) {
|
||||
return getProtoChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
chunkProviderField.set(freshNMSWorld, freshChunkProvider);
|
||||
|
||||
//generator
|
||||
if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderFlat) {
|
||||
GeneratorSettingsFlat generatorSettingFlat = (GeneratorSettingsFlat) originalChunkProvider.getChunkGenerator().getSettings();
|
||||
generator = new ChunkProviderFlat(freshNMSWorld, originalChunkProvider.getChunkGenerator().getWorldChunkManager(), generatorSettingFlat);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderGenerate) { //overworld
|
||||
GeneratorSettingsOverworld settings = (GeneratorSettingsOverworld) originalChunkProvider.getChunkGenerator().getSettings();
|
||||
WorldChunkManager chunkManager = originalChunkProvider.getChunkGenerator().getWorldChunkManager();
|
||||
if (chunkManager instanceof WorldChunkManagerOverworld) { //should always be true
|
||||
chunkManager = fastOverWorldChunkManager(chunkManager);
|
||||
}
|
||||
generator = new ChunkProviderGenerate(freshNMSWorld, chunkManager, settings);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderHell) { //nether
|
||||
GeneratorSettingsNether settings = (GeneratorSettingsNether) originalChunkProvider.getChunkGenerator().getSettings();
|
||||
generator = new ChunkProviderHell(freshNMSWorld, originalChunkProvider.getChunkGenerator().getWorldChunkManager(), settings);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderTheEnd) { //end
|
||||
GeneratorSettingsEnd settings = (GeneratorSettingsEnd) originalChunkProvider.getChunkGenerator().getSettings();
|
||||
generator = new ChunkProviderTheEnd(freshNMSWorld, originalChunkProvider.getChunkGenerator().getWorldChunkManager(), settings);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof CustomChunkGenerator) {
|
||||
ChunkGenerator delegate = (ChunkGenerator) delegateField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = delegate;
|
||||
} else {
|
||||
System.out.println("Unsupported generator type " + originalChunkProvider.getChunkGenerator().getClass().getName());
|
||||
return false;
|
||||
}
|
||||
if (originalNMSWorld.generator != null) {
|
||||
// wrap custom world generator
|
||||
generator = new CustomChunkGenerator(freshNMSWorld, originalNMSWorld.generator);
|
||||
generateConcurrent = originalNMSWorld.generator.isParallelCapable();
|
||||
}
|
||||
|
||||
//lets start then
|
||||
structureManager = tmpStructureManager;
|
||||
lightEngine = freshChunkProvider.getLightEngine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup() {
|
||||
//shutdown chunk provider
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
freshChunkProvider.close(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//remove world from server
|
||||
try {
|
||||
removeWorldFromWorldsMap();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//delete directory
|
||||
try {
|
||||
SafeFiles.tryHardToDeleteDir(tempDir);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtoChunk createProtoChunk(int x, int z) {
|
||||
return new ProtoChunk(new ChunkCoordIntPair(x, z), ChunkConverter.a) {
|
||||
public boolean generateFlatBedrock() {
|
||||
return generateFlatBedrock;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Chunk createChunk(ProtoChunk protoChunk) {
|
||||
return new Chunk(freshNMSWorld, protoChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChunkStatusWrap getFullChunkStatus() {
|
||||
return new ChunkStatusWrap(ChunkStatus.FULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BlockPopulator> getBlockPopulators() {
|
||||
return originalNMSWorld.getWorld().getPopulators();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(Chunk chunk, Random random, BlockPopulator pop) {
|
||||
pop.populate(freshNMSWorld.getWorld(), random, chunk.bukkitChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||
return (chunkX, chunkZ) -> new BukkitGetBlocks_1_15_2(freshNMSWorld, chunkX, chunkZ) {
|
||||
@Override
|
||||
public Chunk ensureLoaded(World nmsWorld, int x, int z) {
|
||||
return getChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected class ChunkStatusWrap extends Regenerator.ChunkStatusWrapper<IChunkAccess> {
|
||||
|
||||
private final ChunkStatus chunkStatus;
|
||||
|
||||
public ChunkStatusWrap(ChunkStatus chunkStatus) {
|
||||
this.chunkStatus = chunkStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int requiredNeigborChunkRadius() {
|
||||
return chunkStatus.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return chunkStatus.d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processChunk(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||
chunkStatus.a(freshNMSWorld,
|
||||
generator,
|
||||
structureManager,
|
||||
lightEngine,
|
||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
||||
accessibleChunks);
|
||||
}
|
||||
}
|
||||
|
||||
//util
|
||||
private void removeWorldFromWorldsMap() {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
||||
map.remove("worldeditregentempworld");
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private WorldChunkManager fastOverWorldChunkManager(WorldChunkManager chunkManager) throws Exception {
|
||||
Field genLayerField = WorldChunkManagerOverworld.class.getDeclaredField("d");
|
||||
genLayerField.setAccessible(true);
|
||||
Field areaLazyField = GenLayer.class.getDeclaredField("b");
|
||||
areaLazyField.setAccessible(true);
|
||||
Method initAreaFactoryMethod = GenLayers.class.getDeclaredMethod("a", WorldType.class, GeneratorSettingsOverworld.class, LongFunction.class);
|
||||
initAreaFactoryMethod.setAccessible(true);
|
||||
|
||||
//init new WorldChunkManagerOverworld
|
||||
BiomeLayoutOverworldConfiguration biomeconfig = new BiomeLayoutOverworldConfiguration(freshNMSWorld.getWorldData())
|
||||
.a((GeneratorSettingsOverworld) originalChunkProvider.getChunkGenerator().getSettings());
|
||||
AreaFactory<FastAreaLazy> factory = (AreaFactory<FastAreaLazy>) initAreaFactoryMethod.invoke(null, biomeconfig.b(), biomeconfig.c(), (LongFunction) (l -> new FastWorldGenContextArea(seed, l)));
|
||||
if (options.hasBiomeType()) {
|
||||
BiomeBase biome = IRegistry.BIOME.get(MinecraftKey.a(options.getBiomeType().getId()));
|
||||
chunkManager = new SingleBiomeWorldChunkManagerOverworld(biome);
|
||||
} else {
|
||||
chunkManager = new WorldChunkManagerOverworld(biomeconfig);
|
||||
//replace genlayer
|
||||
genLayerField.set(chunkManager, new FastGenLayer(factory));
|
||||
}
|
||||
|
||||
return chunkManager;
|
||||
}
|
||||
|
||||
private static class SingleBiomeWorldChunkManagerOverworld extends WorldChunkManager {
|
||||
|
||||
private final BiomeBase biome;
|
||||
|
||||
public SingleBiomeWorldChunkManagerOverworld(BiomeBase biome) {
|
||||
super(ImmutableSet.of(biome));
|
||||
this.biome = biome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase getBiome(int i, int i1, int i2) {
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastWorldGenContextArea implements AreaContextTransformed<FastAreaLazy> {
|
||||
|
||||
private final ConcurrentHashMap<Long, Integer> sharedAreaMap = new ConcurrentHashMap<>();
|
||||
private final NoiseGeneratorPerlin perlinNoise;
|
||||
private final long magicrandom;
|
||||
private final ConcurrentHashMap<Long, Long> map = new ConcurrentHashMap<>(); //needed for multithreaded generation
|
||||
|
||||
public FastWorldGenContextArea(long seed, long lconst) {
|
||||
this.magicrandom = mix(seed, lconst);
|
||||
this.perlinNoise = new NoiseGeneratorPerlin(new Random(seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastAreaLazy a(AreaTransformer8 var0) {
|
||||
return new FastAreaLazy(sharedAreaMap, var0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(long x, long z) {
|
||||
long l = this.magicrandom;
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
this.map.put(Thread.currentThread().getId(), l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int y) {
|
||||
long tid = Thread.currentThread().getId();
|
||||
long e = this.map.computeIfAbsent(tid, i -> 0L);
|
||||
int mod = (int) Math.floorMod(e >> 24L, (long) y);
|
||||
this.map.put(tid, LinearCongruentialGenerator.a(e, this.magicrandom));
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoiseGeneratorPerlin b() {
|
||||
return this.perlinNoise;
|
||||
}
|
||||
|
||||
private static long mix(long seed, long lconst) {
|
||||
long l1 = lconst;
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
long l2 = seed;
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
return l2;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastGenLayer extends GenLayer {
|
||||
|
||||
private final FastAreaLazy areaLazy;
|
||||
|
||||
public FastGenLayer(AreaFactory<FastAreaLazy> factory) throws Exception {
|
||||
super(() -> null);
|
||||
this.areaLazy = factory.make();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int x, int z) {
|
||||
BiomeBase biome = IRegistry.BIOME.fromId(this.areaLazy.a(x, z));
|
||||
if (biome == null)
|
||||
return Biomes.b;
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastAreaLazy implements Area {
|
||||
|
||||
private final AreaTransformer8 transformer;
|
||||
//ConcurrentHashMap is 50% faster that Long2IntLinkedOpenHashMap in a syncronized context
|
||||
//using a map for each thread worsens the performance significantly due to cache misses (factor 5)
|
||||
private final ConcurrentHashMap<Long, Integer> sharedMap;
|
||||
|
||||
public FastAreaLazy(ConcurrentHashMap<Long, Integer> sharedMap, AreaTransformer8 transformer) {
|
||||
this.sharedMap = sharedMap;
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int x, int z) {
|
||||
long zx = ChunkCoordIntPair.pair(x, z);
|
||||
return this.sharedMap.computeIfAbsent(zx, i -> this.transformer.apply(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegenNoOpWorldLoadListener implements WorldLoadListener {
|
||||
|
||||
private RegenNoOpWorldLoadListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair, @Nullable ChunkStatus chunkStatus) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkRadius(int i) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,559 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.regen;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_1.BukkitGetBlocks_1_16_1;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Regenerator;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.server.v1_16_R1.Area;
|
||||
import net.minecraft.server.v1_16_R1.AreaContextTransformed;
|
||||
import net.minecraft.server.v1_16_R1.AreaFactory;
|
||||
import net.minecraft.server.v1_16_R1.AreaTransformer8;
|
||||
import net.minecraft.server.v1_16_R1.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R1.Biomes;
|
||||
import net.minecraft.server.v1_16_R1.Chunk;
|
||||
import net.minecraft.server.v1_16_R1.ChunkConverter;
|
||||
import net.minecraft.server.v1_16_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R1.ChunkGenerator;
|
||||
import net.minecraft.server.v1_16_R1.ChunkGeneratorAbstract;
|
||||
import net.minecraft.server.v1_16_R1.ChunkProviderFlat;
|
||||
import net.minecraft.server.v1_16_R1.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R1.ChunkStatus;
|
||||
import net.minecraft.server.v1_16_R1.Convertable;
|
||||
import net.minecraft.server.v1_16_R1.DefinedStructureManager;
|
||||
import net.minecraft.server.v1_16_R1.DynamicOpsNBT;
|
||||
import net.minecraft.server.v1_16_R1.GenLayer;
|
||||
import net.minecraft.server.v1_16_R1.GenLayers;
|
||||
import net.minecraft.server.v1_16_R1.GeneratorSettingBase;
|
||||
import net.minecraft.server.v1_16_R1.GeneratorSettings;
|
||||
import net.minecraft.server.v1_16_R1.GeneratorSettingsFlat;
|
||||
import net.minecraft.server.v1_16_R1.IChunkAccess;
|
||||
import net.minecraft.server.v1_16_R1.IRegistry;
|
||||
import net.minecraft.server.v1_16_R1.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_16_R1.LinearCongruentialGenerator;
|
||||
import net.minecraft.server.v1_16_R1.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R1.NBTBase;
|
||||
import net.minecraft.server.v1_16_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R1.NoiseGeneratorPerlin;
|
||||
import net.minecraft.server.v1_16_R1.ProtoChunk;
|
||||
import net.minecraft.server.v1_16_R1.ResourceKey;
|
||||
import net.minecraft.server.v1_16_R1.World;
|
||||
import net.minecraft.server.v1_16_R1.WorldChunkManager;
|
||||
import net.minecraft.server.v1_16_R1.WorldChunkManagerOverworld;
|
||||
import net.minecraft.server.v1_16_R1.WorldDataServer;
|
||||
import net.minecraft.server.v1_16_R1.WorldDimension;
|
||||
import net.minecraft.server.v1_16_R1.WorldLoadListener;
|
||||
import net.minecraft.server.v1_16_R1.WorldServer;
|
||||
import net.minecraft.server.v1_16_R1.WorldSettings;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R1.generator.CustomChunkGenerator;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
public class Regen_v1_16_R1 extends Regenerator<IChunkAccess, ProtoChunk, Chunk, Regen_v1_16_R1.ChunkStatusWrap> {
|
||||
|
||||
private static final Field serverWorldsField;
|
||||
private static final Field worldPaperConfigField;
|
||||
private static final Field flatBedrockField;
|
||||
private static final Field generatorSettingBaseField;
|
||||
private static final Field generatorSettingFlatField;
|
||||
private static final Field delegateField;
|
||||
private static final Field chunkProviderField;
|
||||
|
||||
//list of chunk stati in correct order without FULL
|
||||
private static final Map<ChunkStatus, Regenerator.Concurrency> chunkStati = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
chunkStati.put(ChunkStatus.EMPTY, Regenerator.Concurrency.FULL); // radius -1, does nothing
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_REFERENCES, Regenerator.Concurrency.FULL); // radius 8, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.BIOMES, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.NOISE, Regenerator.Concurrency.RADIUS); // radius 8
|
||||
chunkStati.put(ChunkStatus.SURFACE, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.LIQUID_CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.FEATURES, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.LIGHT, Regenerator.Concurrency.FULL); // radius 1, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.SPAWN, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.HEIGHTMAPS, Regenerator.Concurrency.FULL); // radius 0
|
||||
|
||||
try {
|
||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||
serverWorldsField.setAccessible(true);
|
||||
|
||||
Field tmpPaperConfigField = null;
|
||||
Field tmpFlatBedrockField = null;
|
||||
try { //only present on paper
|
||||
tmpPaperConfigField = World.class.getDeclaredField("paperConfig");
|
||||
tmpPaperConfigField.setAccessible(true);
|
||||
|
||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
||||
tmpFlatBedrockField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
tmpPaperConfigField = null;
|
||||
tmpFlatBedrockField = null;
|
||||
}
|
||||
worldPaperConfigField = tmpPaperConfigField;
|
||||
flatBedrockField = tmpFlatBedrockField;
|
||||
|
||||
generatorSettingBaseField = ChunkGeneratorAbstract.class.getDeclaredField("h");
|
||||
generatorSettingBaseField.setAccessible(true);
|
||||
|
||||
generatorSettingFlatField = ChunkProviderFlat.class.getDeclaredField("e");
|
||||
generatorSettingFlatField.setAccessible(true);
|
||||
|
||||
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
|
||||
chunkProviderField = WorldServer.class.getDeclaredField("chunkProvider");
|
||||
chunkProviderField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//runtime
|
||||
private WorldServer originalNMSWorld;
|
||||
private ChunkProviderServer originalChunkProvider;
|
||||
private WorldServer freshNMSWorld;
|
||||
private ChunkProviderServer freshChunkProvider;
|
||||
private Convertable.ConversionSession session;
|
||||
private DefinedStructureManager structureManager;
|
||||
private LightEngineThreaded lightEngine;
|
||||
private ChunkGenerator generator;
|
||||
|
||||
private Path tempDir;
|
||||
|
||||
private boolean generateFlatBedrock = false;
|
||||
|
||||
public Regen_v1_16_R1(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
||||
super(originalBukkitWorld, region, target, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean prepare() {
|
||||
this.originalNMSWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
||||
originalChunkProvider = originalNMSWorld.getChunkProvider();
|
||||
if (!(originalChunkProvider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//flat bedrock? (only on paper)
|
||||
try {
|
||||
generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalNMSWorld));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
seed = options.getSeed().orElse(originalNMSWorld.getSeed());
|
||||
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initNewWorld() throws Exception {
|
||||
//world folder
|
||||
tempDir = java.nio.file.Files.createTempDirectory("WorldEditWorldGen");
|
||||
|
||||
//prepare for world init (see upstream implementation for reference)
|
||||
org.bukkit.World.Environment env = originalBukkitWorld.getEnvironment();
|
||||
org.bukkit.generator.ChunkGenerator gen = originalBukkitWorld.getGenerator();
|
||||
Convertable convertable = Convertable.a(tempDir);
|
||||
ResourceKey<WorldDimension> worldDimKey = getWorldDimKey(env);
|
||||
session = convertable.c("worldeditregentempworld", worldDimKey);
|
||||
WorldDataServer originalWorldData = originalNMSWorld.worldDataServer;
|
||||
|
||||
MinecraftServer server = originalNMSWorld.getServer().getServer();
|
||||
WorldDataServer levelProperties = (WorldDataServer) server.getSaveData();
|
||||
GeneratorSettings newOpts = GeneratorSettings.a.encodeStart(DynamicOpsNBT.a, levelProperties.getGeneratorSettings()).flatMap(tag -> GeneratorSettings.a.parse(this.recursivelySetSeed(new Dynamic<>(DynamicOpsNBT.a, tag), seed, new HashSet<>()))).result().orElseThrow(() -> new IllegalStateException("Unable to map GeneratorOptions"));
|
||||
WorldSettings newWorldSettings = new WorldSettings("worldeditregentempworld", originalWorldData.b.getGameType(), originalWorldData.b.hardcore, originalWorldData.b.getDifficulty(), originalWorldData.b.e(), originalWorldData.b.getGameRules(), originalWorldData.b.g());
|
||||
WorldDataServer newWorldData = new WorldDataServer(newWorldSettings, newOpts, Lifecycle.stable());
|
||||
|
||||
//init world
|
||||
freshNMSWorld = Fawe.get().getQueueHandler().sync((Supplier<WorldServer>) () -> new WorldServer(server, server.executorService, session, newWorldData, originalNMSWorld.getDimensionKey(), originalNMSWorld.getTypeKey(), originalNMSWorld.getDimensionManager(), new RegenNoOpWorldLoadListener(), ((WorldDimension) newOpts.e().a(worldDimKey)).c(), originalNMSWorld.isDebugWorld(), seed, ImmutableList.of(), false, env, gen) {
|
||||
@Override
|
||||
public void doTick(BooleanSupplier booleansupplier) { //no ticking
|
||||
}
|
||||
|
||||
private final BiomeBase singleBiome = options.hasBiomeType() ? IRegistry.BIOME.get(MinecraftKey.a(options.getBiomeType().getId())) : null;
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int i, int j, int k) {
|
||||
if (options.hasBiomeType()) {
|
||||
return singleBiome;
|
||||
}
|
||||
return this.getChunkProvider().getChunkGenerator().getWorldChunkManager().getBiome(i, j, k);
|
||||
}
|
||||
}).get();
|
||||
freshNMSWorld.savingDisabled = true;
|
||||
removeWorldFromWorldsMap();
|
||||
newWorldData.checkName(originalNMSWorld.worldDataServer.getName()); //rename to original world name
|
||||
|
||||
freshChunkProvider = new ChunkProviderServer(freshNMSWorld, session, server.getDataFixer(), server.getDefinedStructureManager(), server.executorService, originalChunkProvider.chunkGenerator, freshNMSWorld.spigotConfig.viewDistance, server.isSyncChunkWrites(), new RegenNoOpWorldLoadListener(), () -> server.D().getWorldPersistentData()) {
|
||||
// redirect to our protoChunks list
|
||||
@Override
|
||||
public IChunkAccess getChunkAt(int x, int z, ChunkStatus chunkstatus, boolean flag) {
|
||||
return getProtoChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
chunkProviderField.set(freshNMSWorld, freshChunkProvider);
|
||||
|
||||
//generator
|
||||
if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderFlat) {
|
||||
GeneratorSettingsFlat generatorSettingFlat = (GeneratorSettingsFlat) generatorSettingFlatField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = new ChunkProviderFlat(generatorSettingFlat);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkGeneratorAbstract) {
|
||||
GeneratorSettingBase generatorSettingBase = (GeneratorSettingBase) generatorSettingBaseField.get(originalChunkProvider.getChunkGenerator());
|
||||
WorldChunkManager chunkManager = originalChunkProvider.getChunkGenerator().getWorldChunkManager();
|
||||
if (chunkManager instanceof WorldChunkManagerOverworld) {
|
||||
chunkManager = fastOverWorldChunkManager(chunkManager);
|
||||
}
|
||||
generator = new ChunkGeneratorAbstract(chunkManager, seed, generatorSettingBase);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof CustomChunkGenerator) {
|
||||
ChunkGenerator delegate = (ChunkGenerator) delegateField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = delegate;
|
||||
} else {
|
||||
System.out.println("Unsupported generator type " + originalChunkProvider.getChunkGenerator().getClass().getName());
|
||||
return false;
|
||||
}
|
||||
if (originalNMSWorld.generator != null) {
|
||||
// wrap custom world generator
|
||||
generator = new CustomChunkGenerator(freshNMSWorld, generator, originalNMSWorld.generator);
|
||||
generateConcurrent = originalNMSWorld.generator.isParallelCapable();
|
||||
}
|
||||
|
||||
//lets start then
|
||||
structureManager = server.getDefinedStructureManager();
|
||||
lightEngine = freshChunkProvider.getLightEngine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup() {
|
||||
try {
|
||||
session.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//shutdown chunk provider
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
freshChunkProvider.close(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//remove world from server
|
||||
try {
|
||||
removeWorldFromWorldsMap();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//delete directory
|
||||
try {
|
||||
SafeFiles.tryHardToDeleteDir(tempDir);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtoChunk createProtoChunk(int x, int z) {
|
||||
return new ProtoChunk(new ChunkCoordIntPair(x, z), ChunkConverter.a) {
|
||||
public boolean generateFlatBedrock() {
|
||||
return generateFlatBedrock;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Chunk createChunk(ProtoChunk protoChunk) {
|
||||
return new Chunk(freshNMSWorld, protoChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChunkStatusWrap getFullChunkStatus() {
|
||||
return new ChunkStatusWrap(ChunkStatus.FULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BlockPopulator> getBlockPopulators() {
|
||||
return originalNMSWorld.getWorld().getPopulators();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(Chunk chunk, Random random, BlockPopulator pop) {
|
||||
pop.populate(freshNMSWorld.getWorld(), random, chunk.bukkitChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||
return (chunkX, chunkZ) -> new BukkitGetBlocks_1_16_1(freshNMSWorld, chunkX, chunkZ) {
|
||||
@Override
|
||||
public Chunk ensureLoaded(World nmsWorld, int x, int z) {
|
||||
return getChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected class ChunkStatusWrap extends Regenerator.ChunkStatusWrapper<IChunkAccess> {
|
||||
|
||||
private final ChunkStatus chunkStatus;
|
||||
|
||||
public ChunkStatusWrap(ChunkStatus chunkStatus) {
|
||||
this.chunkStatus = chunkStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int requiredNeigborChunkRadius() {
|
||||
return chunkStatus.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return chunkStatus.d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processChunk(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||
chunkStatus.a(freshNMSWorld,
|
||||
generator,
|
||||
structureManager,
|
||||
lightEngine,
|
||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
||||
accessibleChunks);
|
||||
}
|
||||
}
|
||||
|
||||
//util
|
||||
private void removeWorldFromWorldsMap() {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
||||
map.remove("worldeditregentempworld");
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ResourceKey<WorldDimension> getWorldDimKey(org.bukkit.World.Environment env) {
|
||||
switch (env) {
|
||||
case NETHER:
|
||||
return WorldDimension.THE_NETHER;
|
||||
case THE_END:
|
||||
return WorldDimension.THE_END;
|
||||
case NORMAL:
|
||||
default:
|
||||
return WorldDimension.OVERWORLD;
|
||||
}
|
||||
}
|
||||
|
||||
private Dynamic<NBTBase> recursivelySetSeed(Dynamic<NBTBase> dynamic, long seed, Set<Dynamic<NBTBase>> seen) {
|
||||
return !seen.add(dynamic) ? dynamic : dynamic.updateMapValues((pair) -> {
|
||||
if (((Dynamic) pair.getFirst()).asString("").equals("seed")) {
|
||||
return pair.mapSecond((v) -> {
|
||||
return v.createLong(seed);
|
||||
});
|
||||
} else {
|
||||
return ((Dynamic) pair.getSecond()).getValue() instanceof NBTTagCompound ? pair.mapSecond((v) -> {
|
||||
return this.recursivelySetSeed((Dynamic) v, seed, seen);
|
||||
}) : pair;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private WorldChunkManager fastOverWorldChunkManager(WorldChunkManager chunkManager) throws Exception {
|
||||
Field legacyBiomeInitLayerField = WorldChunkManagerOverworld.class.getDeclaredField("i");
|
||||
legacyBiomeInitLayerField.setAccessible(true);
|
||||
Field largeBiomesField = WorldChunkManagerOverworld.class.getDeclaredField("j");
|
||||
largeBiomesField.setAccessible(true);
|
||||
Field genLayerField = WorldChunkManagerOverworld.class.getDeclaredField("f");
|
||||
genLayerField.setAccessible(true);
|
||||
Field areaLazyField = GenLayer.class.getDeclaredField("b");
|
||||
areaLazyField.setAccessible(true);
|
||||
Method initAreaFactoryMethod = GenLayers.class.getDeclaredMethod("a", boolean.class, int.class, int.class, LongFunction.class);
|
||||
initAreaFactoryMethod.setAccessible(true);
|
||||
|
||||
//init new WorldChunkManagerOverworld
|
||||
boolean legacyBiomeInitLayer = legacyBiomeInitLayerField.getBoolean(chunkManager);
|
||||
boolean largeBiomes = largeBiomesField.getBoolean(chunkManager);
|
||||
|
||||
AreaFactory<FastAreaLazy> factory = (AreaFactory<FastAreaLazy>) initAreaFactoryMethod.invoke(null, legacyBiomeInitLayer, largeBiomes ? 6 : 4, 4, (LongFunction) (l -> new FastWorldGenContextArea(seed, l)));
|
||||
if (options.hasBiomeType()) {
|
||||
BiomeBase biome = IRegistry.BIOME.get(MinecraftKey.a(options.getBiomeType().getId()));
|
||||
chunkManager = new SingleBiomeWorldChunkManagerOverworld(biome);
|
||||
} else {
|
||||
chunkManager = new WorldChunkManagerOverworld(seed, legacyBiomeInitLayer, largeBiomes);
|
||||
//replace genLayer
|
||||
genLayerField.set(chunkManager, new FastGenLayer(factory));
|
||||
}
|
||||
|
||||
return chunkManager;
|
||||
}
|
||||
|
||||
private static class SingleBiomeWorldChunkManagerOverworld extends WorldChunkManager {
|
||||
|
||||
private final BiomeBase biome;
|
||||
|
||||
public SingleBiomeWorldChunkManagerOverworld(BiomeBase biome) {
|
||||
super(Arrays.asList(biome));
|
||||
this.biome = biome;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Codec<? extends WorldChunkManager> a() {
|
||||
return WorldChunkManagerOverworld.e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase getBiome(int i, int i1, int i2) {
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastWorldGenContextArea implements AreaContextTransformed<FastAreaLazy> {
|
||||
|
||||
private final ConcurrentHashMap<Long, Integer> sharedAreaMap = new ConcurrentHashMap<>();
|
||||
private final NoiseGeneratorPerlin perlinNoise;
|
||||
private final long magicrandom;
|
||||
private final ConcurrentHashMap<Long, Long> map = new ConcurrentHashMap<>(); //needed for multithreaded generation
|
||||
|
||||
public FastWorldGenContextArea(long seed, long lconst) {
|
||||
this.magicrandom = mix(seed, lconst);
|
||||
this.perlinNoise = new NoiseGeneratorPerlin(new Random(seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastAreaLazy a(AreaTransformer8 var0) {
|
||||
return new FastAreaLazy(sharedAreaMap, var0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(long x, long z) {
|
||||
long l = this.magicrandom;
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
this.map.put(Thread.currentThread().getId(), l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int y) {
|
||||
long tid = Thread.currentThread().getId();
|
||||
long e = this.map.computeIfAbsent(tid, i -> 0L);
|
||||
int mod = (int) Math.floorMod(e >> 24L, (long) y);
|
||||
this.map.put(tid, LinearCongruentialGenerator.a(e, this.magicrandom));
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoiseGeneratorPerlin b() {
|
||||
return this.perlinNoise;
|
||||
}
|
||||
|
||||
private static long mix(long seed, long lconst) {
|
||||
long l1 = lconst;
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
long l2 = seed;
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
return l2;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastGenLayer extends GenLayer {
|
||||
|
||||
private final FastAreaLazy areaLazy;
|
||||
|
||||
public FastGenLayer(AreaFactory<FastAreaLazy> factory) throws Exception {
|
||||
super(() -> null);
|
||||
this.areaLazy = factory.make();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int x, int z) {
|
||||
BiomeBase biome = IRegistry.BIOME.fromId(this.areaLazy.a(x, z));
|
||||
if (biome == null)
|
||||
return Biomes.b;
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastAreaLazy implements Area {
|
||||
|
||||
private final AreaTransformer8 transformer;
|
||||
//ConcurrentHashMap is 50% faster that Long2IntLinkedOpenHashMap in a syncronized context
|
||||
//using a map for each thread worsens the performance significantly due to cache misses (factor 5)
|
||||
private final ConcurrentHashMap<Long, Integer> sharedMap;
|
||||
|
||||
public FastAreaLazy(ConcurrentHashMap<Long, Integer> sharedMap, AreaTransformer8 transformer) {
|
||||
this.sharedMap = sharedMap;
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int x, int z) {
|
||||
long zx = ChunkCoordIntPair.pair(x, z);
|
||||
return this.sharedMap.computeIfAbsent(zx, i -> this.transformer.apply(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegenNoOpWorldLoadListener implements WorldLoadListener {
|
||||
|
||||
private RegenNoOpWorldLoadListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair, @Nullable ChunkStatus chunkStatus) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkRadius(int i) {
|
||||
}
|
||||
}
|
||||
}
|
@ -1,582 +0,0 @@
|
||||
package com.sk89q.worldedit.bukkit.adapter.impl.regen;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunkCache;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.bukkit.adapter.mc1_16_2.BukkitGetBlocks_1_16_2;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.sk89q.worldedit.bukkit.adapter.Regenerator;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||
import com.sk89q.worldedit.world.RegenOptions;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.server.v1_16_R2.Area;
|
||||
import net.minecraft.server.v1_16_R2.AreaContextTransformed;
|
||||
import net.minecraft.server.v1_16_R2.AreaFactory;
|
||||
import net.minecraft.server.v1_16_R2.AreaTransformer8;
|
||||
import net.minecraft.server.v1_16_R2.BiomeBase;
|
||||
import net.minecraft.server.v1_16_R2.BiomeRegistry;
|
||||
import net.minecraft.server.v1_16_R2.Chunk;
|
||||
import net.minecraft.server.v1_16_R2.ChunkConverter;
|
||||
import net.minecraft.server.v1_16_R2.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_16_R2.ChunkGenerator;
|
||||
import net.minecraft.server.v1_16_R2.ChunkGeneratorAbstract;
|
||||
import net.minecraft.server.v1_16_R2.ChunkProviderFlat;
|
||||
import net.minecraft.server.v1_16_R2.ChunkProviderServer;
|
||||
import net.minecraft.server.v1_16_R2.ChunkStatus;
|
||||
import net.minecraft.server.v1_16_R2.Convertable;
|
||||
import net.minecraft.server.v1_16_R2.DefinedStructureManager;
|
||||
import net.minecraft.server.v1_16_R2.DynamicOpsNBT;
|
||||
import net.minecraft.server.v1_16_R2.GenLayer;
|
||||
import net.minecraft.server.v1_16_R2.GenLayers;
|
||||
import net.minecraft.server.v1_16_R2.GeneratorSettingBase;
|
||||
import net.minecraft.server.v1_16_R2.GeneratorSettings;
|
||||
import net.minecraft.server.v1_16_R2.GeneratorSettingsFlat;
|
||||
import net.minecraft.server.v1_16_R2.IChunkAccess;
|
||||
import net.minecraft.server.v1_16_R2.IRegistry;
|
||||
import net.minecraft.server.v1_16_R2.IRegistryCustom;
|
||||
import net.minecraft.server.v1_16_R2.LightEngineThreaded;
|
||||
import net.minecraft.server.v1_16_R2.LinearCongruentialGenerator;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftKey;
|
||||
import net.minecraft.server.v1_16_R2.MinecraftServer;
|
||||
import net.minecraft.server.v1_16_R2.NBTBase;
|
||||
import net.minecraft.server.v1_16_R2.NBTTagCompound;
|
||||
import net.minecraft.server.v1_16_R2.NoiseGeneratorPerlin;
|
||||
import net.minecraft.server.v1_16_R2.ProtoChunk;
|
||||
import net.minecraft.server.v1_16_R2.RegistryGeneration;
|
||||
import net.minecraft.server.v1_16_R2.RegistryMaterials;
|
||||
import net.minecraft.server.v1_16_R2.RegistryReadOps;
|
||||
import net.minecraft.server.v1_16_R2.ResourceKey;
|
||||
import net.minecraft.server.v1_16_R2.World;
|
||||
import net.minecraft.server.v1_16_R2.WorldChunkManager;
|
||||
import net.minecraft.server.v1_16_R2.WorldChunkManagerOverworld;
|
||||
import net.minecraft.server.v1_16_R2.WorldDataServer;
|
||||
import net.minecraft.server.v1_16_R2.WorldDimension;
|
||||
import net.minecraft.server.v1_16_R2.WorldLoadListener;
|
||||
import net.minecraft.server.v1_16_R2.WorldServer;
|
||||
import net.minecraft.server.v1_16_R2.WorldSettings;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.CraftWorld;
|
||||
import org.bukkit.craftbukkit.v1_16_R2.generator.CustomChunkGenerator;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
public class Regen_v1_16_R2 extends Regenerator<IChunkAccess, ProtoChunk, Chunk, Regen_v1_16_R2.ChunkStatusWrap> {
|
||||
|
||||
private static final Field serverWorldsField;
|
||||
private static final Field worldPaperConfigField;
|
||||
private static final Field flatBedrockField;
|
||||
private static final Field generatorSettingBaseSupplierField;
|
||||
private static final Field generatorSettingFlatField;
|
||||
private static final Field delegateField;
|
||||
private static final Field chunkProviderField;
|
||||
|
||||
//list of chunk stati in correct order without FULL
|
||||
private static final Map<ChunkStatus, Regenerator.Concurrency> chunkStati = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
chunkStati.put(ChunkStatus.EMPTY, Regenerator.Concurrency.FULL); // radius -1, does nothing
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.STRUCTURE_REFERENCES, Regenerator.Concurrency.FULL); // radius 8, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.BIOMES, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.NOISE, Regenerator.Concurrency.RADIUS); // radius 8
|
||||
chunkStati.put(ChunkStatus.SURFACE, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.LIQUID_CARVERS, Regenerator.Concurrency.NONE); // radius 0, but RADIUS and FULL change results
|
||||
chunkStati.put(ChunkStatus.FEATURES, Regenerator.Concurrency.NONE); // uses unsynchronized maps
|
||||
chunkStati.put(ChunkStatus.LIGHT, Regenerator.Concurrency.FULL); // radius 1, but no writes to other chunks, only current chunk
|
||||
chunkStati.put(ChunkStatus.SPAWN, Regenerator.Concurrency.FULL); // radius 0
|
||||
chunkStati.put(ChunkStatus.HEIGHTMAPS, Regenerator.Concurrency.FULL); // radius 0
|
||||
|
||||
try {
|
||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||
serverWorldsField.setAccessible(true);
|
||||
|
||||
Field tmpPaperConfigField = null;
|
||||
Field tmpFlatBedrockField = null;
|
||||
try { //only present on paper
|
||||
tmpPaperConfigField = World.class.getDeclaredField("paperConfig");
|
||||
tmpPaperConfigField.setAccessible(true);
|
||||
|
||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
||||
tmpFlatBedrockField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
tmpPaperConfigField = null;
|
||||
tmpFlatBedrockField = null;
|
||||
}
|
||||
worldPaperConfigField = tmpPaperConfigField;
|
||||
flatBedrockField = tmpFlatBedrockField;
|
||||
|
||||
generatorSettingBaseSupplierField = ChunkGeneratorAbstract.class.getDeclaredField("h");
|
||||
generatorSettingBaseSupplierField.setAccessible(true);
|
||||
|
||||
generatorSettingFlatField = ChunkProviderFlat.class.getDeclaredField("e");
|
||||
generatorSettingFlatField.setAccessible(true);
|
||||
|
||||
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
|
||||
delegateField.setAccessible(true);
|
||||
|
||||
chunkProviderField = WorldServer.class.getDeclaredField("chunkProvider");
|
||||
chunkProviderField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
//runtime
|
||||
private WorldServer originalNMSWorld;
|
||||
private ChunkProviderServer originalChunkProvider;
|
||||
private WorldServer freshNMSWorld;
|
||||
private ChunkProviderServer freshChunkProvider;
|
||||
private Convertable.ConversionSession session;
|
||||
private DefinedStructureManager structureManager;
|
||||
private LightEngineThreaded lightEngine;
|
||||
private ChunkGenerator generator;
|
||||
|
||||
private Path tempDir;
|
||||
|
||||
private boolean generateFlatBedrock = false;
|
||||
|
||||
public Regen_v1_16_R2(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
||||
super(originalBukkitWorld, region, target, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean prepare() {
|
||||
this.originalNMSWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
||||
originalChunkProvider = originalNMSWorld.getChunkProvider();
|
||||
if (!(originalChunkProvider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//flat bedrock? (only on paper)
|
||||
try {
|
||||
generateFlatBedrock = flatBedrockField.getBoolean(worldPaperConfigField.get(originalNMSWorld));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
seed = options.getSeed().orElse(originalNMSWorld.getSeed());
|
||||
chunkStati.forEach((s, c) -> super.chunkStati.put(new ChunkStatusWrap(s), c));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean initNewWorld() throws Exception {
|
||||
//world folder
|
||||
tempDir = java.nio.file.Files.createTempDirectory("WorldEditWorldGen");
|
||||
|
||||
//prepare for world init (see upstream implementation for reference)
|
||||
org.bukkit.World.Environment env = originalBukkitWorld.getEnvironment();
|
||||
org.bukkit.generator.ChunkGenerator gen = originalBukkitWorld.getGenerator();
|
||||
Convertable convertable = Convertable.a(tempDir);
|
||||
ResourceKey<WorldDimension> worldDimKey = getWorldDimKey(env);
|
||||
session = convertable.c("worldeditregentempworld", worldDimKey);
|
||||
WorldDataServer originalWorldData = originalNMSWorld.worldDataServer;
|
||||
|
||||
MinecraftServer server = originalNMSWorld.getServer().getServer();
|
||||
WorldDataServer levelProperties = (WorldDataServer) server.getSaveData();
|
||||
RegistryReadOps<NBTBase> nbtRegOps = RegistryReadOps.a(DynamicOpsNBT.a, server.dataPackResources.h(), IRegistryCustom.b());
|
||||
GeneratorSettings newOpts = GeneratorSettings.a.encodeStart(nbtRegOps, levelProperties.getGeneratorSettings()).flatMap(tag -> GeneratorSettings.a.parse(this.recursivelySetSeed(new Dynamic<>(nbtRegOps, tag), seed, new HashSet<>()))).result().orElseThrow(() -> new IllegalStateException("Unable to map GeneratorOptions"));
|
||||
WorldSettings newWorldSettings = new WorldSettings("worldeditregentempworld", originalWorldData.b.getGameType(), originalWorldData.b.hardcore, originalWorldData.b.getDifficulty(), originalWorldData.b.e(), originalWorldData.b.getGameRules(), originalWorldData.b.g());
|
||||
WorldDataServer newWorldData = new WorldDataServer(newWorldSettings, newOpts, Lifecycle.stable());
|
||||
|
||||
//init world
|
||||
freshNMSWorld = Fawe.get().getQueueHandler().sync((Supplier<WorldServer>) () -> new WorldServer(server, server.executorService, session, newWorldData, originalNMSWorld.getDimensionKey(), originalNMSWorld.getDimensionManager(), new RegenNoOpWorldLoadListener(), ((WorldDimension) newOpts.d().a(worldDimKey)).c(), originalNMSWorld.isDebugWorld(), seed, ImmutableList.of(), false, env, gen) {
|
||||
@Override
|
||||
public void doTick(BooleanSupplier booleansupplier) { //no ticking
|
||||
}
|
||||
|
||||
private final BiomeBase singleBiome = options.hasBiomeType() ? RegistryGeneration.WORLDGEN_BIOME.get(MinecraftKey.a(options.getBiomeType().getId())) : null;
|
||||
|
||||
@Override
|
||||
public BiomeBase a(int i, int j, int k) {
|
||||
if (options.hasBiomeType()) {
|
||||
return singleBiome;
|
||||
}
|
||||
return this.getChunkProvider().getChunkGenerator().getWorldChunkManager().getBiome(i, j, k);
|
||||
}
|
||||
}).get();
|
||||
freshNMSWorld.savingDisabled = true;
|
||||
removeWorldFromWorldsMap();
|
||||
newWorldData.checkName(originalNMSWorld.worldDataServer.getName()); //rename to original world name
|
||||
|
||||
freshChunkProvider = new ChunkProviderServer(freshNMSWorld, session, server.getDataFixer(), server.getDefinedStructureManager(), server.executorService, originalChunkProvider.chunkGenerator, freshNMSWorld.spigotConfig.viewDistance, server.isSyncChunkWrites(), new RegenNoOpWorldLoadListener(), () -> server.E().getWorldPersistentData()) {
|
||||
// redirect to our protoChunks list
|
||||
@Override
|
||||
public IChunkAccess getChunkAt(int x, int z, ChunkStatus chunkstatus, boolean flag) {
|
||||
return getProtoChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
chunkProviderField.set(freshNMSWorld, freshChunkProvider);
|
||||
|
||||
//generator
|
||||
if (originalChunkProvider.getChunkGenerator() instanceof ChunkProviderFlat) {
|
||||
GeneratorSettingsFlat generatorSettingFlat = (GeneratorSettingsFlat) generatorSettingFlatField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = new ChunkProviderFlat(generatorSettingFlat);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof ChunkGeneratorAbstract) {
|
||||
Supplier<GeneratorSettingBase> generatorSettingBaseSupplier = (Supplier<GeneratorSettingBase>) generatorSettingBaseSupplierField.get(originalChunkProvider.getChunkGenerator());
|
||||
WorldChunkManager chunkManager = originalChunkProvider.getChunkGenerator().getWorldChunkManager();
|
||||
if (chunkManager instanceof WorldChunkManagerOverworld) {
|
||||
chunkManager = fastOverWorldChunkManager(chunkManager);
|
||||
}
|
||||
generator = new ChunkGeneratorAbstract(chunkManager, seed, generatorSettingBaseSupplier);
|
||||
} else if (originalChunkProvider.getChunkGenerator() instanceof CustomChunkGenerator) {
|
||||
ChunkGenerator delegate = (ChunkGenerator) delegateField.get(originalChunkProvider.getChunkGenerator());
|
||||
generator = delegate;
|
||||
} else {
|
||||
System.out.println("Unsupported generator type " + originalChunkProvider.getChunkGenerator().getClass().getName());
|
||||
return false;
|
||||
}
|
||||
if (originalNMSWorld.generator != null) {
|
||||
// wrap custom world generator
|
||||
generator = new CustomChunkGenerator(freshNMSWorld, generator, originalNMSWorld.generator);
|
||||
generateConcurrent = originalNMSWorld.generator.isParallelCapable();
|
||||
}
|
||||
|
||||
//lets start then
|
||||
structureManager = server.getDefinedStructureManager();
|
||||
lightEngine = freshChunkProvider.getLightEngine();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cleanup() {
|
||||
try {
|
||||
session.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//shutdown chunk provider
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
freshChunkProvider.close(false);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//remove world from server
|
||||
try {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
removeWorldFromWorldsMap();
|
||||
});
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
//delete directory
|
||||
try {
|
||||
SafeFiles.tryHardToDeleteDir(tempDir);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ProtoChunk createProtoChunk(int x, int z) {
|
||||
return new ProtoChunk(new ChunkCoordIntPair(x, z), ChunkConverter.a) {
|
||||
public boolean generateFlatBedrock() {
|
||||
return generateFlatBedrock;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Chunk createChunk(ProtoChunk protoChunk) {
|
||||
return new Chunk(freshNMSWorld, protoChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChunkStatusWrap getFullChunkStatus() {
|
||||
return new ChunkStatusWrap(ChunkStatus.FULL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<BlockPopulator> getBlockPopulators() {
|
||||
return originalNMSWorld.getWorld().getPopulators();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populate(Chunk chunk, Random random, BlockPopulator pop) {
|
||||
pop.populate(freshNMSWorld.getWorld(), random, chunk.bukkitChunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||
return (chunkX, chunkZ) -> new BukkitGetBlocks_1_16_2(freshNMSWorld, chunkX, chunkZ) {
|
||||
@Override
|
||||
public Chunk ensureLoaded(World nmsWorld, int x, int z) {
|
||||
return getChunkAt(x, z);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected class ChunkStatusWrap extends Regenerator.ChunkStatusWrapper<IChunkAccess> {
|
||||
|
||||
private final ChunkStatus chunkStatus;
|
||||
|
||||
public ChunkStatusWrap(ChunkStatus chunkStatus) {
|
||||
this.chunkStatus = chunkStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int requiredNeigborChunkRadius() {
|
||||
return chunkStatus.f();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return chunkStatus.d();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processChunk(Long xz, List<IChunkAccess> accessibleChunks) {
|
||||
chunkStatus.a(freshNMSWorld,
|
||||
generator,
|
||||
structureManager,
|
||||
lightEngine,
|
||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
||||
accessibleChunks);
|
||||
}
|
||||
}
|
||||
|
||||
//util
|
||||
private void removeWorldFromWorldsMap() {
|
||||
Fawe.get().getQueueHandler().sync(() -> {
|
||||
try {
|
||||
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
||||
map.remove("worldeditregentempworld");
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private ResourceKey<WorldDimension> getWorldDimKey(org.bukkit.World.Environment env) {
|
||||
switch (env) {
|
||||
case NETHER:
|
||||
return WorldDimension.THE_NETHER;
|
||||
case THE_END:
|
||||
return WorldDimension.THE_END;
|
||||
case NORMAL:
|
||||
default:
|
||||
return WorldDimension.OVERWORLD;
|
||||
}
|
||||
}
|
||||
|
||||
private Dynamic<NBTBase> recursivelySetSeed(Dynamic<NBTBase> dynamic, long seed, Set<Dynamic<NBTBase>> seen) {
|
||||
return !seen.add(dynamic) ? dynamic : dynamic.updateMapValues((pair) -> {
|
||||
if (((Dynamic) pair.getFirst()).asString("").equals("seed")) {
|
||||
return pair.mapSecond((v) -> {
|
||||
return v.createLong(seed);
|
||||
});
|
||||
} else {
|
||||
return ((Dynamic) pair.getSecond()).getValue() instanceof NBTTagCompound ? pair.mapSecond((v) -> {
|
||||
return this.recursivelySetSeed((Dynamic) v, seed, seen);
|
||||
}) : pair;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private WorldChunkManager fastOverWorldChunkManager(WorldChunkManager chunkManager) throws Exception {
|
||||
Field legacyBiomeInitLayerField = WorldChunkManagerOverworld.class.getDeclaredField("i");
|
||||
legacyBiomeInitLayerField.setAccessible(true);
|
||||
Field largeBiomesField = WorldChunkManagerOverworld.class.getDeclaredField("j");
|
||||
largeBiomesField.setAccessible(true);
|
||||
Field biomeRegistryField = WorldChunkManagerOverworld.class.getDeclaredField("k");
|
||||
biomeRegistryField.setAccessible(true);
|
||||
Field areaLazyField = GenLayer.class.getDeclaredField("b");
|
||||
areaLazyField.setAccessible(true);
|
||||
Method initAreaFactoryMethod = GenLayers.class.getDeclaredMethod("a", boolean.class, int.class, int.class, LongFunction.class);
|
||||
initAreaFactoryMethod.setAccessible(true);
|
||||
|
||||
//init new WorldChunkManagerOverworld
|
||||
boolean legacyBiomeInitLayer = legacyBiomeInitLayerField.getBoolean(chunkManager);
|
||||
boolean largebiomes = largeBiomesField.getBoolean(chunkManager);
|
||||
IRegistry<BiomeBase> biomeRegistrynms = (IRegistry<BiomeBase>) biomeRegistryField.get(chunkManager);
|
||||
IRegistry<BiomeBase> biomeRegistry;
|
||||
if (options.hasBiomeType()) {
|
||||
BiomeBase biome = RegistryGeneration.WORLDGEN_BIOME.get(MinecraftKey.a(options.getBiomeType().getId()));
|
||||
biomeRegistry = new RegistryMaterials<>(ResourceKey.a(new MinecraftKey("fawe_biomes")), Lifecycle.experimental());
|
||||
((RegistryMaterials) biomeRegistry).a(0, RegistryGeneration.WORLDGEN_BIOME.c(biome).get(), biome, Lifecycle.experimental());
|
||||
} else {
|
||||
biomeRegistry = biomeRegistrynms;
|
||||
}
|
||||
chunkManager = new FastWorldChunkManagerOverworld(seed, legacyBiomeInitLayer, largebiomes, biomeRegistry);
|
||||
|
||||
//replace genLayer
|
||||
AreaFactory<FastAreaLazy> factory = (AreaFactory<FastAreaLazy>) initAreaFactoryMethod.invoke(null, legacyBiomeInitLayer, largebiomes ? 6 : 4, 4, (LongFunction) (l -> new FastWorldGenContextArea(seed, l)));
|
||||
((FastWorldChunkManagerOverworld) chunkManager).genLayer = new FastGenLayer(factory);
|
||||
|
||||
return chunkManager;
|
||||
}
|
||||
|
||||
private static class FastWorldChunkManagerOverworld extends WorldChunkManager {
|
||||
|
||||
private GenLayer genLayer;
|
||||
private final IRegistry<BiomeBase> k;
|
||||
private final boolean isSingleRegistry;
|
||||
|
||||
public FastWorldChunkManagerOverworld(long seed, boolean legacyBiomeInitLayer, boolean largeBiomes, IRegistry<BiomeBase> biomeRegistry) {
|
||||
super(biomeRegistry.g().collect(Collectors.toList()));
|
||||
this.k = biomeRegistry;
|
||||
this.isSingleRegistry = biomeRegistry.d().size() == 1;
|
||||
this.genLayer = GenLayers.a(seed, legacyBiomeInitLayer, largeBiomes ? 6 : 4, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Codec<? extends WorldChunkManager> a() {
|
||||
return WorldChunkManagerOverworld.e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase getBiome(int i, int i1, int i2) {
|
||||
if (this.isSingleRegistry) {
|
||||
return this.k.fromId(0);
|
||||
}
|
||||
return this.genLayer.a(this.k, i, i2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class FastWorldGenContextArea implements AreaContextTransformed<FastAreaLazy> {
|
||||
|
||||
private final ConcurrentHashMap<Long, Integer> sharedAreaMap = new ConcurrentHashMap<>();
|
||||
private final NoiseGeneratorPerlin perlinNoise;
|
||||
private final long magicrandom;
|
||||
private final ConcurrentHashMap<Long, Long> map = new ConcurrentHashMap<>(); //needed for multithreaded generation
|
||||
|
||||
public FastWorldGenContextArea(long seed, long lconst) {
|
||||
this.magicrandom = mix(seed, lconst);
|
||||
this.perlinNoise = new NoiseGeneratorPerlin(new Random(seed));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FastAreaLazy a(AreaTransformer8 var0) {
|
||||
return new FastAreaLazy(sharedAreaMap, var0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(long x, long z) {
|
||||
long l = this.magicrandom;
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
l = LinearCongruentialGenerator.a(l, x);
|
||||
l = LinearCongruentialGenerator.a(l, z);
|
||||
this.map.put(Thread.currentThread().getId(), l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int y) {
|
||||
long tid = Thread.currentThread().getId();
|
||||
long e = this.map.computeIfAbsent(tid, i -> 0L);
|
||||
int mod = (int) Math.floorMod(e >> 24L, (long) y);
|
||||
this.map.put(tid, LinearCongruentialGenerator.a(e, this.magicrandom));
|
||||
return mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoiseGeneratorPerlin b() {
|
||||
return this.perlinNoise;
|
||||
}
|
||||
|
||||
private static long mix(long seed, long lconst) {
|
||||
long l1 = lconst;
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
l1 = LinearCongruentialGenerator.a(l1, lconst);
|
||||
long l2 = seed;
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
l2 = LinearCongruentialGenerator.a(l2, l1);
|
||||
return l2;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastGenLayer extends GenLayer {
|
||||
|
||||
private final FastAreaLazy areaLazy;
|
||||
|
||||
public FastGenLayer(AreaFactory<FastAreaLazy> factory) throws Exception {
|
||||
super(() -> null);
|
||||
this.areaLazy = factory.make();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeBase a(IRegistry<BiomeBase> registry, int x, int z) {
|
||||
ResourceKey<BiomeBase> key = BiomeRegistry.a(this.areaLazy.a(x, z));
|
||||
if (key == null)
|
||||
return registry.a(BiomeRegistry.a(0));
|
||||
BiomeBase biome = registry.a(key);
|
||||
if (biome == null)
|
||||
return registry.a(BiomeRegistry.a(0));
|
||||
return biome;
|
||||
}
|
||||
}
|
||||
|
||||
private static class FastAreaLazy implements Area {
|
||||
|
||||
private final AreaTransformer8 transformer;
|
||||
//ConcurrentHashMap is 50% faster that Long2IntLinkedOpenHashMap in a syncronized context
|
||||
//using a map for each thread worsens the performance significantly due to cache misses (factor 5)
|
||||
private final ConcurrentHashMap<Long, Integer> sharedMap;
|
||||
|
||||
public FastAreaLazy(ConcurrentHashMap<Long, Integer> sharedMap, AreaTransformer8 transformer) {
|
||||
this.sharedMap = sharedMap;
|
||||
this.transformer = transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int a(int x, int z) {
|
||||
long zx = ChunkCoordIntPair.pair(x, z);
|
||||
return this.sharedMap.computeIfAbsent(zx, i -> this.transformer.apply(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegenNoOpWorldLoadListener implements WorldLoadListener {
|
||||
|
||||
private RegenNoOpWorldLoadListener() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(ChunkCoordIntPair chunkCoordIntPair, @Nullable ChunkStatus chunkStatus) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void b() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunkRadius(int i) {
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user