Telesphoreo 2024-01-02 15:53:42 -06:00
commit 637dc2df15
No known key found for this signature in database
GPG Key ID: 9D1991811E093C02
17 changed files with 243 additions and 73 deletions

View File

@ -27,10 +27,10 @@ jobs:
cache: gradle
java-version: 17
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3

View File

@ -34,7 +34,7 @@ logger.lifecycle("""
*******************************************
""")
var rootVersion by extra("2.8.4")
var rootVersion by extra("2.8.5")
var snapshot by extra("SNAPSHOT")
var revision: String by extra("")
var buildNumber by extra("")

View File

@ -24,7 +24,7 @@ dependencies {
implementation(gradleApi())
implementation("org.ajoberstar.grgit:grgit-gradle:5.2.1")
implementation("com.github.johnrengelman:shadow:8.1.1")
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.10")
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.5.11")
}
kotlin {

View File

@ -1,6 +1,6 @@
[versions]
# Minecraft expectations
paper = "1.20.2-R0.1-SNAPSHOT"
paper = "1.20.4-R0.1-SNAPSHOT"
fastutil = "8.5.9"
guava = "31.1-jre"
log4j = "2.19.0"
@ -14,16 +14,16 @@ mapmanager = "1.8.0-SNAPSHOT"
griefprevention = "16.18.1"
griefdefender = "2.1.0-SNAPSHOT"
residence = "4.5._13.1"
towny = "0.100.0.8"
plotsquared = "7.2.0"
towny = "0.100.0.11"
plotsquared = "7.2.1"
# Third party
bstats = "3.0.2"
sparsebitset = "1.3"
parallelgzip = "1.0.5"
adventure = "4.14.0"
adventure-bukkit = "4.3.1"
checkerqual = "3.41.0"
adventure = "4.15.0"
adventure-bukkit = "4.3.2"
checkerqual = "3.42.0"
truezip = "6.8.4"
auto-value = "1.10.4"
findbugs = "3.0.2"

View File

@ -12,6 +12,6 @@ repositories {
dependencies {
// https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.20.4-R0.1-20231207.202833-1")
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.20.4-R0.1-20231221.211952-22")
compileOnly(libs.paperlib)
}

View File

@ -183,7 +183,7 @@ tasks.named<ShadowJar>("shadowJar") {
include(dependency("org.lz4:lz4-java:1.8.0"))
}
relocate("net.kyori", "com.fastasyncworldedit.core.adventure") {
include(dependency("net.kyori:adventure-nbt:4.14.0"))
include(dependency("net.kyori:adventure-nbt:4.15.0"))
}
relocate("com.zaxxer", "com.fastasyncworldedit.core.math") {
include(dependency("com.zaxxer:SparseBitSet:1.3"))

View File

@ -721,6 +721,13 @@ public class Settings extends Config {
" - Requires clipboard.use-disk to be enabled"
})
public boolean SAVE_CLIPBOARD_NBT_TO_DISK = true;
@Comment({
"Apply a file lock on the clipboard file (only relevant if clipboad.on-disk is enabled)",
" - Prevents other processes using the file whilst in use by FAWE",
" - This extends to other servers, useful if you have multiple servers using a unified clipboard folder",
" - May run into issues where a file lock is not correctly lifted"
})
public boolean LOCK_CLIPBOARD_FILE = false;
}

View File

@ -6,12 +6,11 @@ import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.regions.RegionWrapper;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
public class HeightBoundExtent extends FaweRegionExtent {
@ -50,7 +49,8 @@ public class HeightBoundExtent extends FaweRegionExtent {
@Override
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
if (trimY(set, min, max, true) | trimNBT(set, this::contains)) {
BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0);
if (trimY(set, min, max, true) | trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos)))) {
return set;
}
return null;

View File

@ -305,22 +305,24 @@ public class DiskOptimizedClipboard extends LinearClipboard {
private void init() throws IOException {
if (this.fileChannel == null) {
this.fileChannel = braf.getChannel();
try {
FileLock lock = this.fileChannel.lock();
LOCK_HOLDER_CACHE.put(file.getName(), new LockHolder(lock));
} catch (OverlappingFileLockException e) {
LockHolder existing = LOCK_HOLDER_CACHE.get(file.getName());
if (existing != null) {
long ms = System.currentTimeMillis() - existing.lockHeldSince;
LOGGER.error(
"Cannot lock clipboard file {} acquired by thread {}, {}ms ago",
file.getName(),
existing.thread,
ms
);
if (Settings.settings().CLIPBOARD.LOCK_CLIPBOARD_FILE) {
try {
FileLock lock = this.fileChannel.lock();
LOCK_HOLDER_CACHE.put(file.getName(), new LockHolder(lock));
} catch (OverlappingFileLockException e) {
LockHolder existing = LOCK_HOLDER_CACHE.get(file.getName());
if (existing != null) {
long ms = System.currentTimeMillis() - existing.lockHeldSince;
LOGGER.error(
"Cannot lock clipboard file {} acquired by thread {}, {}ms ago",
file.getName(),
existing.thread,
ms
);
}
// Rethrow to prevent clipboard access
throw e;
}
// Rethrow to prevent clipboard access
throw e;
}
this.byteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, braf.length());
}

View File

@ -155,7 +155,9 @@ public interface IBatchProcessor {
* Utility method to trim entity and blocks with a provided contains function.
*
* @return false if chunk is empty of NBT
* @deprecated tiles are stored in chunk-normalised coordinate space and thus cannot use the same function as entities
*/
@Deprecated(forRemoval = true, since = "2.8.4")
default boolean trimNBT(IChunkSet set, Function<BlockVector3, Boolean> contains) {
Set<CompoundTag> ents = set.getEntities();
if (!ents.isEmpty()) {
@ -169,6 +171,26 @@ public interface IBatchProcessor {
return !tiles.isEmpty() || !ents.isEmpty();
}
/**
* Utility method to trim entity and blocks with a provided contains function.
*
* @return false if chunk is empty of NBT
* @since 2.8.4
*/
default boolean trimNBT(
IChunkSet set, Function<BlockVector3, Boolean> containsEntity, Function<BlockVector3, Boolean> containsTile
) {
Set<CompoundTag> ents = set.getEntities();
if (!ents.isEmpty()) {
ents.removeIf(ent -> !containsEntity.apply(ent.getEntityPosition().toBlockPoint()));
}
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
if (!tiles.isEmpty()) {
tiles.entrySet().removeIf(blockVector3CompoundTagEntry -> !containsTile.apply(blockVector3CompoundTagEntry.getKey()));
}
return !tiles.isEmpty() || !ents.isEmpty();
}
/**
* Join two processors and return the result.
*/

View File

@ -1,6 +1,7 @@
package com.fastasyncworldedit.core.queue;
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import javax.annotation.Nullable;
@ -33,6 +34,16 @@ public interface IChunk extends Trimable, IChunkGet, IChunkSet {
*/
int getZ();
/**
* Return the minimum block coordinate of the chunk
*
* @return BlockVector3 of minimum block coordinate
* @since 2.8.4
*/
default BlockVector3 getChunkBlockCoord() {
return BlockVector3.at(getX() << 4, getMinY(), getZ() << 4);
}
/**
* If the chunk is a delegate, returns its parent's root
*

View File

@ -47,6 +47,7 @@ import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.Logging;
import com.sk89q.worldedit.command.util.annotation.Confirm;
import com.sk89q.worldedit.command.util.annotation.Preload;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
@ -70,6 +71,7 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.NullRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionIntersection;
@ -351,7 +353,9 @@ public class ClipboardCommands {
@Switch(name = 'e', desc = "Paste entities if available")
boolean pasteEntities,
@Switch(name = 'b', desc = "Paste biomes if available")
boolean pasteBiomes
boolean pasteBiomes,
@Switch(name = 'x', desc = "Remove existing entities in the affected region")
boolean removeEntities
) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
final Clipboard clipboard = holder.getClipboard();
@ -364,17 +368,22 @@ public class ClipboardCommands {
}
Region region = clipboard.getRegion().clone();
if (selectPasted || onlySelect) {
if (selectPasted || onlySelect || removeEntities) {
BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
BlockVector3 realTo = to.add(holder.getTransform().apply(clipboardOffset.toVector3()).toBlockPoint());
BlockVector3 max = realTo.add(holder
.getTransform()
.apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3())
.toBlockPoint());
RegionSelector selector = new CuboidRegionSelector(world, realTo, max);
session.setRegionSelector(world, selector);
selector.learnChanges();
selector.explainRegionAdjust(actor, session);
if (removeEntities) {
editSession.getEntities(new CuboidRegion(realTo, max)).forEach(Entity::remove);
}
if (selectPasted || onlySelect) {
RegionSelector selector = new CuboidRegionSelector(world, realTo, max);
session.setRegionSelector(world, selector);
selector.learnChanges();
selector.explainRegionAdjust(actor, session);
}
}
if (onlySelect) {
actor.print(Caption.of("worldedit.paste.selected"));
@ -411,14 +420,19 @@ public class ClipboardCommands {
boolean pasteBiomes,
@ArgFlag(name = 'm', desc = "Only paste blocks matching this mask")
@ClipboardMask
Mask sourceMask
Mask sourceMask,
//FAWE start - entity removal
@Switch(name = 'x', desc = "Remove existing entities in the affected region")
boolean removeEntities
//FAWE end
) throws WorldEditException {
ClipboardHolder holder = session.getClipboard();
//FAWE start - use place
if (holder.getTransform().isIdentity() && sourceMask == null) {
place(actor, world, session, editSession, ignoreAirBlocks, atOrigin, selectPasted, onlySelect,
pasteEntities, pasteBiomes
pasteEntities, pasteBiomes, removeEntities
);
return;
}
@ -445,21 +459,29 @@ public class ClipboardCommands {
messages.addAll(Lists.newArrayList(operation.getStatusMessages()));
}
if (selectPasted || onlySelect) {
if (selectPasted || onlySelect || removeEntities) {
BlockVector3 clipboardOffset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
Vector3 realTo = to.toVector3().add(holder.getTransform().apply(clipboardOffset.toVector3()));
Vector3 max = realTo.add(holder
.getTransform()
.apply(region.getMaximumPoint().subtract(region.getMinimumPoint()).toVector3()));
final CuboidRegionSelector selector;
if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) {
selector = new ExtendingCuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint());
} else {
selector = new CuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint());
// FAWE start - entity remova;l
if (removeEntities) {
editSession.getEntities(new CuboidRegion(realTo.toBlockPoint(), max.toBlockPoint())).forEach(Entity::remove);
}
if (selectPasted || onlySelect) {
//FAWE end
final CuboidRegionSelector selector;
if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) {
selector = new ExtendingCuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint());
} else {
selector = new CuboidRegionSelector(world, realTo.toBlockPoint(), max.toBlockPoint());
}
session.setRegionSelector(world, selector);
selector.learnChanges();
selector.explainRegionAdjust(actor, session);
}
session.setRegionSelector(world, selector);
selector.learnChanges();
selector.explainRegionAdjust(actor, session);
}
if (onlySelect) {

View File

@ -25,27 +25,34 @@ import com.fastasyncworldedit.core.extent.HistoryExtent;
import com.fastasyncworldedit.core.extent.NullExtent;
import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet;
import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.util.ExtentTraverser;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.buffer.ForgetfulExtentBuffer;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.OperationQueue;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import static com.google.common.base.Preconditions.checkNotNull;
@ -168,6 +175,7 @@ public class AbstractDelegateExtent implements Extent {
}
}
//FAWE start
@Override
public boolean cancel() {
ExtentTraverser<Extent> traverser = new ExtentTraverser<>(this);
@ -188,7 +196,6 @@ public class AbstractDelegateExtent implements Extent {
return true;
}
//FAWE start
@Override
public void removeEntity(int x, int y, int z, UUID uuid) {
extent.removeEntity(x, y, z, uuid);
@ -225,11 +232,72 @@ public class AbstractDelegateExtent implements Extent {
}
}
@Override
public boolean isWorld() {
return extent.isWorld();
}
@Override
public List<Countable<BlockType>> getBlockDistribution(final Region region) {
return extent.getBlockDistribution(region);
}
@Override
public List<Countable<BlockState>> getBlockDistributionWithData(final Region region) {
return extent.getBlockDistributionWithData(region);
}
@Override
public int getMaxY() {
return extent.getMaxY();
}
@Override
public int countBlocks(final Region region, final Set<BaseBlock> searchBlocks) {
return extent.countBlocks(region, searchBlocks);
}
@Override
public int countBlocks(final Region region, final Mask searchMask) {
return extent.countBlocks(region, searchMask);
}
@Override
public <B extends BlockStateHolder<B>> int setBlocks(final Region region, final B block) throws MaxChangedBlocksException {
return extent.setBlocks(region, block);
}
@Override
public int setBlocks(final Region region, final Pattern pattern) throws MaxChangedBlocksException {
return extent.setBlocks(region, pattern);
}
@Override
public <B extends BlockStateHolder<B>> int replaceBlocks(
final Region region,
final Set<BaseBlock> filter,
final B replacement
)
throws MaxChangedBlocksException {
return extent.replaceBlocks(region, filter, replacement);
}
@Override
public int replaceBlocks(final Region region, final Set<BaseBlock> filter, final Pattern pattern) throws
MaxChangedBlocksException {
return extent.replaceBlocks(region, filter, pattern);
}
@Override
public int replaceBlocks(final Region region, final Mask mask, final Pattern pattern) throws MaxChangedBlocksException {
return extent.replaceBlocks(region, mask, pattern);
}
@Override
public int setBlocks(final Set<BlockVector3> vset, final Pattern pattern) {
return extent.setBlocks(vset, pattern);
}
@Override
public int getMinY() {
return extent.getMinY();
@ -295,23 +363,29 @@ public class AbstractDelegateExtent implements Extent {
return this;
}
@Override
public <T extends Filter> T apply(final Region region, final T filter, final boolean full) {
return extent.apply(region, filter, full);
}
//FAWE end
protected Operation commitBefore() {
return null;
}
@Override
public BiomeType getBiome(BlockVector3 position) {
//FAWE start - switch top x,y,z
return extent.getBiomeType(position.getX(), position.getY(), position.getZ());
//FAWE end
}
//FAWE start
@Override
public BiomeType getBiomeType(int x, int y, int z) {
return extent.getBiomeType(x, y, z);
}
@Override
public BiomeType getBiome(BlockVector3 position) {
return extent.getBiome(position);
}
/*
History
*/
@Override
public int getEmittedLight(int x, int y, int z) {
return extent.getEmittedLight(x, y, z);
@ -341,13 +415,17 @@ public class AbstractDelegateExtent implements Extent {
new ExtentTraverser<>(this).setNext(new HistoryExtent(extent, changeSet));
}
}
//FAWE end
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException {
//FAWE start - switch to x,y,z
return extent.setBlock(position.getX(), position.getY(), position.getZ(), block);
//FAWE end
}
//FAWE start
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(
int x, int y,
@ -360,6 +438,7 @@ public class AbstractDelegateExtent implements Extent {
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
return setBlock(x, y, z, getBlock(x, y, z).toBaseBlock(tile));
}
//FAWE end
@Override
public boolean fullySupports3DBiomes() {
@ -367,13 +446,16 @@ public class AbstractDelegateExtent implements Extent {
}
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
return extent.setBiome(x, y, z, biome);
public boolean setBiome(BlockVector3 position, BiomeType biome) {
//FAWE start - switch to x,y,z
return extent.setBiome(position.getX(), position.getY(), position.getZ(), biome);
//FAWE end
}
//FAWE start
@Override
public boolean setBiome(BlockVector3 position, BiomeType biome) {
return extent.setBiome(position.getX(), position.getY(), position.getZ(), biome);
public boolean setBiome(int x, int y, int z, BiomeType biome) {
return extent.setBiome(x, y, z, biome);
}
@Override

View File

@ -22,7 +22,6 @@ package com.sk89q.worldedit.regions;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
import com.fastasyncworldedit.core.math.BlockVectorSet;
import com.fastasyncworldedit.core.math.MutableBlockVector2;
import com.fastasyncworldedit.core.math.MutableBlockVector3;
import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IChunk;
@ -805,7 +804,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
return set;
}
trimY(set, minY, maxY, true);
trimNBT(set, this::contains);
BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0);
trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos)));
return set;
}
if (tx >= minX && bx <= maxX && tz >= minZ && bz <= maxZ) {
@ -868,8 +868,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
}
set.setBlocks(layer, arr);
}
trimNBT(set, this::contains);
final BlockVector3 chunkPos = BlockVector3.at(chunk.getX() << 4, 0, chunk.getZ() << 4);
trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos)));
return set;
}
return null;
@ -893,7 +893,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
return null;
}
trimY(set, minY, maxY, false);
trimNBT(set, this::contains);
BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0);
trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos)));
return set;
}
if (tx >= minX && bx <= maxX && tz >= minZ && bz <= maxZ) {
@ -943,7 +944,8 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
}
set.setBlocks(layer, arr);
}
trimNBT(set, bv3 -> !this.contains(bv3));
BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0);
trimNBT(set, bv3 -> !this.contains(bv3), bv3 -> !this.contains(bv3.add(chunkPos)));
return set;
}
return set;

View File

@ -425,7 +425,8 @@ public interface Region extends Iterable<BlockVector3>, Cloneable, IBatchProcess
}
}
if (processExtra) {
trimNBT(set, this::contains);
BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0);
trimNBT(set, this::contains, pos -> this.contains(pos.add(chunkPos)));
}
return set;
} else {
@ -477,7 +478,8 @@ public interface Region extends Iterable<BlockVector3>, Cloneable, IBatchProcess
}
}
if (processExtra) {
trimNBT(set, bv3 -> !this.contains(bv3));
BlockVector3 chunkPos = chunk.getChunkBlockCoord().withY(0);
trimNBT(set, bv3 -> !this.contains(bv3), bv3 -> !this.contains(bv3.add(chunkPos)));
}
return set;
} else {

View File

@ -178,9 +178,18 @@ public class BlockState implements BlockStateHolder<BlockState>, Pattern {
String name = property.getName();
charSequence.setSubstring(propStrStart + name.length() + 2, state.length() - 1);
int index = charSequence.length() <= 0 ? -1 : property.getIndexFor(charSequence);
if (index != -1) {
return type.withPropertyId(index);
try {
int index = charSequence.length() <= 0 ? -1 : property.getIndexFor(charSequence);
if (index != -1) {
return type.withPropertyId(index);
}
} catch (Exception e) {
throw new InputParseException(Caption.of(
"fawe.error.invalid-block-state-property",
TextComponent.of(charSequence.toString()),
TextComponent.of(name),
TextComponent.of(state)
), e);
}
}
int stateId;
@ -200,7 +209,17 @@ public class BlockState implements BlockStateHolder<BlockState>, Pattern {
case ',': {
charSequence.setSubstring(last, i);
if (property != null) {
int index = property.getIndexFor(charSequence);
int index;
try {
index = property.getIndexFor(charSequence);
} catch (Exception e) {
throw new InputParseException(Caption.of(
"fawe.error.invalid-block-state-property",
TextComponent.of(charSequence.toString()),
TextComponent.of(property.getName()),
TextComponent.of(state)
), e);
}
if (index == -1) {
throw SuggestInputParseException.of(charSequence.toString(), (List<Object>) property.getValues());
}

View File

@ -92,6 +92,7 @@
"fawe.error.parser.invalid-data": "Invalid data: {0}",
"fawe.error.unsupported": "Unsupported!",
"fawe.error.invalid-block-type": "Does not match a valid block type: {0}",
"fawe.error.invalid-block-state-property": "Cannot parse value `{0}` for property `{1}`, block state: `{2}`",
"fawe.error.nbt.forbidden": "You are not allowed to use nbt. Lacking permission: {0}",
"fawe.error.invalid-arguments": "Invalid amount of arguments. Expected: {0}",
"fawe.error.unrecognised-tag": "Unrecognised tag: {0} {1}",