Merge pull request #2526 from ZacSharp/buildSkipBlocks
Settings to alter block treatment while builing
This commit is contained in:
commit
ae901219fb
@ -206,6 +206,29 @@ public final class Settings {
|
|||||||
|
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of blocks to be treated as correct.
|
||||||
|
* <p>
|
||||||
|
* If a schematic asks for any block on this list at a certain position, it will be treated as correct, regardless of what it currently is.
|
||||||
|
*/
|
||||||
|
public final Setting<List<Block>> buildSkipBlocks = new Setting<>(new ArrayList<>(Arrays.asList(
|
||||||
|
|
||||||
|
)));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping of blocks to blocks treated as correct in their position
|
||||||
|
* <p>
|
||||||
|
* If a schematic asks for a block on this mapping, all blocks on the mapped list will be accepted at that location as well
|
||||||
|
*/
|
||||||
|
public final Setting<Map<Block, List<Block>>> buildValidSubstitutes = new Setting<>(new HashMap<>());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping of blocks to blocks to be built instead
|
||||||
|
* <p>
|
||||||
|
* If a schematic asks for a block on this mapping, Baritone will place the first placeable block in the mapped list
|
||||||
|
*/
|
||||||
|
public final Setting<Map<Block, List<Block>>> buildSubstitutes = new Setting<>(new HashMap<>());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of blocks to become air
|
* A list of blocks to become air
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -19,7 +19,6 @@ package baritone.api.schematic;
|
|||||||
|
|
||||||
import baritone.api.utils.BlockOptionalMeta;
|
import baritone.api.utils.BlockOptionalMeta;
|
||||||
import net.minecraft.block.state.IBlockState;
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.init.Blocks;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -44,8 +43,6 @@ public class FillSchematic extends AbstractSchematic {
|
|||||||
public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) {
|
public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) {
|
||||||
if (bom.matches(current)) {
|
if (bom.matches(current)) {
|
||||||
return current;
|
return current;
|
||||||
} else if (current.getBlock() != Blocks.AIR) {
|
|
||||||
return Blocks.AIR.getDefaultState();
|
|
||||||
}
|
}
|
||||||
for (IBlockState placeable : approxPlaceable) {
|
for (IBlockState placeable : approxPlaceable) {
|
||||||
if (bom.matches(placeable)) {
|
if (bom.matches(placeable)) {
|
||||||
|
89
src/api/java/baritone/api/schematic/SubstituteSchematic.java
Normal file
89
src/api/java/baritone/api/schematic/SubstituteSchematic.java
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Baritone.
|
||||||
|
*
|
||||||
|
* Baritone 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.
|
||||||
|
*
|
||||||
|
* Baritone 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 Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package baritone.api.schematic;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockAir;
|
||||||
|
import net.minecraft.block.properties.IProperty;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.init.Blocks;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SubstituteSchematic extends AbstractSchematic {
|
||||||
|
|
||||||
|
private final ISchematic schematic;
|
||||||
|
private final Map<Block, List<Block>> substitutions;
|
||||||
|
private final Map<IBlockState, Map<Block, IBlockState>> blockStateCache = new HashMap<>();
|
||||||
|
|
||||||
|
public SubstituteSchematic(ISchematic schematic, Map<Block,List<Block>> substitutions) {
|
||||||
|
super(schematic.widthX(), schematic.heightY(), schematic.lengthZ());
|
||||||
|
this.schematic = schematic;
|
||||||
|
this.substitutions = substitutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean inSchematic(int x, int y, int z, IBlockState currentState) {
|
||||||
|
return schematic.inSchematic(x, y, z, currentState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) {
|
||||||
|
IBlockState desired = schematic.desiredState(x, y, z, current, approxPlaceable);
|
||||||
|
Block desiredBlock = desired.getBlock();
|
||||||
|
if (!substitutions.containsKey(desiredBlock)) {
|
||||||
|
return desired;
|
||||||
|
}
|
||||||
|
List<Block> substitutes = substitutions.get(desiredBlock);
|
||||||
|
if (substitutes.contains(current.getBlock()) && !(current.getBlock() instanceof BlockAir)) {// don't preserve air, it's almost always there and almost never wanted
|
||||||
|
return withBlock(desired, current.getBlock());
|
||||||
|
}
|
||||||
|
for (Block substitute : substitutes) {
|
||||||
|
if (substitute instanceof BlockAir) {
|
||||||
|
return current.getBlock() instanceof BlockAir ? current : Blocks.AIR.getDefaultState(); // can always "place" air
|
||||||
|
}
|
||||||
|
for (IBlockState placeable : approxPlaceable) {
|
||||||
|
if (substitute.equals(placeable.getBlock())) {
|
||||||
|
return withBlock(desired, placeable.getBlock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return substitutes.get(0).getDefaultState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBlockState withBlock(IBlockState state, Block block) {
|
||||||
|
if (blockStateCache.containsKey(state) && blockStateCache.get(state).containsKey(block)) {
|
||||||
|
return blockStateCache.get(state).get(block);
|
||||||
|
}
|
||||||
|
Collection<IProperty<?>> properties = state.getPropertyKeys();
|
||||||
|
IBlockState newState = block.getDefaultState();
|
||||||
|
for (IProperty<?> property : properties) {
|
||||||
|
try {
|
||||||
|
newState = copySingleProp(state, newState, property);
|
||||||
|
} catch (IllegalArgumentException e) { //property does not exist for target block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockStateCache.computeIfAbsent(state, s -> new HashMap<Block,IBlockState>()).put(block, newState);
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
private <T extends Comparable<T>> IBlockState copySingleProp(IBlockState fromState, IBlockState toState, IProperty<T> prop) {
|
||||||
|
return toState.withProperty(prop, fromState.getValue(prop));
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,7 @@ import java.nio.file.NoSuchFileException;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@ -261,6 +262,36 @@ public class SettingsUtil {
|
|||||||
public boolean accepts(Type type) {
|
public boolean accepts(Type type) {
|
||||||
return List.class.isAssignableFrom(TypeUtils.resolveBaseClass(type));
|
return List.class.isAssignableFrom(TypeUtils.resolveBaseClass(type));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
MAPPING() {
|
||||||
|
@Override
|
||||||
|
public Object parse(ParserContext context, String raw) {
|
||||||
|
Type keyType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
|
||||||
|
Type valueType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[1];
|
||||||
|
Parser keyParser = Parser.getParser(keyType);
|
||||||
|
Parser valueParser = Parser.getParser(valueType);
|
||||||
|
|
||||||
|
return Stream.of(raw.split(",(?=[^,]*->)"))
|
||||||
|
.map(s -> s.split("->"))
|
||||||
|
.collect(Collectors.toMap(s -> keyParser.parse(context, s[0]), s -> valueParser.parse(context, s[1])));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(ParserContext context, Object value) {
|
||||||
|
Type keyType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
|
||||||
|
Type valueType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[1];
|
||||||
|
Parser keyParser = Parser.getParser(keyType);
|
||||||
|
Parser valueParser = Parser.getParser(valueType);
|
||||||
|
|
||||||
|
return ((Map<?,?>) value).entrySet().stream()
|
||||||
|
.map(o -> keyParser.toString(context, o.getKey()) + "->" + valueParser.toString(context, o.getValue()))
|
||||||
|
.collect(Collectors.joining(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accepts(Type type) {
|
||||||
|
return Map.class.isAssignableFrom(TypeUtils.resolveBaseClass(type));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Class<?> cla$$;
|
private final Class<?> cla$$;
|
||||||
|
@ -26,6 +26,7 @@ import baritone.api.process.IBuilderProcess;
|
|||||||
import baritone.api.process.PathingCommand;
|
import baritone.api.process.PathingCommand;
|
||||||
import baritone.api.process.PathingCommandType;
|
import baritone.api.process.PathingCommandType;
|
||||||
import baritone.api.schematic.FillSchematic;
|
import baritone.api.schematic.FillSchematic;
|
||||||
|
import baritone.api.schematic.SubstituteSchematic;
|
||||||
import baritone.api.schematic.ISchematic;
|
import baritone.api.schematic.ISchematic;
|
||||||
import baritone.api.schematic.IStaticSchematic;
|
import baritone.api.schematic.IStaticSchematic;
|
||||||
import baritone.api.schematic.format.ISchematicFormat;
|
import baritone.api.schematic.format.ISchematicFormat;
|
||||||
@ -85,6 +86,9 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
this.schematic = schematic;
|
this.schematic = schematic;
|
||||||
this.realSchematic = null;
|
this.realSchematic = null;
|
||||||
|
if (!Baritone.settings().buildSubstitutes.value.isEmpty()) {
|
||||||
|
this.schematic = new SubstituteSchematic(this.schematic, Baritone.settings().buildSubstitutes.value);
|
||||||
|
}
|
||||||
int x = origin.getX();
|
int x = origin.getX();
|
||||||
int y = origin.getY();
|
int y = origin.getY();
|
||||||
int z = origin.getZ();
|
int z = origin.getZ();
|
||||||
@ -588,7 +592,8 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// this is not in render distance
|
// this is not in render distance
|
||||||
if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ))) {
|
if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ))
|
||||||
|
&& !Baritone.settings().buildSkipBlocks.value.contains(schematic.desiredState(x, y, z, current, this.approxPlaceable).getBlock())) {
|
||||||
// and we've never seen this position be correct
|
// and we've never seen this position be correct
|
||||||
// therefore mark as incorrect
|
// therefore mark as incorrect
|
||||||
incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ));
|
incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ));
|
||||||
@ -833,6 +838,12 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
|||||||
if (!(current.getBlock() instanceof BlockAir) && Baritone.settings().buildIgnoreExisting.value && !itemVerify) {
|
if (!(current.getBlock() instanceof BlockAir) && Baritone.settings().buildIgnoreExisting.value && !itemVerify) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (Baritone.settings().buildSkipBlocks.value.contains(desired.getBlock()) && !itemVerify) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Baritone.settings().buildValidSubstitutes.value.getOrDefault(desired.getBlock(), Collections.emptyList()).contains(current.getBlock()) && !itemVerify) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return current.equals(desired);
|
return current.equals(desired);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -870,7 +881,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
|||||||
return COST_INF;
|
return COST_INF;
|
||||||
}
|
}
|
||||||
IBlockState sch = getSchematic(x, y, z, current);
|
IBlockState sch = getSchematic(x, y, z, current);
|
||||||
if (sch != null) {
|
if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) {
|
||||||
// TODO this can return true even when allowPlace is off.... is that an issue?
|
// TODO this can return true even when allowPlace is off.... is that an issue?
|
||||||
if (sch.getBlock() == Blocks.AIR) {
|
if (sch.getBlock() == Blocks.AIR) {
|
||||||
// we want this to be air, but they're asking if they can place here
|
// we want this to be air, but they're asking if they can place here
|
||||||
@ -904,7 +915,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
|||||||
return COST_INF;
|
return COST_INF;
|
||||||
}
|
}
|
||||||
IBlockState sch = getSchematic(x, y, z, current);
|
IBlockState sch = getSchematic(x, y, z, current);
|
||||||
if (sch != null) {
|
if (sch != null && !Baritone.settings().buildSkipBlocks.value.contains(sch.getBlock())) {
|
||||||
if (sch.getBlock() == Blocks.AIR) {
|
if (sch.getBlock() == Blocks.AIR) {
|
||||||
// it should be air
|
// it should be air
|
||||||
// regardless of current contents, we can break it
|
// regardless of current contents, we can break it
|
||||||
|
Loading…
x
Reference in New Issue
Block a user