This commit is contained in:
IronApollo 2020-05-13 17:45:17 -04:00
commit 34d40cb856
49 changed files with 471 additions and 96 deletions

View File

@ -12,6 +12,7 @@ FAWE is a fork of WorldEdit that has huge speed and memory improvements and cons
* [Discord](https://discord.gg/KxkjDVg)
* [Wiki](https://github.com/IntellectualSites/FastAsyncWorldEdit-1.13/wiki)
* [Report Issue](https://github.com/IntellectualSites/FastAsyncWorldEdit-1.13/issues)
* [Crowdin](https://intellectualsites.crowdin.com/fastasyncworldedit)
## Downloads
### 1.13+

Binary file not shown.

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

29
gradlew vendored
View File

@ -154,19 +154,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@ -175,14 +175,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

3
gradlew.bat vendored
View File

@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

View File

@ -1,18 +1,23 @@
package com.boydti.fawe.bukkit.adapter;
import com.boydti.fawe.config.Settings;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import java.util.Map;
import java.util.function.Function;
public class NMSAdapter {
public static int createPalette(int[] blockToPalette, int[] paletteToBlock, int[] blocksCopy,
int[] num_palette_buffer, char[] set, Map<BlockVector3, Integer> ticking_blocks) {
int[] num_palette_buffer, char[] set, Map<BlockVector3, Integer> ticking_blocks, boolean fastmode) {
int air = 0;
int num_palette = 0;
char lastOrdinal = BlockID.__RESERVED__;
boolean lastticking = false;
boolean tick_placed = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_PLACED;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
switch (ordinal) {
@ -24,11 +29,22 @@ public class NMSAdapter {
air++;
break;
default:
BlockState state = BlockState.getFromOrdinal(ordinal);
if (state.getMaterial().isTicksRandomly()) {
ticking_blocks.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
WorldEditPlugin.getInstance().getBukkitImplAdapter()
.getInternalBlockStateId(state).orElse(0));
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];
@ -45,10 +61,14 @@ public class NMSAdapter {
public static int createPalette(int layer, int[] blockToPalette, int[] paletteToBlock,
int[] blocksCopy, int[] num_palette_buffer, Function<Integer, char[]> get, char[] set,
Map<BlockVector3, Integer> ticking_blocks) {
Map<BlockVector3, Integer> ticking_blocks, boolean fastmode) {
int air = 0;
int num_palette = 0;
char[] getArr = null;
char lastOrdinal = BlockID.__RESERVED__;
boolean lastticking = false;
boolean tick_placed = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_PLACED;
boolean tick_existing = Settings.IMP.EXPERIMENTAL.ALLOW_TICK_EXISTING;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
switch (ordinal) {
@ -65,6 +85,24 @@ public class NMSAdapter {
case BlockID.VOID_AIR:
air++;
break;
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));
}
}
}
set[i] = ordinal;
break;
@ -75,11 +113,21 @@ public class NMSAdapter {
air++;
break;
}
BlockState state = BlockState.getFromOrdinal(ordinal);
if (state.getMaterial().isTicksRandomly()) {
ticking_blocks.put(BlockVector3.at(i & 15, (i >> 8) & 15, (i >> 4) & 15),
WorldEditPlugin.getInstance().getBukkitImplAdapter()
.getInternalBlockStateId(state).orElse(0));
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];
if (palette == Integer.MAX_VALUE) {

View File

@ -199,11 +199,11 @@ public final class BukkitAdapter_1_14 extends NMSAdapter {
/*
NMS conversion
*/
public static ChunkSection newChunkSection(final int layer, final char[] blocks) {
return newChunkSection(layer, null, blocks);
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
return newChunkSection(layer, null, blocks, fastmode);
}
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set) {
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
if (set == null) {
return newChunkSection(layer);
}
@ -216,9 +216,9 @@ public final class BukkitAdapter_1_14 extends NMSAdapter {
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
int air;
if (get == null) {
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, set, ticking_blocks);
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, set, ticking_blocks, fastmode);
} else {
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, get, set, ticking_blocks);
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, get, set, ticking_blocks, fastmode);
}
int num_palette = num_palette_buffer[0];
// BlockStates

View File

@ -5,10 +5,12 @@ import static org.slf4j.LoggerFactory.getLogger;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.blocks.CharBlocks;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
import com.boydti.fawe.bukkit.adapter.DelegateLock;
import com.boydti.fawe.bukkit.adapter.mc1_14.nbt.LazyCompoundTag_1_14;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.AdaptedMap;
import com.boydti.fawe.object.collection.BitArray;
import com.google.common.base.Suppliers;
@ -227,6 +229,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
try {
WorldServer nmsWorld = world;
Chunk nmsChunk = ensureLoaded(nmsWorld, X, Z);
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
// Remove existing tiles
{
@ -262,7 +265,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
ChunkSection newSection;
ChunkSection existingSection = sections[layer];
if (existingSection == null) {
newSection = BukkitAdapter_1_14.newChunkSection(layer, setArr);
newSection = BukkitAdapter_1_14.newChunkSection(layer, setArr, fastmode);
if (BukkitAdapter_1_14.setSectionAtomic(sections, null, newSection, layer)) {
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
continue;
@ -274,6 +277,10 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
}
}
}
//ensure that the server doesn't try to tick the chunksection while we're editing it.
BukkitAdapter_1_14.fieldTickingBlockCount.set(existingSection, (short) 0);
DelegateLock lock = BukkitAdapter_1_14.applyLock(existingSection);
synchronized (this) {
synchronized (lock) {
@ -290,7 +297,7 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
} else if (lock.isModified()) {
this.reset(layer);
}
newSection = BukkitAdapter_1_14.newChunkSection(layer, this::load, setArr);
newSection = BukkitAdapter_1_14.newChunkSection(layer, this::load, setArr, fastmode);
if (!BukkitAdapter_1_14.setSectionAtomic(sections, existingSection, newSection, layer)) {
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
continue;
@ -620,7 +627,37 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
if (aggressive) {
sections = null;
nmsChunk = null;
return super.trim(true);
} else {
for (int i = 0; i < 16; i++) {
if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) {
continue;
}
ChunkSection existing = getSections()[i];
try {
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_14.fieldPalette.get(blocksExisting);
int paletteSize;
if (palette instanceof DataPaletteLinear) {
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
} else if (palette instanceof DataPaletteHash) {
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
} else {
super.trim(false, i);
continue;
}
if (paletteSize == 1) {
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
continue;
}
super.trim(false, i);
} catch (IllegalAccessException ignored) {
super.trim(false, i);
}
}
return true;
}
return super.trim(aggressive);
}
}

View File

@ -186,11 +186,11 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
/*
NMS conversion
*/
public static ChunkSection newChunkSection(final int layer, final char[] blocks) {
return newChunkSection(layer, null, blocks);
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
return newChunkSection(layer, null, blocks, fastmode);
}
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set) {
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
if (set == null) {
return newChunkSection(layer);
}
@ -203,9 +203,9 @@ public final class BukkitAdapter_1_15 extends NMSAdapter {
Map<BlockVector3, Integer> ticking_blocks = new HashMap<>();
int air;
if (get == null) {
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, set, ticking_blocks);
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, set, ticking_blocks, fastmode);
} else {
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, get, set, ticking_blocks);
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, get, set, ticking_blocks, fastmode);
}
int num_palette = num_palette_buffer[0];
// BlockStates

View File

@ -5,10 +5,12 @@ import static org.slf4j.LoggerFactory.getLogger;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.blocks.CharBlocks;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
import com.boydti.fawe.bukkit.adapter.DelegateLock;
import com.boydti.fawe.bukkit.adapter.mc1_15.nbt.LazyCompoundTag_1_15;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.AdaptedMap;
import com.boydti.fawe.object.collection.BitArray;
import com.google.common.base.Suppliers;
@ -235,6 +237,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
try {
WorldServer nmsWorld = world;
Chunk nmsChunk = ensureLoaded(nmsWorld, X, Z);
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
// Remove existing tiles
{
@ -270,7 +273,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
ChunkSection newSection;
ChunkSection existingSection = sections[layer];
if (existingSection == null) {
newSection = BukkitAdapter_1_15.newChunkSection(layer, setArr);
newSection = BukkitAdapter_1_15.newChunkSection(layer, setArr, fastmode);
if (BukkitAdapter_1_15.setSectionAtomic(sections, null, newSection, layer)) {
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
continue;
@ -282,6 +285,10 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
}
}
}
//ensure that the server doesn't try to tick the chunksection while we're editing it.
BukkitAdapter_1_15.fieldTickingBlockCount.set(existingSection, (short) 0);
DelegateLock lock = BukkitAdapter_1_15.applyLock(existingSection);
synchronized (this) {
synchronized (lock) {
@ -298,7 +305,7 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
} else if (lock.isModified()) {
this.reset(layer);
}
newSection = BukkitAdapter_1_15.newChunkSection(layer, this::load, setArr);
newSection = BukkitAdapter_1_15.newChunkSection(layer, this::load, setArr, fastmode);
if (!BukkitAdapter_1_15.setSectionAtomic(sections, existingSection, newSection, layer)) {
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
continue;
@ -640,7 +647,37 @@ public class BukkitGetBlocks_1_15 extends CharGetBlocks {
if (aggressive) {
sections = null;
nmsChunk = null;
return super.trim(true);
} else {
for (int i = 0; i < 16; i++) {
if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) {
continue;
}
ChunkSection existing = getSections()[i];
try {
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_15.fieldPalette.get(blocksExisting);
int paletteSize;
if (palette instanceof DataPaletteLinear) {
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
} else if (palette instanceof DataPaletteHash) {
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
} else {
super.trim(false, i);
continue;
}
if (paletteSize == 1) {
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
continue;
}
super.trim(false, i);
} catch (IllegalAccessException ignored) {
super.trim(false, i);
}
}
return true;
}
return super.trim(aggressive);
}
}

View File

@ -187,11 +187,11 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter {
/*
NMS conversion
*/
public static ChunkSection newChunkSection(final int layer, final char[] blocks) {
return newChunkSection(layer, null, blocks);
public static ChunkSection newChunkSection(final int layer, final char[] blocks, boolean fastmode) {
return newChunkSection(layer, null, blocks, fastmode);
}
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set) {
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set, boolean fastmode) {
if (set == null) {
return newChunkSection(layer);
}
@ -205,10 +205,10 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter {
int air;
if (get == null) {
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer,
set, ticking_blocks);
set, ticking_blocks, fastmode);
} else {
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy,
num_palette_buffer, get, set, ticking_blocks);
num_palette_buffer, get, set, ticking_blocks, fastmode);
}
int num_palette = num_palette_buffer[0];
// BlockStates
@ -251,10 +251,11 @@ public final class BukkitAdapter_1_15_2 extends NMSAdapter {
fieldPalette.set(dataPaletteBlocks, palette);
fieldSize.set(dataPaletteBlocks, bitsPerEntry);
setCount(ticking_blocks.size(), 4096 - air, section);
ticking_blocks.forEach((pos, ordinal) -> {
section.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
Block.getByCombinedId(ordinal));
});
if (!fastmode) {
ticking_blocks.forEach((pos, ordinal) -> section
.setType(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(),
Block.getByCombinedId(ordinal)));
}
} catch (final IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException(e);
}

View File

@ -3,10 +3,12 @@ package com.boydti.fawe.bukkit.adapter.mc1_15_2;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.blocks.CharBlocks;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.beta.implementation.queue.QueueHandler;
import com.boydti.fawe.bukkit.adapter.DelegateLock;
import com.boydti.fawe.bukkit.adapter.mc1_15_2.nbt.LazyCompoundTag_1_15_2;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.AdaptedMap;
import com.boydti.fawe.object.collection.BitArray;
import com.google.common.base.Suppliers;
@ -242,6 +244,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
try {
WorldServer nmsWorld = world;
Chunk nmsChunk = ensureLoaded(nmsWorld, X, Z);
boolean fastmode = set.isFastMode() && Settings.IMP.QUEUE.NO_TICK_FASTMODE;
// Remove existing tiles
{
@ -282,7 +285,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
ChunkSection newSection;
ChunkSection existingSection = sections[layer];
if (existingSection == null) {
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, setArr);
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, setArr, fastmode);
if (BukkitAdapter_1_15_2.setSectionAtomic(sections, null, newSection, layer)) {
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
continue;
@ -294,7 +297,11 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
}
}
}
BukkitAdapter_1_15_2.fieldTickingBlockCount.set(existingSection, (short) 0);
//ensure that the server doesn't try to tick the chunksection while we're editing it.
DelegateLock lock = BukkitAdapter_1_15_2.applyLock(existingSection);
synchronized (this) {
synchronized (lock) {
lock.untilFree();
@ -310,7 +317,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
} else if (lock.isModified()) {
this.reset(layer);
}
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr);
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr, fastmode);
if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) {
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
continue;
@ -644,7 +651,37 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks {
if (aggressive) {
sections = null;
nmsChunk = null;
return super.trim(true);
} else {
for (int i = 0; i < 16; i++) {
if (!hasSection(i) || super.sections[i] == CharBlocks.EMPTY) {
continue;
}
ChunkSection existing = getSections()[i];
try {
final DataPaletteBlock<IBlockData> blocksExisting = existing.getBlocks();
final DataPalette<IBlockData> palette = (DataPalette<IBlockData>) BukkitAdapter_1_15_2.fieldPalette.get(blocksExisting);
int paletteSize;
if (palette instanceof DataPaletteLinear) {
paletteSize = ((DataPaletteLinear<IBlockData>) palette).b();
} else if (palette instanceof DataPaletteHash) {
paletteSize = ((DataPaletteHash<IBlockData>) palette).b();
} else {
super.trim(false, i);
continue;
}
if (paletteSize == 1) {
//If the cached palette size is 1 then no blocks can have been changed i.e. do not need to update these chunks.
continue;
}
super.trim(false, i);
} catch (IllegalAccessException ignored) {
super.trim(false, i);
}
}
return true;
}
return super.trim(aggressive);
}
}

View File

@ -55,6 +55,7 @@ import org.bukkit.entity.Item;
import org.bukkit.entity.LightningStrike;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.inventory.ItemStack;
@ -649,6 +650,11 @@ public class AsyncWorld extends PassthroughExtent implements World {
return TaskManager.IMP.sync(() -> parent.spawn(location, clazz, function));
}
@Override
public <T extends Entity> @NotNull T spawn(@NotNull Location location, @NotNull Class<T> clazz, @Nullable Consumer<T> function, CreatureSpawnEvent.@NotNull SpawnReason reason) throws IllegalArgumentException {
return null;
}
@Override
public FallingBlock spawnFallingBlock(Location location, MaterialData data) throws IllegalArgumentException {
return TaskManager.IMP.sync(() -> parent.spawnFallingBlock(location, data));
@ -1053,6 +1059,21 @@ public class AsyncWorld extends PassthroughExtent implements World {
return parent.getViewDistance();
}
@Override
public void setViewDistance(int viewDistance) {
}
@Override
public int getNoTickViewDistance() {
return 0;
}
@Override
public void setNoTickViewDistance(int viewDistance) {
}
@Override
public RayTraceResult rayTrace(Location arg0, Vector arg1, double arg2, FluidCollisionMode arg3, boolean arg4,
double arg5, Predicate<Entity> arg6) {
@ -1174,6 +1195,11 @@ public class AsyncWorld extends PassthroughExtent implements World {
return parent.getChunkAtAsync(arg0, arg1, arg2);
}
@Override
public @NotNull CompletableFuture<Chunk> getChunkAtAsync(int x, int z, boolean gen, boolean urgent) {
return null;
}
@Override
public boolean isDayTime() {
return parent.isDayTime();

View File

@ -145,4 +145,9 @@ public class CombinedBlocks implements IBlocks {
public boolean trim(boolean aggressive) {
return false;
}
@Override
public boolean trim(boolean aggressive, int layer) {
return false;
}
}

View File

@ -41,6 +41,8 @@ public interface IBlocks extends Trimable {
.map(layer -> (1 << layer)).sum();
}
boolean trim(boolean aggressive, int layer);
IBlocks reset();
default byte[] toByteArray(boolean full) {

View File

@ -3,14 +3,12 @@ package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.OutputExtent;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Map;
import javax.annotation.Nullable;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
/**
* Interface for setting blocks
@ -42,6 +40,13 @@ public interface IChunkSet extends IBlocks, OutputExtent {
return getBiomes() != null;
}
default boolean isFastMode() {
return false;
}
//default to avoid tricky child classes. We only need it in a few cases anyway.
default void setFastMode(boolean fastMode){}
@Override
IChunkSet reset();

View File

@ -82,6 +82,10 @@ public interface IQueueExtent<T extends IChunk> extends Flushable, Trimable, ICh
return BlockVector3.at(30000000, FaweCache.IMP.WORLD_MAX_Y, 30000000);
}
void setFastMode(boolean fastMode);
boolean isFastMode();
/**
* Create a new root IChunk object<br> - Full chunks will be reused, so a more optimized chunk
* can be returned in that case<br> - Don't wrap the chunk, that should be done in {@link
@ -143,6 +147,7 @@ public interface IQueueExtent<T extends IChunk> extends Flushable, Trimable, ICh
T chunk = this.getOrCreateChunk(chunkX, chunkZ);
// Initialize
chunk.init(this, chunkX, chunkZ);
chunk.setFastMode(isFastMode());
T newChunk = filter.applyChunk(chunk, region);
if (newChunk != null) {

View File

@ -153,4 +153,9 @@ public class BitSetBlocks implements IChunkSet {
public boolean trim(boolean aggressive) {
return false;
}
@Override
public boolean trim(boolean aggressive, int layer) {
return false;
}
}

View File

@ -60,6 +60,17 @@ public abstract class CharBlocks implements IBlocks {
return result;
}
@Override
public boolean trim(boolean aggressive, int layer) {
boolean result = true;
if (sections[layer] == EMPTY && blocks[layer] != null) {
blocks[layer] = null;
} else {
result = false;
}
return result;
}
@Override
public IChunkSet reset() {
for (int i = 0; i < 16; i++) {

View File

@ -25,6 +25,13 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
return true;
}
@Override
public boolean trim(boolean aggressive, int layer) {
sections[layer] = EMPTY;
blocks[layer] = null;
return true;
}
@Override
public IChunkSet reset() {
super.reset();

View File

@ -34,6 +34,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
public BlockVector3ChunkMap<CompoundTag> tiles;
public HashSet<CompoundTag> entities;
public HashSet<UUID> entityRemoves;
private boolean fastMode = false;
private CharSetBlocks() {}
@ -131,6 +132,16 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
entityRemoves.add(uuid);
}
@Override
public void setFastMode(boolean fastMode) {
this.fastMode = fastMode;
}
@Override
public boolean isFastMode() {
return fastMode;
}
@Override
public boolean isEmpty() {
if (biomes != null) {

View File

@ -85,6 +85,11 @@ public class FallbackChunkGet implements IChunkGet {
return true;
}
@Override
public boolean trim(boolean aggressive, int layer) {
return true;
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
for (int layer = 0; layer < 16; layer++) {

View File

@ -50,6 +50,10 @@ object NullChunkGet : IChunkGet {
return true
}
override fun trim(aggressive: Boolean, layer: Int): Boolean {
return true
}
override fun <T : Future<T>> call(set: IChunkSet, finalize: Runnable): T? {
return null
}

View File

@ -42,6 +42,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
private IQueueExtent<? extends IChunk> extent; // the parent queue extent which has this chunk
private int chunkX;
private int chunkZ;
private boolean fastmode;
private ChunkHolder() {
this.delegate = NULL;
@ -100,6 +101,16 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
return getOrCreateGet().load(layer);
}
@Override
public boolean isFastMode() {
return fastmode;
}
@Override
public void setFastMode(boolean fastmode) {
this.fastmode = fastmode;
}
@Override
public CompoundTag getEntity(UUID uuid) {
return delegate.get(this).getEntity(uuid);
@ -313,6 +324,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
public void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region, boolean full) {
final IChunkGet get = getOrCreateGet();
final IChunkSet set = getOrCreateSet();
set.setFastMode(fastmode);
try {
block.filter(this, get, set, filter, region, full);
} finally {
@ -344,6 +356,11 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
return false;
}
@Override
public boolean trim(boolean aggressive, int layer) {
return this.trim(aggressive);
}
@Override
public boolean isEmpty() {
return chunkSet == null || chunkSet.isEmpty();

View File

@ -117,5 +117,9 @@ object NullChunk : IQueueChunk<Nothing> {
override fun trim(aggressive: Boolean): Boolean {
return true
}
override fun trim(aggressive: Boolean, layer: Int): Boolean {
return true
}
}

View File

@ -4,7 +4,6 @@ import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.sk89q.worldedit.extent.Extent;
public class BatchProcessorHolder implements IBatchProcessorHolder {
private IBatchProcessor processor = EmptyBatchProcessor.INSTANCE;

View File

@ -44,12 +44,14 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
private final QueueHandler handler;
private final BatchProcessorHolder processor;
private int changes;
private final boolean fastmode;
public ParallelQueueExtent(QueueHandler handler, World world) {
public ParallelQueueExtent(QueueHandler handler, World world, boolean fastmode) {
super(handler.getQueue(world, new BatchProcessorHolder()));
this.world = world;
this.handler = handler;
this.processor = (BatchProcessorHolder) getExtent().getProcessor();
this.fastmode = fastmode;
}
@Override
@ -94,6 +96,7 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
final Filter newFilter = filter.fork();
// Create a chunk that we will reuse/reset for each operation
final IQueueExtent<IQueueChunk> queue = getNewQueue();
queue.setFastMode(fastmode);
synchronized (queue) {
ChunkFilterBlock block = null;
@ -162,7 +165,8 @@ public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrap
@Override
public int replaceBlocks(Region region, Mask mask, Pattern pattern)
throws MaxChangedBlocksException {
return this.changes = apply(region, mask.toFilter(pattern), false).getBlocksApplied();
boolean full = mask.replacesAir();
return this.changes = apply(region, mask.toFilter(pattern), full).getBlocksApplied();
}
@Override

View File

@ -49,6 +49,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
private boolean enabledQueue = true;
private boolean fastmode = false;
/**
* Safety check to ensure that the thread being used matches the one being initialized on. - Can
* be removed later
@ -80,6 +82,16 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
return cacheSet.get(chunkX, chunkZ);
}
@Override
public void setFastMode(boolean fastmode) {
this.fastmode = fastmode;
}
@Override
public boolean isFastMode() {
return fastmode;
}
/**
* Resets the queue.
*/

View File

@ -309,6 +309,11 @@ public class Settings extends Config {
})
public int DISCARD_AFTER_MS = 60000;
@Comment({
"When using fastmode also do not bother to fix existing ticking blocks"
})
public boolean NO_TICK_FASTMODE = true;
public static class PROGRESS {
@Comment({"Display constant titles about the progress of a user's edit",
" - false = disabled",
@ -369,6 +374,18 @@ public class Settings extends Config {
"Other experimental features"
})
public boolean OTHER = false;
@Comment({
"Allow blocks placed by WorldEdit to tick. This could cause the big lags.",
"This has no effect on existing blocks one way or the other."
})
public boolean ALLOW_TICK_PLACED = false;
@Comment({
"Force re-ticking of existing blocks not edited by FAWE.",
"This will increase time taken slightly."
})
public boolean ALLOW_TICK_EXISTING = true;
}
public static class WEB {

View File

@ -549,6 +549,11 @@ public class MCAChunk implements IChunk {
return isEmpty();
}
@Override
public boolean trim(boolean aggressive, int layer) {
return hasSection(layer);
}
@Override
public CompoundTag getEntity(UUID uuid) {
return this.entities.get(uuid);

View File

@ -184,7 +184,11 @@ public class CPUOptimizedClipboard extends LinearClipboard {
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(int index, B block) {
states[index] = block.getOrdinalChar();
char ordinal = block.getOrdinalChar();
if (ordinal == 0) {
ordinal = 1;
}
states[index] = ordinal;
boolean hasNbt = block instanceof BaseBlock && block.hasNbtData();
if (hasNbt) {
setTile(index, block.getNbtData());

View File

@ -388,6 +388,9 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
try {
int index = HEADER_SIZE + (getIndex(x, y, z) << 1);
char ordinal = block.getOrdinalChar();
if (ordinal == 0) {
ordinal = 1;
}
byteBuffer.putChar(index, ordinal);
boolean hasNbt = block instanceof BaseBlock && block.hasNbtData();
if (hasNbt) {

View File

@ -263,6 +263,9 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(int index, B block) {
int ordinal = block.getOrdinal();
if (ordinal == 0) {
ordinal = 1;
}
setOrdinal(index, ordinal);
boolean hasNbt = block instanceof BaseBlock && block.hasNbtData();
if (hasNbt) {

View File

@ -296,7 +296,7 @@ public class EditSessionBuilder {
if (unwrapped instanceof IQueueExtent) {
extent = queue = (IQueueExtent) unwrapped;
} else if (Settings.IMP.QUEUE.PARALLEL_THREADS > 1 && threaded) {
ParallelQueueExtent parallel = new ParallelQueueExtent(Fawe.get().getQueueHandler(), world);
ParallelQueueExtent parallel = new ParallelQueueExtent(Fawe.get().getQueueHandler(), world, fastmode);
queue = parallel.getExtent();
extent = parallel;
} else {

View File

@ -72,6 +72,7 @@ import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
@ -366,7 +367,7 @@ public class ClipboardCommands {
e.printStackTrace();
}
}
player.print(Caption.of("fawe.web.download.link" , urlText));
player.print(Caption.of("fawe.web.download.link" , urlText).clickEvent(ClickEvent.openUrl(urlText)));
}
}

View File

@ -134,8 +134,8 @@ public class GenerationCommands {
@Arg(desc = "TODO", def = "100") int threshold, @Arg(desc = "BlockVector2", def = "") BlockVector2 dimensions) throws WorldEditException, IOException {
TextureUtil tu = Fawe.get().getCachedTextureUtil(randomize, 0, threshold);
URL url = new URL(argStr);
if (!url.getHost().equalsIgnoreCase("i.imgur.com") && !url.getHost().equalsIgnoreCase("empcraft.com")) {
throw new IOException("Only i.imgur.com or empcraft.com/ui links are allowed!");
if (!url.getHost().equalsIgnoreCase("i.imgur.com")) {
throw new IOException("Only i.imgur.com links are allowed!");
}
BufferedImage image = MainUtil.readImage(url);
if (dimensions != null) {

View File

@ -212,6 +212,7 @@ public class SchematicCommands {
}
UUID uuid = UUID.fromString(filename.substring(4));
URL webUrl = new URL(Settings.IMP.WEB.URL);
format = ClipboardFormats.findByAlias(formatName);
URL url = new URL(webUrl, "uploads/" + uuid + "." + format.getPrimaryFileExtension());
ReadableByteChannel byteChannel = Channels.newChannel(url.openStream());
in = Channels.newInputStream(byteChannel);

View File

@ -364,6 +364,12 @@ public class DefaultBlockParser extends InputParser<BaseBlock> {
}
state = fuzzyBuilder.build();
}
} else {
for (Map.Entry<Property<?>, Object> blockState : blockStates.entrySet()) {
@SuppressWarnings("unchecked")
Property<Object> objProp = (Property<Object>) blockState.getKey();
state = state.with(objProp, blockState.getValue());
}
}
}
// this should be impossible but IntelliJ isn't that smart

View File

@ -223,11 +223,13 @@ public class FastSchematicReader extends NBTSchematicReader {
int volume = width * height * length;
if (palette.length < 128) {
for (int index = 0; index < volume; index++) {
linear.setBlock(index, getBlockState(fis.read()));
int ordinal = fis.read();
linear.setBlock(index, getBlockState(ordinal));
}
} else {
for (int index = 0; index < volume; index++) {
linear.setBlock(index, getBlockState(fis.readVarInt()));
int ordinal = fis.readVarInt();
linear.setBlock(index, getBlockState(ordinal));
}
}
} else {
@ -235,7 +237,8 @@ public class FastSchematicReader extends NBTSchematicReader {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
clipboard.setBlock(x, y, z, getBlockState(fis.read()));
int ordinal = fis.read();
clipboard.setBlock(x, y, z, getBlockState(ordinal));
}
}
}
@ -243,7 +246,8 @@ public class FastSchematicReader extends NBTSchematicReader {
for (int y = 0; y < height; y++) {
for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) {
clipboard.setBlock(x, y, z, getBlockState(fis.readVarInt()));
int ordinal = fis.readVarInt();
clipboard.setBlock(x, y, z, getBlockState(ordinal));
}
}
}

View File

@ -21,7 +21,6 @@ package com.sk89q.worldedit.extent.clipboard.io;
import com.boydti.fawe.jnbt.streamer.IntValueReader;
import com.boydti.fawe.object.FaweOutputStream;
import com.boydti.fawe.object.clipboard.LinearClipboard;
import com.boydti.fawe.util.IOUtil;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.CompoundTag;
@ -45,7 +44,6 @@ import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
@ -181,6 +179,9 @@ public class FastSchematicWriter implements ClipboardWriter {
}
int ordinal = block.getOrdinal();
if (ordinal == 0) {
ordinal = 1;
}
char value = palette[ordinal];
if (value == Character.MAX_VALUE) {
int size = paletteMax++;
@ -338,4 +339,4 @@ public class FastSchematicWriter implements ClipboardWriter {
public void close() throws IOException {
outputStream.close();
}
}
}

View File

@ -189,7 +189,15 @@ public class BlockMask extends ABlockMask {
@Override
public boolean test(Extent extent, BlockVector3 vector) {
return ordinals[vector.getOrdinal(extent)];
int test = vector.getOrdinal(extent);
return ordinals[test] || replacesAir() && test == 0;
}
@Override
public boolean replacesAir() {
return ordinals[BlockTypes.AIR.getDefaultState().getOrdinal()]
|| ordinals[BlockTypes.CAVE_AIR.getDefaultState().getOrdinal()]
|| ordinals[BlockTypes.VOID_AIR.getDefaultState().getOrdinal()];
}
@Override

View File

@ -26,6 +26,8 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Map;
import javax.annotation.Nullable;
@ -65,6 +67,11 @@ public class BlockStateMask extends AbstractExtentMask {
.allMatch(entry -> block.getState(entry.getKey()) == entry.getValue());
}
@Override
public boolean replacesAir() {
return test(BlockTypes.AIR.getDefaultState()) || test(BlockTypes.CAVE_AIR.getDefaultState()) || test(BlockTypes.VOID_AIR.getDefaultState());
}
@Nullable
@Override
public Mask2D toMask2D() {

View File

@ -43,6 +43,7 @@ import org.jetbrains.annotations.NotNull;
public class BlockTypeMask extends AbstractExtentMask {
private final boolean[] types;
private boolean hasAir;
/**
* Create a new block mask.
@ -63,7 +64,9 @@ public class BlockTypeMask extends AbstractExtentMask {
public BlockTypeMask(Extent extent, @NotNull BlockType... block) {
super(extent);
this.types = new boolean[BlockTypes.size()];
for (BlockType type : block) this.types[type.getInternalId()] = true;
for (BlockType type : block) {
add(type);
}
}
/**
@ -76,9 +79,6 @@ public class BlockTypeMask extends AbstractExtentMask {
for (BlockType type : blocks) {
add(type);
}
for (BlockType type : blocks) {
this.types[type.getInternalId()] = true;
}
}
/**
@ -88,6 +88,9 @@ public class BlockTypeMask extends AbstractExtentMask {
*/
public void add(@NotNull BlockType... block) {
for (BlockType type : block) {
if (!hasAir && (type == BlockTypes.AIR || type == BlockTypes.CAVE_AIR || type == BlockTypes.VOID_AIR)) {
hasAir = true;
}
this.types[type.getInternalId()] = true;
}
}
@ -110,6 +113,11 @@ public class BlockTypeMask extends AbstractExtentMask {
return test(vector.getBlock(extent).getBlockType());
}
@Override
public boolean replacesAir() {
return hasAir;
}
public boolean test(BlockType block) {
return types[block.getInternalId()];
}

View File

@ -123,4 +123,8 @@ public interface Mask {
}
};
}
default boolean replacesAir() {
return false;
}
}

View File

@ -88,7 +88,11 @@ public class OffsetMask extends AbstractMask {
@Override
public boolean test(Extent extent, BlockVector3 pos) {
return getMask().test(extent, pos);
BlockVector3 testPos = pos.add(offset);
if (testPos.getBlockY() < 0 || testPos.getBlockY() > 255) {
return false;
}
return getMask().test(extent, pos.add(offset));
}
@Nullable

View File

@ -1,13 +1,12 @@
package com.sk89q.worldedit.function.mask;
import com.boydti.fawe.Fawe;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
public class SingleBlockStateMask extends ABlockMask {
private final char ordinal;
private final boolean isAir;
public BlockState getBlockState() {
return BlockState.getFromOrdinal(ordinal);
@ -15,12 +14,14 @@ public class SingleBlockStateMask extends ABlockMask {
public SingleBlockStateMask(Extent extent, BlockState state) {
super(extent);
isAir = state.isAir();
this.ordinal = state.getOrdinalChar();
}
@Override
public boolean test(Extent extent, BlockVector3 vector) {
return ordinal == vector.getOrdinal(extent);
int test = vector.getOrdinal(extent);
return ordinal == test || isAir && test == 0;
}
@Override
@ -33,6 +34,11 @@ public class SingleBlockStateMask extends ABlockMask {
return new InverseSingleBlockStateMask(getExtent(), BlockState.getFromOrdinal(ordinal));
}
@Override
public boolean replacesAir() {
return isAir;
}
@Override
public Mask tryCombine(Mask mask) {
if (mask instanceof ABlockMask) {

View File

@ -8,10 +8,12 @@ import com.sk89q.worldedit.world.block.BlockTypesCache;
public class SingleBlockTypeMask extends ABlockMask {
private final int internalId;
private final boolean isAir;
public SingleBlockTypeMask(Extent extent, BlockType type) {
super(extent);
this.internalId = type.getInternalId();
isAir = type == BlockTypes.AIR || type == BlockTypes.CAVE_AIR || type == BlockTypes.VOID_AIR;
this.internalId = type.getInternalId();
}
@Override
@ -27,4 +29,9 @@ public class SingleBlockTypeMask extends ABlockMask {
public BlockType getBlockType() {
return BlockTypes.get(internalId);
}
@Override
public boolean replacesAir() {
return isAir;
}
}

View File

@ -1,6 +1,7 @@
package com.sk89q.worldedit.world.block;
import com.boydti.fawe.util.MathMan;
import com.google.common.primitives.Booleans;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
@ -166,12 +167,14 @@ public class BlockTypesCache {
public static final BlockType[] values;
public static final BlockState[] states;
public static final boolean[] ticking;
protected static final Set<String> $NAMESPACES = new LinkedHashSet<>();
static {
try {
ArrayList<BlockState> stateList = new ArrayList<>();
ArrayList<Boolean> tickList = new ArrayList<>();
Platform platform = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS);
Registries registries = platform.getRegistries();
@ -202,7 +205,7 @@ public class BlockTypesCache {
if (values[internalId] != null) {
throw new IllegalStateException("Invalid duplicate id for " + field.getName());
}
BlockType type = register(defaultState, internalId, stateList);
BlockType type = register(defaultState, internalId, stateList, tickList);
// Note: Throws IndexOutOfBoundsError if nothing is registered and blocksMap is empty
values[internalId] = type;
}
@ -214,7 +217,7 @@ public class BlockTypesCache {
String defaultState = entry.getValue();
// Skip already registered ids
for (; values[internalId] != null; internalId++);
BlockType type = register(defaultState, internalId, stateList);
BlockType type = register(defaultState, internalId, stateList, tickList);
values[internalId] = type;
}
}
@ -223,7 +226,7 @@ public class BlockTypesCache {
}
states = stateList.toArray(new BlockState[stateList.size()]);
ticking = Booleans.toArray(tickList);
} catch (Throwable e) {
e.printStackTrace();
@ -231,12 +234,14 @@ public class BlockTypesCache {
}
}
private static BlockType register(final String id, int internalId, List<BlockState> states) {
private static BlockType register(final String id, int internalId, List<BlockState> states, List<Boolean> tickList) {
// Get the enum name (remove namespace if minecraft:)
int propStart = id.indexOf('[');
String typeName = id.substring(0, propStart == -1 ? id.length() : propStart);
String enumName = (typeName.startsWith("minecraft:") ? typeName.substring(10) : typeName).toUpperCase(Locale.ROOT);
int oldsize = states.size();
BlockType existing = new BlockType(id, internalId, states);
tickList.addAll(Collections.nCopies(states.size() - oldsize, existing.getMaterial().isTicksRandomly()));
// register states
BlockType.REGISTRY.register(typeName, existing);
String nameSpace = typeName.substring(0, typeName.indexOf(':'));

View File

@ -72,10 +72,10 @@
"fawe.worldedit.history.command.history.clear": "History cleared",
"fawe.worldedit.history.command.redo.error": "Nothing left to redo. (See also `/inspect` and `/frb`)",
"fawe.worldedit.history.command.history.other.error": "Unable to find session for {0}.",
"fawe.worldedit.history.command.redo.success": "Redo successful{0}.",
"fawe.worldedit.history.command.redo.success": "Redo successful {0}.",
"fawe.worldedit.history.command.undo.error": "Nothing left to undo. (See also `/inspect` and `/frb`)",
"fawe.worldedit.history.command.undo.disabled": "Undo disabled, use: //fast",
"fawe.worldedit.history.command.undo.success": "Undo successful{0}.",
"fawe.worldedit.history.command.undo.success": "Undo successful {0}.",
"fawe.worldedit.operation.operation": "Operation queued ({0})",
@ -97,7 +97,7 @@
"fawe.worldedit.selection.selection.shift": "Region shifted",
"fawe.worldedit.selection.selection.cleared": "Selection cleared",
"fawe.worldedit.anvil.world.is.loaded": "The world shouldn't be in use when executing. Unload the world, or use use -f to override (save first)",
"fawe.worldedit.anvil.world.is.loaded": "The world shouldn't be in use when executing. Unload the world, or use -f to override (save first)",
"fawe.worldedit.brush.brush.reset": "Reset your brush. (SHIFT + Click)",
"fawe.worldedit.brush.brush.none": "You aren't holding a brush!",
@ -238,7 +238,7 @@
"fawe.error.command.syntax": "Usage: {0}",
"fawe.error.no-perm": "You are lacking the permission node: {0}",
"fawe.error.block.not.allowed": "You are not allowed to use",
"fawe.error.block.not.allowed": "You are not allowed to use: {0}",
"fawe.error.setting.disable": "Lacking setting: {0}",
"fawe.error.brush.not.found": "Available brushes: {0}",
"fawe.error.brush.incompatible": "Brush not compatible with this version",
@ -373,7 +373,7 @@
"worldedit.limit.set": "Block change limit set to {0}.",
"worldedit.limit.return-to-default": "(Use //limit to go back to the default.)",
"worldedit.timeout.too-high": "Your maximum allowable timeout is {0}ms.",
"worldedit.timeout.set": "Timeout time set to {0} ms.",
"worldedit.timeout.set": "Timeout time set to {0}ms.",
"worldedit.timeout.return-to-default": " (Use //timeout to go back to the default.)",
"worldedit.fast.disabled": "Fast mode disabled.",
"worldedit.fast.enabled": "Fast mode enabled. Lighting in the affected chunks may be wrong and/or you may need to rejoin to see changes.",