Fixes to BlockMask and "char" masks (#1787)

* If a char mask  is successfully created from the full input, return it

* Don't double-up adding a block to a BlockMaskBuilder (if adding by regex is successful)
 - InputParseException is thrown if unsuccessful

* Fix optimisation of BlockMask for negation of a single block type
 - Fixes #1755

* Allow early returning of an optimized MaskIntersection to avoid unnecessary work

* Actually allow underscore in isAlphanumericUnd
 - Fixes #1626

* Replace a few more hard-coded air internal IDs

* Don't fail silently if BlockMaskBuilder#addRegex doesn't work when testing all block types

* Remove unused import
This commit is contained in:
Jordan 2022-06-16 15:24:48 +01:00 committed by GitHub
parent f2bab901f4
commit fd00635533
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 23 deletions

View File

@ -127,6 +127,9 @@ public class RichMaskParser extends FaweParser<Mask> {
case '%', '$', '<', '>', '!' -> { case '%', '$', '<', '>', '!' -> {
input = input.substring(input.indexOf(char0) + 1); input = input.substring(input.indexOf(char0) + 1);
mask = parseFromInput(char0 + "[" + input + "]", context); mask = parseFromInput(char0 + "[" + input + "]", context);
if (mask != null) {
return mask;
}
} }
case '#' -> { case '#' -> {
if (!(input.charAt(1) == '#')) { if (!(input.charAt(1) == '#')) {
@ -145,6 +148,10 @@ public class RichMaskParser extends FaweParser<Mask> {
try { try {
builder.addRegex(full); builder.addRegex(full);
} catch (InputParseException ignored) { } catch (InputParseException ignored) {
context.setPreferringWildcard(false);
context.setRestricted(false);
BaseBlock block = worldEdit.getBlockFactory().parseFromInput(full, context);
builder.add(block);
} catch (PatternSyntaxException e) { } catch (PatternSyntaxException e) {
throw new SuggestInputParseException( throw new SuggestInputParseException(
new NoMatchException(Caption.of("fawe.error.parse.unknown-mask", full, new NoMatchException(Caption.of("fawe.error.parse.unknown-mask", full,
@ -166,10 +173,6 @@ public class RichMaskParser extends FaweParser<Mask> {
} }
); );
} }
context.setPreferringWildcard(false);
context.setRestricted(false);
BaseBlock block = worldEdit.getBlockFactory().parseFromInput(full, context);
builder.add(block);
mask = builder.build(extent); mask = builder.build(extent);
} }
} }

View File

@ -123,7 +123,7 @@ public class BlockMaskBuilder {
if (input.charAt(input.length() - 1) == ']') { if (input.charAt(input.length() - 1) == ']') {
int propStart = StringMan.findMatchingBracket(input, input.length() - 1); int propStart = StringMan.findMatchingBracket(input, input.length() - 1);
if (propStart == -1) { if (propStart == -1) {
return; throw new InputParseException(Caption.of("fawe.error.no-block-found", TextComponent.of(input)));
} }
MutableCharSequence charSequence = MutableCharSequence.getTemporal(); MutableCharSequence charSequence = MutableCharSequence.getTemporal();
@ -250,11 +250,16 @@ public class BlockMaskBuilder {
if (StringMan.isAlphanumericUnd(input)) { if (StringMan.isAlphanumericUnd(input)) {
add(BlockTypes.parse(input)); add(BlockTypes.parse(input));
} else { } else {
boolean success = false;
for (BlockType myType : BlockTypesCache.values) { for (BlockType myType : BlockTypesCache.values) {
if (myType.getId().matches(input)) { if (myType.getId().matches(input)) {
add(myType); add(myType);
success = true;
} }
} }
if (!success) {
throw new InputParseException(Caption.of("fawe.error.no-block-found", TextComponent.of(input)));
}
} }
} }
}); });

View File

@ -295,7 +295,7 @@ public class StringMan {
public static boolean isAlphanumericUnd(CharSequence str) { public static boolean isAlphanumericUnd(CharSequence str) {
for (int i = 0; i < str.length(); i++) { for (int i = 0; i < str.length(); i++) {
final char c = str.charAt(i); final char c = str.charAt(i);
if (c < 0x30 || c >= 0x3a && c <= 0x40 || c > 0x5a && c <= 0x60 || c > 0x7a) { if (c < 0x30 || c >= 0x3a && c <= 0x40 || c > 0x5a && c <= 0x60 && c != 0x5f || c > 0x7a) {
return false; return false;
} }
} }

View File

@ -210,15 +210,14 @@ public class BlockMask extends ABlockMask {
@Override @Override
public boolean replacesAir() { public boolean replacesAir() {
return ordinals[1] return ordinals[BlockTypesCache.ReservedIDs.AIR]
|| ordinals[2] || ordinals[BlockTypesCache.ReservedIDs.CAVE_AIR]
|| ordinals[3]; || ordinals[BlockTypesCache.ReservedIDs.VOID_AIR];
} }
@Override @Override
public Mask tryCombine(Mask mask) { public Mask tryCombine(Mask mask) {
if (mask instanceof ABlockMask) { if (mask instanceof ABlockMask other) {
ABlockMask other = (ABlockMask) mask;
boolean modified = false; boolean modified = false;
boolean hasAny = false; boolean hasAny = false;
for (int i = 0; i < ordinals.length; i++) { for (int i = 0; i < ordinals.length; i++) {
@ -241,8 +240,7 @@ public class BlockMask extends ABlockMask {
@Override @Override
public Mask tryOr(Mask mask) { public Mask tryOr(Mask mask) {
if (mask instanceof ABlockMask) { if (mask instanceof ABlockMask other) {
ABlockMask other = (ABlockMask) mask;
boolean modified = false; boolean modified = false;
for (int i = 0; i < ordinals.length; i++) { for (int i = 0; i < ordinals.length; i++) {
if (!ordinals[i]) { if (!ordinals[i]) {
@ -273,23 +271,27 @@ public class BlockMask extends ABlockMask {
int setTypes = 0; int setTypes = 0;
BlockType setType = null; BlockType setType = null;
BlockType unsetType = null;
int totalTypes = 0; int totalTypes = 0;
for (BlockType type : BlockTypesCache.values) { for (BlockType type : BlockTypesCache.values) {
if (type != null) { if (type != null) {
totalTypes++; totalTypes++;
boolean hasAll = true; boolean hasAll = true;
boolean hasAny = false;
List<BlockState> all = type.getAllStates(); List<BlockState> all = type.getAllStates();
for (BlockState state : all) { for (BlockState state : all) {
totalStates++; totalStates++;
hasAll &= test(state); boolean result = test(state);
hasAll &= result;
hasAny |= result;
} }
if (hasAll) { if (hasAll) {
setTypes++; setTypes++;
setType = type; setType = type;
setStates += all.size(); setStates += all.size();
setState = type.getDefaultState(); setState = type.getDefaultState();
} else { } else if (hasAny) {
for (BlockState state : all) { for (BlockState state : all) {
if (test(state)) { if (test(state)) {
setStates++; setStates++;
@ -298,6 +300,10 @@ public class BlockMask extends ABlockMask {
unsetState = state; unsetState = state;
} }
} }
} else if (all.size() == 1) {
unsetState = all.get(0);
} else {
unsetType = type;
} }
} }
} }
@ -313,7 +319,11 @@ public class BlockMask extends ABlockMask {
} }
if (setStates == totalStates - 1) { if (setStates == totalStates - 1) {
return new InverseSingleBlockStateMask(getExtent(), unsetState); if (unsetState != null) {
return new InverseSingleBlockStateMask(getExtent(), unsetState);
} else {
throw new IllegalArgumentException("unsetState cannot be null when passed to InverseSingleBlockStateMask");
}
} }
if (setTypes == 1) { if (setTypes == 1) {
@ -321,7 +331,11 @@ public class BlockMask extends ABlockMask {
} }
if (setTypes == totalTypes - 1) { if (setTypes == totalTypes - 1) {
throw new IllegalArgumentException("unsetType cannot be null when passed to InverseSingleBlockTypeMask"); if (unsetType != null) {
return new InverseSingleBlockTypeMask(getExtent(), unsetType);
} else {
throw new IllegalArgumentException("unsetType cannot be null when passed to InverseSingleBlockTypeMask");
}
} }
return null; return null;
@ -329,15 +343,15 @@ public class BlockMask extends ABlockMask {
@Override @Override
public Mask inverse() { public Mask inverse() {
boolean[] cloned = ordinals.clone(); boolean[] cloned = new boolean[ordinals.length];
for (int i = 0; i < cloned.length; i++) { for (int i = 0; i < cloned.length; i++) {
cloned[i] = !cloned[i]; cloned[i] = !ordinals[i];
} }
if (replacesAir()) { if (replacesAir()) {
cloned[1] = false; cloned[BlockTypesCache.ReservedIDs.__RESERVED__] = false;
cloned[2] = false; cloned[BlockTypesCache.ReservedIDs.AIR] = false;
cloned[3] = false; cloned[BlockTypesCache.ReservedIDs.CAVE_AIR] = false;
cloned[0] = false; cloned[BlockTypesCache.ReservedIDs.VOID_AIR] = false;
} }
return new BlockMask(getExtent(), cloned); return new BlockMask(getExtent(), cloned);
} }

View File

@ -163,6 +163,14 @@ public class MaskIntersection extends AbstractMask {
while (combineMasks(pairingFunction(), failedCombines)) { while (combineMasks(pairingFunction(), failedCombines)) {
changed = true; changed = true;
} }
if (masks.isEmpty()) {
formArray(); // This MaskIntersection instance may be reused for whatever reason, so ensure the array is correct.
return Masks.alwaysTrue();
}
if (masks.size() == 1) {
formArray(); // This MaskIntersection instance may be reused for whatever reason, so ensure the array is correct.
return masks.iterator().next();
}
// Optimize / combine // Optimize / combine
do { do {
changed |= optimizeMasks(optimized); changed |= optimizeMasks(optimized);