mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-11-16 17:16:11 +00:00
Add fluid ticking and refactor post-processing a bit (#1554)
* Make postProcessSet a default method and change to void * Throwable#getMessage is nullable * Move (re-)ticking to a post-processor per "platform" - Add fluid ticking * chore: Ignore (for us) irrelevant rules * chore: Fix correct toml syntax? * Re-add removed method for API-compliance and refactor it to have a use * Switch to javax annotations * Switch to recalcBlockCounts for ticking blocks. * No need to set air count anymore either * We can still "not tick" in fast mode in 1.17.2 * update adapters * Let paper create the chunk section if biomes are null * Adjust notes to settings * 1.17.2 didn't exist * Add 1.18.2 * Don't attempt to cache plains biome ID * Use correct annotation Co-authored-by: NotMyFault <mc.cache@web.de>
This commit is contained in:
parent
5d18e15128
commit
e9db749e2f
4
.lift.toml
Normal file
4
.lift.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
jdkVersion = "17"
|
||||||
|
build = "gradle clean build -x test"
|
||||||
|
tools = ["findsecbugs", "ErrorProne", "Semgrep", "Detekt", "ESLint", "Infer"]
|
||||||
|
ignoreRules = ["CatchAndPrintStackTrace", "ReferenceEquality", "FallThrough", "FutureReturnValueIgnored"]
|
@ -6,6 +6,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
|||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
@ -694,4 +695,9 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBatchProcessor getTickingPostProcessor() {
|
||||||
|
return new PaperweightPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -410,7 +410,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||||
forceLoadSections = false;
|
forceLoadSections = false;
|
||||||
copy = createCopy ? new PaperweightGetBlocks_Copy(serverLevel) : null;
|
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
||||||
try {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
ServerLevel nmsWorld = serverLevel;
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||||
@ -461,6 +461,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
bitMask |= 1 << layer;
|
bitMask |= 1 << layer;
|
||||||
|
|
||||||
|
// Changes may still be written to chunk SET
|
||||||
char[] tmp = set.load(layerNo);
|
char[] tmp = set.load(layerNo);
|
||||||
char[] setArr = new char[4096];
|
char[] setArr = new char[4096];
|
||||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||||
@ -477,6 +478,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
LevelChunkSection newSection;
|
LevelChunkSection newSection;
|
||||||
LevelChunkSection existingSection = levelChunkSections[layer];
|
LevelChunkSection existingSection = levelChunkSections[layer];
|
||||||
|
// Don't attempt to tick section whilst we're editing
|
||||||
|
if (existingSection != null) {
|
||||||
|
PaperweightPlatformAdapter.clearCounts(existingSection);
|
||||||
|
existingSection.tickingList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (existingSection == null) {
|
if (existingSection == null) {
|
||||||
newSection = PaperweightPlatformAdapter.newChunkSection(layerNo, setArr, fastmode, adapter);
|
newSection = PaperweightPlatformAdapter.newChunkSection(layerNo, setArr, fastmode, adapter);
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, layer)) {
|
if (PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, null, newSection, layer)) {
|
||||||
@ -492,10 +499,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PaperweightPlatformAdapter.fieldTickingBlockCount.set(existingSection, (short) 0);
|
|
||||||
|
|
||||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
//ensure that the server doesn't try to tick the chunksection while we're editing it (again).
|
||||||
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
|
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
|
||||||
|
PaperweightPlatformAdapter.clearCounts(existingSection);
|
||||||
|
existingSection.tickingList.clear();
|
||||||
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
// lock.acquire();
|
// lock.acquire();
|
||||||
|
@ -19,6 +19,7 @@ import net.minecraft.world.entity.Entity;
|
|||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.chunk.ChunkBiomeContainer;
|
import net.minecraft.world.level.chunk.ChunkBiomeContainer;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -35,13 +36,15 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
private final ServerLevel serverLevel;
|
final ServerLevel serverLevel;
|
||||||
|
final LevelChunk levelChunk;
|
||||||
private ChunkBiomeContainer chunkBiomeContainer;
|
private ChunkBiomeContainer chunkBiomeContainer;
|
||||||
|
|
||||||
protected PaperweightGetBlocks_Copy(ServerLevel world) {
|
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
|
||||||
this.serverLevel = world;
|
this.levelChunk = levelChunk;
|
||||||
this.minHeight = world.getMinBuildHeight();
|
this.serverLevel = levelChunk.level;
|
||||||
this.maxHeight = world.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
this.minHeight = serverLevel.getMinBuildHeight();
|
||||||
|
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
||||||
this.blocks = new char[getSectionCount()][];
|
this.blocks = new char[getSectionCount()][];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ import com.fastasyncworldedit.core.util.ReflectionUtils;
|
|||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.mojang.datafixers.util.Either;
|
import com.mojang.datafixers.util.Either;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
@ -54,9 +53,7 @@ import java.lang.invoke.MethodHandles;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
@ -71,9 +68,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
|
|
||||||
public static final Field fieldBitsPerEntry;
|
public static final Field fieldBitsPerEntry;
|
||||||
|
|
||||||
public static final Field fieldTickingFluidContent;
|
private static final Field fieldTickingFluidContent;
|
||||||
public static final Field fieldTickingBlockCount;
|
private static final Field fieldTickingBlockCount;
|
||||||
public static final Field fieldNonEmptyBlockCount;
|
private static final Field fieldNonEmptyBlockCount;
|
||||||
|
|
||||||
private static final Field fieldBiomes;
|
private static final Field fieldBiomes;
|
||||||
|
|
||||||
@ -271,15 +268,20 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
NMS conversion
|
NMS conversion
|
||||||
*/
|
*/
|
||||||
public static LevelChunkSection newChunkSection(
|
public static LevelChunkSection newChunkSection(
|
||||||
final int layer, final char[] blocks, boolean fastmode,
|
final int layer,
|
||||||
|
final char[] blocks,
|
||||||
|
boolean fastMode,
|
||||||
CachedBukkitAdapter adapter
|
CachedBukkitAdapter adapter
|
||||||
) {
|
) {
|
||||||
return newChunkSection(layer, null, blocks, fastmode, adapter);
|
return newChunkSection(layer, null, blocks, fastMode, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LevelChunkSection newChunkSection(
|
public static LevelChunkSection newChunkSection(
|
||||||
final int layer, final Function<Integer, char[]> get, char[] set,
|
final int layer,
|
||||||
boolean fastmode, CachedBukkitAdapter adapter
|
final Function<Integer, char[]> get,
|
||||||
|
char[] set,
|
||||||
|
boolean fastMode,
|
||||||
|
CachedBukkitAdapter adapter
|
||||||
) {
|
) {
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
return newChunkSection(layer);
|
return newChunkSection(layer);
|
||||||
@ -289,19 +291,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
|
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
|
||||||
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
|
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
|
||||||
try {
|
try {
|
||||||
int[] num_palette_buffer = new int[1];
|
int num_palette;
|
||||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
|
||||||
int air;
|
|
||||||
if (get == null) {
|
if (get == null) {
|
||||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter
|
||||||
set, ticking_blocks, fastmode, adapter
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter);
|
||||||
num_palette_buffer, get, set, ticking_blocks, fastmode, adapter
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
int num_palette = num_palette_buffer[0];
|
|
||||||
// BlockStates
|
// BlockStates
|
||||||
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
||||||
if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) {
|
if (Settings.settings().PROTOCOL_SUPPORT_FIX || num_palette != 1) {
|
||||||
@ -364,17 +360,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
fieldStorage.set(dataPaletteBlocks, nmsBits);
|
fieldStorage.set(dataPaletteBlocks, nmsBits);
|
||||||
fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer);
|
fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer);
|
||||||
fieldBits.set(dataPaletteBlocks, bitsPerEntry);
|
fieldBits.set(dataPaletteBlocks, bitsPerEntry);
|
||||||
setCount(ticking_blocks.size(), 4096 - air, levelChunkSection);
|
|
||||||
if (!fastmode) {
|
|
||||||
ticking_blocks.forEach((pos, ordinal) -> levelChunkSection
|
|
||||||
.setBlockState(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
|
|
||||||
Block.stateById(ordinal)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} catch (final IllegalAccessException e) {
|
} catch (final IllegalAccessException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fastMode) {
|
||||||
|
levelChunkSection.recalcBlockCounts();
|
||||||
|
}
|
||||||
return levelChunkSection;
|
return levelChunkSection;
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||||
@ -386,11 +378,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
return new LevelChunkSection(layer);
|
return new LevelChunkSection(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final LevelChunkSection section) throws
|
public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException {
|
||||||
IllegalAccessException {
|
fieldTickingFluidContent.setShort(section, (short) 0);
|
||||||
fieldTickingFluidContent.setShort(section, (short) 0); // TODO FIXME
|
fieldTickingBlockCount.setShort(section, (short) 0);
|
||||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
|
||||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Biome[] getBiomeArray(ChunkBiomeContainer chunkBiomeContainer) {
|
public static Biome[] getBiomeArray(ChunkBiomeContainer chunkBiomeContainer) {
|
||||||
|
@ -0,0 +1,175 @@
|
|||||||
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
|
import com.fastasyncworldedit.core.queue.IChunk;
|
||||||
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
|
import com.fastasyncworldedit.core.registry.state.PropertyKey;
|
||||||
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.Fluids;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class PaperweightPostProcessor implements IBatchProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) {
|
||||||
|
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
|
||||||
|
// The PostProcessor shouldn't be added, but just in case
|
||||||
|
if (!tickFluid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet;
|
||||||
|
layer:
|
||||||
|
for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) {
|
||||||
|
char[] set = iChunkSet.loadIfPresent(layer);
|
||||||
|
if (set == null) {
|
||||||
|
// No edit means no need to process
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char[] get = null;
|
||||||
|
for (int i = 0; i < 4096; i++) {
|
||||||
|
char ordinal = set[i];
|
||||||
|
char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
|
||||||
|
boolean fromGet = false; // Used for liquids
|
||||||
|
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
|
if (get == null) {
|
||||||
|
get = getBlocks.load(layer);
|
||||||
|
}
|
||||||
|
// If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't
|
||||||
|
// actually being set
|
||||||
|
if (get == null) {
|
||||||
|
continue layer;
|
||||||
|
}
|
||||||
|
fromGet = true;
|
||||||
|
ordinal = replacedOrdinal = get[i];
|
||||||
|
}
|
||||||
|
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
|
continue;
|
||||||
|
} else if (!fromGet) { // if fromGet, don't do the same again
|
||||||
|
if (get == null) {
|
||||||
|
get = getBlocks.load(layer);
|
||||||
|
}
|
||||||
|
replacedOrdinal = get[i];
|
||||||
|
}
|
||||||
|
boolean ticking = BlockTypesCache.ticking[ordinal];
|
||||||
|
boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal];
|
||||||
|
boolean replacedWasLiquid = false;
|
||||||
|
BlockState replacedState = null;
|
||||||
|
if (!ticking) {
|
||||||
|
// If the block being replaced was not ticking, it cannot be a liquid
|
||||||
|
if (!replacedWasTicking) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If the block being replaced is not fluid, we do not need to worry
|
||||||
|
if (!(replacedWasLiquid =
|
||||||
|
(replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||||
|
boolean liquid = state.getMaterial().isLiquid();
|
||||||
|
int x = i & 15;
|
||||||
|
int y = (i >> 8) & 15;
|
||||||
|
int z = (i >> 4) & 15;
|
||||||
|
BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z);
|
||||||
|
if (liquid || replacedWasLiquid) {
|
||||||
|
if (liquid) {
|
||||||
|
addFluid(getBlocks.serverLevel, state, position);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this
|
||||||
|
// may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up
|
||||||
|
// being ticked anyway. We only need it to be "hit" once.
|
||||||
|
if (!wasAdjacentToWater(get, set, i, x, y, z)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addFluid(getBlocks.serverLevel, replacedState, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Extent construct(final Extent child) {
|
||||||
|
throw new UnsupportedOperationException("Processing only");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProcessorScope getScope() {
|
||||||
|
return ProcessorScope.READING_SET_BLOCKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
|
||||||
|
if (set == null || get == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char ordinal;
|
||||||
|
char reserved = BlockTypesCache.ReservedIDs.__RESERVED__;
|
||||||
|
if (x > 0 && set[i - 1] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x < 15 && set[i + 1] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (z > 0 && set[i - 16] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (z < 15 && set[i + 16] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y > 0 && set[i - 256] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y < 15 && set[i + 256] != reserved) {
|
||||||
|
return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private boolean isFluid(char ordinal) {
|
||||||
|
return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) {
|
||||||
|
Fluid type;
|
||||||
|
if (replacedState.getBlockType() == BlockTypes.LAVA) {
|
||||||
|
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA;
|
||||||
|
} else {
|
||||||
|
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
|
||||||
|
}
|
||||||
|
serverLevel.getLiquidTicks().scheduleTick(
|
||||||
|
position,
|
||||||
|
type,
|
||||||
|
type.getTickDelay(serverLevel)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,6 +6,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
|||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
@ -686,4 +687,9 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBatchProcessor getTickingPostProcessor() {
|
||||||
|
return new PaperweightPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -398,11 +398,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||||
forceLoadSections = false;
|
forceLoadSections = false;
|
||||||
copy = createCopy ? new PaperweightGetBlocks_Copy(serverLevel) : null;
|
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
||||||
try {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
ServerLevel nmsWorld = serverLevel;
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||||
boolean fastmode = set.isFastMode() && Settings.settings().QUEUE.NO_TICK_FASTMODE;
|
|
||||||
|
|
||||||
// Remove existing tiles. Create a copy so that we can remove blocks
|
// Remove existing tiles. Create a copy so that we can remove blocks
|
||||||
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
||||||
@ -470,7 +469,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection(
|
LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||||
layerNo,
|
layerNo,
|
||||||
new char[4096],
|
new char[4096],
|
||||||
fastmode,
|
|
||||||
adapter,
|
adapter,
|
||||||
biomeRegistry,
|
biomeRegistry,
|
||||||
biomeData
|
biomeData
|
||||||
@ -498,6 +496,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
bitMask |= 1 << getSectionIndex;
|
bitMask |= 1 << getSectionIndex;
|
||||||
|
|
||||||
|
// Changes may still be written to chunk SET
|
||||||
char[] tmp = set.load(layerNo);
|
char[] tmp = set.load(layerNo);
|
||||||
char[] setArr = new char[4096];
|
char[] setArr = new char[4096];
|
||||||
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
System.arraycopy(tmp, 0, setArr, 0, 4096);
|
||||||
@ -508,6 +507,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
LevelChunkSection newSection;
|
LevelChunkSection newSection;
|
||||||
LevelChunkSection existingSection = levelChunkSections[getSectionIndex];
|
LevelChunkSection existingSection = levelChunkSections[getSectionIndex];
|
||||||
|
// Don't attempt to tick section whilst we're editing
|
||||||
|
if (existingSection != null) {
|
||||||
|
PaperweightPlatformAdapter.clearCounts(existingSection);
|
||||||
|
existingSection.tickingList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (createCopy) {
|
if (createCopy) {
|
||||||
char[] tmpLoad = loadPrivately(layerNo);
|
char[] tmpLoad = loadPrivately(layerNo);
|
||||||
@ -529,7 +533,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||||
layerNo,
|
layerNo,
|
||||||
setArr,
|
setArr,
|
||||||
fastmode,
|
|
||||||
adapter,
|
adapter,
|
||||||
biomeRegistry,
|
biomeRegistry,
|
||||||
biomeData
|
biomeData
|
||||||
@ -547,9 +550,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PaperweightPlatformAdapter.fieldTickingBlockCount.set(existingSection, (short) 0);
|
|
||||||
|
|
||||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
//ensure that the server doesn't try to tick the chunksection while we're editing it. (Again)
|
||||||
|
PaperweightPlatformAdapter.clearCounts(existingSection);
|
||||||
|
existingSection.tickingList.clear();
|
||||||
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
|
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
|
||||||
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
@ -583,7 +587,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
layerNo,
|
layerNo,
|
||||||
this::loadPrivately,
|
this::loadPrivately,
|
||||||
setArr,
|
setArr,
|
||||||
fastmode,
|
|
||||||
adapter,
|
adapter,
|
||||||
biomeRegistry,
|
biomeRegistry,
|
||||||
biomeData
|
biomeData
|
||||||
@ -1052,7 +1055,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
z,
|
z,
|
||||||
biomeRegistry.get(ResourceLocation.tryParse(biomeType.getId()))
|
biomeRegistry.getOptional(ResourceLocation.tryParse(biomeType.getId())).orElseThrow()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -35,13 +36,15 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
private final ServerLevel serverLevel;
|
final ServerLevel serverLevel;
|
||||||
|
final LevelChunk levelChunk;
|
||||||
private PalettedContainer<Biome>[] biomes = null;
|
private PalettedContainer<Biome>[] biomes = null;
|
||||||
|
|
||||||
protected PaperweightGetBlocks_Copy(ServerLevel world) {
|
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
|
||||||
this.serverLevel = world;
|
this.levelChunk = levelChunk;
|
||||||
this.minHeight = world.getMinBuildHeight();
|
this.serverLevel = levelChunk.level;
|
||||||
this.maxHeight = world.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
this.minHeight = serverLevel.getMinBuildHeight();
|
||||||
|
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
||||||
this.blocks = new char[getSectionCount()][];
|
this.blocks = new char[getSectionCount()][];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ import com.fastasyncworldedit.core.util.ReflectionUtils;
|
|||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.mojang.datafixers.util.Either;
|
import com.mojang.datafixers.util.Either;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
@ -85,9 +84,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
public static final Field fieldPalette;
|
public static final Field fieldPalette;
|
||||||
|
|
||||||
|
|
||||||
public static final Field fieldTickingFluidCount;
|
private static final Field fieldTickingFluidCount;
|
||||||
public static final Field fieldTickingBlockCount;
|
private static final Field fieldTickingBlockCount;
|
||||||
public static final Field fieldNonEmptyBlockCount;
|
private static final Field fieldNonEmptyBlockCount;
|
||||||
|
|
||||||
private static final MethodHandle methodGetVisibleChunk;
|
private static final MethodHandle methodGetVisibleChunk;
|
||||||
|
|
||||||
@ -301,16 +300,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
NMS conversion
|
NMS conversion
|
||||||
*/
|
*/
|
||||||
public static LevelChunkSection newChunkSection(
|
public static LevelChunkSection newChunkSection(
|
||||||
final int layer, final char[] blocks, boolean fastmode,
|
final int layer,
|
||||||
CachedBukkitAdapter adapter, Registry<Biome> biomeRegistry,
|
final char[] blocks,
|
||||||
|
CachedBukkitAdapter adapter,
|
||||||
|
Registry<Biome> biomeRegistry,
|
||||||
@Nullable PalettedContainer<Biome> biomes
|
@Nullable PalettedContainer<Biome> biomes
|
||||||
) {
|
) {
|
||||||
return newChunkSection(layer, null, blocks, fastmode, adapter, biomeRegistry, biomes);
|
return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LevelChunkSection newChunkSection(
|
public static LevelChunkSection newChunkSection(
|
||||||
final int layer, final Function<Integer, char[]> get, char[] set,
|
final int layer,
|
||||||
boolean fastmode, CachedBukkitAdapter adapter, Registry<Biome> biomeRegistry,
|
final Function<Integer, char[]> get,
|
||||||
|
char[] set,
|
||||||
|
CachedBukkitAdapter adapter,
|
||||||
|
Registry<Biome> biomeRegistry,
|
||||||
@Nullable PalettedContainer<Biome> biomes
|
@Nullable PalettedContainer<Biome> biomes
|
||||||
) {
|
) {
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
@ -321,24 +325,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
|
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
|
||||||
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
|
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
|
||||||
try {
|
try {
|
||||||
int[] num_palette_buffer = new int[1];
|
int num_palette;
|
||||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
|
||||||
int air;
|
|
||||||
if (get == null) {
|
if (get == null) {
|
||||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter);
|
||||||
set, ticking_blocks, fastmode, adapter
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter);
|
||||||
num_palette_buffer, get, set, ticking_blocks, fastmode, adapter
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
int num_palette = num_palette_buffer[0];
|
|
||||||
// BlockStates
|
|
||||||
|
|
||||||
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
||||||
Object configuration =
|
|
||||||
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(new FakeIdMapBlock(num_palette), bitsPerEntry);
|
|
||||||
if (bitsPerEntry > 0 && bitsPerEntry < 5) {
|
if (bitsPerEntry > 0 && bitsPerEntry < 5) {
|
||||||
bitsPerEntry = 4;
|
bitsPerEntry = 4;
|
||||||
} else if (bitsPerEntry > 8) {
|
} else if (bitsPerEntry > 8) {
|
||||||
@ -365,7 +359,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
} else {
|
} else {
|
||||||
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits);
|
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits);
|
||||||
}
|
}
|
||||||
final Palette<net.minecraft.world.level.block.state.BlockState> blockStatePalette;
|
|
||||||
List<net.minecraft.world.level.block.state.BlockState> palette;
|
List<net.minecraft.world.level.block.state.BlockState> palette;
|
||||||
if (bitsPerEntry < 9) {
|
if (bitsPerEntry < 9) {
|
||||||
palette = new ArrayList<>();
|
palette = new ArrayList<>();
|
||||||
@ -390,30 +383,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
palette
|
palette
|
||||||
);
|
);
|
||||||
LevelChunkSection levelChunkSection;
|
LevelChunkSection levelChunkSection;
|
||||||
try {
|
if (biomes == null) {
|
||||||
//fieldStorage.set(dataPaletteBlocks, nmsBits);
|
biomes = new PalettedContainer<>(
|
||||||
//fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer);
|
biomeRegistry,
|
||||||
if (biomes == null) {
|
biomeRegistry.getOrThrow(Biomes.PLAINS),
|
||||||
biomes = new PalettedContainer<>(
|
PalettedContainer.Strategy.SECTION_BIOMES,
|
||||||
biomeRegistry,
|
null
|
||||||
biomeRegistry.getOrThrow(Biomes.PLAINS),
|
);
|
||||||
PalettedContainer.Strategy.SECTION_BIOMES,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
levelChunkSection = new LevelChunkSection(layer, blockStatePalettedContainer, biomes);
|
|
||||||
setCount(ticking_blocks.size(), 4096 - air, levelChunkSection);
|
|
||||||
if (!fastmode) {
|
|
||||||
ticking_blocks.forEach((pos, ordinal) -> levelChunkSection.setBlockState(
|
|
||||||
pos.getBlockX(),
|
|
||||||
pos.getBlockY(),
|
|
||||||
pos.getBlockZ(),
|
|
||||||
Block.stateById(ordinal)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} catch (final IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
|
levelChunkSection = new LevelChunkSection(layer, blockStatePalettedContainer, biomes);
|
||||||
|
|
||||||
return levelChunkSection;
|
return levelChunkSection;
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
@ -422,23 +400,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") // Only deprecated in paper
|
||||||
private static LevelChunkSection newChunkSection(
|
private static LevelChunkSection newChunkSection(
|
||||||
int layer, Registry<Biome> biomeRegistry,
|
int layer, Registry<Biome> biomeRegistry,
|
||||||
@Nullable PalettedContainer<Biome> biomes
|
@Nullable PalettedContainer<Biome> biomes
|
||||||
) {
|
) {
|
||||||
|
if (biomes == null) {
|
||||||
|
return new LevelChunkSection(layer, biomeRegistry);
|
||||||
|
}
|
||||||
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
|
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
|
||||||
Block.BLOCK_STATE_REGISTRY,
|
Block.BLOCK_STATE_REGISTRY,
|
||||||
Blocks.AIR.defaultBlockState(),
|
Blocks.AIR.defaultBlockState(),
|
||||||
PalettedContainer.Strategy.SECTION_STATES,
|
PalettedContainer.Strategy.SECTION_STATES,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
PalettedContainer<Biome> biomesPalette = biomes != null ? biomes : new PalettedContainer<>(
|
return new LevelChunkSection(layer, dataPaletteBlocks, biomes);
|
||||||
biomeRegistry,
|
|
||||||
biomeRegistry.getOrThrow(Biomes.PLAINS),
|
|
||||||
PalettedContainer.Strategy.SECTION_BIOMES,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
return new LevelChunkSection(layer, dataPaletteBlocks, biomesPalette);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -541,11 +517,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
return biomePalettedContainer;
|
return biomePalettedContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final LevelChunkSection section) throws
|
public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException {
|
||||||
IllegalAccessException {
|
fieldTickingFluidCount.setShort(section, (short) 0);
|
||||||
fieldTickingFluidCount.setShort(section, (short) 0); // TODO FIXME
|
fieldTickingBlockCount.setShort(section, (short) 0);
|
||||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
|
||||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BiomeType adapt(Biome biome, LevelAccessor levelAccessor) {
|
public static BiomeType adapt(Biome biome, LevelAccessor levelAccessor) {
|
||||||
|
@ -0,0 +1,175 @@
|
|||||||
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
|
import com.fastasyncworldedit.core.queue.IChunk;
|
||||||
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
|
import com.fastasyncworldedit.core.registry.state.PropertyKey;
|
||||||
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.Fluids;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class PaperweightPostProcessor implements IBatchProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) {
|
||||||
|
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
|
||||||
|
// The PostProcessor shouldn't be added, but just in case
|
||||||
|
if (!tickFluid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet;
|
||||||
|
layer:
|
||||||
|
for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) {
|
||||||
|
char[] set = iChunkSet.loadIfPresent(layer);
|
||||||
|
if (set == null) {
|
||||||
|
// No edit means no need to process
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char[] get = null;
|
||||||
|
for (int i = 0; i < 4096; i++) {
|
||||||
|
char ordinal = set[i];
|
||||||
|
char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
|
||||||
|
boolean fromGet = false; // Used for liquids
|
||||||
|
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
|
if (get == null) {
|
||||||
|
get = getBlocks.load(layer);
|
||||||
|
}
|
||||||
|
// If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't
|
||||||
|
// actually being set
|
||||||
|
if (get == null) {
|
||||||
|
continue layer;
|
||||||
|
}
|
||||||
|
fromGet = true;
|
||||||
|
ordinal = replacedOrdinal = get[i];
|
||||||
|
}
|
||||||
|
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
|
continue;
|
||||||
|
} else if (!fromGet) { // if fromGet, don't do the same again
|
||||||
|
if (get == null) {
|
||||||
|
get = getBlocks.load(layer);
|
||||||
|
}
|
||||||
|
replacedOrdinal = get[i];
|
||||||
|
}
|
||||||
|
boolean ticking = BlockTypesCache.ticking[ordinal];
|
||||||
|
boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal];
|
||||||
|
boolean replacedWasLiquid = false;
|
||||||
|
BlockState replacedState = null;
|
||||||
|
if (!ticking) {
|
||||||
|
// If the block being replaced was not ticking, it cannot be a liquid
|
||||||
|
if (!replacedWasTicking) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If the block being replaced is not fluid, we do not need to worry
|
||||||
|
if (!(replacedWasLiquid =
|
||||||
|
(replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||||
|
boolean liquid = state.getMaterial().isLiquid();
|
||||||
|
int x = i & 15;
|
||||||
|
int y = (i >> 8) & 15;
|
||||||
|
int z = (i >> 4) & 15;
|
||||||
|
BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z);
|
||||||
|
if (liquid || replacedWasLiquid) {
|
||||||
|
if (liquid) {
|
||||||
|
addFluid(getBlocks.serverLevel, state, position);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this
|
||||||
|
// may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up
|
||||||
|
// being ticked anyway. We only need it to be "hit" once.
|
||||||
|
if (!wasAdjacentToWater(get, set, i, x, y, z)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addFluid(getBlocks.serverLevel, replacedState, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Extent construct(final Extent child) {
|
||||||
|
throw new UnsupportedOperationException("Processing only");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProcessorScope getScope() {
|
||||||
|
return ProcessorScope.READING_SET_BLOCKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
|
||||||
|
if (set == null || get == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char ordinal;
|
||||||
|
char reserved = BlockTypesCache.ReservedIDs.__RESERVED__;
|
||||||
|
if (x > 0 && set[i - 1] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x < 15 && set[i + 1] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (z > 0 && set[i - 16] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (z < 15 && set[i + 16] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y > 0 && set[i - 256] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y < 15 && set[i + 256] != reserved) {
|
||||||
|
return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private boolean isFluid(char ordinal) {
|
||||||
|
return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) {
|
||||||
|
Fluid type;
|
||||||
|
if (replacedState.getBlockType() == BlockTypes.LAVA) {
|
||||||
|
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA;
|
||||||
|
} else {
|
||||||
|
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
|
||||||
|
}
|
||||||
|
serverLevel.scheduleTick(
|
||||||
|
position,
|
||||||
|
type,
|
||||||
|
type.getTickDelay(serverLevel)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,6 +6,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
|||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
@ -690,4 +691,9 @@ public final class PaperweightFaweAdapter extends CachedBukkitAdapter implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBatchProcessor getTickingPostProcessor() {
|
||||||
|
return new PaperweightPostProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
private final int minSectionPosition;
|
private final int minSectionPosition;
|
||||||
private final int maxSectionPosition;
|
private final int maxSectionPosition;
|
||||||
private final IdMap<Holder<Biome>> biomeRegistry;
|
private final Registry<Biome> biomeRegistry;
|
||||||
|
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
||||||
private LevelChunkSection[] sections;
|
private LevelChunkSection[] sections;
|
||||||
private LevelChunk levelChunk;
|
private LevelChunk levelChunk;
|
||||||
private DataLayer[] blockLight;
|
private DataLayer[] blockLight;
|
||||||
@ -124,7 +125,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
this.maxSectionPosition = maxHeight >> 4;
|
this.maxSectionPosition = maxHeight >> 4;
|
||||||
this.skyLight = new DataLayer[getSectionCount()];
|
this.skyLight = new DataLayer[getSectionCount()];
|
||||||
this.blockLight = new DataLayer[getSectionCount()];
|
this.blockLight = new DataLayer[getSectionCount()];
|
||||||
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY).asHolderIdMap();
|
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY);
|
||||||
|
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkX() {
|
public int getChunkX() {
|
||||||
@ -399,11 +401,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||||
forceLoadSections = false;
|
forceLoadSections = false;
|
||||||
copy = createCopy ? new PaperweightGetBlocks_Copy(serverLevel) : null;
|
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
||||||
try {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
ServerLevel nmsWorld = serverLevel;
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||||
boolean fastmode = set.isFastMode() && Settings.settings().QUEUE.NO_TICK_FASTMODE;
|
|
||||||
|
|
||||||
// Remove existing tiles. Create a copy so that we can remove blocks
|
// Remove existing tiles. Create a copy so that we can remove blocks
|
||||||
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
||||||
@ -466,12 +467,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
if (existingSection == null) {
|
if (existingSection == null) {
|
||||||
PalettedContainer<Holder<Biome>> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer(
|
PalettedContainer<Holder<Biome>> biomeData = PaperweightPlatformAdapter.getBiomePalettedContainer(
|
||||||
biomes[setSectionIndex],
|
biomes[setSectionIndex],
|
||||||
biomeRegistry
|
biomeHolderIdMap
|
||||||
);
|
);
|
||||||
LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection(
|
LevelChunkSection newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||||
layerNo,
|
layerNo,
|
||||||
new char[4096],
|
new char[4096],
|
||||||
fastmode,
|
|
||||||
adapter,
|
adapter,
|
||||||
biomeRegistry,
|
biomeRegistry,
|
||||||
biomeData
|
biomeData
|
||||||
@ -527,19 +527,18 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
if (existingSection == null) {
|
if (existingSection == null) {
|
||||||
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
|
PalettedContainer<Holder<Biome>> biomeData = biomes == null ? new PalettedContainer<>(
|
||||||
biomeRegistry,
|
biomeHolderIdMap,
|
||||||
biomeRegistry.byIdOrThrow(WorldEditPlugin
|
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter()
|
.getBukkitImplAdapter()
|
||||||
.getInternalBiomeId(
|
.getInternalBiomeId(
|
||||||
BiomeTypes.PLAINS)),
|
BiomeTypes.PLAINS)),
|
||||||
PalettedContainer.Strategy.SECTION_BIOMES,
|
PalettedContainer.Strategy.SECTION_BIOMES,
|
||||||
null
|
null
|
||||||
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeRegistry);
|
) : PaperweightPlatformAdapter.getBiomePalettedContainer(biomes[setSectionIndex], biomeHolderIdMap);
|
||||||
newSection = PaperweightPlatformAdapter.newChunkSection(
|
newSection = PaperweightPlatformAdapter.newChunkSection(
|
||||||
layerNo,
|
layerNo,
|
||||||
setArr,
|
setArr,
|
||||||
fastmode,
|
|
||||||
adapter,
|
adapter,
|
||||||
biomeRegistry,
|
biomeRegistry,
|
||||||
biomeData
|
biomeData
|
||||||
@ -562,9 +561,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PaperweightPlatformAdapter.fieldTickingBlockCount.set(existingSection, (short) 0);
|
|
||||||
|
|
||||||
//ensure that the server doesn't try to tick the chunksection while we're editing it.
|
//ensure that the server doesn't try to tick the chunksection while we're editing it. (Again)
|
||||||
|
PaperweightPlatformAdapter.clearCounts(existingSection);
|
||||||
|
existingSection.tickingList.clear();
|
||||||
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
|
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
|
||||||
|
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
@ -601,7 +601,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
layerNo,
|
layerNo,
|
||||||
this::loadPrivately,
|
this::loadPrivately,
|
||||||
setArr,
|
setArr,
|
||||||
fastmode,
|
|
||||||
adapter,
|
adapter,
|
||||||
biomeRegistry,
|
biomeRegistry,
|
||||||
biomeData
|
biomeData
|
||||||
@ -1070,7 +1069,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
z,
|
z,
|
||||||
biomeRegistry.byIdOrThrow(WorldEditPlugin
|
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter()
|
.getBukkitImplAdapter()
|
||||||
.getInternalBiomeId(biomeType))
|
.getInternalBiomeId(biomeType))
|
||||||
|
@ -20,6 +20,7 @@ import net.minecraft.server.level.ServerLevel;
|
|||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -37,13 +38,15 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
private final ServerLevel serverLevel;
|
final ServerLevel serverLevel;
|
||||||
|
final LevelChunk levelChunk;
|
||||||
private PalettedContainer<Holder<Biome>>[] biomes = null;
|
private PalettedContainer<Holder<Biome>>[] biomes = null;
|
||||||
|
|
||||||
protected PaperweightGetBlocks_Copy(ServerLevel world) {
|
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
|
||||||
this.serverLevel = world;
|
this.levelChunk = levelChunk;
|
||||||
this.minHeight = world.getMinBuildHeight();
|
this.serverLevel = levelChunk.level;
|
||||||
this.maxHeight = world.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
this.minHeight = serverLevel.getMinBuildHeight();
|
||||||
|
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
||||||
this.blocks = new char[getSectionCount()][];
|
this.blocks = new char[getSectionCount()][];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import com.mojang.datafixers.util.Either;
|
|||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
@ -84,10 +83,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
public static final Field fieldStorage;
|
public static final Field fieldStorage;
|
||||||
public static final Field fieldPalette;
|
public static final Field fieldPalette;
|
||||||
|
|
||||||
|
private static final Field fieldTickingFluidCount;
|
||||||
public static final Field fieldTickingFluidCount;
|
private static final Field fieldTickingBlockCount;
|
||||||
public static final Field fieldTickingBlockCount;
|
private static final Field fieldNonEmptyBlockCount;
|
||||||
public static final Field fieldNonEmptyBlockCount;
|
|
||||||
|
|
||||||
private static final MethodHandle methodGetVisibleChunk;
|
private static final MethodHandle methodGetVisibleChunk;
|
||||||
|
|
||||||
@ -303,16 +301,21 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
NMS conversion
|
NMS conversion
|
||||||
*/
|
*/
|
||||||
public static LevelChunkSection newChunkSection(
|
public static LevelChunkSection newChunkSection(
|
||||||
final int layer, final char[] blocks, boolean fastmode,
|
final int layer,
|
||||||
CachedBukkitAdapter adapter, IdMap<Holder<Biome>> biomeRegistry,
|
final char[] blocks,
|
||||||
|
CachedBukkitAdapter adapter,
|
||||||
|
Registry<Biome> biomeRegistry,
|
||||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||||
) {
|
) {
|
||||||
return newChunkSection(layer, null, blocks, fastmode, adapter, biomeRegistry, biomes);
|
return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LevelChunkSection newChunkSection(
|
public static LevelChunkSection newChunkSection(
|
||||||
final int layer, final Function<Integer, char[]> get, char[] set,
|
final int layer,
|
||||||
boolean fastmode, CachedBukkitAdapter adapter, IdMap<Holder<Biome>> biomeRegistry,
|
final Function<Integer, char[]> get,
|
||||||
|
char[] set,
|
||||||
|
CachedBukkitAdapter adapter,
|
||||||
|
Registry<Biome> biomeRegistry,
|
||||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||||
) {
|
) {
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
@ -323,24 +326,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
|
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
|
||||||
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
|
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
|
||||||
try {
|
try {
|
||||||
int[] num_palette_buffer = new int[1];
|
int num_palette;
|
||||||
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
|
|
||||||
int air;
|
|
||||||
if (get == null) {
|
if (get == null) {
|
||||||
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
|
num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter);
|
||||||
set, ticking_blocks, fastmode, adapter
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
|
num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter);
|
||||||
num_palette_buffer, get, set, ticking_blocks, fastmode, adapter
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
int num_palette = num_palette_buffer[0];
|
|
||||||
// BlockStates
|
|
||||||
|
|
||||||
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
||||||
Object configuration =
|
|
||||||
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(new FakeIdMapBlock(num_palette), bitsPerEntry);
|
|
||||||
if (bitsPerEntry > 0 && bitsPerEntry < 5) {
|
if (bitsPerEntry > 0 && bitsPerEntry < 5) {
|
||||||
bitsPerEntry = 4;
|
bitsPerEntry = 4;
|
||||||
} else if (bitsPerEntry > 8) {
|
} else if (bitsPerEntry > 8) {
|
||||||
@ -367,7 +360,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
} else {
|
} else {
|
||||||
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits);
|
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits);
|
||||||
}
|
}
|
||||||
final Palette<net.minecraft.world.level.block.state.BlockState> blockStatePalette;
|
|
||||||
List<net.minecraft.world.level.block.state.BlockState> palette;
|
List<net.minecraft.world.level.block.state.BlockState> palette;
|
||||||
if (bitsPerEntry < 9) {
|
if (bitsPerEntry < 9) {
|
||||||
palette = new ArrayList<>();
|
palette = new ArrayList<>();
|
||||||
@ -391,62 +383,43 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
nmsBits,
|
nmsBits,
|
||||||
palette
|
palette
|
||||||
);
|
);
|
||||||
LevelChunkSection levelChunkSection;
|
if (biomes == null) {
|
||||||
try {
|
IdMap<Holder<Biome>> biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
||||||
//fieldStorage.set(dataPaletteBlocks, nmsBits);
|
biomes = new PalettedContainer<>(
|
||||||
//fieldPalette.set(dataPaletteBlocks, blockStatePalettedContainer);
|
biomeHolderIdMap,
|
||||||
if (biomes == null) {
|
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
|
||||||
biomes = new PalettedContainer<>(
|
.getInstance()
|
||||||
biomeRegistry,
|
.getBukkitImplAdapter()
|
||||||
biomeRegistry.byIdOrThrow(WorldEditPlugin
|
.getInternalBiomeId(
|
||||||
.getInstance()
|
BiomeTypes.PLAINS)),
|
||||||
.getBukkitImplAdapter()
|
PalettedContainer.Strategy.SECTION_BIOMES,
|
||||||
.getInternalBiomeId(BiomeTypes.PLAINS)),
|
null
|
||||||
PalettedContainer.Strategy.SECTION_BIOMES,
|
);
|
||||||
null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
levelChunkSection = new LevelChunkSection(layer, blockStatePalettedContainer, biomes);
|
|
||||||
setCount(ticking_blocks.size(), 4096 - air, levelChunkSection);
|
|
||||||
if (!fastmode) {
|
|
||||||
ticking_blocks.forEach((pos, ordinal) -> levelChunkSection.setBlockState(
|
|
||||||
pos.getBlockX(),
|
|
||||||
pos.getBlockY(),
|
|
||||||
pos.getBlockZ(),
|
|
||||||
Block.stateById(ordinal)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} catch (final IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return levelChunkSection;
|
return new LevelChunkSection(layer, blockStatePalettedContainer, biomes);
|
||||||
} catch (final Throwable e) {
|
} catch (final Throwable e) {
|
||||||
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation") // Only deprecated in paper
|
||||||
private static LevelChunkSection newChunkSection(
|
private static LevelChunkSection newChunkSection(
|
||||||
int layer, IdMap<Holder<Biome>> biomeRegistry,
|
int layer,
|
||||||
|
Registry<Biome> biomeRegistry,
|
||||||
@Nullable PalettedContainer<Holder<Biome>> biomes
|
@Nullable PalettedContainer<Holder<Biome>> biomes
|
||||||
) {
|
) {
|
||||||
|
if (biomes == null) {
|
||||||
|
return new LevelChunkSection(layer, biomeRegistry);
|
||||||
|
}
|
||||||
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
|
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
|
||||||
Block.BLOCK_STATE_REGISTRY,
|
Block.BLOCK_STATE_REGISTRY,
|
||||||
Blocks.AIR.defaultBlockState(),
|
Blocks.AIR.defaultBlockState(),
|
||||||
PalettedContainer.Strategy.SECTION_STATES,
|
PalettedContainer.Strategy.SECTION_STATES,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
PalettedContainer<Holder<Biome>> biomesPalette = biomes != null ? biomes : new PalettedContainer<>(
|
return new LevelChunkSection(layer, dataPaletteBlocks, biomes);
|
||||||
biomeRegistry,
|
|
||||||
biomeRegistry.byIdOrThrow(WorldEditPlugin
|
|
||||||
.getInstance()
|
|
||||||
.getBukkitImplAdapter()
|
|
||||||
.getInternalBiomeId(BiomeTypes.PLAINS)),
|
|
||||||
PalettedContainer.Strategy.SECTION_BIOMES,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
return new LevelChunkSection(layer, dataPaletteBlocks, biomesPalette);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -556,11 +529,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
return biomePalettedContainer;
|
return biomePalettedContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final LevelChunkSection section) throws
|
public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException {
|
||||||
IllegalAccessException {
|
fieldTickingFluidCount.setShort(section, (short) 0);
|
||||||
fieldTickingFluidCount.setShort(section, (short) 0); // TODO FIXME
|
fieldTickingBlockCount.setShort(section, (short) 0);
|
||||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
|
||||||
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BiomeType adapt(Holder<Biome> biome, LevelAccessor levelAccessor) {
|
public static BiomeType adapt(Holder<Biome> biome, LevelAccessor levelAccessor) {
|
||||||
|
@ -0,0 +1,175 @@
|
|||||||
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
|
import com.fastasyncworldedit.core.queue.IChunk;
|
||||||
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
|
import com.fastasyncworldedit.core.registry.state.PropertyKey;
|
||||||
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.Fluids;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class PaperweightPostProcessor implements IBatchProcessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) {
|
||||||
|
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
|
||||||
|
// The PostProcessor shouldn't be added, but just in case
|
||||||
|
if (!tickFluid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet;
|
||||||
|
layer:
|
||||||
|
for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) {
|
||||||
|
char[] set = iChunkSet.loadIfPresent(layer);
|
||||||
|
if (set == null) {
|
||||||
|
// No edit means no need to process
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
char[] get = null;
|
||||||
|
for (int i = 0; i < 4096; i++) {
|
||||||
|
char ordinal = set[i];
|
||||||
|
char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
|
||||||
|
boolean fromGet = false; // Used for liquids
|
||||||
|
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
|
if (get == null) {
|
||||||
|
get = getBlocks.load(layer);
|
||||||
|
}
|
||||||
|
// If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't
|
||||||
|
// actually being set
|
||||||
|
if (get == null) {
|
||||||
|
continue layer;
|
||||||
|
}
|
||||||
|
fromGet = true;
|
||||||
|
ordinal = replacedOrdinal = get[i];
|
||||||
|
}
|
||||||
|
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
|
continue;
|
||||||
|
} else if (!fromGet) { // if fromGet, don't do the same again
|
||||||
|
if (get == null) {
|
||||||
|
get = getBlocks.load(layer);
|
||||||
|
}
|
||||||
|
replacedOrdinal = get[i];
|
||||||
|
}
|
||||||
|
boolean ticking = BlockTypesCache.ticking[ordinal];
|
||||||
|
boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal];
|
||||||
|
boolean replacedWasLiquid = false;
|
||||||
|
BlockState replacedState = null;
|
||||||
|
if (!ticking) {
|
||||||
|
// If the block being replaced was not ticking, it cannot be a liquid
|
||||||
|
if (!replacedWasTicking) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If the block being replaced is not fluid, we do not need to worry
|
||||||
|
if (!(replacedWasLiquid =
|
||||||
|
(replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlockState state = BlockState.getFromOrdinal(ordinal);
|
||||||
|
boolean liquid = state.getMaterial().isLiquid();
|
||||||
|
int x = i & 15;
|
||||||
|
int y = (i >> 8) & 15;
|
||||||
|
int z = (i >> 4) & 15;
|
||||||
|
BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z);
|
||||||
|
if (liquid || replacedWasLiquid) {
|
||||||
|
if (liquid) {
|
||||||
|
addFluid(getBlocks.serverLevel, state, position);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this
|
||||||
|
// may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up
|
||||||
|
// being ticked anyway. We only need it to be "hit" once.
|
||||||
|
if (!wasAdjacentToWater(get, set, i, x, y, z)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
addFluid(getBlocks.serverLevel, replacedState, position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Extent construct(final Extent child) {
|
||||||
|
throw new UnsupportedOperationException("Processing only");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProcessorScope getScope() {
|
||||||
|
return ProcessorScope.READING_SET_BLOCKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
|
||||||
|
if (set == null || get == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char ordinal;
|
||||||
|
char reserved = BlockTypesCache.ReservedIDs.__RESERVED__;
|
||||||
|
if (x > 0 && set[i - 1] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x < 15 && set[i + 1] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (z > 0 && set[i - 16] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (z < 15 && set[i + 16] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y > 0 && set[i - 256] != reserved) {
|
||||||
|
if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y < 15 && set[i + 256] != reserved) {
|
||||||
|
return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private boolean isFluid(char ordinal) {
|
||||||
|
return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) {
|
||||||
|
Fluid type;
|
||||||
|
if (replacedState.getBlockType() == BlockTypes.LAVA) {
|
||||||
|
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA;
|
||||||
|
} else {
|
||||||
|
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
|
||||||
|
}
|
||||||
|
serverLevel.scheduleTick(
|
||||||
|
position,
|
||||||
|
type,
|
||||||
|
type.getTickDelay(serverLevel)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
@ -1,25 +1,21 @@
|
|||||||
package com.fastasyncworldedit.bukkit.adapter;
|
package com.fastasyncworldedit.bukkit.adapter;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
||||||
|
|
||||||
public static int createPalette(
|
public static int createPalette(
|
||||||
int[] blockToPalette, int[] paletteToBlock, int[] blocksCopy,
|
int[] blockToPalette,
|
||||||
int[] num_palette_buffer, char[] set, Map<BlockVector3, Integer> ticking_blocks, boolean fastmode,
|
int[] paletteToBlock,
|
||||||
|
int[] blocksCopy,
|
||||||
|
char[] set,
|
||||||
CachedBukkitAdapter adapter
|
CachedBukkitAdapter adapter
|
||||||
) {
|
) {
|
||||||
int air = 0;
|
|
||||||
int num_palette = 0;
|
int num_palette = 0;
|
||||||
for (int i = 0; i < 4096; i++) {
|
for (int i = 0; i < 4096; i++) {
|
||||||
char ordinal = set[i];
|
char ordinal = set[i];
|
||||||
@ -42,52 +38,26 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
|||||||
}
|
}
|
||||||
System.arraycopy(adapter.getOrdinalToIbdID(), 0, blockToPalette, 0, adapter.getOrdinalToIbdID().length);
|
System.arraycopy(adapter.getOrdinalToIbdID(), 0, blockToPalette, 0, adapter.getOrdinalToIbdID().length);
|
||||||
}
|
}
|
||||||
char lastOrdinal = 0;
|
|
||||||
boolean lastticking = false;
|
|
||||||
boolean tick_placed = Settings.settings().EXPERIMENTAL.ALLOW_TICK_PLACED;
|
|
||||||
for (int i = 0; i < 4096; i++) {
|
for (int i = 0; i < 4096; i++) {
|
||||||
char ordinal = set[i];
|
char ordinal = set[i];
|
||||||
switch (ordinal) {
|
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
case BlockTypesCache.ReservedIDs.__RESERVED__:
|
ordinal = BlockTypesCache.ReservedIDs.AIR;
|
||||||
ordinal = BlockTypesCache.ReservedIDs.AIR;
|
|
||||||
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR:
|
|
||||||
air++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!fastmode && !tick_placed) {
|
|
||||||
boolean ticking;
|
|
||||||
if (ordinal != lastOrdinal) {
|
|
||||||
ticking = BlockTypesCache.ticking[ordinal];
|
|
||||||
lastOrdinal = ordinal;
|
|
||||||
lastticking = ticking;
|
|
||||||
} else {
|
|
||||||
ticking = lastticking;
|
|
||||||
}
|
|
||||||
if (ticking) {
|
|
||||||
BlockState state = BlockState.getFromOrdinal(ordinal);
|
|
||||||
ticking_blocks
|
|
||||||
.put(
|
|
||||||
BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
|
|
||||||
WorldEditPlugin.getInstance().getBukkitImplAdapter()
|
|
||||||
.getInternalBlockStateId(state).orElse(0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
int palette = blockToPalette[ordinal];
|
int palette = blockToPalette[ordinal];
|
||||||
blocksCopy[i] = palette;
|
blocksCopy[i] = palette;
|
||||||
}
|
}
|
||||||
num_palette_buffer[0] = num_palette;
|
return num_palette;
|
||||||
return air;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int createPalette(
|
public static int createPalette(
|
||||||
int layer, int[] blockToPalette, int[] paletteToBlock,
|
int layer,
|
||||||
int[] blocksCopy, int[] num_palette_buffer, Function<Integer, char[]> get, char[] set,
|
int[] blockToPalette,
|
||||||
Map<BlockVector3, Integer> ticking_blocks, boolean fastmode,
|
int[] paletteToBlock,
|
||||||
|
int[] blocksCopy,
|
||||||
|
Function<Integer, char[]> get,
|
||||||
|
char[] set,
|
||||||
CachedBukkitAdapter adapter
|
CachedBukkitAdapter adapter
|
||||||
) {
|
) {
|
||||||
int air = 0;
|
|
||||||
int num_palette = 0;
|
int num_palette = 0;
|
||||||
char[] getArr = null;
|
char[] getArr = null;
|
||||||
for (int i = 0; i < 4096; i++) {
|
for (int i = 0; i < 4096; i++) {
|
||||||
@ -117,73 +87,21 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
|||||||
}
|
}
|
||||||
System.arraycopy(adapter.getOrdinalToIbdID(), 0, blockToPalette, 0, adapter.getOrdinalToIbdID().length);
|
System.arraycopy(adapter.getOrdinalToIbdID(), 0, blockToPalette, 0, adapter.getOrdinalToIbdID().length);
|
||||||
}
|
}
|
||||||
char lastOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
|
|
||||||
boolean lastticking = false;
|
|
||||||
boolean tick_placed = Settings.settings().EXPERIMENTAL.ALLOW_TICK_PLACED;
|
|
||||||
boolean tick_existing = Settings.settings().EXPERIMENTAL.ALLOW_TICK_EXISTING;
|
|
||||||
for (int i = 0; i < 4096; i++) {
|
for (int i = 0; i < 4096; i++) {
|
||||||
char ordinal = set[i];
|
char ordinal= set[i];
|
||||||
switch (ordinal) {
|
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
case BlockTypesCache.ReservedIDs.__RESERVED__ -> {
|
if (getArr == null) {
|
||||||
if (getArr == null) {
|
getArr = get.apply(layer);
|
||||||
getArr = get.apply(layer);
|
|
||||||
}
|
|
||||||
set[i] = switch (ordinal = getArr[i]) {
|
|
||||||
case BlockTypesCache.ReservedIDs.__RESERVED__:
|
|
||||||
ordinal = BlockTypesCache.ReservedIDs.AIR;
|
|
||||||
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR:
|
|
||||||
air++;
|
|
||||||
yield ordinal;
|
|
||||||
default:
|
|
||||||
if (!fastmode && !tick_placed && tick_existing) {
|
|
||||||
boolean ticking;
|
|
||||||
if (ordinal != lastOrdinal) {
|
|
||||||
ticking = BlockTypesCache.ticking[ordinal];
|
|
||||||
lastOrdinal = ordinal;
|
|
||||||
lastticking = ticking;
|
|
||||||
} else {
|
|
||||||
ticking = lastticking;
|
|
||||||
}
|
|
||||||
if (ticking) {
|
|
||||||
BlockState state = BlockState.getFromOrdinal(ordinal);
|
|
||||||
ticking_blocks.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
|
|
||||||
WorldEditPlugin
|
|
||||||
.getInstance()
|
|
||||||
.getBukkitImplAdapter()
|
|
||||||
.getInternalBlockStateId(state)
|
|
||||||
.orElse(0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
yield ordinal;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR -> air++;
|
if ((ordinal = getArr[i]) == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
}
|
ordinal = BlockTypesCache.ReservedIDs.AIR;
|
||||||
if (!fastmode && tick_placed) {
|
|
||||||
boolean ticking;
|
|
||||||
if (ordinal != lastOrdinal) {
|
|
||||||
ticking = BlockTypesCache.ticking[ordinal];
|
|
||||||
lastOrdinal = ordinal;
|
|
||||||
lastticking = ticking;
|
|
||||||
} else {
|
|
||||||
ticking = lastticking;
|
|
||||||
}
|
|
||||||
if (ticking) {
|
|
||||||
BlockState state = BlockState.getFromOrdinal(ordinal);
|
|
||||||
ticking_blocks.put(
|
|
||||||
BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
|
|
||||||
WorldEditPlugin.getInstance().getBukkitImplAdapter()
|
|
||||||
.getInternalBlockStateId(state).orElse(0)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int palette = blockToPalette[ordinal];
|
int palette = blockToPalette[ordinal];
|
||||||
blocksCopy[i] = palette;
|
blocksCopy[i] = palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_palette_buffer[0] = num_palette;
|
return num_palette;
|
||||||
return air;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,7 +20,9 @@
|
|||||||
package com.sk89q.worldedit.bukkit;
|
package com.sk89q.worldedit.bukkit;
|
||||||
|
|
||||||
import com.fastasyncworldedit.bukkit.util.MinecraftVersion;
|
import com.fastasyncworldedit.bukkit.util.MinecraftVersion;
|
||||||
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.sk89q.bukkit.util.CommandInfo;
|
import com.sk89q.bukkit.util.CommandInfo;
|
||||||
import com.sk89q.bukkit.util.CommandRegistration;
|
import com.sk89q.bukkit.util.CommandRegistration;
|
||||||
@ -289,5 +291,17 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser
|
|||||||
public int versionMaxY() {
|
public int versionMaxY() {
|
||||||
return MinecraftVersion.getCurrent().isEqualOrHigherThan(MinecraftVersion.CAVES_18) ? 319 : 255;
|
return MinecraftVersion.getCurrent().isEqualOrHigherThan(MinecraftVersion.CAVES_18) ? 319 : 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBatchProcessor getPlatformPostProcessor(boolean fastMode) {
|
||||||
|
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
|
||||||
|
if (!tickFluid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (Settings.settings().QUEUE.NO_TICK_FASTMODE && fastMode) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.plugin.getBukkitImplAdapter().getTickingPostProcessor();
|
||||||
|
}
|
||||||
//FAWE end
|
//FAWE end
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import com.fastasyncworldedit.bukkit.adapter.IBukkitAdapter;
|
|||||||
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
import com.sk89q.jnbt.AdventureNBTConverter;
|
import com.sk89q.jnbt.AdventureNBTConverter;
|
||||||
@ -350,5 +351,15 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
|
|||||||
default Map<String, List<Property<?>>> getAllProperties() {
|
default Map<String, List<Property<?>>> getAllProperties() {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link IBatchProcessor} instance for post-processing of chunks to sort ticking of placed/existing blocks and
|
||||||
|
* fluids if the plugin is configured to do so
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
default IBatchProcessor getTickingPostProcessor() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
//FAWE end
|
//FAWE end
|
||||||
}
|
}
|
||||||
|
@ -604,7 +604,7 @@ public enum FaweCache implements Trimable {
|
|||||||
} else if (throwable.getCause() instanceof FaweException) {
|
} else if (throwable.getCause() instanceof FaweException) {
|
||||||
handleFaweException((FaweException) throwable.getCause());
|
handleFaweException((FaweException) throwable.getCause());
|
||||||
} else {
|
} else {
|
||||||
int hash = throwable.getMessage().hashCode();
|
int hash = throwable.getMessage() != null ? throwable.getMessage().hashCode() : 0;
|
||||||
if (hash != lastException) {
|
if (hash != lastException) {
|
||||||
lastException = hash;
|
lastException = hash;
|
||||||
LOGGER.catching(throwable);
|
LOGGER.catching(throwable);
|
||||||
|
@ -567,7 +567,8 @@ public class Settings extends Config {
|
|||||||
public int DISCARD_AFTER_MS = 60000;
|
public int DISCARD_AFTER_MS = 60000;
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"When using fastmode also do not bother to fix existing ticking blocks"
|
"When using fastmode do not bother to tick existing/placed blocks/fluids",
|
||||||
|
"Only works in versions up to 1.17.1"
|
||||||
})
|
})
|
||||||
public boolean NO_TICK_FASTMODE = true;
|
public boolean NO_TICK_FASTMODE = true;
|
||||||
|
|
||||||
@ -625,16 +626,11 @@ public class Settings extends Config {
|
|||||||
public boolean OTHER = false;
|
public boolean OTHER = false;
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Allow blocks placed by WorldEdit to tick. This could cause the big lags.",
|
"Allow fluids placed by FAWE to tick (flow). This could cause the big lags.",
|
||||||
"This has no effect on existing blocks one way or the other."
|
"This has no effect on existing blocks one way or the other.",
|
||||||
|
"Changes due to fluid flow will not be tracked by history, thus may have unintended consequences"
|
||||||
})
|
})
|
||||||
public boolean ALLOW_TICK_PLACED = false;
|
public boolean ALLOW_TICK_FLUIDS = false;
|
||||||
|
|
||||||
@Comment({
|
|
||||||
"Force re-ticking of existing blocks not edited by FAWE.",
|
|
||||||
"This will increase time taken slightly."
|
|
||||||
})
|
|
||||||
public boolean ALLOW_TICK_EXISTING = true;
|
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)",
|
"Sets a maximum limit (in kb) for the size of a player's schematics directory (per-player mode only)",
|
||||||
|
@ -167,11 +167,6 @@ public class DisallowedBlocksExtent extends AbstractDelegateExtent implements IB
|
|||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<IChunkSet> postProcessSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
|
||||||
return CompletableFuture.completedFuture(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Extent construct(final Extent child) {
|
public Extent construct(final Extent child) {
|
||||||
|
@ -56,9 +56,4 @@ public class HeightBoundExtent extends FaweRegionExtent {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
|
||||||
return CompletableFuture.completedFuture(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -178,8 +178,13 @@ public class MultiRegionExtent extends FaweRegionExtent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
public Future<?> postProcessSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
||||||
return intersection.postProcessSet(chunk, get, set);
|
return intersection.postProcessSet(chunk, get, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcess(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
|
intersection.postProcess(chunk, get, set);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -342,7 +342,12 @@ public class NullExtent extends FaweRegionExtent implements IBatchProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
public Future<?> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
|
throw reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcess(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
throw reason;
|
throw reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,10 +46,17 @@ public class SingleRegionExtent extends FaweRegionExtent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
public Future<?> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
|
// Most likely will do nothing, but perhaps people will find some fun way of using this via API (though doubtful)
|
||||||
return region.postProcessSet(chunk, get, set);
|
return region.postProcessSet(chunk, get, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcess(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
|
// Most likely will do nothing, but perhaps people will find some fun way of using this via API (though doubtful)
|
||||||
|
region.postProcess(chunk, get, set);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean processGet(int chunkX, int chunkZ) {
|
public boolean processGet(int chunkX, int chunkZ) {
|
||||||
return region.containsChunk(chunkX, chunkZ);
|
return region.containsChunk(chunkX, chunkZ);
|
||||||
|
@ -143,11 +143,6 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc
|
|||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<IChunkSet> postProcessSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
|
||||||
return CompletableFuture.completedFuture(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Extent construct(final Extent child) {
|
public Extent construct(final Extent child) {
|
||||||
|
@ -28,10 +28,15 @@ public class BatchProcessorHolder implements IBatchProcessorHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
public Future<?> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
return getPostProcessor().postProcessSet(chunk, get, set);
|
return getPostProcessor().postProcessSet(chunk, get, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postProcess(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
|
getPostProcessor().postProcess(chunk, get, set);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flush() {
|
public void flush() {
|
||||||
getProcessor().flush();
|
getProcessor().flush();
|
||||||
|
@ -29,13 +29,6 @@ public final class EmptyBatchProcessor implements IBatchProcessor {
|
|||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nonnull
|
|
||||||
public Future<IChunkSet> postProcessSet(@Nullable IChunk chunk, @Nullable IChunkGet get, @Nullable IChunkSet set) {
|
|
||||||
// Doesn't need to do anything
|
|
||||||
return CompletableFuture.completedFuture(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public IBatchProcessor join(@Nullable IBatchProcessor other) {
|
public IBatchProcessor join(@Nullable IBatchProcessor other) {
|
||||||
return other;
|
return other;
|
||||||
|
@ -31,10 +31,15 @@ public interface IBatchProcessorHolder extends IBatchProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
default Future<?> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
return getPostProcessor().postProcessSet(chunk, get, set);
|
return getPostProcessor().postProcessSet(chunk, get, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void postProcess(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
|
getPostProcessor().postProcess(chunk, get, set);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default boolean processGet(int chunkX, int chunkZ) {
|
default boolean processGet(int chunkX, int chunkZ) {
|
||||||
return getProcessor().processGet(chunkX, chunkZ);
|
return getProcessor().processGet(chunkX, chunkZ);
|
||||||
|
@ -9,6 +9,7 @@ import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
|||||||
import com.fastasyncworldedit.core.queue.IChunk;
|
import com.fastasyncworldedit.core.queue.IChunk;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
|
import com.fastasyncworldedit.core.util.MultiFuture;
|
||||||
import com.fastasyncworldedit.core.util.StringMan;
|
import com.fastasyncworldedit.core.util.StringMan;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
@ -24,7 +25,6 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@ -129,37 +129,64 @@ public class MultiBatchProcessor implements IBatchProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
public Future<?> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
try {
|
List<Future<?>> futures = new ArrayList<>();
|
||||||
for (IBatchProcessor processor : processors) {
|
for (IBatchProcessor processor : processors) {
|
||||||
|
try {
|
||||||
// We do NOT want to edit blocks in post processing
|
// We do NOT want to edit blocks in post processing
|
||||||
if (processor.getScope() != ProcessorScope.READING_SET_BLOCKS) {
|
if (processor.getScope() != ProcessorScope.READING_SET_BLOCKS) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
set = processor.postProcessSet(chunk, get, set).get();
|
futures.add(processor.postProcessSet(chunk, get, set));
|
||||||
if (set == null) {
|
} catch (Throwable e) {
|
||||||
return null;
|
if (e instanceof FaweException) {
|
||||||
|
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e, LOGGER);
|
||||||
|
} else if (e.getCause() instanceof FaweException) {
|
||||||
|
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e.getCause(), LOGGER);
|
||||||
|
} else {
|
||||||
|
String message = e.getMessage();
|
||||||
|
int hash = message != null ? message.hashCode() : 0;
|
||||||
|
if (lastException != hash) {
|
||||||
|
lastException = hash;
|
||||||
|
exceptionCount = 0;
|
||||||
|
LOGGER.catching(e);
|
||||||
|
} else if (exceptionCount < Settings.settings().QUEUE.PARALLEL_THREADS) {
|
||||||
|
exceptionCount++;
|
||||||
|
LOGGER.warn(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CompletableFuture.completedFuture(set);
|
}
|
||||||
} catch (Throwable e) {
|
return new MultiFuture(futures);
|
||||||
if (e instanceof FaweException) {
|
}
|
||||||
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e, LOGGER);
|
|
||||||
} else if (e.getCause() instanceof FaweException) {
|
@Override
|
||||||
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e.getCause(), LOGGER);
|
public void postProcess(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
} else {
|
for (IBatchProcessor processor : processors) {
|
||||||
String message = e.getMessage();
|
try {
|
||||||
int hash = message.hashCode();
|
// We do NOT want to edit blocks in post processing
|
||||||
if (lastException != hash) {
|
if (processor.getScope() != ProcessorScope.READING_SET_BLOCKS) {
|
||||||
lastException = hash;
|
continue;
|
||||||
exceptionCount = 0;
|
}
|
||||||
LOGGER.catching(e);
|
processor.postProcess(chunk, get, set);
|
||||||
} else if (exceptionCount < Settings.settings().QUEUE.PARALLEL_THREADS) {
|
} catch (Throwable e) {
|
||||||
exceptionCount++;
|
if (e instanceof FaweException) {
|
||||||
LOGGER.warn(message);
|
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e, LOGGER);
|
||||||
|
} else if (e.getCause() instanceof FaweException) {
|
||||||
|
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e.getCause(), LOGGER);
|
||||||
|
} else {
|
||||||
|
String message = e.getMessage();
|
||||||
|
int hash = message != null ? message.hashCode() : 0;
|
||||||
|
if (lastException != hash) {
|
||||||
|
lastException = hash;
|
||||||
|
exceptionCount = 0;
|
||||||
|
LOGGER.catching(e);
|
||||||
|
} else if (exceptionCount < Settings.settings().QUEUE.PARALLEL_THREADS) {
|
||||||
|
exceptionCount++;
|
||||||
|
LOGGER.warn(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,11 +24,6 @@ public final class NullProcessor implements IBatchProcessor {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Future<IChunkSet> postProcessSet(@Nonnull IChunk chunk, @Nonnull IChunkGet get, @Nonnull IChunkSet set) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public Extent construct(@Nonnull Extent child) {
|
public Extent construct(@Nonnull Extent child) {
|
||||||
return new NullExtent();
|
return new NullExtent();
|
||||||
|
@ -136,11 +136,6 @@ public class HeightmapProcessor implements IBatchProcessor {
|
|||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
|
||||||
return CompletableFuture.completedFuture(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public Extent construct(Extent child) {
|
public Extent construct(Extent child) {
|
||||||
|
@ -46,11 +46,6 @@ public class RelightProcessor implements IBatchProcessor {
|
|||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
|
||||||
return CompletableFuture.completedFuture(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable
|
public @Nullable
|
||||||
Extent construct(Extent child) {
|
Extent construct(Extent child) {
|
||||||
|
@ -228,8 +228,13 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Future<IChunkSet> postProcessSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
public void postProcess(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
||||||
return (Future<IChunkSet>) addWriteTask(() -> processSet(chunk, get, set));
|
addWriteTask(() -> processSet(chunk, get, set));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<?> postProcessSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
||||||
|
return addWriteTask(() -> processSet(chunk, get, set));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,13 +6,12 @@ import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
|||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@ -23,7 +22,27 @@ public interface IBatchProcessor {
|
|||||||
*/
|
*/
|
||||||
IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set);
|
IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set);
|
||||||
|
|
||||||
Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set);
|
/**
|
||||||
|
* Post-process a chunk that has been edited. Set should NOT be modified here, changes will NOT be flushed to the world,
|
||||||
|
* but MAY be flushed to history. Defaults to nothing as most Processors will not use it. Post-processors that are not
|
||||||
|
* technically blocking should override this method to allow post-processors to become blocking if required.
|
||||||
|
*/
|
||||||
|
default Future<?> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
|
// Do not need to default to below method. FAWE itself by default will only call the method below.
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post-process a chunk that has been edited. Set should NOT be modified here, changes will NOT be flushed to the world,
|
||||||
|
* but MAY be flushed to history. Defaults to nothing as most Processors will not use it. If the post-processor will run
|
||||||
|
* tasks asynchronously/not be blocking, use {@link IBatchProcessor#postProcessSet} to return a Future.
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
default void postProcess(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
|
// Default to above for compatibility and to ensure whatever method is overridden by child classes is called
|
||||||
|
postProcessSet(chunk, get, set);
|
||||||
|
}
|
||||||
|
|
||||||
default boolean processGet(int chunkX, int chunkZ) {
|
default boolean processGet(int chunkX, int chunkZ) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -145,7 +145,7 @@ public class ParallelQueueExtent extends PassthroughExtent {
|
|||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
String message = e.getMessage();
|
String message = e.getMessage();
|
||||||
int hash = message.hashCode();
|
int hash = message != null ? message.hashCode() : 0;
|
||||||
if (lastException != hash) {
|
if (lastException != hash) {
|
||||||
lastException = hash;
|
lastException = hash;
|
||||||
exceptionCount = 0;
|
exceptionCount = 0;
|
||||||
|
@ -401,7 +401,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
|||||||
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e.getCause(), LOGGER);
|
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e.getCause(), LOGGER);
|
||||||
} else {
|
} else {
|
||||||
String message = e.getMessage();
|
String message = e.getMessage();
|
||||||
int hash = message.hashCode();
|
int hash = message != null ? message.hashCode() : 0;
|
||||||
if (lastException != hash) {
|
if (lastException != hash) {
|
||||||
lastException = hash;
|
lastException = hash;
|
||||||
exceptionCount = 0;
|
exceptionCount = 0;
|
||||||
@ -441,7 +441,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
|||||||
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e.getCause(), LOGGER);
|
Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) e.getCause(), LOGGER);
|
||||||
} else {
|
} else {
|
||||||
String message = e.getMessage();
|
String message = e.getMessage();
|
||||||
int hash = message.hashCode();
|
int hash = message != null ? message.hashCode() : 0;
|
||||||
if (lastException != hash) {
|
if (lastException != hash) {
|
||||||
lastException = hash;
|
lastException = hash;
|
||||||
exceptionCount = 0;
|
exceptionCount = 0;
|
||||||
|
@ -1010,7 +1010,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
return get.call(set, finalize);
|
return get.call(set, finalize);
|
||||||
} finally {
|
} finally {
|
||||||
if (postProcess) {
|
if (postProcess) {
|
||||||
getExtent().postProcessSet(this, get.getCopy(), set);
|
getExtent().postProcess(this, get.getCopy(), set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.fastasyncworldedit.core.util;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
public class MultiFuture implements Future<Object[]> {
|
||||||
|
|
||||||
|
private final List<Future<?>> futures;
|
||||||
|
|
||||||
|
public MultiFuture(List<Future<?>> futures) {
|
||||||
|
this.futures = futures;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean cancel(final boolean mayInterruptIfRunning) {
|
||||||
|
return futures.stream().allMatch(f -> f.cancel(mayInterruptIfRunning));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return futures.stream().allMatch(Future::isCancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDone() {
|
||||||
|
return futures.stream().allMatch(Future::isDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] get() {
|
||||||
|
return futures.stream().map(f -> {
|
||||||
|
try {
|
||||||
|
return f.get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}).toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] get(final long timeout, @Nonnull final TimeUnit unit) {
|
||||||
|
return futures.stream().map(f -> {
|
||||||
|
try {
|
||||||
|
return f.get(timeout / futures.size(), unit);
|
||||||
|
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}).toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -45,6 +45,7 @@ import com.fastasyncworldedit.core.history.changeset.BlockBagChangeSet;
|
|||||||
import com.fastasyncworldedit.core.history.changeset.NullChangeSet;
|
import com.fastasyncworldedit.core.history.changeset.NullChangeSet;
|
||||||
import com.fastasyncworldedit.core.limit.FaweLimit;
|
import com.fastasyncworldedit.core.limit.FaweLimit;
|
||||||
import com.fastasyncworldedit.core.limit.PropertyRemap;
|
import com.fastasyncworldedit.core.limit.PropertyRemap;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IQueueChunk;
|
import com.fastasyncworldedit.core.queue.IQueueChunk;
|
||||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
|
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
|
||||||
@ -560,7 +561,7 @@ public final class EditSessionBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// There's no need to do lighting (and it'll also just be a pain to implement) if we're not placing chunks
|
// There's no need to do the below (and it'll also just be a pain to implement) if we're not placing chunks
|
||||||
if (placeChunks) {
|
if (placeChunks) {
|
||||||
if (((relightMode != null && relightMode != RelightMode.NONE) || (relightMode == null && Settings.settings().LIGHTING.MODE > 0))) {
|
if (((relightMode != null && relightMode != RelightMode.NONE) || (relightMode == null && Settings.settings().LIGHTING.MODE > 0))) {
|
||||||
relighter = WorldEdit.getInstance().getPlatformManager()
|
relighter = WorldEdit.getInstance().getPlatformManager()
|
||||||
@ -569,6 +570,22 @@ public final class EditSessionBuilder {
|
|||||||
extent.addProcessor(new RelightProcessor(relighter));
|
extent.addProcessor(new RelightProcessor(relighter));
|
||||||
}
|
}
|
||||||
extent.addProcessor(new HeightmapProcessor(world.getMinY(), world.getMaxY()));
|
extent.addProcessor(new HeightmapProcessor(world.getMinY(), world.getMaxY()));
|
||||||
|
IBatchProcessor platformProcessor = WorldEdit
|
||||||
|
.getInstance()
|
||||||
|
.getPlatformManager()
|
||||||
|
.queryCapability(Capability.WORLD_EDITING)
|
||||||
|
.getPlatformProcessor(fastMode);
|
||||||
|
if (platformProcessor != null) {
|
||||||
|
extent.addProcessor(platformProcessor);
|
||||||
|
}
|
||||||
|
IBatchProcessor platformPostProcessor = WorldEdit
|
||||||
|
.getInstance()
|
||||||
|
.getPlatformManager()
|
||||||
|
.queryCapability(Capability.WORLD_EDITING)
|
||||||
|
.getPlatformPostProcessor(fastMode);
|
||||||
|
if (platformPostProcessor != null) {
|
||||||
|
extent.addPostProcessor(platformPostProcessor);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
relighter = NullRelighter.INSTANCE;
|
relighter = NullRelighter.INSTANCE;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package com.sk89q.worldedit.extension.platform;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
|
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.sk89q.worldedit.LocalConfiguration;
|
import com.sk89q.worldedit.LocalConfiguration;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
@ -248,5 +249,24 @@ public interface Platform extends Keyed {
|
|||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
int versionMaxY();
|
int versionMaxY();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a {@link IBatchProcessor} to be used in edit processing. Null if not required.
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default IBatchProcessor getPlatformProcessor(boolean fastMode) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a {@link IBatchProcessor} to be used in edit post-processing. Used for things such as tick-placed and tick fluids.
|
||||||
|
* Null if not required.
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default IBatchProcessor getPlatformPostProcessor(boolean fastMode) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
//FAWE end
|
//FAWE end
|
||||||
}
|
}
|
||||||
|
@ -111,12 +111,6 @@ public class MaskingExtent extends AbstractDelegateExtent implements IBatchProce
|
|||||||
return filter.filter(chunk, get, set, MaskingExtent.this);
|
return filter.filter(chunk, get, set, MaskingExtent.this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
|
||||||
// This should not do anything otherwise dangerous...
|
|
||||||
return CompletableFuture.completedFuture(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyBlock(final FilterBlock block) {
|
public void applyBlock(final FilterBlock block) {
|
||||||
if (!this.mask.test(block)) {
|
if (!this.mask.test(block)) {
|
||||||
|
@ -471,12 +471,6 @@ public interface Region extends Iterable<BlockVector3>, Cloneable, IBatchProcess
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
default Future<IChunkSet> postProcessSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
|
||||||
// Doesn't need to do anything
|
|
||||||
return CompletableFuture.completedFuture(set);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default Extent construct(Extent child) {
|
default Extent construct(Extent child) {
|
||||||
if (isGlobal()) {
|
if (isGlobal()) {
|
||||||
|
@ -23,6 +23,7 @@ import com.fastasyncworldedit.core.configuration.Caption;
|
|||||||
import com.fastasyncworldedit.core.queue.IChunk;
|
import com.fastasyncworldedit.core.queue.IChunk;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
|
import com.fastasyncworldedit.core.util.MultiFuture;
|
||||||
import com.google.common.collect.Iterators;
|
import com.google.common.collect.Iterators;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.sk89q.worldedit.math.BlockVector2;
|
import com.sk89q.worldedit.math.BlockVector2;
|
||||||
@ -35,6 +36,7 @@ import java.util.Collections;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
@ -172,6 +174,15 @@ public class RegionIntersection extends AbstractRegion {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Future<?> postProcessSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
||||||
|
final ArrayList<Future<?>> futures = new ArrayList<>();
|
||||||
|
for (Region region : regions) {
|
||||||
|
futures.add(region.postProcessSet(chunk, get, set));
|
||||||
|
}
|
||||||
|
return new MultiFuture(futures);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set, boolean asBlacklist) {
|
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set, boolean asBlacklist) {
|
||||||
if (!asBlacklist) {
|
if (!asBlacklist) {
|
||||||
|
@ -198,6 +198,9 @@ public class BlockTypesCache {
|
|||||||
|
|
||||||
public static final BlockType[] values;
|
public static final BlockType[] values;
|
||||||
public static final BlockState[] states;
|
public static final BlockState[] states;
|
||||||
|
/**
|
||||||
|
* Array of blockstates in order of ordinal indicating if the block ticks, e.g. leaves, water
|
||||||
|
*/
|
||||||
public static final boolean[] ticking;
|
public static final boolean[] ticking;
|
||||||
private static final Map<String, List<Property<?>>> allProperties = new HashMap<>();
|
private static final Map<String, List<Property<?>>> allProperties = new HashMap<>();
|
||||||
|
|
||||||
@ -283,7 +286,8 @@ public class BlockTypesCache {
|
|||||||
String enumName = (typeName.startsWith("minecraft:") ? typeName.substring(10) : typeName).toUpperCase(Locale.ROOT);
|
String enumName = (typeName.startsWith("minecraft:") ? typeName.substring(10) : typeName).toUpperCase(Locale.ROOT);
|
||||||
int oldsize = states.size();
|
int oldsize = states.size();
|
||||||
BlockType existing = new BlockType(id, internalId, states);
|
BlockType existing = new BlockType(id, internalId, states);
|
||||||
tickList.addAll(Collections.nCopies(states.size() - oldsize, existing.getMaterial().isTicksRandomly()));
|
tickList.addAll(Collections.nCopies(states.size() - oldsize,
|
||||||
|
existing.getMaterial().isTicksRandomly() || existing.getMaterial().isLiquid()));
|
||||||
// register states
|
// register states
|
||||||
BlockType.REGISTRY.register(typeName, existing);
|
BlockType.REGISTRY.register(typeName, existing);
|
||||||
String nameSpace = typeName.substring(0, typeName.indexOf(':'));
|
String nameSpace = typeName.substring(0, typeName.indexOf(':'));
|
||||||
|
Loading…
Reference in New Issue
Block a user