Merge branch 'IntellectualSites:main' into main

This commit is contained in:
2023-07-02 23:37:39 -05:00
committed by GitHub
75 changed files with 637 additions and 17868 deletions

View File

@ -356,8 +356,8 @@ public class Fawe {
);
if (Settings.settings().QUEUE.TARGET_SIZE < 4 * Settings.settings().QUEUE.PARALLEL_THREADS) {
LOGGER.error(
"queue.target_size is {}, and queue.parallel_threads is {}. It is HIGHLY recommended that queue" +
".target_size be at least four times queue.parallel_threads or greater.",
"queue.target-size is {}, and queue.parallel_threads is {}. It is HIGHLY recommended that queue" +
".target-size be at least four times queue.parallel-threads or greater.",
Settings.settings().QUEUE.TARGET_SIZE,
Settings.settings().QUEUE.PARALLEL_THREADS
);

View File

@ -584,7 +584,8 @@ public class Settings extends Config {
@Comment({"Display constant titles about the progress of a user's edit",
" - false = disabled",
" - title = Display progress titles",
" - chat = Display progress in chat"
" - chat = Display progress in chat",
" - Currently not implemented"
})
public String DISPLAY = "false";
@Comment("How often edit progress is displayed")
@ -622,10 +623,11 @@ public class Settings extends Config {
public boolean PERSISTENT_BRUSHES = true;
@Comment({
"[SAFE] Keep entities that are positioned in non-air blocks when editing an area",
"Might cause client-side FPS lag in some situations"
"[SAFE] Keep entities that are positioned in non-air blocks when editing an area (default: true)",
" - Might cause client-side FPS lag in some situations",
" - Requires fast-placement to be true"
})
public boolean KEEP_ENTITIES_IN_BLOCKS = false;
public boolean KEEP_ENTITIES_IN_BLOCKS = true;
@Comment({
"[SAFE] Attempt to remove entities from the world if they were not present in the expected chunk (default: true)",

View File

@ -0,0 +1,57 @@
package com.fastasyncworldedit.core.extent.processor;
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.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockTypes;
import org.jetbrains.annotations.Nullable;
/**
* Processor that removes existing entities that would not be in air after the edit
*
* @since TODO
*/
public class EntityInBlockRemovingProcessor implements IBatchProcessor {
@Override
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
for (CompoundTag tag : get.getEntities()) {
// Empty tags for seemingly non-existent entities can exist?
if (tag.getList("Pos").size() == 0) {
continue;
}
BlockVector3 pos = tag.getEntityPosition().toBlockPoint();
int x = pos.getX() & 15;
int y = pos.getY();
int z = pos.getZ() & 15;
if (!set.hasSection(y >> 4)) {
continue;
}
if (set.getBlock(x, y, z).getBlockType() != BlockTypes.__RESERVED__ && !set
.getBlock(x, y, z)
.getBlockType()
.getMaterial()
.isAir()) {
set.removeEntity(tag.getUUID());
}
}
return set;
}
@Nullable
@Override
public Extent construct(final Extent child) {
throw new UnsupportedOperationException("Processing only");
}
@Override
public ProcessorScope getScope() {
// After block removal but before history
return ProcessorScope.CUSTOM;
}
}

View File

@ -7,7 +7,8 @@ package com.fastasyncworldedit.core.extent.processor;
* - CHANGING_BLOCKS (processors that may ADD or CHANGE blocks being set)
* - REMOVING_BLOCKS (processors that may ADD, CHANGE or REMOVE blocks being set)
* - CUSTOM (processors that do not specify a SCOPE)
* - READING_SET_BLOCKS (processors that do not alter blocks at all, and read the blocks that are actually going to set, e.g. history processors)
* - READING_SET_BLOCKS (processors that do not alter blocks at all, and read the blocks that are actually going to set, e.g.
* history processors). There is no guarantee that changes made here will be stored in history.
*/
public enum ProcessorScope {
ADDING_BLOCKS(0),

View File

@ -20,12 +20,11 @@ import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -36,10 +35,12 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
public class BlockMaskBuilder {
private static final Operator GREATER = (a, b) -> a > b;
@ -63,58 +64,97 @@ public class BlockMaskBuilder {
this.bitSets = bitSets;
}
private boolean filterRegex(BlockType blockType, PropertyKey key, String regex) {
private boolean handleRegex(BlockType blockType, PropertyKey key, String regex, FuzzyStateAllowingBuilder builder) {
Property<Object> property = blockType.getProperty(key);
if (property == null) {
return false;
}
List<Object> values = property.getValues();
boolean result = false;
List<Object> values = property.getValues();
for (int i = 0; i < values.size(); i++) {
Object value = values.get(i);
if (!value.toString().matches(regex) && has(blockType, property, i)) {
filter(blockType, property, i);
if (values.get(i).toString().matches(regex)) {
builder.allow(property, i);
result = true;
}
}
return result;
}
private boolean filterOperator(BlockType blockType, PropertyKey key, Operator operator, CharSequence value) {
private boolean handleOperator(
BlockType blockType,
PropertyKey key,
Operator operator,
CharSequence stringValue,
FuzzyStateAllowingBuilder builder
) {
Property<Object> property = blockType.getProperty(key);
if (property == null) {
return false;
}
int index = property.getIndexFor(value);
int index = property.getIndexFor(stringValue);
List<Object> values = property.getValues();
boolean result = false;
for (int i = 0; i < values.size(); i++) {
if (!operator.test(index, i) && has(blockType, property, i)) {
filter(blockType, property, i);
if (operator.test(index, i)) {
builder.allow(property, i);
result = true;
}
}
return result;
}
private boolean filterRegexOrOperator(BlockType type, PropertyKey key, Operator operator, CharSequence value) {
boolean result = false;
if (!type.hasProperty(key)) {
if (operator == EQUAL) {
result = bitSets[type.getInternalId()] != null;
remove(type);
private boolean handleRegexOrOperator(
BlockType type,
PropertyKey key,
Operator operator,
CharSequence value,
FuzzyStateAllowingBuilder builder
) {
if (!type.hasProperty(key) && operator == EQUAL) {
return false;
}
if (value.length() == 0) {
return false;
}
if ((operator == EQUAL || operator == EQUAL_OR_NULL) && !StringMan.isAlphanumericUnd(value)) {
return handleRegex(type, key, value.toString(), builder);
} else {
return handleOperator(type, key, operator, value, builder);
}
}
private void add(FuzzyStateAllowingBuilder builder) {
long[] states = bitSets[builder.getType().getInternalId()];
if (states == ALL) {
bitSets[builder.getType().getInternalId()] = states = FastBitSet.create(builder.getType().getMaxStateId() + 1);
FastBitSet.unsetAll(states);
}
applyRecursive(0, builder.getType().getInternalId(), builder, states);
}
private void applyRecursive(
int propertiesIndex,
int state,
FuzzyStateAllowingBuilder builder,
long[] states
) {
AbstractProperty<?> current = (AbstractProperty<?>) builder.getType().getProperties().get(propertiesIndex);
List<?> values = current.getValues();
if (propertiesIndex + 1 < builder.getType().getProperties().size()) {
for (int i = 0; i < values.size(); i++) {
if (builder.allows(current) || builder.allows(current, i)) {
int newState = current.modifyIndex(state, i);
applyRecursive(propertiesIndex + 1, newState, builder, states);
}
}
} else {
if (value.length() == 0) {
return result;
}
if ((operator == EQUAL || operator == EQUAL_OR_NULL) && !StringMan.isAlphanumericUnd(value)) {
result = filterRegex(type, key, value.toString());
} else {
result = filterOperator(type, key, operator, value);
for (int i = 0; i < values.size(); i++) {
if (builder.allows(current) || builder.allows(current, i)) {
int index = current.modifyIndex(state, i) >> BlockTypesCache.BIT_OFFSET;
FastBitSet.set(states, index);
}
}
}
return result;
}
public BlockMaskBuilder addRegex(final String input) throws InputParseException {
@ -130,26 +170,28 @@ public class BlockMaskBuilder {
charSequence.setString(input);
charSequence.setSubstring(0, propStart);
BlockType type = null;
List<BlockType> blockTypeList = null;
List<BlockType> blockTypeList;
List<FuzzyStateAllowingBuilder> builders;
if (StringMan.isAlphanumericUnd(charSequence)) {
type = BlockTypes.parse(charSequence.toString());
BlockType type = BlockTypes.parse(charSequence.toString());
blockTypeList = Collections.singletonList(type);
builders = Collections.singletonList(new FuzzyStateAllowingBuilder(type));
add(type);
} else {
String regex = charSequence.toString();
blockTypeList = new ArrayList<>();
for (BlockType myType : BlockTypesCache.values) {
if (myType.getId().matches(regex)) {
blockTypeList.add(myType);
add(myType);
builders = new ArrayList<>();
Pattern pattern = Pattern.compile("(minecraft:)?" + regex);
for (BlockType type : BlockTypesCache.values) {
if (pattern.matcher(type.getId()).find()) {
blockTypeList.add(type);
builders.add(new FuzzyStateAllowingBuilder(type));
add(type);
}
}
if (blockTypeList.isEmpty()) {
throw new InputParseException(Caption.of("fawe.error.no-block-found", TextComponent.of(input)));
}
if (blockTypeList.size() == 1) {
type = blockTypeList.get(0);
}
}
// Empty string
charSequence.setSubstring(0, 0);
@ -169,11 +211,11 @@ public class BlockMaskBuilder {
}
case ']', ',' -> {
charSequence.setSubstring(last, i);
if (key == null && PropertyKey.getByName(charSequence) == null) {
if (key == null && (key = PropertyKey.getByName(charSequence)) == null) {
suggest(
input,
charSequence.toString(),
type != null ? Collections.singleton(type) : blockTypeList
blockTypeList
);
}
if (operator == null) {
@ -182,34 +224,20 @@ public class BlockMaskBuilder {
() -> Arrays.asList("=", "~", "!", "<", ">", "<=", ">=")
);
}
boolean filtered = false;
if (type != null) {
filtered = filterRegexOrOperator(type, key, operator, charSequence);
} else {
for (BlockType myType : blockTypeList) {
filtered |= filterRegexOrOperator(myType, key, operator, charSequence);
for (int index = 0; index < blockTypeList.size(); index++) {
if (!handleRegexOrOperator(
blockTypeList.get(index),
key,
operator,
charSequence,
builders.get(index)
)) {
// If we cannot find a matching property for all to mask, do not mask the block
blockTypeList.remove(index);
builders.remove(index);
index--;
}
}
if (!filtered) {
String value = charSequence.toString();
final PropertyKey fKey = key;
Collection<BlockType> types = type != null ? Collections.singleton(type) : blockTypeList;
throw new SuggestInputParseException(Caption.of("fawe.error.no-value-for-input", input), () -> {
HashSet<String> values = new HashSet<>();
types.stream().filter(t -> t.hasProperty(fKey)).forEach(t -> {
Property<Object> p = t.getProperty(fKey);
for (int j = 0; j < p.getValues().size(); j++) {
if (has(t, p, j)) {
String o = p.getValues().get(j).toString();
if (o.startsWith(value)) {
values.add(o);
}
}
}
});
return new ArrayList<>(values);
});
}
// Reset state
key = null;
operator = null;
@ -235,7 +263,7 @@ public class BlockMaskBuilder {
suggest(
input,
charSequence.toString(),
type != null ? Collections.singleton(type) : blockTypeList
blockTypeList
);
}
}
@ -245,13 +273,18 @@ public class BlockMaskBuilder {
}
}
}
for (FuzzyStateAllowingBuilder builder : builders) {
if (builder.allows()) {
add(builder);
}
}
} else {
if (StringMan.isAlphanumericUnd(input)) {
add(BlockTypes.parse(input));
} else {
boolean success = false;
for (BlockType myType : BlockTypesCache.values) {
if (myType.getId().matches(input)) {
if (myType.getId().matches("(minecraft:)?" + input)) {
add(myType);
success = true;
}
@ -275,16 +308,6 @@ public class BlockMaskBuilder {
return this;
}
private <T> boolean has(BlockType type, Property<T> property, int index) {
AbstractProperty<T> prop = (AbstractProperty<T>) property;
long[] states = bitSets[type.getInternalId()];
if (states == null) {
return false;
}
int localI = index << prop.getBitOffset() >> BlockTypesCache.BIT_OFFSET;
return (states == ALL || FastBitSet.get(states, localI));
}
private void suggest(String input, String property, Collection<BlockType> finalTypes) throws InputParseException {
throw new SuggestInputParseException(Caption.of("worldedit.error.parser.unknown-property", property, input), () -> {
Set<PropertyKey> keys = PropertyKeySet.empty();
@ -381,42 +404,6 @@ public class BlockMaskBuilder {
return this;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public <T> BlockMaskBuilder filter(
Predicate<BlockType> typePredicate,
BiPredicate<BlockType, Map.Entry<Property<T>, T>> allowed
) {
for (int i = 0; i < bitSets.length; i++) {
long[] states = bitSets[i];
if (states == null) {
continue;
}
BlockType type = BlockTypes.get(i);
if (!typePredicate.test(type)) {
bitSets[i] = null;
continue;
}
List<AbstractProperty<?>> properties = (List<AbstractProperty<?>>) type.getProperties();
for (AbstractProperty<?> prop : properties) {
List<?> values = prop.getValues();
for (int j = 0; j < values.size(); j++) {
int localI = j << prop.getBitOffset() >> BlockTypesCache.BIT_OFFSET;
if (states == ALL || FastBitSet.get(states, localI)) {
if (!allowed.test(type, new AbstractMap.SimpleEntry(prop, values.get(j)))) {
if (states == ALL) {
bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1);
FastBitSet.setAll(states);
}
FastBitSet.clear(states, localI);
reset(false);
}
}
}
}
}
return this;
}
public BlockMaskBuilder add(BlockType type) {
bitSets[type.getInternalId()] = ALL;
return this;
@ -478,117 +465,6 @@ public class BlockMaskBuilder {
return this;
}
@SuppressWarnings({"unchecked", "rawtypes"})
public BlockMaskBuilder addAll(
Predicate<BlockType> typePredicate,
BiPredicate<BlockType, Map.Entry<Property<?>, ?>> propPredicate
) {
for (int i = 0; i < bitSets.length; i++) {
long[] states = bitSets[i];
if (states == ALL) {
continue;
}
BlockType type = BlockTypes.get(i);
if (!typePredicate.test(type)) {
continue;
}
for (AbstractProperty<?> prop : (List<AbstractProperty<?>>) type.getProperties()) {
List<?> values = prop.getValues();
for (int j = 0; j < values.size(); j++) {
int localI = j << prop.getBitOffset() >> BlockTypesCache.BIT_OFFSET;
if (states == null || !FastBitSet.get(states, localI)) {
if (propPredicate.test(type, new AbstractMap.SimpleEntry(prop, values.get(j)))) {
if (states == null) {
bitSets[i] = states = FastBitSet.create(type.getMaxStateId() + 1);
}
FastBitSet.set(states, localI);
reset(false);
}
}
}
}
}
return this;
}
public <T> BlockMaskBuilder add(BlockType type, Property<T> property, int index) {
AbstractProperty<T> prop = (AbstractProperty<T>) property;
long[] states = bitSets[type.getInternalId()];
if (states == ALL) {
return this;
}
List<T> values = property.getValues();
int localI = index << prop.getBitOffset() >> BlockTypesCache.BIT_OFFSET;
if (states == null || !FastBitSet.get(states, localI)) {
if (states == null) {
bitSets[type.getInternalId()] = states = FastBitSet.create(type.getMaxStateId() + 1);
}
set(type, states, property, index);
reset(false);
}
return this;
}
public <T> BlockMaskBuilder filter(BlockType type, Property<T> property, int index) {
AbstractProperty<T> prop = (AbstractProperty<T>) property;
long[] states = bitSets[type.getInternalId()];
if (states == null) {
return this;
}
List<T> values = property.getValues();
int localI = index << prop.getBitOffset() >> BlockTypesCache.BIT_OFFSET;
if (states == ALL || FastBitSet.get(states, localI)) {
if (states == ALL) {
bitSets[type.getInternalId()] = states = FastBitSet.create(type.getMaxStateId() + 1);
FastBitSet.setAll(states);
}
clear(type, states, property, index);
reset(false);
}
return this;
}
private void applyRecursive(List<Property> properties, int propertiesIndex, int state, long[] states, boolean set) {
AbstractProperty current = (AbstractProperty) properties.get(propertiesIndex);
List values = current.getValues();
if (propertiesIndex + 1 < properties.size()) {
for (int i = 0; i < values.size(); i++) {
int newState = current.modifyIndex(state, i);
applyRecursive(properties, propertiesIndex + 1, newState, states, set);
}
} else {
for (int i = 0; i < values.size(); i++) {
int index = current.modifyIndex(state, i) >> BlockTypesCache.BIT_OFFSET;
if (set) {
FastBitSet.set(states, index);
} else {
FastBitSet.clear(states, index);
}
}
}
}
private void set(BlockType type, long[] bitSet, Property property, int index) {
FastBitSet.set(bitSet, index);
if (type.getProperties().size() > 1) {
ArrayList<Property> properties = new ArrayList<>(type.getProperties());
properties.remove(property);
int state = ((AbstractProperty) property).modifyIndex(type.getInternalId(), index);
applyRecursive(properties, 0, state, bitSet, true);
}
}
private void clear(BlockType type, long[] bitSet, Property property, int index) {
FastBitSet.clear(bitSet, index);
if (type.getProperties().size() > 1) {
ArrayList<Property> properties = new ArrayList<>(type.getProperties());
properties.remove(property);
int state = ((AbstractProperty) property).modifyIndex(type.getInternalId(), index);
applyRecursive(properties, 0, state, bitSet, false);
}
}
public BlockMaskBuilder optimize() {
if (!optimizedStates) {
for (int i = 0; i < bitSets.length; i++) {
@ -667,4 +543,56 @@ public class BlockMaskBuilder {
}
private static class FuzzyStateAllowingBuilder {
private final BlockType type;
private final Map<Property<?>, List<Integer>> masked = new HashMap<>();
private FuzzyStateAllowingBuilder(BlockType type) {
this.type = type;
}
private BlockType getType() {
return this.type;
}
private List<Property<?>> getMaskedProperties() {
return masked
.entrySet()
.stream()
.filter(e -> !e.getValue().isEmpty())
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
private void allow(Property<?> property, int index) {
checkNotNull(property);
if (!type.hasProperty(property.getKey())) {
throw new IllegalArgumentException(String.format(
"Property %s cannot be applied to block type %s",
property.getName(),
type.getId()
));
}
masked.computeIfAbsent(property, k -> new ArrayList<>()).add(index);
}
private boolean allows() {
//noinspection SimplifyStreamApiCallChains - Marginally faster like this
return !masked.isEmpty() && !masked.values().stream().anyMatch(List::isEmpty);
}
private boolean allows(Property<?> property) {
return !masked.containsKey(property);
}
private boolean allows(Property<?> property, int index) {
if (!masked.containsKey(property)) {
return true;
}
return masked.get(property).contains(index);
}
}
}

View File

@ -50,7 +50,7 @@ public class SimpleChangeSetSummary implements ChangeSetSummary {
public Map<BlockState, Integer> getBlocks() {
HashMap<BlockState, Integer> map = new HashMap<>();
for (int i = 0; i < blocks.length; i++) {
if (blocks[i] != 0) {
if (blocks[i] != BlockTypesCache.ReservedIDs.__RESERVED__) {
BlockState state = BlockTypesCache.states[i];
map.put(state, blocks[i]);
}

View File

@ -69,6 +69,10 @@ public class FastBitSet {
Arrays.fill(bits, -1L);
}
public static void unsetAll(long[] bits) {
Arrays.fill(bits, 0);
}
public static void and(long[] bits, final long[] other) {
final int end = Math.min(other.length, bits.length);
for (int i = 0; i < end; ++i) {

View File

@ -193,6 +193,7 @@ public class ParallelQueueExtent extends PassthroughExtent {
public int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
if (vset instanceof Region) {
this.changes = setBlocks((Region) vset, pattern);
return this.changes;
}
// TODO optimize parallel
for (BlockVector3 blockVector3 : vset) {

View File

@ -122,7 +122,7 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
@Override
public CompoundTag getTile(int x, int y, int z) {
return tiles.get(x, y, z);
return tiles == null ? null : tiles.get(x, y, z);
}
@Override

View File

@ -45,8 +45,8 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
private final ReentrantWrappedStampedLock calledLock = new ReentrantWrappedStampedLock();
private IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes)
private IChunkSet chunkSet; // The blocks to be set to the chunkExisting
private volatile IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes)
private volatile IChunkSet chunkSet; // The blocks to be set to the chunkExisting
private IBlockDelegate delegate; // delegate handles the abstraction of the chunk layers
private IQueueExtent<? extends IChunk> extent; // the parent queue extent which has this chunk
private int chunkX;
@ -1042,13 +1042,12 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
calledLock.lock();
final long stamp = calledLock.getStampChecked();
if (chunkSet != null && !chunkSet.isEmpty()) {
this.delegate = GET;
chunkSet.setBitMask(bitMask);
try {
return this.call(chunkSet.createCopy(), () -> {
this.delegate = NULL;
chunkSet = null;
calledLock.unlock(stamp);
});
IChunkSet copy = chunkSet.createCopy();
chunkSet = null;
return this.call(copy, () -> calledLock.unlock(stamp));
} catch (Throwable t) {
calledLock.unlock();
throw t;

View File

@ -17,10 +17,30 @@ public class FaweMask implements IDelegateRegion {
return region;
}
/**
* Test if the mask is still valid
*
* @param player player to test
* @param type type of mask
* @return if still valid
*/
public boolean isValid(Player player, FaweMaskManager.MaskType type) {
return false;
}
/**
* Test if the mask is still valid
*
* @param player player to test
* @param type type of mask
* @param notify if the player should be notified
* @return if still valid
* @since TODO
*/
public boolean isValid(Player player, FaweMaskManager.MaskType type, boolean notify) {
return isValid(player, type);
}
@Override
public Region clone() {
throw new UnsupportedOperationException("Clone not supported");

View File

@ -1,7 +1,6 @@
package com.fastasyncworldedit.core.regions;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.regions.filter.RegionFilter;
import com.sk89q.worldedit.entity.Player;
import java.util.Locale;
@ -28,6 +27,15 @@ public abstract class FaweMaskManager {
*/
public abstract FaweMask getMask(final Player player, MaskType type, boolean isWhitelist);
/**
* Get a {@link FaweMask} for the given player and {@link MaskType}. If isWhitelist is false, will return a "blacklist" mask.
*
* @since TODO
*/
public FaweMask getMask(final Player player, MaskType type, boolean isWhitelist, boolean notify) {
return getMask(player, type, isWhitelist);
}
public boolean isExclusive() {
return Settings.settings().REGION_RESTRICTIONS_OPTIONS.EXCLUSIVE_MANAGERS.contains(this.key);
}

View File

@ -108,27 +108,22 @@ public class WEManager {
}
player.setMeta("lastMaskWorld", world);
Set<FaweMask> masks = player.getMeta("lastMask");
Set<Region> backupRegions = new HashSet<>();
Set<Region> regions = new HashSet<>();
if (masks == null || !isWhitelist) {
masks = new HashSet<>();
} else {
synchronized (masks) {
boolean removed = false;
boolean inMask = false;
if (!masks.isEmpty()) {
Iterator<FaweMask> iterator = masks.iterator();
while (iterator.hasNext()) {
FaweMask mask = iterator.next();
if (mask.isValid(player, type)) {
if (mask.isValid(player, type, false)) {
Region region = mask.getRegion();
if (region.contains(loc.toBlockPoint())) {
regions.add(region);
} else {
removed = true;
backupRegions.add(region);
}
inMask |= region.contains(loc.toBlockPoint());
regions.add(region);
} else {
if (Settings.settings().ENABLED_COMPONENTS.DEBUG) {
player.printDebug(Caption.of("fawe.error.region-mask-invalid", mask.getClass().getSimpleName()));
@ -138,39 +133,44 @@ public class WEManager {
}
}
}
if (!removed) {
if (!removed && inMask) {
return regions.toArray(new Region[0]);
}
masks.clear();
}
}
for (FaweMaskManager manager : managers) {
if (player.hasPermission("fawe." + manager.getKey())) {
try {
if (manager.isExclusive() && !masks.isEmpty()) {
continue;
}
final FaweMask mask = manager.getMask(player, FaweMaskManager.MaskType.getDefaultMaskType(), isWhitelist);
if (mask != null) {
regions.add(mask.getRegion());
masks.add(mask);
if (manager.isExclusive()) {
break;
synchronized (masks) {
for (FaweMaskManager manager : managers) {
if (player.hasPermission("fawe." + manager.getKey())) {
try {
if (manager.isExclusive() && !masks.isEmpty()) {
continue;
}
final FaweMask mask = manager.getMask(
player,
FaweMaskManager.MaskType.getDefaultMaskType(),
isWhitelist,
masks.isEmpty()
);
if (mask != null) {
regions.add(mask.getRegion());
masks.add(mask);
if (manager.isExclusive()) {
break;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
} catch (Throwable e) {
e.printStackTrace();
} else {
player.printError(TextComponent.of("Missing permission " + "fawe." + manager.getKey()));
}
} else {
player.printError(TextComponent.of("Missing permission " + "fawe." + manager.getKey()));
}
}
if (isWhitelist) {
regions.addAll(backupRegions);
if (!masks.isEmpty()) {
player.setMeta("lastMask", masks);
} else {
player.deleteMeta("lastMask");
if (isWhitelist) {
if (!masks.isEmpty()) {
player.setMeta("lastMask", masks);
} else {
player.deleteMeta("lastMask");
}
}
}
return regions.toArray(new Region[0]);

View File

@ -2161,10 +2161,12 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final int ceilRadiusX = (int) Math.ceil(radiusX);
final int ceilRadiusZ = (int) Math.ceil(radiusZ);
double xSqr;
double zSqr;
double distanceSq;
double xSqr, zSqr, distanceSq;
double xn, zn;
double dx2, dz2;
double nextXn = 0;
double nextZn, nextMinZn;
int xx, x_x, zz, z_z, yy;
if (thickness != 0) {
double nextMinXn = 0;
@ -2172,19 +2174,18 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final double minInvRadiusZ = 1 / (radiusZ - thickness);
forX:
for (int x = 0; x <= ceilRadiusX; ++x) {
final double xn = nextXn;
double dx2 = nextMinXn * nextMinXn;
xn = nextXn;
dx2 = nextMinXn * nextMinXn;
nextXn = (x + 1) * invRadiusX;
nextMinXn = (x + 1) * minInvRadiusX;
double nextZn = 0;
double nextMinZn = 0;
nextZn = 0;
nextMinZn = 0;
xSqr = xn * xn;
xx = px + x;
x_x = px - x;
forZ:
for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
double dz2 = nextMinZn * nextMinZn;
nextZn = (z + 1) * invRadiusZ;
nextMinZn = (z + 1) * minInvRadiusZ;
zn = nextZn;
zSqr = zn * zn;
distanceSq = xSqr + zSqr;
if (distanceSq > 1) {
@ -2193,16 +2194,23 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
}
break forZ;
}
dz2 = nextMinZn * nextMinZn;
nextZn = (z + 1) * invRadiusZ;
nextMinZn = (z + 1) * minInvRadiusZ;
if ((dz2 + nextMinXn * nextMinXn <= 1) && (nextMinZn * nextMinZn + dx2 <= 1)) {
continue;
}
zz = pz + z;
z_z = pz - z;
for (int y = 0; y < height; ++y) {
this.setBlock(mutableBlockVector3.setComponents(px + x, py + y, pz + z), block);
this.setBlock(mutableBlockVector3.setComponents(px - x, py + y, pz + z), block);
this.setBlock(mutableBlockVector3.setComponents(px + x, py + y, pz - z), block);
this.setBlock(mutableBlockVector3.setComponents(px - x, py + y, pz - z), block);
yy = py + y;
this.setBlock(xx, yy, zz, block);
this.setBlock(x_x, yy, zz, block);
this.setBlock(xx, yy, z_z, block);
this.setBlock(x_x, yy, z_z, block);
}
}
}
@ -2210,14 +2218,17 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
//FAWE end
forX:
for (int x = 0; x <= ceilRadiusX; ++x) {
final double xn = nextXn;
xn = nextXn;
nextXn = (x + 1) * invRadiusX;
double nextZn = 0;
nextZn = 0;
xSqr = xn * xn;
// FAWE start
xx = px + x;
x_x = px - x;
//FAWE end
forZ:
for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
nextZn = (z + 1) * invRadiusZ;
zn = nextZn;
zSqr = zn * zn;
distanceSq = xSqr + zSqr;
if (distanceSq > 1) {
@ -2227,18 +2238,27 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
break forZ;
}
// FAWE start
nextZn = (z + 1) * invRadiusZ;
//FAWE end
if (!filled) {
if ((zSqr + nextXn * nextXn <= 1) && (nextZn * nextZn + xSqr <= 1)) {
continue;
}
}
//FAWE start
zz = pz + z;
z_z = pz - z;
//FAWE end
for (int y = 0; y < height; ++y) {
//FAWE start - mutable
this.setBlock(mutableBlockVector3.setComponents(px + x, py + y, pz + z), block);
this.setBlock(mutableBlockVector3.setComponents(px - x, py + y, pz + z), block);
this.setBlock(mutableBlockVector3.setComponents(px + x, py + y, pz - z), block);
this.setBlock(mutableBlockVector3.setComponents(px - x, py + y, pz - z), block);
//FAWE start
yy = py + y;
this.setBlock(xx, yy, zz, block);
this.setBlock(x_x, yy, zz, block);
this.setBlock(xx, yy, z_z, block);
this.setBlock(x_x, yy, z_z, block);
//FAWE end
}
}
@ -2293,7 +2313,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
int px = pos.getBlockX();
int py = pos.getBlockY();
int pz = pos.getBlockZ();
MutableBlockVector3 mutable = new MutableBlockVector3();
final int ceilRadiusX = (int) Math.ceil(radiusX);
final int ceilRadiusY = (int) Math.ceil(radiusY);
@ -2301,31 +2320,43 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
double threshold = 0.5;
double dx, dy, dz, dxy, dxz, dyz, dxyz;
int xx, x_x, yy, y_y, zz, z_z;
double xnx, yny, znz;
double nextXn = 0;
double dx;
double dy;
double dz;
double dxy;
double dxyz;
double nextYn, nextZn;
double nextXnSq, nextYnSq, nextZnSq;
double xn, yn, zn;
forX:
for (int x = 0; x <= ceilRadiusX; ++x) {
final double xn = nextXn;
xn = nextXn;
dx = xn * xn;
nextXn = (x + 1) * invRadiusX;
double nextYn = 0;
nextXnSq = nextXn * nextXn;
nextYn = 0;
xx = px + x;
x_x = px - x;
xnx = x * nx;
forY:
for (int y = 0; y <= ceilRadiusY; ++y) {
final double yn = nextYn;
yn = nextYn;
dy = yn * yn;
dxy = dx + dy;
nextYn = (y + 1) * invRadiusY;
double nextZn = 0;
nextYnSq = nextYn * nextYn;
nextZn = 0;
yy = py + y;
y_y = py - y;
yny = y * ny;
forZ:
for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
zn = nextZn;
dz = zn * zn;
dxyz = dxy + dz;
dxz = dx + dz;
dyz = dy + dz;
nextZn = (z + 1) * invRadiusZ;
nextZnSq = nextZn * nextZn;
if (dxyz > 1) {
if (z == 0) {
if (y == 0) {
@ -2336,34 +2367,37 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
break forZ;
}
if (!filled) {
if (nextXn * nextXn + dy + dz <= 1 && nextYn * nextYn + dx + dz <= 1 && nextZn * nextZn + dx + dy <= 1) {
if (nextXnSq + dyz <= 1 && nextYnSq + dxz <= 1 && nextZnSq + dxy <= 1) {
continue;
}
}
zz = pz + z;
z_z = pz - z;
znz = z * nz;
if (Math.abs((x) * nx + (y) * ny + (z) * nz) < threshold) {
setBlock(mutable.setComponents(px + x, py + y, pz + z), block);
if (Math.abs(xnx + yny + znz) < threshold) {
setBlock(xx, yy, zz, block);
}
if (Math.abs((-x) * nx + (y) * ny + (z) * nz) < threshold) {
setBlock(mutable.setComponents(px - x, py + y, pz + z), block);
if (Math.abs(-xnx + yny + znz) < threshold) {
setBlock(x_x, yy, zz, block);
}
if (Math.abs((x) * nx + (-y) * ny + (z) * nz) < threshold) {
setBlock(mutable.setComponents(px + x, py - y, pz + z), block);
if (Math.abs(xnx - yny + znz) < threshold) {
setBlock(xx, y_y, zz, block);
}
if (Math.abs((x) * nx + (y) * ny + (-z) * nz) < threshold) {
setBlock(mutable.setComponents(px + x, py + y, pz - z), block);
if (Math.abs(xnx + yny - znz) < threshold) {
setBlock(xx, yy, z_z, block);
}
if (Math.abs((-x) * nx + (-y) * ny + (z) * nz) < threshold) {
setBlock(mutable.setComponents(px - x, py - y, pz + z), block);
if (Math.abs(-xnx - yny + znz) < threshold) {
setBlock(x_x, y_y, zz, block);
}
if (Math.abs((x) * nx + (-y) * ny + (-z) * nz) < threshold) {
setBlock(mutable.setComponents(px + x, py - y, pz - z), block);
if (Math.abs(xnx - yny - znz) < threshold) {
setBlock(xx, y_y, z_z, block);
}
if (Math.abs((-x) * nx + (y) * ny + (-z) * nz) < threshold) {
setBlock(mutable.setComponents(px - x, py + y, pz - z), block);
if (Math.abs(-xnx + yny - znz) < threshold) {
setBlock(x_x, yy, z_z, block);
}
if (Math.abs((-x) * nx + (-y) * ny + (-z) * nz) < threshold) {
setBlock(mutable.setComponents(px - x, py - y, pz - z), block);
if (Math.abs(-xnx - yny - znz) < threshold) {
setBlock(x_x, y_y, z_z, block);
}
}
}
@ -2418,29 +2452,38 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final int ceilRadiusZ = (int) Math.ceil(radiusZ);
//FAWE start
int yy;
//FAWE end
double nextXn = 0;
double nextYn, nextZn;
double nextXnSq, nextYnSq, nextZnSq;
double xn, yn, zn, dx, dy, dz;
double dxy, dxz, dyz, dxyz;
int xx, x_x, yy, zz, z_z;
forX:
for (int x = 0; x <= ceilRadiusX; ++x) {
final double xn = nextXn;
double dx = xn * xn;
xn = nextXn;
dx = xn * xn;
nextXn = (x + 1) * invRadiusX;
double nextZn = 0;
nextXnSq = nextXn * nextXn;
xx = px + x;
x_x = px - x;
nextZn = 0;
forZ:
for (int z = 0; z <= ceilRadiusZ; ++z) {
final double zn = nextZn;
double dz = zn * zn;
double dxz = dx + dz;
zn = nextZn;
dz = zn * zn;
dxz = dx + dz;
nextZn = (z + 1) * invRadiusZ;
double nextYn = 0;
nextZnSq = nextZn * nextZn;
zz = pz + z;
z_z = pz - z;
nextYn = 0;
forY:
for (int y = 0; y <= ceilRadiusY; ++y) {
final double yn = nextYn;
double dy = yn * yn;
double dxyz = dxz + dy;
yn = nextYn;
dy = yn * yn;
dxyz = dxz + dy;
nextYn = (y + 1) * invRadiusY;
if (dxyz > 1) {
@ -2453,40 +2496,45 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
break forY;
}
nextYnSq = nextYn * nextYn;
dxy = dx + dy;
dyz = dy + dz;
if (!filled) {
if (nextXn * nextXn + dy + dz <= 1 && nextYn * nextYn + dx + dz <= 1 && nextZn * nextZn + dx + dy <= 1) {
if (nextXnSq + dyz <= 1 && nextYnSq + dxz <= 1 && nextZnSq + dxy <= 1) {
continue;
}
}
//FAWE start
yy = py + y;
if (yy <= maxY) {
this.setBlock(px + x, py + y, pz + z, block);
this.setBlock(xx, yy, zz, block);
if (x != 0) {
this.setBlock(px - x, py + y, pz + z, block);
this.setBlock(x_x, yy, zz, block);
}
if (z != 0) {
this.setBlock(px + x, py + y, pz - z, block);
this.setBlock(xx, yy, z_z, block);
if (x != 0) {
this.setBlock(px - x, py + y, pz - z, block);
this.setBlock(x_x, yy, z_z, block);
}
}
}
if (y != 0 && (yy = py - y) >= minY) {
this.setBlock(px + x, yy, pz + z, block);
this.setBlock(xx, yy, zz, block);
if (x != 0) {
this.setBlock(px - x, yy, pz + z, block);
this.setBlock(x_x, yy, zz, block);
}
if (z != 0) {
this.setBlock(px + x, yy, pz - z, block);
this.setBlock(xx, yy, z_z, block);
if (x != 0) {
this.setBlock(px - x, yy, pz - z, block);
this.setBlock(x_x, yy, z_z, block);
}
}
}
}
}
}
//FAWE end
return changes;
//FAWE end
@ -2509,17 +2557,22 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
int bz = position.getZ();
int height = size;
int yy, xx, x_x, zz, z_z;
for (int y = 0; y <= height; ++y) {
size--;
yy = y + by;
for (int x = 0; x <= size; ++x) {
xx = bx + x;
x_x = bx - x;
for (int z = 0; z <= size; ++z) {
zz = bz + z;
z_z = bz - z;
if ((filled && z <= size && x <= size) || z == size || x == size) {
setBlock(x + bx, y + by, z + bz, block);
setBlock(-x + bx, y + by, z + bz, block);
setBlock(x + bx, y + by, -z + bz, block);
setBlock(-x + bx, y + by, -z + bz, block);
setBlock(xx, yy, zz, block);
setBlock(x_x, yy, zz, block);
setBlock(xx, yy, z_z, block);
setBlock(x_x, yy, z_z, block);
}
}
}
@ -3774,19 +3827,28 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
int radiusSqr = (int) (size * size);
int sizeInt = (int) size * 2;
int xx, yy, zz;
double distance;
double noise;
if (sphericity == 1) {
double nx, ny, nz;
double d1, d2;
for (int x = -sizeInt; x <= sizeInt; x++) {
double nx = seedX + x * distort;
double d1 = x * x * modX;
nx = seedX + x * distort;
d1 = x * x * modX;
xx = px + x;
for (int y = -sizeInt; y <= sizeInt; y++) {
double d2 = d1 + y * y * modY;
double ny = seedY + y * distort;
d2 = d1 + y * y * modY;
ny = seedY + y * distort;
yy = py + y;
for (int z = -sizeInt; z <= sizeInt; z++) {
double nz = seedZ + z * distort;
double distance = d2 + z * z * modZ;
double noise = amplitude * SimplexNoise.noise(nx, ny, nz);
nz = seedZ + z * distort;
distance = d2 + z * z * modZ;
zz = pz + z;
noise = amplitude * SimplexNoise.noise(nx, ny, nz);
if (distance + distance * noise < radiusSqr) {
setBlock(px + x, py + y, pz + z, pattern);
setBlock(xx, yy, zz, pattern);
}
}
}
@ -3803,39 +3865,48 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
MutableVector3 mutable = new MutableVector3();
double roughness = 1 - sphericity;
int x;
int y;
int z;
double xScaled;
double yScaled;
double zScaled;
double manDist;
double distSqr;
for (int xr = -sizeInt; xr <= sizeInt; xr++) {
xx = px + xr;
for (int yr = -sizeInt; yr <= sizeInt; yr++) {
yy = py + yr;
for (int zr = -sizeInt; zr <= sizeInt; zr++) {
zz = pz + zr;
// pt == mutable as it's a MutableVector3
// so it must be set each time
mutable.mutX(xr);
mutable.mutY(yr);
mutable.mutZ(zr);
mutable.setComponents(xr, yr, zr);
Vector3 pt = transform.apply(mutable);
int x = MathMan.roundInt(pt.getX());
int y = MathMan.roundInt(pt.getY());
int z = MathMan.roundInt(pt.getZ());
x = MathMan.roundInt(pt.getX());
y = MathMan.roundInt(pt.getY());
z = MathMan.roundInt(pt.getZ());
double xScaled = Math.abs(x) * modX;
double yScaled = Math.abs(y) * modY;
double zScaled = Math.abs(z) * modZ;
double manDist = xScaled + yScaled + zScaled;
double distSqr = x * x * modX + z * z * modZ + y * y * modY;
xScaled = Math.abs(x) * modX;
yScaled = Math.abs(y) * modY;
zScaled = Math.abs(z) * modZ;
manDist = xScaled + yScaled + zScaled;
distSqr = x * x * modX + z * z * modZ + y * y * modY;
double distance = Math.sqrt(distSqr) * sphericity + MathMan.max(
distance = Math.sqrt(distSqr) * sphericity + MathMan.max(
manDist,
xScaled * manScaleX,
yScaled * manScaleY,
zScaled * manScaleZ
) * roughness;
double noise = amplitude * SimplexNoise.noise(
noise = amplitude * SimplexNoise.noise(
seedX + x * distort,
seedZ + z * distort,
seedZ + z * distort
);
if (distance + distance * noise < r) {
setBlock(px + xr, py + yr, pz + zr, pattern);
setBlock(xx, yy, zz, pattern);
}
}
}

View File

@ -32,6 +32,7 @@ import com.fastasyncworldedit.core.extent.NullExtent;
import com.fastasyncworldedit.core.extent.SingleRegionExtent;
import com.fastasyncworldedit.core.extent.SlowExtent;
import com.fastasyncworldedit.core.extent.StripNBTExtent;
import com.fastasyncworldedit.core.extent.processor.EntityInBlockRemovingProcessor;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightmapProcessor;
import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
@ -72,7 +73,6 @@ import org.apache.logging.log4j.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
@ -99,7 +99,6 @@ public final class EditSessionBuilder {
private RelightMode relightMode;
private Relighter relighter;
private Boolean wnaMode;
private AbstractChangeSet changeTask;
private Extent bypassHistory;
private Extent bypassAll;
private Extent extent;
@ -522,7 +521,6 @@ public final class EditSessionBuilder {
changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1);
}
if (combineStages) {
changeTask = changeSet;
this.extent = extent.enableHistory(changeSet);
} else {
this.extent = new HistoryExtent(extent, changeSet);
@ -546,25 +544,6 @@ public final class EditSessionBuilder {
}
}
}
FaweRegionExtent regionExtent = null;
if (disallowedRegions != null) { // Always use MultiRegionExtent if we have blacklist regions
regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions, disallowedRegions);
} else if (allowedRegions == null) {
allowedRegions = new Region[]{RegionWrapper.GLOBAL()};
} else {
if (allowedRegions.length == 0) {
regionExtent = new NullExtent(this.extent, FaweCache.NO_REGION);
} else {
if (allowedRegions.length == 1) {
regionExtent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]);
} else {
regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions, null);
}
}
}
if (placeChunks && regionExtent != null) {
queue.addProcessor(regionExtent);
}
// 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 (((relightMode != null && relightMode != RelightMode.NONE) || (relightMode == null && Settings.settings().LIGHTING.MODE > 0))) {
@ -574,6 +553,11 @@ public final class EditSessionBuilder {
queue.addProcessor(new RelightProcessor(relighter));
}
queue.addProcessor(new HeightmapProcessor(world.getMinY(), world.getMaxY()));
if (!Settings.settings().EXPERIMENTAL.KEEP_ENTITIES_IN_BLOCKS) {
queue.addProcessor(new EntityInBlockRemovingProcessor());
}
IBatchProcessor platformProcessor = WorldEdit
.getInstance()
.getPlatformManager()
@ -593,24 +577,13 @@ public final class EditSessionBuilder {
} else {
relighter = NullRelighter.INSTANCE;
}
Consumer<Component> onErrorMessage;
if (getActor() != null) {
onErrorMessage = c -> getActor().print(Caption.of("fawe.error.occurred-continuing", c));
} else {
onErrorMessage = c -> {
};
}
if (limit != null && !limit.isUnlimited() && regionExtent != null) {
this.extent = new LimitExtent(regionExtent, limit, onErrorMessage);
} else if (limit != null && !limit.isUnlimited()) {
this.extent = new LimitExtent(this.extent, limit, onErrorMessage);
} else if (regionExtent != null) {
this.extent = regionExtent;
}
if (this.limit != null && this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) {
this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT);
StripNBTExtent ext = new StripNBTExtent(this.extent, this.limit.STRIP_NBT);
if (placeChunks) {
queue.addProcessor((IBatchProcessor) this.extent);
queue.addProcessor(ext);
}
if (!placeChunks || !combineStages) {
this.extent = ext;
}
}
if (this.limit != null && !this.limit.isUnlimited()) {
@ -623,12 +596,50 @@ public final class EditSessionBuilder {
}
Set<PropertyRemap<?>> remaps = this.limit.REMAP_PROPERTIES;
if (!limitBlocks.isEmpty() || (remaps != null && !remaps.isEmpty())) {
this.extent = new DisallowedBlocksExtent(this.extent, limitBlocks, remaps);
DisallowedBlocksExtent ext = new DisallowedBlocksExtent(this.extent, limitBlocks, remaps);
if (placeChunks) {
queue.addProcessor((IBatchProcessor) this.extent);
queue.addProcessor(ext);
}
if (!placeChunks || !combineStages) {
this.extent = ext;
}
}
}
FaweRegionExtent regionExtent = null;
if (disallowedRegions != null) { // Always use MultiRegionExtent if we have blacklist regions
regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions, disallowedRegions);
} else if (allowedRegions == null) {
allowedRegions = new Region[]{RegionWrapper.GLOBAL()};
} else {
if (allowedRegions.length == 0) {
regionExtent = new NullExtent(this.extent, FaweCache.NO_REGION);
} else {
if (allowedRegions.length == 1) {
regionExtent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]);
} else {
regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions, null);
}
}
}
if (regionExtent != null) {
if (placeChunks) {
queue.addProcessor(regionExtent);
}
if (!placeChunks || !combineStages) {
this.extent = regionExtent;
}
}
Consumer<Component> onErrorMessage;
if (getActor() != null) {
onErrorMessage = c -> getActor().print(Caption.of("fawe.error.occurred-continuing", c));
} else {
onErrorMessage = c -> {
};
}
if (limit != null && !limit.isUnlimited()) {
this.extent = new LimitExtent(this.extent, limit, onErrorMessage);
}
this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY);
}
return this;
@ -699,7 +710,7 @@ public final class EditSessionBuilder {
* Get the change set that will be used for history
*/
public AbstractChangeSet getChangeTask() {
return changeTask;
return changeSet;
}
/**

View File

@ -160,17 +160,7 @@ public class ExtentEntityCopy implements EntityFunction {
// Remove
if (isRemoving() && success) {
//FAWE start
UUID uuid = null;
if (tag.containsKey("UUID")) {
int[] arr = tag.getIntArray("UUID");
uuid = new UUID((long) arr[0] << 32 | (arr[1] & 0xFFFFFFFFL), (long) arr[2] << 32 | (arr[3] & 0xFFFFFFFFL));
} else if (tag.containsKey("UUIDMost")) {
uuid = new UUID(tag.getLong("UUIDMost"), tag.getLong("UUIDLeast"));
} else if (tag.containsKey("WorldUUIDMost")) {
uuid = new UUID(tag.getLong("WorldUUIDMost"), tag.getLong("WorldUUIDLeast"));
} else if (tag.containsKey("PersistentIDMSB")) {
uuid = new UUID(tag.getLong("PersistentIDMSB"), tag.getLong("PersistentIDLSB"));
}
UUID uuid = entity.getState().getNbtData().getUUID();
if (uuid != null) {
if (source != null) {
source.removeEntity(

View File

@ -229,6 +229,7 @@ public abstract class BreadthFirstSearch implements Operation {
*/
public void visit(BlockVector3 position) {
if (!visited.contains(position)) {
isVisitable(position, position); // Ignore this, just to initialize mask on this point
queue.add(position);
visited.add(position);
}

View File

@ -165,6 +165,9 @@ public final class TreeGenerator {
}
//FAWE end
},
MANGROVE("Mangrove tree", "mangrove"),
TALL_MANGROVE("Tall mangrove tree", "tall_mangrove"),
CHERRY("Cherry blossom", "cherry"),
RANDOM("Random tree", "rand", "random") {
@Override
public boolean generate(EditSession editSession, BlockVector3 pos) throws MaxChangedBlocksException {

View File

@ -78,13 +78,35 @@ public class BlockType implements Keyed, Pattern {
this.id = i == -1 ? id : id.substring(0, i);
this.settings = new BlockTypesCache.Settings(this, id, internalId, states);
}
//FAWE end
//FAWE start
/**
* @deprecated You should not be initialising your own BlockTypes, use {@link BlockTypes#get(String)} instead. If there is
* a specific requirement to actually create new block types, please contact the FAWE devs to discuss. Use
* {@link BlockTypes#get(String)} instead.
*/
@Deprecated(since = "TODO")
//FAWE end
public BlockType(String id) {
this(id, null);
}
//FAWE start
/**
* @deprecated You should not be initialising your own BlockTypes, use {@link BlockTypes#get(String)} instead. If there is
* a specific requirement to actually create new block types, please contact the FAWE devs to discuss. Use
* {@link BlockTypes#get(String)} instead.
*/
@Deprecated(since = "TODO")
//FAWE end
public BlockType(String id, Function<BlockState, BlockState> values) {
// If it has no namespace, assume minecraft.
if (!id.contains(":")) {
id = "minecraft:" + id;
}
this.id = id;
//FAWE start
//TODO fix the line below
this.settings = new BlockTypesCache.Settings(this, id, 0, null);
}

View File

@ -182,7 +182,7 @@ public class FuzzyBlockState extends BlockState {
checkNotNull(property);
checkNotNull(value);
checkNotNull(type, "The type must be set before the properties!");
type.getProperty(property.getName()); // Verify the property is valid for this type
checkNotNull(type.getProperty(property.getName())); // Verify the property is valid for this type
values.put(property, value);
return this;
}