Conflicts:
	worldedit-bukkit/build.gradle.kts
This commit is contained in:
MattBDev
2021-01-18 15:59:51 -05:00
36 changed files with 412 additions and 262 deletions

View File

@ -9,8 +9,6 @@ import org.jetbrains.annotations.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.locks.ReentrantLock;
public abstract class CharBlocks implements IBlocks {
public static final Logger logger = LoggerFactory.getLogger(CharBlocks.class);

View File

@ -71,6 +71,7 @@ public class NMSRelighter implements Relighter {
private final int maxY;
private final boolean calculateHeightMaps;
private final ReentrantLock lightingLock;
private final AtomicBoolean finished = new AtomicBoolean(false);
private boolean removeFirst;
public NMSRelighter(IQueueExtent<IQueueChunk> queue, boolean calculateHeightMaps) {
@ -95,10 +96,15 @@ public class NMSRelighter implements Relighter {
}
@Override
public synchronized ReentrantLock getLock() {
public ReentrantLock getLock() {
return lightingLock;
}
@Override
public boolean isFinished() {
return finished.get();
}
@Override public synchronized void removeAndRelight(boolean sky) {
removeFirst = true;
fixLightingSafe(sky);
@ -839,10 +845,12 @@ public class NMSRelighter implements Relighter {
}
if (Settings.IMP.LIGHTING.ASYNC) {
queue.flush();
finished.set(true);
} else {
TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override public void run(Object value) {
queue.flush();
finished.set(true);
}
});
}
@ -873,6 +881,7 @@ public class NMSRelighter implements Relighter {
Fawe.imp().getPlatformAdapter().sendChunk(chunk.getOrCreateGet(), bitMask, true);
iter.remove();
}
finished.set(true);
}
};
if (Settings.IMP.LIGHTING.ASYNC) {
@ -1000,7 +1009,7 @@ public class NMSRelighter implements Relighter {
BlockMaterial material = state.getMaterial();
int opacity = material.getLightOpacity();
int brightness = material.getLightValue();
if (brightness != iChunk.getEmmittedLight(x, y, z)) {
if (brightness > 0 && brightness != iChunk.getEmmittedLight(x, y, z)) {
addLightUpdate(bx + x, y, bz + z);
}

View File

@ -53,4 +53,9 @@ public class NullRelighter implements Relighter {
public ReentrantLock getLock() {
return null;
}
@Override
public boolean isFinished() {
return true;
}
}

View File

@ -70,6 +70,13 @@ public interface Relighter {
ReentrantLock getLock();
/**
* Returns true if the Relighter has been flushed
*
* @return true if finished
*/
boolean isFinished();
class SkipReason {
public static final byte NONE = 0;
public static final byte AIR = 1;

View File

@ -16,11 +16,14 @@ import com.boydti.fawe.beta.implementation.processors.EmptyBatchProcessor;
import com.boydti.fawe.beta.implementation.processors.ExtentBatchProcessorHolder;
import com.boydti.fawe.beta.implementation.processors.ProcessorScope;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.MemUtil;
import com.google.common.util.concurrent.Futures;
import com.sk89q.worldedit.extent.Extent;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
@ -35,6 +38,9 @@ import java.util.concurrent.locks.ReentrantLock;
*/
public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implements IQueueExtent<IQueueChunk> {
// Don't bother with the full classpath.
private static final Logger log = LoggerFactory.getLogger("SingleThreadQueueExtent");
// Pool discarded chunks for reuse (can safely be cleared by another thread)
// private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
// Chunks currently being queued / worked on
@ -108,7 +114,9 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
for (IChunk chunk : this.chunks.values()) {
chunk.recycle();
}
getChunkLock.lock();
this.chunks.clear();
getChunkLock.unlock();
}
this.enabledQueue = true;
this.lastChunk = null;
@ -157,7 +165,9 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
lastChunk = null;
}
final long index = MathMan.pairInt(chunk.getX(), chunk.getZ());
getChunkLock.lock();
chunks.remove(index, chunk);
getChunkLock.unlock();
V future = submitUnchecked(chunk);
submissions.add(future);
return future;
@ -291,7 +301,15 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
while (future != null) {
future = (Future) future.get();
}
} catch (InterruptedException | ExecutionException e) {
} catch (FaweException messageOnly) {
log.warn(messageOnly.getMessage());
} catch (ExecutionException e) {
if (e.getCause() instanceof FaweException) {
log.warn(e.getCause().getClass().getCanonicalName() + ": " + e.getCause().getMessage());
} else {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@ -302,7 +320,15 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
while (first != null) {
first = (Future) first.get();
}
} catch (InterruptedException | ExecutionException e) {
} catch (FaweException messageOnly) {
log.warn(messageOnly.getMessage());
} catch (ExecutionException e) {
if (e.getCause() instanceof FaweException) {
log.warn(e.getCause().getClass().getCanonicalName() + ": " + e.getCause().getMessage());
} else {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@ -313,7 +339,15 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
if (next.isDone()) {
try {
next = (Future) next.get();
} catch (InterruptedException | ExecutionException e) {
} catch (FaweException messageOnly) {
log.warn(messageOnly.getMessage());
} catch (ExecutionException e) {
if (e.getCause() instanceof FaweException) {
log.warn(e.getCause().getClass().getCanonicalName() + ": " + e.getCause().getMessage());
} else {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
@ -344,7 +378,9 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
}
}
}
getChunkLock.lock();
chunks.clear();
getChunkLock.unlock();
}
pollSubmissions(0, true);
}

View File

@ -389,7 +389,7 @@ public class Settings extends Config {
})
public boolean ALLOW_TICK_EXISTING = true;
@Comment({
"Do not wait for a chunk's history to save before sending it",
"[SAFE] Do not wait for a chunk's history to save before sending it",
" - Undo/redo commands will wait until the history has been written to disk before executing",
" - Requires combine_stages = true"
})

View File

@ -4,7 +4,6 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.brush.visualization.VisualExtent;
import com.boydti.fawe.object.mask.IdMask;
import com.boydti.fawe.object.visitor.DFSRecursiveVisitor;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.tool.brush.Brush;
@ -14,7 +13,6 @@ import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.MathUtils;
import com.sk89q.worldedit.math.MutableVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.math.interpolation.Node;
@ -197,15 +195,15 @@ public class SplineBrush implements Brush, ResettableTool {
if (det_max == det_x) {
double a = (xz * yz - xy * zz) / det_x;
double b = (xy * yz - xz * yy) / det_x;
dir = BlockVector3.at(1.0, (int) MathUtils.roundHalfUp(a), (int) MathUtils.roundHalfUp(b));
dir = BlockVector3.at(1.0, a, b);
} else if (det_max == det_y) {
double a = (yz * xz - xy * zz) / det_y;
double b = (xy * xz - yz * xx) / det_y;
dir = BlockVector3.at((int) MathUtils.roundHalfUp(a), 1.0, (int) MathUtils.roundHalfUp(b));
dir = BlockVector3.at(a, 1.0, b);
} else {
double a = (yz * xy - xz * yy) / det_z;
double b = (xz * xy - yz * xx) / det_z;
dir = BlockVector3.at((int) MathUtils.roundHalfUp(a), (int) MathUtils.roundHalfUp(b), 1.0);
dir = BlockVector3.at(a, b, 1.0);
}
return dir.normalize();
}

View File

@ -42,7 +42,7 @@ public class PositionTransformExtent extends ResettableExtent {
mutable.mutY(pos.getY() - min.getY());
mutable.mutZ(pos.getZ() - min.getZ());
MutableVector3 tmp = new MutableVector3(transform.apply(mutable.toVector3()));
return min.add(tmp.toBlockPoint());
return min.add(tmp.roundHalfUp().toBlockPoint());
}
@Override

View File

@ -1098,16 +1098,16 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
limit.set(originalLimit);
try {
if (relighter != null && !(relighter instanceof NullRelighter)) {
// Only relight once!
if (!relighter.getLock().tryLock()) {
relighter.getLock().lock();
relighter.getLock().unlock();
} else {
if (Settings.IMP.LIGHTING.REMOVE_FIRST) {
relighter.removeAndRelight(true);
} else {
relighter.fixSkyLighting();
relighter.fixBlockLighting();
// Don't relight twice!
if (!relighter.isFinished() && relighter.getLock().tryLock()) {
try {
if (Settings.IMP.LIGHTING.REMOVE_FIRST) {
relighter.removeAndRelight(true);
} else {
relighter.fixLightingSafe(true);
}
} finally {
relighter.getLock().unlock();
}
}
}
@ -1201,10 +1201,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
// Pick how we're going to visit blocks
RecursiveVisitor visitor = new DirectionalVisitor(mask, replace, origin, direction, (int) (radius * 2 + 1));
// With queue enabled, FAWE may start attempting to place chunks before the operation is finished.
// This is unnacceptable for recursive operations.
disableQueue();
// Start at the origin
visitor.visit(origin);
@ -1263,10 +1259,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1));
}
// With queue enabled, FAWE may start attempting to place chunks before the operation is finished.
// This is unnacceptable for recursive operations.
disableQueue();
// Start at the origin
visitor.visit(origin);
@ -1747,10 +1739,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
}
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1));
// With queue enabled, FAWE may start attempting to place chunks before the operation is finished.
// This is unnacceptable for recursive operations.
disableQueue();
// Around the origin in a 3x3 block
for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) {
if (mask.test(position)) {
@ -1792,10 +1780,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
BlockReplace replace = new BlockReplace(this, fluid.getDefaultState());
NonRisingVisitor visitor = new NonRisingVisitor(mask, replace);
// With queue enabled, FAWE may start attempting to place chunks before the operation is finished.
// This is unnacceptable for recursive operations.
disableQueue();
// Around the origin in a 3x3 block
for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) {
if (liquidMask.test(position)) {

View File

@ -36,6 +36,7 @@ import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.GroundFunction;
import com.sk89q.worldedit.function.generator.FloraGenerator;
import com.sk89q.worldedit.function.mask.AbstractExtentMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.MaskIntersection;
@ -300,6 +301,9 @@ public class RegionCommands {
if (from == null) {
from = new ExistingBlockMask(editSession);
}
if (from instanceof AbstractExtentMask) {
((AbstractExtentMask) from).setExtent(editSession);
}
int affected = editSession.replaceBlocks(region, from, to);
actor.printInfo(TranslatableComponent.of("worldedit.replace.replaced", TextComponent.of(affected)));
return affected;

View File

@ -19,11 +19,17 @@ import org.enginehub.piston.exception.StopExecutionException;
import org.enginehub.piston.inject.InjectAnnotation;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import org.enginehub.piston.inject.MemoizingValueAccess;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
@ -45,6 +51,9 @@ public @interface Confirm {
REGION {
@Override
public boolean passes(Actor actor, InjectedValueAccess context, double value) {
if (checkExisting(context)) {
return true;
}
Region region = context.injectedValue(Key.of(Region.class, Selection.class)).orElseThrow(IncompleteRegionException::new);
BlockVector3 pos1 = region.getMinimumPoint();
BlockVector3 pos2 = region.getMaximumPoint();
@ -62,6 +71,9 @@ public @interface Confirm {
RADIUS {
@Override
public boolean passes(Actor actor, InjectedValueAccess context, double value) {
if (checkExisting(context)) {
return true;
}
int max = WorldEdit.getInstance().getConfiguration().maxRadius;
if (max != -1 && value > max) {
actor.print(Caption.of("fawe.cancel.worldedit.cancel.reason.confirm.radius",
@ -74,6 +86,9 @@ public @interface Confirm {
LIMIT {
@Override
public boolean passes(Actor actor, InjectedValueAccess context, double value) {
if (checkExisting(context)) {
return true;
}
int max = 50; //TODO configurable, get Key.of(Method.class) @Limit
if (max != -1 && value > max) {
actor.print(Caption.of("fawe.cancel.worldedit.cancel.reason.confirm.limit",
@ -86,6 +101,9 @@ public @interface Confirm {
ALWAYS {
@Override
public boolean passes(Actor actor, InjectedValueAccess context, double value) {
if (checkExisting(context)) {
return true;
}
actor.print(TranslatableComponent.of("fawe.cancel.worldedit.cancel.reason.confirm"));
return confirm(actor, context);
}
@ -96,6 +114,13 @@ public @interface Confirm {
}
public <T extends Number> T check(Actor actor, InjectedValueAccess context, T value) {
boolean isSuggestion = context.injectedValue(Key.of(boolean.class)).orElse(false);
if (isSuggestion) {
return value;
}
if (checkExisting(context)) {
return value;
}
if (!passes(actor, context, value.doubleValue())) {
throw new StopExecutionException(TextComponent.empty());
}
@ -130,6 +155,24 @@ public @interface Confirm {
try {
lock.lock();
actor.setMeta("cmdConfirm", wait);
try {
// This is really dumb but also stops the double //confirm requirement...
final MemoizingValueAccess memoizingValueAccess;
if (!(context instanceof MemoizingValueAccess)) {
if (!context.getClass().getSimpleName().contains("AutoValue_CommandParametersImpl")) {
LoggerFactory.getLogger(Confirm.class).warn("InjectedValueAccess " + context.getClass().getName() + " given to Confirm");
return true;
}
memoizingValueAccess = (MemoizingValueAccess) Reflect.injectedValues.get(context);
} else {
memoizingValueAccess = (MemoizingValueAccess) context;
}
Map<Key<?>, Optional<?>> memory = (Map<Key<?>, Optional<?>>) Reflect.memory.get(memoizingValueAccess);
memory.put(Key.of(InterruptableCondition.class), Optional.of(wait));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// Waits till 15 seconds then returns false unless awakened
if (condition.await(15, TimeUnit.SECONDS)) {
return true;
}
@ -141,5 +184,39 @@ public @interface Confirm {
}
return false;
}
boolean checkExisting(InjectedValueAccess context) {
Optional<InterruptableCondition> lock = context.injectedValue(Key.of(InterruptableCondition.class));
// lock if locked will be held by current thread unless something has gone REALLY wrong
// in which case this is the least of our worries...
return lock.isPresent();
}
}
class Reflect {
static final Field memory;
static final Field injectedValues;
static {
Field memoryField;
try {
memoryField = MemoizingValueAccess.class.getDeclaredField("memory");
memoryField.setAccessible(true);
} catch (NoSuchFieldException e) {
e.printStackTrace();
memoryField = null;
}
memory = memoryField;
Field injectedValuesField;
try {
Class<?> c = Class.forName("org.enginehub.piston.impl.AutoValue_CommandParametersImpl");
injectedValuesField = c.getDeclaredField("injectedValues");
injectedValuesField.setAccessible(true);
} catch (NoSuchFieldException | ClassNotFoundException e) {
e.printStackTrace();
injectedValuesField = null;
}
injectedValues = injectedValuesField;
}
}
}

View File

@ -609,7 +609,7 @@ public final class PlatformCommandManager {
if (actor == null) {
context = globalInjectedValues;
} else {
context = initializeInjectedValues(args::toString, actor, null);
context = initializeInjectedValues(args::toString, actor, null, false);
}
return parseCommand(args, context);
}
@ -688,7 +688,7 @@ public final class PlatformCommandManager {
}
}
MemoizingValueAccess context = initializeInjectedValues(event::getArguments, actor, event);
MemoizingValueAccess context = initializeInjectedValues(event::getArguments, actor, event, false);
ThrowableSupplier<Throwable> task = () -> commandManager.execute(context, ImmutableList.copyOf(split));
@ -800,7 +800,7 @@ public final class PlatformCommandManager {
getCommandManager(), actor, "//help");
}
private MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor actor, Event event) {
private MemoizingValueAccess initializeInjectedValues(Arguments arguments, Actor actor, Event event, boolean isSuggestions) {
InjectedValueStore store = MapBackedValueStore.create();
store.injectValue(Key.of(Actor.class), ValueProvider.constant(actor));
if (actor instanceof Player) {
@ -817,6 +817,7 @@ public final class PlatformCommandManager {
localSession.tellVersion(actor);
return Optional.of(localSession);
});
store.injectValue(Key.of(boolean.class), context -> Optional.of(isSuggestions));
store.injectValue(Key.of(InjectedValueStore.class), ValueProvider.constant(store));
store.injectValue(Key.of(Event.class), ValueProvider.constant(event));
return MemoizingValueAccess.wrap(
@ -841,7 +842,7 @@ public final class PlatformCommandManager {
List<String> argStrings = split.stream()
.map(Substring::getSubstring)
.collect(Collectors.toList());
MemoizingValueAccess access = initializeInjectedValues(() -> arguments, event.getActor(), event);
MemoizingValueAccess access = initializeInjectedValues(() -> arguments, event.getActor(), event, true);
ImmutableSet<Suggestion> suggestions;
try {
suggestions = commandManager.getSuggestions(access, argStrings);

View File

@ -7,7 +7,9 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
import org.enginehub.piston.converter.ConversionResult;
import org.enginehub.piston.converter.FailedConversion;
import org.enginehub.piston.converter.SuccessfulConversion;
import org.enginehub.piston.exception.StopExecutionException;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.InjectedValueStore;
import org.enginehub.piston.inject.Key;
@ -97,7 +99,11 @@ public class Bindings {
@Override
public ConversionResult<Object> convert(String s, InjectedValueAccess access) {
return SuccessfulConversion.fromSingle(invoke(s, argsFunc, access, method));
Object o = invoke(s, argsFunc, access, method);
if (o == null) {
return FailedConversion.from(new NullPointerException());
}
return SuccessfulConversion.fromSingle(o);
}
});
}
@ -118,7 +124,10 @@ public class Bindings {
}
return method.invoke(this, args);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
if (!(e.getCause() instanceof StopExecutionException)) {
throw new RuntimeException(e);
}
return null;
}
}
}

View File

@ -120,7 +120,7 @@ public interface InputExtent {
* @param position location
* @return the light level at the location
*/
default int getEmmittedLight(MutableBlockVector3 position) {
default int getEmmittedLight(BlockVector3 position) {
return getEmmittedLight(position.getX(), position.getY(), position.getZ());
}

View File

@ -24,13 +24,21 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.LayerFunction;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.registry.state.BooleanProperty;
import com.sk89q.worldedit.registry.state.EnumProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Locale;
import java.util.Map;
public class SnowSimulator implements LayerFunction {
public static final BooleanProperty snowy = (BooleanProperty) (Property<?>) BlockTypes.GRASS_BLOCK.getProperty("snowy");
private static final EnumProperty slab = (EnumProperty) (Property<?>) BlockTypes.SANDSTONE_SLAB.getProperty("type");
private static final EnumProperty stair = (EnumProperty) (Property<?>) BlockTypes.SANDSTONE_STAIRS.getProperty("half");
private static final EnumProperty trapdoor = (EnumProperty) (Property<?>) BlockTypes.ACACIA_TRAPDOOR.getProperty("half");
private static final BooleanProperty trapdoorOpen = (BooleanProperty) (Property<?>) BlockTypes.ACACIA_TRAPDOOR.getProperty("open");
private final BlockState ice = BlockTypes.ICE.getDefaultState();
private final BlockState snow = BlockTypes.SNOW.getDefaultState();
@ -92,6 +100,7 @@ public class SnowSimulator implements LayerFunction {
return false;
}
// Can't put snow this far up
if (position.getBlockY() == this.extent.getMaximumPoint().getBlockY()) {
return false;
@ -103,6 +112,22 @@ public class SnowSimulator implements LayerFunction {
// Can only replace air (or snow in stack mode)
if (!above.getBlockType().getMaterial().isAir() && (!stack || above.getBlockType() != BlockTypes.SNOW)) {
return false;
} else if (!block.getBlockType().getId().toLowerCase(Locale.ROOT).contains("ice") && this.extent.getEmmittedLight(abovePosition) > 10) {
return false;
} else if (!block.getBlockType().getMaterial().isFullCube()) {
Map<Property<?>, Object> states = block.getStates();
if (states.containsKey(slab) && block.getState(slab).equalsIgnoreCase("bottom")) {
return false;
} else if (states.containsKey(trapdoorOpen) && states.containsKey(trapdoor) && (block.getState(trapdoorOpen)
|| block.getState(trapdoor).equalsIgnoreCase("bottom"))) {
return false;
} else if (states.containsKey(stair) && block.getState(stair).equalsIgnoreCase("bottom")) {
return false;
} else {
return false;
}
} else if (!block.getBlockType().getId().toLowerCase(Locale.ROOT).contains("ice") && block.getBlockType().getMaterial().isTranslucent()) {
return false;
}
if (stack && above.getBlockType() == BlockTypes.SNOW) {

View File

@ -34,9 +34,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
/**
* Tests true if the biome at applied points is the same as the one given.
*/
public class BiomeMask extends AbstractMask {
public class BiomeMask extends AbstractExtentMask {
private final Extent extent;
private final Set<BiomeType> biomes = new HashSet<>();
/**
@ -46,9 +45,8 @@ public class BiomeMask extends AbstractMask {
* @param biomes a list of biomes to match
*/
public BiomeMask(Extent extent, Collection<BiomeType> biomes) {
checkNotNull(extent);
super(extent);
checkNotNull(biomes);
this.extent = extent;
this.biomes.addAll(biomes);
}
@ -92,7 +90,7 @@ public class BiomeMask extends AbstractMask {
@Override
public boolean test(BlockVector3 vector) {
BiomeType biome = extent.getBiome(vector);
BiomeType biome = getExtent().getBiome(vector);
return biomes.contains(biome);
}
@ -104,7 +102,12 @@ public class BiomeMask extends AbstractMask {
@Override
public Mask copy() {
return new BiomeMask(extent, new HashSet<>(biomes));
return new BiomeMask(getExtent(), new HashSet<>(biomes));
}
@Override
public boolean test(Extent extent, BlockVector3 position) {
BiomeType biome = getExtent().getBiome(position);
return biomes.contains(biome);
}
}

View File

@ -20,37 +20,13 @@
package com.sk89q.worldedit.internal.block;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.registry.BlockRegistry;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.BitSet;
import java.util.OptionalInt;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkState;
public final class BlockStateIdAccess {
private static final int INVALID_ID = -1;
private static final int EXPECTED_BLOCK_COUNT = 2 << 13;
private static final Int2ObjectOpenHashMap<BlockState> TO_STATE =
new Int2ObjectOpenHashMap<>(EXPECTED_BLOCK_COUNT);
static {
TO_STATE.defaultReturnValue(null);
}
public interface BlockStateInternalId {
int getInternalId(BlockState blockState);
void setInternalId(BlockState blockState, int internalId);
}
private static BlockStateInternalId blockStateInternalId;
public static void setBlockStateInternalId(BlockStateInternalId blockStateInternalId) {
BlockStateIdAccess.blockStateInternalId = blockStateInternalId;
}
/**
* An invalid internal ID, for verification purposes.
@ -65,8 +41,7 @@ public final class BlockStateIdAccess {
}
public static int getBlockStateId(BlockState holder) {
return holder.getOrdinal();
//return blockStateInternalId.getInternalId(holder);
return holder.getInternalId();
}
@Nullable
@ -74,39 +49,6 @@ public final class BlockStateIdAccess {
return BlockState.getFromOrdinal(id);
}
/**
* For platforms that don't have an internal ID system,
* {@link BlockRegistry#getInternalBlockStateId(BlockState)} will return
* {@link OptionalInt#empty()}. In those cases, we will use our own ID system,
* since it's useful for other entries as well.
*
* @return an unused ID in WorldEdit's ID tracker
*/
private static int provideUnusedWorldEditId() {
return usedIds.nextClearBit(0);
}
private static final BitSet usedIds = new BitSet();
public static void register(BlockState blockState, int id) {
int i = isValidInternalId(id) ? id : provideUnusedWorldEditId();
BlockState existing = getBlockStateById(id);
checkState(existing == null || existing == blockState,
"BlockState %s is using the same block ID (%s) as BlockState %s",
blockState, i, existing);
blockStateInternalId.setInternalId(blockState, i);
TO_STATE.put(i, blockState);
usedIds.set(i);
}
public static void clear() {
for (BlockState value : TO_STATE.values()) {
blockStateInternalId.setInternalId(value, invalidId());
}
TO_STATE.clear();
usedIds.clear();
}
private BlockStateIdAccess() {
}

View File

@ -83,16 +83,31 @@ public abstract class Vector3 {
return YzxOrderComparator.YZX_ORDER;
}
/**
* Gets the x coordinate rounded, accounting for negative coordinates
*
* @return the x coordinate
*/
public int getBlockX() {
return (int) MathUtils.roundHalfUp(getX());
return MathMan.roundInt(getX());
}
/**
* Gets the y coordinate rounded, accounting for negative coordinates
*
* @return the y coordinate
*/
public int getBlockY() {
return (int) MathUtils.roundHalfUp(getY());
return MathMan.roundInt(getY());
}
/**
* Gets the z coordinate rounded, accounting for negative coordinates
*
* @return the z coordinate
*/
public int getBlockZ() {
return (int) MathUtils.roundHalfUp(getZ());
return MathMan.roundInt(getZ());
}
public MutableVector3 setComponents(Vector3 other) {
@ -487,6 +502,15 @@ public abstract class Vector3 {
return Vector3.at(Math.floor(getX() + 0.5), Math.floor(getY() + 0.5), Math.floor(getZ() + 0.5));
}
/**
* Rounds all components using {@link MathUtils#roundHalfUp(double)}
*
* @return a new vector
*/
public Vector3 roundHalfUp() {
return Vector3.at(MathUtils.roundHalfUp(getX()), MathUtils.roundHalfUp(getY()), MathUtils.roundHalfUp(getZ()));
}
/**
* Returns a vector with the absolute values of the components of
* this vector.
@ -595,8 +619,7 @@ public abstract class Vector3 {
* @return a new {@code BlockVector}
*/
public static BlockVector3 toBlockPoint(double x, double y, double z) {
return BlockVector3.at(MathUtils.roundHalfUp(x), MathUtils.roundHalfUp(y), MathUtils.roundHalfUp(z));
//return BlockVector3.at(x, y, z);
return BlockVector3.at(x, y, z);
}
/**

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.util;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
@ -80,8 +79,7 @@ public enum Direction {
}
Direction(Vector3 vector, int flags, int left, int right) {
this.blockPoint = BlockVector3.at(MathMan.roundInt(Math.signum(vector.getX())),
MathMan.roundInt(Math.signum(vector.getY())), MathMan.roundInt(Math.signum(vector.getZ())));
this.blockPoint = BlockVector3.at(Math.signum(vector.getX()), Math.signum(vector.getY()), Math.signum(vector.getZ()));
this.direction = vector.normalize();
this.flags = flags;
this.left = left;

View File

@ -75,7 +75,6 @@ public class BlockState implements BlockStateHolder<BlockState>, Pattern {
* @deprecated Magic Numbers
* @return BlockState
*/
@Deprecated
public static BlockState getFromInternalId(int combinedId) throws InputParseException {
return BlockTypes.getFromStateId(combinedId).withStateId(combinedId);
@ -408,11 +407,7 @@ public class BlockState implements BlockStateHolder<BlockState>, Pattern {
}
public boolean isAir() {
try {
return material.isAir();
} catch (NullPointerException ignored) {
return getMaterial().isAir();
}
return blockType.getMaterial().isAir();
}
@Override