Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-03 01:50:07 +01:00
Added a few new things using block states.
* `//set ##*tag` sets all states in the tag (not just default state per type) * `//set ^type` is a pattern changing block type but copying all valid existing states * `//set ^[prop=val,...]` sets the property `prop` to `val` wherever the existing block has that property * `//set ^type[prop=val,...]` does both of the above Those work anywhere a pattern is taken, of course. * The mask syntax `^[prop=val]` matches blocks with the property `prop` set to `val`, or blocks that don't have the property at all. * The mask syntax `^=[prop=val]` only matches blocks that have the property. Those work anywhere a mask is taken, of course. (`//mask`, `//gmask`, `//replace`, etc) The `//drain` command now takes `-w` flag that removes the waterlogged state from blocks (in addition to removing water, as before).
Dieser Commit ist enthalten in:
Ursprung
1ae0e88b63
Commit
88014b18a3
@ -53,6 +53,7 @@ import com.sk89q.worldedit.function.block.Naturalizer;
|
||||
import com.sk89q.worldedit.function.generator.GardenPatchGenerator;
|
||||
import com.sk89q.worldedit.function.mask.BlockMask;
|
||||
import com.sk89q.worldedit.function.mask.BlockTypeMask;
|
||||
import com.sk89q.worldedit.function.mask.BlockStateMask;
|
||||
import com.sk89q.worldedit.function.mask.BoundedHeightMask;
|
||||
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
@ -68,6 +69,7 @@ import com.sk89q.worldedit.function.operation.OperationQueue;
|
||||
import com.sk89q.worldedit.function.operation.Operations;
|
||||
import com.sk89q.worldedit.function.pattern.BlockPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.pattern.WaterloggedRemover;
|
||||
import com.sk89q.worldedit.function.util.RegionOffset;
|
||||
import com.sk89q.worldedit.function.visitor.DownwardVisitor;
|
||||
import com.sk89q.worldedit.function.visitor.LayerVisitor;
|
||||
@ -115,7 +117,9 @@ import com.sk89q.worldedit.world.block.BlockType;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
import com.sk89q.worldedit.world.registry.LegacyMapper;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@ -125,8 +129,6 @@ import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An {@link Extent} that handles history, {@link BlockBag}s, change limits,
|
||||
* block re-ordering, and much more. Most operations in WorldEdit use this class.
|
||||
@ -1283,15 +1285,38 @@ public class EditSession implements Extent, AutoCloseable {
|
||||
* @throws MaxChangedBlocksException thrown if too many blocks are changed
|
||||
*/
|
||||
public int drainArea(BlockVector3 origin, double radius) throws MaxChangedBlocksException {
|
||||
return drainArea(origin, radius, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drain nearby pools of water or lava, optionally removed waterlogged states from blocks.
|
||||
*
|
||||
* @param origin the origin to drain from, which will search a 3x3 area
|
||||
* @param radius the radius of the removal, where a value should be 0 or greater
|
||||
* @param waterlogged true to make waterlogged blocks non-waterlogged as well
|
||||
* @return number of blocks affected
|
||||
* @throws MaxChangedBlocksException thrown if too many blocks are changed
|
||||
*/
|
||||
public int drainArea(BlockVector3 origin, double radius, boolean waterlogged) throws MaxChangedBlocksException {
|
||||
checkNotNull(origin);
|
||||
checkArgument(radius >= 0, "radius >= 0 required");
|
||||
|
||||
MaskIntersection mask = new MaskIntersection(
|
||||
new BoundedHeightMask(0, getWorld().getMaxY()),
|
||||
new RegionMask(new EllipsoidRegion(null, origin, Vector3.at(radius, radius, radius))),
|
||||
getWorld().createLiquidMask());
|
||||
waterlogged ? new MaskUnion(
|
||||
getWorld().createLiquidMask(),
|
||||
new BlockStateMask(this, new HashMap<String, String>() {{
|
||||
put("waterlogged", "true");
|
||||
}}, true))
|
||||
: getWorld().createLiquidMask());
|
||||
|
||||
BlockReplace replace = new BlockReplace(this, new BlockPattern(BlockTypes.AIR.getDefaultState()));
|
||||
BlockReplace replace;
|
||||
if (waterlogged) {
|
||||
replace = new BlockReplace(this, new WaterloggedRemover(this));
|
||||
} else {
|
||||
replace = new BlockReplace(this, new BlockPattern(BlockTypes.AIR.getDefaultState()));
|
||||
}
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace);
|
||||
|
||||
// Around the origin in a 3x3 block
|
||||
@ -2197,7 +2222,7 @@ public class EditSession implements Extent, AutoCloseable {
|
||||
|
||||
try {
|
||||
if (expression.evaluate(scaled.getX(), scaled.getZ()) <= 0) {
|
||||
return null; // TODO should return OUTSIDE? seems to cause issues otherwise, workedaround for now
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Allow biome setting via a script variable (needs BiomeType<->int mapping)
|
||||
|
@ -19,9 +19,13 @@
|
||||
|
||||
package com.sk89q.worldedit.blocks;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Block-related utility methods.
|
||||
@ -48,4 +52,28 @@ public final class Blocks {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string->string map to find the matching Property and values for the given BlockType.
|
||||
*
|
||||
* @param states the desired states and values
|
||||
* @param type the block type to get properties and values for
|
||||
* @return a property->value map
|
||||
*/
|
||||
public static Map<Property<Object>, Object> resolveProperties(Map<String, String> states, BlockType type) {
|
||||
Map<String, ? extends Property<?>> existing = type.getPropertyMap();
|
||||
Map<Property<Object>, Object> newMap = Maps.newHashMap();
|
||||
states.forEach((key, value) -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
Property<Object> prop = (Property<Object>) existing.get(key);
|
||||
if (prop == null) return;
|
||||
Object val = null;
|
||||
try {
|
||||
val = prop.getValueFor(value);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
if (val == null) return;
|
||||
newMap.put(prop, val);
|
||||
});
|
||||
return newMap;
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,10 @@ public class UtilityCommands {
|
||||
@Command(
|
||||
aliases = { "/drain" },
|
||||
usage = "<radius>",
|
||||
flags = "w",
|
||||
desc = "Drain a pool",
|
||||
help = "Removes all connected water sources.\n" +
|
||||
" If -w is specified, also makes waterlogged blocks non-waterlogged.",
|
||||
min = 1,
|
||||
max = 1
|
||||
)
|
||||
@ -151,9 +154,10 @@ public class UtilityCommands {
|
||||
public void drain(Player player, LocalSession session, EditSession editSession, CommandContext args) throws WorldEditException {
|
||||
|
||||
double radius = Math.max(0, args.getDouble(0));
|
||||
boolean waterlogged = args.hasFlag('w');
|
||||
we.checkMaxRadius(radius);
|
||||
int affected = editSession.drainArea(
|
||||
session.getPlacementPosition(player), radius);
|
||||
session.getPlacementPosition(player), radius, waterlogged);
|
||||
player.print(affected + " block(s) have been changed.");
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ package com.sk89q.worldedit.extension.factory;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.BiomeMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.BlockCategoryMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.BlockStateMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.BlocksMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.ExistingMaskParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.mask.ExpressionMaskParser;
|
||||
@ -67,6 +68,7 @@ public final class MaskFactory extends AbstractFactory<Mask> {
|
||||
register(new OffsetMaskParser(worldEdit));
|
||||
register(new BiomeMaskParser(worldEdit));
|
||||
register(new NoiseMaskParser(worldEdit));
|
||||
register(new BlockStateMaskParser(worldEdit));
|
||||
register(new NegateMaskParser(worldEdit));
|
||||
register(new ExpressionMaskParser(worldEdit));
|
||||
register(new BlocksMaskParser(worldEdit));
|
||||
|
@ -24,6 +24,7 @@ import com.sk89q.worldedit.extension.factory.parser.pattern.BlockCategoryPattern
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.ClipboardPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.RandomPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.SingleBlockPatternParser;
|
||||
import com.sk89q.worldedit.extension.factory.parser.pattern.TypeOrStateApplyingPatternParser;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.internal.registry.AbstractFactory;
|
||||
|
||||
@ -44,10 +45,16 @@ public final class PatternFactory extends AbstractFactory<Pattern> {
|
||||
public PatternFactory(WorldEdit worldEdit) {
|
||||
super(worldEdit);
|
||||
|
||||
register(new ClipboardPatternParser(worldEdit));
|
||||
register(new BlockCategoryPatternParser(worldEdit));
|
||||
register(new SingleBlockPatternParser(worldEdit));
|
||||
// split and parse each sub-pattern
|
||||
register(new RandomPatternParser(worldEdit));
|
||||
|
||||
// individual patterns
|
||||
register(new BlockCategoryPatternParser(worldEdit));
|
||||
register(new ClipboardPatternParser(worldEdit));
|
||||
register(new TypeOrStateApplyingPatternParser(worldEdit));
|
||||
|
||||
// inner-most pattern: just one block
|
||||
register(new SingleBlockPatternParser(worldEdit));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.extension.factory.parser.mask;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.BlockStateMask;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.NoiseFilter;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.math.noise.RandomNoise;
|
||||
import com.sk89q.worldedit.session.request.Request;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BlockStateMaskParser extends InputParser<Mask> {
|
||||
|
||||
public BlockStateMaskParser(WorldEdit worldEdit) {
|
||||
super(worldEdit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
if (!(input.startsWith("^[") || input.startsWith("^=[")) || !input.endsWith("]")) {
|
||||
return null;
|
||||
}
|
||||
Extent extent = Request.request().getEditSession();
|
||||
boolean strict = input.charAt(1) == '=';
|
||||
String states = input.substring(2 + (strict ? 1 : 0), input.length() - 1);
|
||||
try {
|
||||
return new BlockStateMask(extent,
|
||||
Splitter.on(',').omitEmptyStrings().trimResults().withKeyValueSeparator('=').split(states),
|
||||
strict);
|
||||
} catch (Exception e) {
|
||||
throw new InputParseException("Invalid states.", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -28,9 +28,11 @@ import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.world.block.BlockCategories;
|
||||
import com.sk89q.worldedit.world.block.BlockCategory;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BlockCategoryPatternParser extends InputParser<Pattern> {
|
||||
@ -46,17 +48,34 @@ public class BlockCategoryPatternParser extends InputParser<Pattern> {
|
||||
|
||||
@Override
|
||||
public Pattern parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
if(!input.startsWith("##")) {
|
||||
if (!input.startsWith("##")) {
|
||||
return null;
|
||||
}
|
||||
BlockCategory category = BlockCategories.get(input.substring(2).toLowerCase());
|
||||
String tag = input.substring(2).toLowerCase();
|
||||
boolean anyState = false;
|
||||
if (tag.startsWith("*")) {
|
||||
tag = tag.substring(1);
|
||||
anyState = true;
|
||||
}
|
||||
|
||||
BlockCategory category = BlockCategories.get(tag);
|
||||
if (category == null) {
|
||||
throw new InputParseException("Unknown block tag: " + input.substring(2));
|
||||
throw new InputParseException("Unknown block tag: " + tag);
|
||||
}
|
||||
RandomPattern randomPattern = new RandomPattern();
|
||||
|
||||
for (BlockType blockType : category.getAll()) {
|
||||
randomPattern.add(new BlockPattern(blockType.getDefaultState()), 1.0 / category.getAll().size());
|
||||
Set<BlockType> blocks = category.getAll();
|
||||
if (blocks.isEmpty()) {
|
||||
throw new InputParseException("Block tag " + category.getId() + " had no blocks!");
|
||||
}
|
||||
|
||||
if (anyState) {
|
||||
blocks.stream().flatMap(blockType -> blockType.getAllStates().stream()).forEach(state ->
|
||||
randomPattern.add(new BlockPattern(state), 1.0));
|
||||
} else {
|
||||
for (BlockType blockType : blocks) {
|
||||
randomPattern.add(new BlockPattern(blockType.getDefaultState()), 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
return randomPattern;
|
||||
|
@ -21,14 +21,13 @@ package com.sk89q.worldedit.extension.factory.parser.pattern;
|
||||
|
||||
import com.sk89q.util.StringUtil;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.factory.BlockFactory;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.function.pattern.BlockPattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.pattern.RandomPattern;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RandomPatternParser extends InputParser<Pattern> {
|
||||
|
||||
@ -38,14 +37,16 @@ public class RandomPatternParser extends InputParser<Pattern> {
|
||||
|
||||
@Override
|
||||
public Pattern parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
BlockFactory blockRegistry = worldEdit.getBlockFactory();
|
||||
RandomPattern randomPattern = new RandomPattern();
|
||||
|
||||
String[] splits = input.split(",");
|
||||
for (String token : StringUtil.parseListInQuotes(splits, ',', '[', ']')) {
|
||||
BaseBlock block;
|
||||
|
||||
List<String> patterns = StringUtil.parseListInQuotes(splits, ',', '[', ']');
|
||||
if (patterns.size() == 1) {
|
||||
return null; // let a 'single'-pattern parser handle it
|
||||
}
|
||||
for (String token : patterns) {
|
||||
double chance;
|
||||
Pattern innerPattern;
|
||||
|
||||
// Parse special percentage syntax
|
||||
if (token.matches("[0-9]+(\\.[0-9]*)?%.*")) {
|
||||
@ -55,14 +56,14 @@ public class RandomPatternParser extends InputParser<Pattern> {
|
||||
throw new InputParseException("Missing the type after the % symbol for '" + input + "'");
|
||||
} else {
|
||||
chance = Double.parseDouble(p[0]);
|
||||
block = blockRegistry.parseFromInput(p[1], context);
|
||||
innerPattern = worldEdit.getPatternFactory().parseFromInput(p[1], context);
|
||||
}
|
||||
} else {
|
||||
chance = 1;
|
||||
block = blockRegistry.parseFromInput(token, context);
|
||||
innerPattern = worldEdit.getPatternFactory().parseFromInput(token, context);
|
||||
}
|
||||
|
||||
randomPattern.add(new BlockPattern(block), chance);
|
||||
randomPattern.add(innerPattern, chance);
|
||||
}
|
||||
|
||||
return randomPattern;
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.extension.factory.parser.pattern;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.buffer.ExtentBuffer;
|
||||
import com.sk89q.worldedit.function.pattern.ExtentBufferedCompositePattern;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.function.pattern.StateApplyingPattern;
|
||||
import com.sk89q.worldedit.function.pattern.TypeApplyingPattern;
|
||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class TypeOrStateApplyingPatternParser extends InputParser<Pattern> {
|
||||
|
||||
public TypeOrStateApplyingPatternParser(WorldEdit worldEdit) {
|
||||
super(worldEdit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pattern parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
if (!input.startsWith("^")) {
|
||||
return null;
|
||||
}
|
||||
Extent extent = context.requireExtent();
|
||||
input = input.substring(1);
|
||||
|
||||
String[] parts = input.split("\\[", 2);
|
||||
String type = parts[0];
|
||||
|
||||
if (parts.length == 1) {
|
||||
return new TypeApplyingPattern(extent,
|
||||
worldEdit.getBlockFactory().parseFromInput(type, context).getBlockType().getDefaultState());
|
||||
} else {
|
||||
// states given
|
||||
if (!parts[1].endsWith("]")) throw new InputParseException("Invalid state format.");
|
||||
Map<String, String> statesToSet = Splitter.on(',')
|
||||
.omitEmptyStrings().trimResults().withKeyValueSeparator('=')
|
||||
.split(parts[1].substring(0, parts[1].length() - 1));
|
||||
if (type.isEmpty()) {
|
||||
return new StateApplyingPattern(extent, statesToSet);
|
||||
} else {
|
||||
Extent buffer = new ExtentBuffer(extent);
|
||||
Pattern typeApplier = new TypeApplyingPattern(buffer,
|
||||
worldEdit.getBlockFactory().parseFromInput(type, context).getBlockType().getDefaultState());
|
||||
Pattern stateApplier = new StateApplyingPattern(buffer, statesToSet);
|
||||
return new ExtentBufferedCompositePattern(buffer, typeApplier, stateApplier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.extent.buffer;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
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.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Buffers changes to an {@link Extent} and allows retrieval of the changed blocks,
|
||||
* without modifying the underlying extent.
|
||||
*/
|
||||
public class ExtentBuffer extends AbstractDelegateExtent {
|
||||
|
||||
private final Map<BlockVector3, BaseBlock> buffer = Maps.newHashMap();
|
||||
private final Mask mask;
|
||||
|
||||
/**
|
||||
* Create a new extent buffer that will buffer every change.
|
||||
*
|
||||
* @param delegate the delegate extent for {@link Extent#getBlock(BlockVector3)}, etc. calls
|
||||
*/
|
||||
public ExtentBuffer(Extent delegate) {
|
||||
this(delegate, Masks.alwaysTrue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new extent buffer that will buffer changes that meet the criteria
|
||||
* of the given mask.
|
||||
*
|
||||
* @param delegate the delegate extent for {@link Extent#getBlock(BlockVector3)}, etc. calls
|
||||
* @param mask the mask
|
||||
*/
|
||||
public ExtentBuffer(Extent delegate, Mask mask) {
|
||||
super(delegate);
|
||||
checkNotNull(delegate);
|
||||
checkNotNull(mask);
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(BlockVector3 position) {
|
||||
if (mask.test(position)) {
|
||||
return getOrDefault(position).toImmutableState();
|
||||
}
|
||||
return super.getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
if (mask.test(position)) {
|
||||
return getOrDefault(position);
|
||||
}
|
||||
return super.getFullBlock(position);
|
||||
}
|
||||
|
||||
private BaseBlock getOrDefault(BlockVector3 position) {
|
||||
return buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 location, T block) throws WorldEditException {
|
||||
if (mask.test(location)) {
|
||||
buffer.put(location, block.toBaseBlock());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.function.mask;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.worldedit.blocks.Blocks;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
|
||||
public class BlockStateMask extends AbstractExtentMask {
|
||||
|
||||
private final Map<String, String> states;
|
||||
private final boolean strict;
|
||||
private Map<BlockType, Map<Property<Object>, Object>> cache = Maps.newHashMap();
|
||||
|
||||
/**
|
||||
* Creates a mask that checks if a given block has the desired properties set to the desired value.
|
||||
*
|
||||
* @param extent the extent to get blocks from
|
||||
* @param states the desired states (property -> value) that a block should have to match the mask
|
||||
* @param strict true to only match blocks that have all properties and values, false to also match blocks that
|
||||
* do not have the properties (but only fail blocks with the properties but wrong values)
|
||||
*/
|
||||
public BlockStateMask(Extent extent, Map<String, String> states, boolean strict) {
|
||||
super(extent);
|
||||
this.states = states;
|
||||
this.strict = strict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(BlockVector3 vector) {
|
||||
BlockState block = getExtent().getBlock(vector);
|
||||
final Map<Property<Object>, Object> checkProps = cache
|
||||
.computeIfAbsent(block.getBlockType(), (b -> Blocks.resolveProperties(states, b)));
|
||||
if (strict && checkProps.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return checkProps.entrySet().stream()
|
||||
.allMatch(entry -> block.getState(entry.getKey()) == entry.getValue());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Mask2D toMask2D() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.function.pattern;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public abstract class AbstractExtentPattern extends AbstractPattern implements ExtentPattern {
|
||||
|
||||
private final Extent extent;
|
||||
|
||||
public AbstractExtentPattern(Extent extent) {
|
||||
this.extent = extent;
|
||||
checkNotNull(extent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent getExtent() {
|
||||
return extent;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.function.pattern;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.buffer.ExtentBuffer;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
/**
|
||||
* A pattern that composes multiple patterns consecutively, ensuring that changes from one
|
||||
* pattern are realized by the subsequent one(s). For best results, use an {@link ExtentBuffer}
|
||||
* to avoid changing blocks in an underlying extent (e.g. the world).
|
||||
*/
|
||||
public class ExtentBufferedCompositePattern extends AbstractExtentPattern {
|
||||
|
||||
private final Pattern[] patterns;
|
||||
|
||||
/**
|
||||
* Construct a new instance of this pattern.
|
||||
*
|
||||
* <p>Note that all patterns passed which are ExtentPatterns should use the same extent as the one
|
||||
* passed to this constructor, or block changes may not be realized by those patterns.</p>
|
||||
*
|
||||
* @param extent the extent to buffer changes to
|
||||
* @param patterns the patterns to apply, in order
|
||||
*/
|
||||
public ExtentBufferedCompositePattern(Extent extent, Pattern... patterns) {
|
||||
super(extent);
|
||||
checkArgument(patterns.length != 0, "patterns cannot be empty");
|
||||
this.patterns = patterns;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock apply(BlockVector3 position) {
|
||||
BaseBlock lastBlock = null;
|
||||
for (Pattern pattern : patterns) {
|
||||
lastBlock = pattern.apply(position);
|
||||
try {
|
||||
getExtent().setBlock(position, lastBlock);
|
||||
} catch (WorldEditException ignored) { // buffer doesn't throw
|
||||
}
|
||||
}
|
||||
return lastBlock;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.function.pattern;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
|
||||
public interface ExtentPattern extends Pattern {
|
||||
|
||||
/**
|
||||
* Get the extent associated with this pattern.
|
||||
*
|
||||
* @return the extent for this pattern
|
||||
*/
|
||||
public Extent getExtent();
|
||||
}
|
@ -28,10 +28,9 @@ import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
/**
|
||||
* Returns the blocks from {@link Extent}, repeating when out of bounds.
|
||||
*/
|
||||
public class RepeatingExtentPattern extends AbstractPattern {
|
||||
public class RepeatingExtentPattern extends AbstractExtentPattern {
|
||||
|
||||
private final BlockVector3 size;
|
||||
private Extent extent;
|
||||
private BlockVector3 origin;
|
||||
private BlockVector3 offset;
|
||||
|
||||
@ -42,31 +41,12 @@ public class RepeatingExtentPattern extends AbstractPattern {
|
||||
* @param offset the offset
|
||||
*/
|
||||
public RepeatingExtentPattern(Extent extent, BlockVector3 origin, BlockVector3 offset) {
|
||||
setExtent(extent);
|
||||
super(extent);
|
||||
setOrigin(origin);
|
||||
setOffset(offset);
|
||||
size = extent.getMaximumPoint().subtract(extent.getMinimumPoint()).add(1, 1, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extent.
|
||||
*
|
||||
* @return the extent
|
||||
*/
|
||||
public Extent getExtent() {
|
||||
return extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the extent.
|
||||
*
|
||||
* @param extent the extent
|
||||
*/
|
||||
public void setExtent(Extent extent) {
|
||||
checkNotNull(extent);
|
||||
this.extent = extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the offset.
|
||||
*
|
||||
@ -111,7 +91,7 @@ public class RepeatingExtentPattern extends AbstractPattern {
|
||||
int x = Math.abs(base.getBlockX()) % size.getBlockX();
|
||||
int y = Math.abs(base.getBlockY()) % size.getBlockY();
|
||||
int z = Math.abs(base.getBlockZ()) % size.getBlockZ();
|
||||
return extent.getFullBlock(BlockVector3.at(x, y, z).add(origin));
|
||||
return getExtent().getFullBlock(BlockVector3.at(x, y, z).add(origin));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.function.pattern;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static com.sk89q.worldedit.blocks.Blocks.resolveProperties;
|
||||
|
||||
public class StateApplyingPattern extends AbstractExtentPattern {
|
||||
|
||||
private final Map<String, String> states;
|
||||
private Map<BlockType, Map<Property<Object>, Object>> cache = Maps.newHashMap();
|
||||
|
||||
public StateApplyingPattern(Extent extent, Map<String, String> statesToSet) {
|
||||
super(extent);
|
||||
this.states = statesToSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock apply(BlockVector3 position) {
|
||||
BlockState block = getExtent().getBlock(position);
|
||||
for (Entry<Property<Object>, Object> entry : cache
|
||||
.computeIfAbsent(block.getBlockType(), (b -> resolveProperties(states, b))).entrySet()) {
|
||||
block = block.with(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return block.toBaseBlock();
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.function.pattern;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Applies a block type while retaining all possible states.
|
||||
*/
|
||||
public class TypeApplyingPattern extends AbstractExtentPattern {
|
||||
private final BlockState blockState;
|
||||
|
||||
public TypeApplyingPattern(Extent extent, BlockState blockState) {
|
||||
super(extent);
|
||||
this.blockState = blockState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock apply(BlockVector3 position) {
|
||||
BlockState oldBlock = getExtent().getBlock(position);
|
||||
BlockState newBlock = blockState;
|
||||
for (Entry<Property<?>, Object> entry : oldBlock.getStates().entrySet()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Property<Object> prop = (Property<Object>) entry.getKey();
|
||||
newBlock = newBlock.with(prop, entry.getValue());
|
||||
}
|
||||
return newBlock.toBaseBlock();
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.function.pattern;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.registry.state.Property;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
/**
|
||||
* Removes the waterlogged state from blocks if possible. If not possible, returns air.
|
||||
*/
|
||||
public class WaterloggedRemover extends AbstractExtentPattern {
|
||||
|
||||
public WaterloggedRemover(Extent extent) {
|
||||
super(extent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock apply(BlockVector3 position) {
|
||||
BaseBlock block = getExtent().getFullBlock(position);
|
||||
@SuppressWarnings("unchecked")
|
||||
Property<Object> prop = (Property<Object>) block.getBlockType().getPropertyMap().getOrDefault("waterlogged", null);
|
||||
if (prop != null) {
|
||||
return block.with(prop, false);
|
||||
}
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
}
|
@ -32,8 +32,8 @@ public final class BlockCategories {
|
||||
public static final BlockCategory BIRCH_LOGS = register("minecraft:birch_logs");
|
||||
public static final BlockCategory BUTTONS = register("minecraft:buttons");
|
||||
public static final BlockCategory CARPETS = register("minecraft:carpets");
|
||||
public static final BlockCategory CORAL = register("minecraft:coral");
|
||||
public static final BlockCategory CORAL_PLANTS = register("minecraft:coral_plants");
|
||||
public static final BlockCategory CORALS = register("minecraft:corals");
|
||||
public static final BlockCategory CORAL_BLOCKS = register("minecraft:coral_blocks");
|
||||
public static final BlockCategory DARK_OAK_LOGS = register("minecraft:dark_oak_logs");
|
||||
public static final BlockCategory DOORS = register("minecraft:doors");
|
||||
public static final BlockCategory ENDERMAN_HOLDABLE = register("minecraft:enderman_holdable");
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren