Additional work towards 1.16 compatibility

- Very basic implementation of the SideEffects system. Will definitely need fine tuning for it to be functional, but is not considered a priority in my opinion.
- Minor changes to the World interface and World implementations related to the SideEffects system. Shouldn't be the cause of any new bugs but be on the lookout.
- Included debug in BukkitImplLoader.java to assist contributors in understanding what needs to be implemented for the adapter to load properly.

Still very WIP but we're a few steps closer. So far, this is coming along better than I anticipated. Hopefully we can keep the momentum.
This commit is contained in:
Matthew Miller
2020-03-08 16:09:36 +10:00
committed by IronApollo
parent f2bc8d86fc
commit 82adab77b4
39 changed files with 877 additions and 176 deletions

View File

@ -13,12 +13,16 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable;
import java.io.File;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
@ -35,6 +39,11 @@ public class MCAWorld extends AbstractWorld {
return path.getName();
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
return false;
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
@ -46,6 +55,11 @@ public class MCAWorld extends AbstractWorld {
return false;
}
@Override
public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException {
return SideEffectSet.none().getSideEffectsToApply();
}
@Override
public boolean clearContainerBlockContents(BlockVector3 position) {
return false;

View File

@ -29,10 +29,7 @@ import com.boydti.fawe.util.TextureUtil;
import com.boydti.fawe.util.image.Drawable;
import com.boydti.fawe.util.image.ImageViewer;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.*;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
@ -48,9 +45,7 @@ import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Identifiable;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.*;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
@ -68,6 +63,7 @@ import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
@ -750,12 +746,24 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
return BlockVector3.at(getWidth() - 1, 255, getLength() - 1);
}
@Override
public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet)
throws WorldEditException{
return SideEffectSet.none().getSideEffectsToApply();
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block)
throws WorldEditException {
return setBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ(), block);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects)
throws WorldEditException {
return setBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ(), block);
}
private boolean setBlock(int x, int y, int z, char combined) {
int index = z * getWidth() + x;
if (index < 0 || index >= getArea()) {

View File

@ -24,9 +24,7 @@ import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.*;
import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -38,6 +36,7 @@ import com.sk89q.worldedit.world.weather.WeatherType;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Set;
public class WorldWrapper extends AbstractWorld {
@ -88,6 +87,12 @@ public class WorldWrapper extends AbstractWorld {
return parent.useItem(position, item, face);
}
@Override
public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet)
throws WorldEditException{
return parent.applySideEffects(position, previousType, sideEffectSet);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException {
return parent.setBlock(position, block, notifyAndLight);
@ -99,6 +104,11 @@ public class WorldWrapper extends AbstractWorld {
return parent.setBlock(x, y, z, block);
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
return parent.setBlock(position, block, sideEffects);
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
return parent.setTile(x, y, z, tile);

View File

@ -117,6 +117,7 @@ import com.sk89q.worldedit.regions.shape.RegionShape;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
@ -572,6 +573,20 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
disableHistory(enabled);
}
/**
* Set which block updates should occur.
*
* @param sideEffectSet side effects to enable
*/
public void setSideEffectApplier(SideEffectSet sideEffectSet) {
//Do nothing; TODO: SideEffects currently not fully implemented in FAWE.
}
public SideEffectSet getSideEffectApplier() {
//Do nothing; TODO: SideEffects currently not fully implemented in FAWE.
return SideEffectSet.defaults();
}
/**
* Disable history (or re-enable)
*

View File

@ -72,6 +72,7 @@ import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.util.HandSide;
import com.sk89q.worldedit.util.Identifiable;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
@ -145,7 +146,7 @@ public class LocalSession implements TextureHolder {
private transient Snapshot snapshotExperimental;
private transient boolean hasCUISupport = false;
private transient int cuiVersion = -1;
private transient boolean fastMode = false;
private transient SideEffectSet sideEffectSet = SideEffectSet.defaults();
private transient Mask mask;
private transient Mask sourceMask;
private transient TextureUtil texture;
@ -1494,7 +1495,7 @@ public class LocalSession implements TextureHolder {
builder.blockBag(blockBag);
}
builder.command(command);
builder.fastmode(fastMode);
builder.fastmode(!this.sideEffectSet.doesApplyAny());
editSession = builder.build();
@ -1513,7 +1514,7 @@ public class LocalSession implements TextureHolder {
}
private void prepareEditingExtents(EditSession editSession, Actor actor) {
editSession.setFastMode(fastMode);
editSession.setSideEffectApplier(sideEffectSet);
editSession.setReorderMode(reorderMode);
if (editSession.getSurvivalExtent() != null) {
editSession.getSurvivalExtent().setStripNbt(!actor.hasPermission("worldedit.setnbt"));
@ -1521,13 +1522,32 @@ public class LocalSession implements TextureHolder {
editSession.setTickingWatchdog(tickingWatchdog);
}
/**
* Gets the side effect applier of this session.
*
* @return the side effect applier
*/
public SideEffectSet getSideEffectSet() {
return this.sideEffectSet;
}
/**
* Sets the side effect applier for this session
*
* @param sideEffectSet the side effect applier
*/
public void setSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
/**
* Checks if the session has fast mode enabled.
*
* @return true if fast mode is enabled
*/
@Deprecated
public boolean hasFastMode() {
return fastMode;
return !this.sideEffectSet.doesApplyAny();
}
/**
@ -1535,8 +1555,9 @@ public class LocalSession implements TextureHolder {
*
* @param fastMode true if fast mode is enabled
*/
@Deprecated
public void setFastMode(boolean fastMode) {
this.fastMode = fastMode;
this.sideEffectSet = fastMode ? SideEffectSet.none() : SideEffectSet.defaults();
}
/**

View File

@ -49,10 +49,13 @@ import java.util.ArrayList;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.formatting.component.PaginationBox;
import com.sk89q.worldedit.util.formatting.component.SideEffectBox;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.item.ItemType;
import java.io.FileNotFoundException;
@ -142,24 +145,62 @@ public class GeneralCommands {
@Command(
name = "/fast",
desc = "Toggle fast mode"
desc = "Toggle fast mode side effects"
)
@CommandPermissions("worldedit.fast")
public void fast(Actor actor, LocalSession session,
@Arg(desc = "The new fast mode state", def = "")
Boolean fastMode) {
boolean hasFastMode = session.hasFastMode();
if (fastMode != null && fastMode == hasFastMode) {
actor.printError(TranslatableComponent.of(fastMode ? "worldedit.fast.enabled.already" : "worldedit.fast.disabled.already"));
return;
@Arg(desc = "The side effect", def = "")
SideEffect sideEffect,
@Arg(desc = "The new side effect state", def = "")
SideEffect.State newState,
@Switch(name = 'h', desc = "Show the info box")
boolean showInfoBox) throws WorldEditException {
if (sideEffect != null) {
SideEffect.State currentState = session.getSideEffectSet().getState(sideEffect);
if (newState != null && newState == currentState) {
if (!showInfoBox) {
actor.printError(TranslatableComponent.of(
"worldedit.fast.sideeffect.already-set",
TranslatableComponent.of(sideEffect.getDisplayName()),
TranslatableComponent.of(newState.getDisplayName())
));
}
return;
}
if (newState != null) {
session.setSideEffectSet(session.getSideEffectSet().with(sideEffect, newState));
if (!showInfoBox) {
actor.printInfo(TranslatableComponent.of(
"worldedit.fast.sideeffect.set",
TranslatableComponent.of(sideEffect.getDisplayName()),
TranslatableComponent.of(newState.getDisplayName())
));
}
} else {
actor.printInfo(TranslatableComponent.of(
"worldedit.fast.sideeffect.get",
TranslatableComponent.of(sideEffect.getDisplayName()),
TranslatableComponent.of(currentState.getDisplayName())
));
}
} else if (newState != null) {
SideEffectSet applier = session.getSideEffectSet();
for (SideEffect sideEffectEntry : SideEffect.values()) {
applier = applier.with(sideEffectEntry, newState);
}
session.setSideEffectSet(applier);
if (!showInfoBox) {
actor.printInfo(TranslatableComponent.of(
"worldedit.fast.sideeffect.set-all",
TranslatableComponent.of(newState.getDisplayName())
));
}
}
if (hasFastMode) {
session.setFastMode(false);
actor.printInfo(TranslatableComponent.of("worldedit.fast.disabled"));
} else {
session.setFastMode(true);
actor.printInfo(TranslatableComponent.of("worldedit.fast.enabled"));
if (sideEffect == null || showInfoBox) {
SideEffectBox sideEffectBox = new SideEffectBox(session.getSideEffectSet());
actor.print(sideEffectBox.create(1));
}
}

View File

@ -23,6 +23,7 @@ import com.boydti.fawe.object.brush.scroll.Scroll;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.command.util.HookMode;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.TreeGenerator;
import org.enginehub.piston.CommandManager;
import org.enginehub.piston.converter.ArgumentConverter;
@ -30,6 +31,7 @@ import org.enginehub.piston.converter.MultiKeyConverter;
import org.enginehub.piston.inject.Key;
import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Set;
@ -48,6 +50,11 @@ public final class EnumConverter {
full(EditSession.ReorderMode.class,
r -> ImmutableSet.of(r.getDisplayName()),
null));
commandManager.registerConverter(Key.of(SideEffect.State.class),
MultiKeyConverter.from(
EnumSet.of(SideEffect.State.OFF, SideEffect.State.ON),
r -> ImmutableSet.of(r.name().toLowerCase(Locale.US)),
null));
commandManager.registerConverter(Key.of(HookMode.class),
basic(HookMode.class));
commandManager.registerConverter(Key.of(Scroll.Action.class),

View File

@ -0,0 +1,75 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.command.argument;
import static org.enginehub.piston.converter.SuggestionHelper.limitByPrefix;
import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.EntityRemover;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.formatting.text.Component;
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.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
public class SideEffectConverter implements ArgumentConverter<SideEffect> {
public static void register(CommandManager commandManager) {
commandManager.registerConverter(Key.of(SideEffect.class), new SideEffectConverter());
}
private final TextComponent choices = TextComponent.of("any side effect");
private SideEffectConverter() {
}
private Collection<SideEffect> getSideEffects() {
return WorldEdit.getInstance().getPlatformManager().getSupportedSideEffects();
}
@Override
public Component describeAcceptableArguments() {
return choices;
}
@Override
public List<String> getSuggestions(String input, InjectedValueAccess context) {
return limitByPrefix(getSideEffects().stream().map(sideEffect -> sideEffect.name().toLowerCase(Locale.US)), input);
}
@Override
public ConversionResult<SideEffect> convert(String argument, InjectedValueAccess context) {
try {
return SuccessfulConversion.fromSingle(SideEffect.valueOf(argument.toUpperCase(Locale.US)));
} catch (Exception e) {
return FailedConversion.from(e);
}
}
}

View File

@ -21,14 +21,17 @@ package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.registry.Registries;
import org.enginehub.piston.CommandManager;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Represents a platform that WorldEdit has been implemented for.
@ -174,4 +177,5 @@ public interface Platform {
*/
Map<Capability, Preference> getCapabilities();
Set<SideEffect> getSupportedSideEffects();
}

View File

@ -94,6 +94,7 @@ import com.sk89q.worldedit.command.argument.ExpressionConverter;
import com.sk89q.worldedit.command.argument.FactoryConverter;
import com.sk89q.worldedit.command.argument.RegionFactoryConverter;
import com.sk89q.worldedit.command.argument.RegistryConverter;
import com.sk89q.worldedit.command.argument.SideEffectConverter;
import com.sk89q.worldedit.command.argument.VectorConverter;
import com.sk89q.worldedit.command.argument.WorldConverter;
import com.sk89q.worldedit.command.argument.ZonedDateTimeConverter;
@ -255,6 +256,7 @@ public final class PlatformCommandManager {
RegionFactoryConverter.register(commandManager);
WorldConverter.register(commandManager);
ExpressionConverter.register(commandManager);
SideEffectConverter.register(commandManager);
registerBindings(new ConsumeBindings(worldEdit, this));
registerBindings(new PrimitiveBindings(worldEdit));

View File

@ -48,9 +48,11 @@ import com.sk89q.worldedit.event.platform.PlayerInputEvent;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.world.World;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.Iterator;
import java.util.List;
@ -304,6 +306,10 @@ public class PlatformManager {
return queryCapability(Capability.CONFIGURATION).getConfiguration();
}
public Collection<SideEffect> getSupportedSideEffects() {
return queryCapability(Capability.WORLD_EDITING).getSupportedSideEffects();
}
@Subscribe
public void handlePlatformReady(PlatformReadyEvent event) {
choosePreferred();

View File

@ -21,17 +21,16 @@ package com.sk89q.worldedit.extent.buffer;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Maps;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.collection.BlockMap;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Map;
import java.util.Optional;
/**
* Buffers changes to an {@link Extent} and allows retrieval of the changed blocks,
@ -39,7 +38,7 @@ import java.util.Optional;
*/
public class ExtentBuffer extends AbstractBufferingExtent {
private final Map<BlockVector3, BaseBlock> buffer = Maps.newHashMap();
private final Map<BlockVector3, BaseBlock> buffer = BlockMap.create();
private final Mask mask;
/**

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.extent.reorder;
import com.google.common.collect.ImmutableSortedSet;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
import com.sk89q.worldedit.extent.Extent;

View File

@ -27,67 +27,38 @@ import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.RunContext;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.collection.BlockMap;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Implements "fast mode" which may skip physics, lighting, etc.
* An extent that sets blocks in the world, with a {@link SideEffectSet}.
*/
public class FastModeExtent extends AbstractDelegateExtent {
public class SideEffectExtent extends AbstractDelegateExtent {
private final World world;
private final Set<BlockVector3> positions = new HashSet<>();
private final Map<BlockVector3, BlockState> positions = BlockMap.create();
private final Set<BlockVector2> dirtyChunks = new HashSet<>();
private boolean enabled = true;
private SideEffectSet sideEffectSet = SideEffectSet.defaults();
private boolean postEditSimulation;
/**
* Create a new instance with fast mode enabled.
*
* @param world the world
*/
public FastModeExtent(World world) {
this(world, true);
}
/**
* Create a new instance.
*
* @param world the world
* @param enabled true to enable fast mode
*/
public FastModeExtent(World world, boolean enabled) {
public SideEffectExtent(World world) {
super(world);
checkNotNull(world);
this.world = world;
this.enabled = enabled;
if (enabled) {
this.postEditSimulation = true;
}
}
/**
* Return whether fast mode is enabled.
*
* @return true if fast mode is enabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* Set fast mode enable status.
*
* @param enabled true to enable fast mode
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isPostEditSimulationEnabled() {
@ -98,26 +69,28 @@ public class FastModeExtent extends AbstractDelegateExtent {
this.postEditSimulation = enabled;
}
public SideEffectSet getSideEffectSet() {
return this.sideEffectSet;
}
public void setSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
if (enabled || postEditSimulation) {
if (sideEffectSet.getState(SideEffect.LIGHTING) == SideEffect.State.DELAYED) {
dirtyChunks.add(BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4));
if (world.setBlock(location, block, false)) {
if (!enabled && postEditSimulation) {
positions.add(location);
}
return true;
}
return false;
} else {
return world.setBlock(location, block, true);
}
if (postEditSimulation) {
positions.put(location, world.getBlock(location));
}
return world.setBlock(location, block, postEditSimulation ? SideEffectSet.none() : sideEffectSet);
}
public boolean commitRequired() {
return enabled || postEditSimulation;
return postEditSimulation || !dirtyChunks.isEmpty();
}
@Override
@ -132,11 +105,11 @@ public class FastModeExtent extends AbstractDelegateExtent {
world.fixAfterFastMode(dirtyChunks);
}
if (!enabled && postEditSimulation) {
Iterator<BlockVector3> positionIterator = positions.iterator();
if (postEditSimulation) {
Iterator<Map.Entry<BlockVector3, BlockState>> positionIterator = positions.entrySet().iterator();
while (run.shouldContinue() && positionIterator.hasNext()) {
BlockVector3 position = positionIterator.next();
world.notifyAndLightBlock(position, BlockTypes.AIR.getDefaultState());
Map.Entry<BlockVector3, BlockState> position = positionIterator.next();
world.applySideEffects(position.getKey(), position.getValue(), sideEffectSet);
positionIterator.remove();
}
@ -151,5 +124,4 @@ public class FastModeExtent extends AbstractDelegateExtent {
}
};
}
}

View File

@ -0,0 +1,68 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util;
import java.util.Locale;
public enum SideEffect {
LIGHTING(State.ON),
NEIGHBORS(State.ON),
CONNECTIONS(State.ON),
ENTITY_AI(State.OFF),
PLUGIN_EVENTS(State.OFF);
private final String displayName;
private final String description;
private final State defaultValue;
SideEffect(State defaultValue) {
this.displayName = "worldedit.sideeffect." + this.name().toLowerCase(Locale.US);
this.description = "worldedit.sideeffect." + this.name().toLowerCase(Locale.US) + ".description";
this.defaultValue = defaultValue;
}
public String getDisplayName() {
return this.displayName;
}
public String getDescription() {
return this.description;
}
public State getDefaultValue() {
return this.defaultValue;
}
public enum State {
OFF,
ON,
DELAYED;
private final String displayName;
State() {
this.displayName = "worldedit.sideeffect.state." + this.name().toLowerCase(Locale.US);
}
public String getDisplayName() {
return this.displayName;
}
}
}

View File

@ -0,0 +1,94 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
public class SideEffectSet {
private static final SideEffectSet DEFAULT = new SideEffectSet(
Arrays.stream(SideEffect.values()).collect(Collectors.toMap(Function.identity(), SideEffect::getDefaultValue))
);
private static final SideEffectSet NONE = new SideEffectSet();
private final Map<SideEffect, SideEffect.State> sideEffects;
private final Set<SideEffect> appliedSideEffects;
private final boolean appliesAny;
private SideEffectSet() {
this(ImmutableMap.of());
}
public SideEffectSet(Map<SideEffect, SideEffect.State> sideEffects) {
this.sideEffects = Maps.immutableEnumMap(sideEffects);
appliedSideEffects = sideEffects.entrySet()
.stream()
.filter(entry -> entry.getValue() != SideEffect.State.OFF)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
appliesAny = !appliedSideEffects.isEmpty();
}
public SideEffectSet with(SideEffect sideEffect, SideEffect.State state) {
Map<SideEffect, SideEffect.State> entries = this.sideEffects.isEmpty() ? Maps.newEnumMap(SideEffect.class) : new EnumMap<>(this.sideEffects);
entries.put(sideEffect, state);
return new SideEffectSet(entries);
}
public boolean doesApplyAny() {
return this.appliesAny;
}
public SideEffect.State getState(SideEffect effect) {
return sideEffects.getOrDefault(effect, effect.getDefaultValue());
}
/**
* Gets whether this side effect is not off.
*
* This returns whether it is either delayed or on.
*
* @param effect The side effect
* @return Whether it should apply
*/
public boolean shouldApply(SideEffect effect) {
return getState(effect) != SideEffect.State.OFF;
}
public Set<SideEffect> getSideEffectsToApply() {
return this.appliedSideEffects;
}
public static SideEffectSet defaults() {
return DEFAULT;
}
public static SideEffectSet none() {
return NONE;
}
}

View File

@ -0,0 +1,88 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.formatting.component;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.event.HoverEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
public class SideEffectBox extends PaginationBox {
private static List<SideEffect> sideEffects;
private SideEffectSet sideEffectSet;
private static List<SideEffect> getSideEffects() {
if (sideEffects == null) {
sideEffects = WorldEdit.getInstance().getPlatformManager().getSupportedSideEffects()
.stream()
.sorted(Comparator.comparing(Enum::name))
.collect(Collectors.toList());
}
return sideEffects;
}
public SideEffectBox(SideEffectSet sideEffectSet) {
super("Side Effects");
this.sideEffectSet = sideEffectSet;
}
private static final SideEffect.State[] SHOWN_VALUES = {SideEffect.State.OFF, SideEffect.State.ON};
@Override
public Component getComponent(int number) {
SideEffect effect = getSideEffects().get(number);
SideEffect.State state = this.sideEffectSet.getState(effect);
TextComponent.Builder builder = TextComponent.builder();
builder = builder.append(TranslatableComponent.of(effect.getDisplayName(), TextColor.YELLOW)
.hoverEvent(HoverEvent.of(HoverEvent.Action.SHOW_TEXT, TranslatableComponent.of(effect.getDescription()))));
for (SideEffect.State uiState : SHOWN_VALUES) {
builder = builder.append(TextComponent.space());
builder = builder.append(TranslatableComponent.of(uiState.getDisplayName(), uiState == state ? TextColor.WHITE : TextColor.GRAY)
.clickEvent(ClickEvent.runCommand("//fast -h " + effect.name().toLowerCase(Locale.US) + " " + uiState.name().toLowerCase(Locale.US)))
.hoverEvent(HoverEvent.showText(uiState == state
? TranslatableComponent.of("worldedit.sideeffect.box.current")
: TranslatableComponent.of("worldedit.sideeffect.box.change-to", TranslatableComponent.of(uiState.getDisplayName()))
))
);
}
return builder.build();
}
@Override
public int getComponentsSize() {
return getSideEffects().size();
}
}

View File

@ -32,6 +32,7 @@ import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.block.BlockType;
@ -57,7 +58,7 @@ public abstract class AbstractWorld implements World {
@Override
public final <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 pt, B block) throws WorldEditException {
return setBlock(pt, block, true);
return setBlock(pt, block, SideEffectSet.defaults());
}
@Override

View File

@ -23,6 +23,7 @@ import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.implementation.packet.ChunkPacket;
import com.boydti.fawe.beta.implementation.blocks.NullChunkGet;
import com.sk89q.jnbt.CompoundTag;
import com.google.common.collect.ImmutableSet;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
@ -35,6 +36,8 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
@ -48,6 +51,7 @@ import com.sk89q.worldedit.world.weather.WeatherTypes;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* A null implementation of {@link World} that drops all changes and
@ -71,13 +75,14 @@ public class NullWorld extends AbstractWorld {
}
@Override
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException {
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException {
return false;
}
@Override
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
return false;
public Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet)
throws WorldEditException {
return ImmutableSet.of();
}
@Override

View File

@ -37,15 +37,19 @@ import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.Keyed;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.weather.WeatherType;
import javax.annotation.Nullable;
import java.nio.file.Path;
import java.util.Locale;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Represents a world (dimension).
@ -112,10 +116,28 @@ public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
* @param notifyAndLight true to to notify and light
* @return true if the block was successfully set (return value may not be accurate)
*/
@Deprecated
default <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws WorldEditException {
return setBlock(position, block);
return setBlock(position, block, notifyAndLight ? SideEffectSet.defaults() : SideEffectSet.none());
}
/**
* Similar to {@link Extent#setBlock(BlockVector3, BlockStateHolder)} but a
* {@code sideEffects} parameter indicates which side effects should be applied
* to the block. This includes block updates, lighting, and others. See {@link SideEffect}
* for a full list.
*
* <p>Not all implementations support all side effects. Use
* {@link Platform#getSupportedSideEffects()} for a list of supported side effects.
* Non-supported side effects will be ignored.</p>
*
* @param position position of the block
* @param block block to set
* @param sideEffects which side effects to perform
* @return true if the block was successfully set (return value may not be accurate)
*/
<B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 position, B block, SideEffectSet sideEffects) throws WorldEditException;
/**
* Notifies the simulation that the block at the given location has
* been changed and it must be re-lighted (and issue other events).
@ -124,7 +146,20 @@ public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
* @param previousType the type of the previous block that was there
* @return true if the block was successfully notified
*/
boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException;
@Deprecated
default boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
return !applySideEffects(position, previousType, SideEffectSet.defaults()).isEmpty();
}
/**
* Applies a set of side effects on the given block.
*
* @param position position of the block
* @param previousType the type of the previous block that was there
* @param sideEffectSet which side effects to perform
* @return a set of side effects that were applied
*/
Set<SideEffect> applySideEffects(BlockVector3 position, BlockState previousType, SideEffectSet sideEffectSet) throws WorldEditException;
/**
* Get the light level at the given block.