From 7d74a65ec08ee9f71f694a46caf44e2cee520a8d Mon Sep 17 00:00:00 2001 From: Glease <4586901+Glease@users.noreply.github.com> Date: Tue, 13 Sep 2022 21:22:34 +0800 Subject: [PATCH] expose what blocks this element might place --- .../structure/IStructureElement.java | 129 +++- .../structure/IStructureElementChain.java | 20 + .../structure/LazyStructureElement.java | 8 + .../structure/StructureUtility.java | 689 ++++++------------ 4 files changed, 358 insertions(+), 488 deletions(-) diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElement.java b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElement.java index d6102667..06f34c76 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElement.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElement.java @@ -4,10 +4,18 @@ import static com.gtnewhorizon.structurelib.StructureLib.LOGGER; import static com.gtnewhorizon.structurelib.StructureLib.PANIC_MODE; import com.gtnewhorizon.structurelib.StructureLibAPI; +import com.gtnewhorizon.structurelib.util.ItemStackPredicate; +import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode; +import java.util.Arrays; +import java.util.Collections; import java.util.function.Consumer; +import java.util.function.Predicate; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.IChatComponent; import net.minecraft.world.World; @@ -58,6 +66,30 @@ public interface IStructureElement { return PlaceResult.SKIP; } + /** + * A simplified version of survivalPlaceBlock. Return null if not implemented. + *

+ * BY OVERRIDING THIS TO NULL, YOU ACKNOWLEDGE THAT THE {@link #check(Object, World, int, int, int)} OF THIS + * CLASS IS SIDE EFFECT FREE AND CAN HAVE ITS CHECK CALLED WITHOUT BREAKING ANYTHING. OTHERWISE OVERRIDE THE + * {@link #survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)} TO PROVIDE A SIDEEFFECT + * FREE {@link PlaceResult#SKIP}. + *

+ * It should be noticed that this filter is only advisory and the actual {@link #survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)} + * or {@link #check(Object, World, int, int, int)} are free to reject/accept/place blocks not contained in this list, + * e.g. when the element can be placed anywhere in the structure, but no more than 3 overall; when the structure + * element cannot know all blocks it will accept at the time of calling; when this is backed by a legacy + * {@link IStructureElement} that just didn't implement this API. + * + * @param trigger trigger item + * @param env autoplacing environment + * @return null if not implemented, otherwise an instance describing what kind of blocks will be placed by {@link #survivalPlaceBlock(Object, World, int, int, int, ItemStack, AutoPlaceEnvironment)} + */ + @Nullable + default BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return null; + } + /** * Try place the block by taking resource from given IItemSource. *

@@ -69,10 +101,26 @@ public interface IStructureElement { */ default PlaceResult survivalPlaceBlock( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + BlocksToPlace e = getBlocksToPlace(t, world, x, y, z, trigger, env); + IItemSource source = env.getSource(); EntityPlayer actor = env.getActor(); + Consumer chatter = env.getChatter(); + if (e != null) { + if (check(t, world, x, y, z)) return PlaceResult.SKIP; + if (e.getStacks() == null) { + ItemStack taken = source.takeOne(e.getPredicate(), true); + return StructureUtility.survivalPlaceBlock( + taken, NBTMode.EXACT, taken.stackTagCompound, true, world, x, y, z, source, actor, chatter); + } + for (ItemStack stack : e.getStacks()) { + if (!source.takeOne(stack, true)) continue; + return StructureUtility.survivalPlaceBlock( + stack, NBTMode.EXACT, stack.stackTagCompound, true, world, x, y, z, source, actor, chatter); + } + return PlaceResult.REJECT; + } if (actor instanceof EntityPlayerMP) - return survivalPlaceBlock( - t, world, x, y, z, trigger, env.getSource(), (EntityPlayerMP) actor, env.getChatter()); + return survivalPlaceBlock(t, world, x, y, z, trigger, source, (EntityPlayerMP) actor, chatter); if (PANIC_MODE) throw new RuntimeException("Panic Tripwire hit"); if (StructureLibAPI.isDebugEnabled()) LOGGER.info( @@ -154,4 +202,81 @@ public interface IStructureElement { */ ACCEPT_STOP; } + + final class BlocksToPlace { + public static final BlocksToPlace errored = createEmpty(); + private final Predicate predicate; + private final Iterable stacks; + + public static BlocksToPlace createEmpty() { + return new BlocksToPlace(s -> false, Collections.emptyList()); + } + + public static BlocksToPlace create(ItemStack... stacks) { + return create(Arrays.asList(stacks)); + } + + public static BlocksToPlace create(Iterable stacks) { + Predicate predicate = null; + + for (ItemStack stack : stacks) { + ItemStackPredicate p = ItemStackPredicate.from(stack, NBTMode.EXACT); + if (predicate == null) predicate = p; + else predicate = predicate.or(p); + } + + return new BlocksToPlace(predicate, stacks); + } + + public static BlocksToPlace create(Block block, int meta) { + Item itemBlock = Item.getItemFromBlock(block); + if (itemBlock instanceof ISpecialItemBlock) { + meta = ((ISpecialItemBlock) itemBlock).getItemMetaFromBlockMeta(block, meta); + } + return create(itemBlock, meta); + } + + public static BlocksToPlace create(Item item, int meta) { + return new BlocksToPlace( + ItemStackPredicate.from(item).setMeta(meta), + Collections.singletonList(new ItemStack(item, 1, meta))); + } + + public static BlocksToPlace create(ItemStack itemStack) { + return new BlocksToPlace(ItemStackPredicate.from(itemStack), Collections.singletonList(itemStack)); + } + + public static BlocksToPlace create(Predicate predicate) { + return new BlocksToPlace(predicate, null); + } + + BlocksToPlace(Predicate predicate, Iterable stacks) { + this.predicate = predicate; + this.stacks = stacks; + } + + /** + * Get the blocks to place filter. This is usually slower as it requires walking through inventories one by one. + *

+ * Suitable for use with {@link IItemSource#takeOne(Predicate, boolean)} + * @return a predicate. never null. + */ + @Nonnull + public Predicate getPredicate() { + return predicate; + } + + /** + * Get the ItemStacks that this one is known to accept. Can be null if this info is not available at the time + * this instance is constructed. + *

+ * Suitable for use with {@link IItemSource#takeOne(ItemStack, boolean)}. + *

+ * This should be equivalent to the predicate returned from {@link #getPredicate()} + */ + @Nullable + public Iterable getStacks() { + return stacks; + } + } } diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementChain.java b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementChain.java index 3cd05b6a..fe58b7e4 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementChain.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/IStructureElementChain.java @@ -1,8 +1,11 @@ package com.gtnewhorizon.structurelib.structure; +import com.google.common.collect.Iterables; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; +import java.util.function.Predicate; +import javax.annotation.Nullable; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.util.IChatComponent; @@ -44,6 +47,23 @@ public interface IStructureElementChain extends IStructureElement { return false; } + @Nullable + @Override + default BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + Predicate predicate = null; + List> is = new ArrayList<>(); + for (IStructureElement fallback : fallbacks()) { + BlocksToPlace e = fallback.getBlocksToPlace(t, world, x, y, z, trigger, env); + if (e == null) continue; + if (predicate == null) predicate = e.getPredicate(); + else predicate = predicate.or(e.getPredicate()); + is.add(e.getStacks()); + } + if (predicate == null) return null; + return new BlocksToPlace(predicate, Iterables.concat(is)); + } + @Override default PlaceResult survivalPlaceBlock( T t, diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/LazyStructureElement.java b/src/main/java/com/gtnewhorizon/structurelib/structure/LazyStructureElement.java index 907f74ac..8cb1bacc 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/LazyStructureElement.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/LazyStructureElement.java @@ -2,6 +2,7 @@ package com.gtnewhorizon.structurelib.structure; import java.util.function.Consumer; import java.util.function.Function; +import javax.annotation.Nullable; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.util.IChatComponent; @@ -38,6 +39,13 @@ class LazyStructureElement implements IStructureElementDeferred { return get(t).spawnHint(t, world, x, y, z, trigger); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return get(t).getBlocksToPlace(t, world, x, y, z, trigger, env); + } + @Override public PlaceResult survivalPlaceBlock( T t, diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/StructureUtility.java b/src/main/java/com/gtnewhorizon/structurelib/structure/StructureUtility.java index 0992e8a7..84cef049 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/structure/StructureUtility.java +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/StructureUtility.java @@ -2,6 +2,7 @@ package com.gtnewhorizon.structurelib.structure; import static java.lang.Integer.MIN_VALUE; +import com.google.common.collect.ImmutableList; import com.gtnewhorizon.structurelib.StructureLib; import com.gtnewhorizon.structurelib.StructureLibAPI; import com.gtnewhorizon.structurelib.alignment.constructable.ChannelDataAccessor; @@ -9,10 +10,12 @@ import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; import com.gtnewhorizon.structurelib.structure.IStructureElement.PlaceResult; import com.gtnewhorizon.structurelib.structure.adders.IBlockAdder; import com.gtnewhorizon.structurelib.structure.adders.ITileAdder; +import com.gtnewhorizon.structurelib.util.ItemStackPredicate; import com.gtnewhorizon.structurelib.util.ItemStackPredicate.NBTMode; import com.gtnewhorizon.structurelib.util.Vec3Impl; import cpw.mods.fml.common.registry.GameRegistry; import java.util.*; +import java.util.Map.Entry; import java.util.function.*; import javax.annotation.Nullable; import net.minecraft.block.Block; @@ -128,7 +131,7 @@ public class StructureUtility { private static final Map STEP = new HashMap<>(); @SuppressWarnings("rawtypes") - private static final IStructureElement AIR = new IStructureElement() { + private static final IStructureElement AIR = new StructureElement_Bridge() { @Override public boolean check(Object t, World world, int x, int y, int z) { return world.isAirBlock(x, y, z); @@ -149,24 +152,16 @@ public class StructureUtility { @Override @Deprecated public PlaceResult survivalPlaceBlock( - Object o, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { + Object o, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { if (check(o, world, x, y, z)) return PlaceResult.SKIP; - if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) return PlaceResult.REJECT; + if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, env.getActor())) return PlaceResult.REJECT; world.setBlock(x, y, z, Blocks.air, 0, 2); return PlaceResult.ACCEPT; } }; @SuppressWarnings("rawtypes") - private static final IStructureElement NOT_AIR = new IStructureElement() { + private static final IStructureElement NOT_AIR = new StructureElement_Bridge() { @Override public boolean check(Object t, World world, int x, int y, int z) { return !world.isAirBlock(x, y, z); @@ -184,21 +179,19 @@ public class StructureUtility { return true; } + @Override + public BlocksToPlace getBlocksToPlace( + Object o, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return BlocksToPlace.create(Objects::nonNull); + } + @Override public PlaceResult survivalPlaceBlock( - Object o, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { + Object o, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { if (check(o, world, x, y, z)) return PlaceResult.SKIP; // user should place anything here. // maybe make this configurable, but for now we try to take some cobble from user - if (s.takeOne(new ItemStack(Blocks.cobblestone), false)) { + if (env.getSource().takeOne(new ItemStack(Blocks.cobblestone), false)) { world.setBlock(x, y, z, Blocks.cobblestone, 0, 2); } return PlaceResult.REJECT; @@ -206,7 +199,7 @@ public class StructureUtility { }; @SuppressWarnings("rawtypes") - private static final IStructureElement ERROR = new IStructureElement() { + private static final IStructureElement ERROR = new StructureElement_Bridge() { @Override public boolean check(Object t, World world, int x, int y, int z) { return false; @@ -225,15 +218,7 @@ public class StructureUtility { @Override public PlaceResult survivalPlaceBlock( - Object o, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { + Object o, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { return PlaceResult.REJECT; } }; @@ -723,6 +708,14 @@ public class StructureUtility { return true; } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + Pair hint = getHint(trigger); + return BlocksToPlace.create(hint.getKey(), hint.getValue()); + } + @Override public PlaceResult survivalPlaceBlock( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { @@ -802,6 +795,14 @@ public class StructureUtility { return true; } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + if (getBlock() == null) return error().getBlocksToPlace(t, world, x, y, z, trigger, env); + return BlocksToPlace.create(getBlock(), meta); + } + @Override public PlaceResult survivalPlaceBlock( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { @@ -864,6 +865,14 @@ public class StructureUtility { } else return fallback.placeBlock(t, world, x, y, z, trigger); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + if (init()) return BlocksToPlace.create(block, meta); + return fallback.getBlocksToPlace(t, world, x, y, z, trigger, env); + } + @Override @Deprecated public PlaceResult survivalPlaceBlock( @@ -1031,7 +1040,9 @@ public class StructureUtility { throw new IllegalArgumentException(); } if (defaultBlock instanceof ICustomBlockSetting) { - return new StructureElement_Bridge() { + return new IStructureElement() { + private BlocksToPlace blocksToPlace; + @Override public boolean check(T t, World world, int x, int y, int z) { Block worldBlock = world.getBlock(x, y, z); @@ -1050,25 +1061,31 @@ public class StructureUtility { return true; } + @Nullable @Override - @Deprecated - public PlaceResult survivalPlaceBlock( + public BlocksToPlace getBlocksToPlace( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - if (check(t, world, x, y, z)) return PlaceResult.SKIP; - return StructureUtility.survivalPlaceBlock( - defaultBlock, - defaultMeta, - world, - x, - y, - z, - env.getSource(), - env.getActor(), - env.getChatter()); + if (blocksToPlace == null) { + ImmutableList.Builder blocks = ImmutableList.builder(); + Predicate predicate = s -> true; + for (Entry e : blocsMap.entrySet()) { + Item i = Item.getItemFromBlock(e.getKey()); + int meta = e.getValue(); + if (i instanceof ISpecialItemBlock) + meta = ((ISpecialItemBlock) i).getItemMetaFromBlockMeta(e.getKey(), meta); + ItemStack stack = new ItemStack(i, 1, meta); + blocks.add(stack); + predicate = predicate.and(ItemStackPredicate.from(stack)); + } + blocksToPlace = new BlocksToPlace(predicate, blocks.build()); + } + return blocksToPlace; } }; } else { - return new StructureElement_Bridge() { + return new IStructureElement() { + private BlocksToPlace blocksToPlace; + @Override public boolean check(T t, World world, int x, int y, int z) { Block worldBlock = world.getBlock(x, y, z); @@ -1088,20 +1105,23 @@ public class StructureUtility { } @Override - @Deprecated - public PlaceResult survivalPlaceBlock( + public BlocksToPlace getBlocksToPlace( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - if (check(t, world, x, y, z)) return PlaceResult.SKIP; - return StructureUtility.survivalPlaceBlock( - defaultBlock, - defaultMeta, - world, - x, - y, - z, - env.getSource(), - env.getActor(), - env.getChatter()); + if (blocksToPlace == null) { + ImmutableList.Builder blocks = ImmutableList.builder(); + Predicate predicate = s -> true; + for (Entry e : blocsMap.entrySet()) { + Item i = Item.getItemFromBlock(e.getKey()); + int meta = e.getValue(); + if (i instanceof ISpecialItemBlock) + meta = ((ISpecialItemBlock) i).getItemMetaFromBlockMeta(e.getKey(), meta); + ItemStack stack = new ItemStack(i, 1, meta); + blocks.add(stack); + predicate = predicate.and(ItemStackPredicate.from(stack)); + } + blocksToPlace = new BlocksToPlace(predicate, blocks.build()); + } + return blocksToPlace; } }; } @@ -1126,7 +1146,9 @@ public class StructureUtility { } } if (defaultBlock instanceof ICustomBlockSetting) { - return new StructureElement_Bridge() { + return new IStructureElement() { + private BlocksToPlace blocksToPlace; + @Override public boolean check(T t, World world, int x, int y, int z) { Block worldBlock = world.getBlock(x, y, z); @@ -1147,24 +1169,30 @@ public class StructureUtility { } @Override - @Deprecated - public PlaceResult survivalPlaceBlock( + public BlocksToPlace getBlocksToPlace( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - if (check(t, world, x, y, z)) return PlaceResult.SKIP; - return StructureUtility.survivalPlaceBlock( - defaultBlock, - defaultMeta, - world, - x, - y, - z, - env.getSource(), - env.getActor(), - env.getChatter()); + if (blocksToPlace == null) { + ImmutableList.Builder blocks = ImmutableList.builder(); + Predicate predicate = s -> true; + for (Entry> e : blocsMap.entrySet()) { + Item i = Item.getItemFromBlock(e.getKey()); + for (int meta : e.getValue()) { + if (i instanceof ISpecialItemBlock) + meta = ((ISpecialItemBlock) i).getItemMetaFromBlockMeta(e.getKey(), meta); + ItemStack stack = new ItemStack(i, 1, meta); + blocks.add(stack); + predicate = predicate.and(ItemStackPredicate.from(stack)); + } + } + blocksToPlace = new BlocksToPlace(predicate, blocks.build()); + } + return blocksToPlace; } }; } else { - return new StructureElement_Bridge() { + return new IStructureElement() { + private BlocksToPlace blocksToPlace; + @Override public boolean check(T t, World world, int x, int y, int z) { Block worldBlock = world.getBlock(x, y, z); @@ -1185,20 +1213,24 @@ public class StructureUtility { } @Override - @Deprecated - public PlaceResult survivalPlaceBlock( + public BlocksToPlace getBlocksToPlace( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - if (check(t, world, x, y, z)) return PlaceResult.SKIP; - return StructureUtility.survivalPlaceBlock( - defaultBlock, - defaultMeta, - world, - x, - y, - z, - env.getSource(), - env.getActor(), - env.getChatter()); + if (blocksToPlace == null) { + ImmutableList.Builder blocks = ImmutableList.builder(); + Predicate predicate = s -> true; + for (Entry> e : blocsMap.entrySet()) { + Item i = Item.getItemFromBlock(e.getKey()); + for (int meta : e.getValue()) { + if (i instanceof ISpecialItemBlock) + meta = ((ISpecialItemBlock) i).getItemMetaFromBlockMeta(e.getKey(), meta); + ItemStack stack = new ItemStack(i, 1, meta); + blocks.add(stack); + predicate = predicate.and(ItemStackPredicate.from(stack)); + } + } + blocksToPlace = new BlocksToPlace(predicate, blocks.build()); + } + return blocksToPlace; } }; } @@ -1217,7 +1249,7 @@ public class StructureUtility { throw new IllegalArgumentException(); } if (block instanceof ICustomBlockSetting) { - return new StructureElement_Bridge() { + return new IStructureElement() { @Override public boolean check(T t, World world, int x, int y, int z) { Block worldBlock = world.getBlock(x, y, z); @@ -1237,24 +1269,13 @@ public class StructureUtility { } @Override - @Deprecated - public PlaceResult survivalPlaceBlock( + public BlocksToPlace getBlocksToPlace( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - if (check(t, world, x, y, z)) return PlaceResult.SKIP; - return StructureUtility.survivalPlaceBlock( - defaultBlock, - defaultMeta, - world, - x, - y, - z, - env.getSource(), - env.getActor(), - env.getChatter()); + return BlocksToPlace.create(block, meta); } }; } else { - return new StructureElement_Bridge() { + return new IStructureElement() { @Override public boolean check(T t, World world, int x, int y, int z) { Block worldBlock = world.getBlock(x, y, z); @@ -1274,20 +1295,9 @@ public class StructureUtility { } @Override - @Deprecated - public PlaceResult survivalPlaceBlock( + public BlocksToPlace getBlocksToPlace( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - if (check(t, world, x, y, z)) return PlaceResult.SKIP; - return StructureUtility.survivalPlaceBlock( - defaultBlock, - defaultMeta, - world, - x, - y, - z, - env.getSource(), - env.getActor(), - env.getChatter()); + return BlocksToPlace.create(block, meta); } }; } @@ -1301,7 +1311,7 @@ public class StructureUtility { throw new IllegalArgumentException(); } if (block instanceof ICustomBlockSetting) { - return new StructureElement_Bridge() { + return new IStructureElement() { @Override public boolean check(T t, World world, int x, int y, int z) { return block == world.getBlock(x, y, z); @@ -1320,24 +1330,14 @@ public class StructureUtility { } @Override - @Deprecated - public PlaceResult survivalPlaceBlock( + public BlocksToPlace getBlocksToPlace( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - if (check(t, world, x, y, z)) return PlaceResult.SKIP; - return StructureUtility.survivalPlaceBlock( - defaultBlock, - defaultMeta, - world, - x, - y, - z, - env.getSource(), - env.getActor(), - env.getChatter()); + // there is getSubItems on ItemBlock, but it's client only + return BlocksToPlace.create(defaultBlock, defaultMeta); } }; } else { - return new StructureElement_Bridge() { + return new IStructureElement() { @Override public boolean check(T t, World world, int x, int y, int z) { return block == world.getBlock(x, y, z); @@ -1356,20 +1356,10 @@ public class StructureUtility { } @Override - @Deprecated - public PlaceResult survivalPlaceBlock( + public BlocksToPlace getBlocksToPlace( T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - if (check(t, world, x, y, z)) return PlaceResult.SKIP; - return StructureUtility.survivalPlaceBlock( - defaultBlock, - defaultMeta, - world, - x, - y, - z, - env.getSource(), - env.getActor(), - env.getChatter()); + // there is getSubItems on ItemBlock, but it's client only + return BlocksToPlace.create(defaultBlock, defaultMeta); } }; } @@ -1577,6 +1567,13 @@ public class StructureUtility { return element.spawnHint(t, world, x, y, z, trigger); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return element.getBlocksToPlace(t, world, x, y, z, trigger, env); + } + @Override @Deprecated public PlaceResult survivalPlaceBlock( @@ -1628,6 +1625,13 @@ public class StructureUtility { return element.spawnHint(t, world, x, y, z, trigger); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return element.getBlocksToPlace(t, world, x, y, z, trigger, env); + } + @Override @Deprecated public PlaceResult survivalPlaceBlock( @@ -1688,6 +1692,14 @@ public class StructureUtility { return predicate.test(t) && downstream.placeBlock(t, world, x, y, z, trigger); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + if (predicate.test(t)) return downstream.getBlocksToPlace(t, world, x, y, z, trigger, env); + return BlocksToPlace.createEmpty(); + } + @Override @Deprecated public PlaceResult survivalPlaceBlock( @@ -1784,6 +1796,13 @@ public class StructureUtility { return elem.placeBlock(t.getCurrentContext(), world, x, y, z, trigger); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return elem.getBlocksToPlace(t.getCurrentContext(), world, x, y, z, trigger, env); + } + @Override @Deprecated public PlaceResult survivalPlaceBlock( @@ -1873,6 +1892,13 @@ public class StructureUtility { return to.get().spawnHint(t, world, x, y, z, trigger); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return to.get().getBlocksToPlace(t, world, x, y, z, trigger, env); + } + @Override @Deprecated public PlaceResult survivalPlaceBlock( @@ -1927,6 +1953,13 @@ public class StructureUtility { return to.apply(t).spawnHint(t, world, x, y, z, trigger); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return to.apply(t).getBlocksToPlace(t, world, x, y, z, trigger, env); + } + @Override public PlaceResult survivalPlaceBlock( T t, @@ -1983,42 +2016,7 @@ public class StructureUtility { if (keyExtractor == null || map == null) { throw new IllegalArgumentException(); } - return new IStructureElementDeferred() { - @Override - public boolean check(T t, World world, int x, int y, int z) { - return map.get(keyExtractor.apply(t)).check(t, world, x, y, z); - } - - @Override - public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.get(keyExtractor.apply(t)).placeBlock(t, world, x, y, z, trigger); - } - - @Override - public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.get(keyExtractor.apply(t)).spawnHint(t, world, x, y, z, trigger); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { - return map.get(keyExtractor.apply(t)).survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - return map.get(keyExtractor.apply(t)).survivalPlaceBlock(t, world, x, y, z, trigger, env); - } - }; + return defer(keyExtractor.andThen(map::get)); } /** @@ -2061,44 +2059,7 @@ public class StructureUtility { if (keyExtractor == null || map == null) { throw new IllegalArgumentException(); } - return new IStructureElementDeferred() { - @Override - public boolean check(T t, World world, int x, int y, int z) { - return map.getOrDefault(keyExtractor.apply(t), defaultElem).check(t, world, x, y, z); - } - - @Override - public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.getOrDefault(keyExtractor.apply(t), defaultElem).placeBlock(t, world, x, y, z, trigger); - } - - @Override - public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.getOrDefault(keyExtractor.apply(t), defaultElem).spawnHint(t, world, x, y, z, trigger); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { - return map.getOrDefault(keyExtractor.apply(t), defaultElem) - .survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - return map.getOrDefault(keyExtractor.apply(t), defaultElem) - .survivalPlaceBlock(t, world, x, y, z, trigger, env); - } - }; + return defer(keyExtractor.andThen(key -> map.getOrDefault(key, defaultElem))); } /** @@ -2139,42 +2100,7 @@ public class StructureUtility { if (keyExtractor == null || array == null) { throw new IllegalArgumentException(); } - return new IStructureElementDeferred() { - @Override - public boolean check(T t, World world, int x, int y, int z) { - return array[keyExtractor.apply(t)].check(t, world, x, y, z); - } - - @Override - public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { - return array[keyExtractor.apply(t)].placeBlock(t, world, x, y, z, trigger); - } - - @Override - public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { - return array[keyExtractor.apply(t)].spawnHint(t, world, x, y, z, trigger); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { - return array[keyExtractor.apply(t)].survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - return array[keyExtractor.apply(t)].survivalPlaceBlock(t, world, x, y, z, trigger, env); - } - }; + return defer(keyExtractor.andThen(i -> array[i])); } /** @@ -2247,6 +2173,13 @@ public class StructureUtility { return to.apply(t, trigger).spawnHint(t, world, x, y, z, trigger); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return to.apply(t, trigger).getBlocksToPlace(t, world, x, y, z, trigger, env); + } + @Override public PlaceResult survivalPlaceBlock( T t, @@ -2311,43 +2244,7 @@ public class StructureUtility { if (keyExtractor == null || map == null) { throw new IllegalArgumentException(); } - return new IStructureElementDeferred() { - @Override - public boolean check(T t, World world, int x, int y, int z) { - return map.get(keyExtractor.apply(t, null)).check(t, world, x, y, z); - } - - @Override - public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.get(keyExtractor.apply(t, trigger)).placeBlock(t, world, x, y, z, trigger); - } - - @Override - public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.get(keyExtractor.apply(t, trigger)).spawnHint(t, world, x, y, z, trigger); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { - return map.get(keyExtractor.apply(t, trigger)) - .survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - return map.get(keyExtractor.apply(t, trigger)).survivalPlaceBlock(t, world, x, y, z, trigger, env); - } - }; + return defer(keyExtractor.andThen(map::get)); } /** @@ -2398,47 +2295,7 @@ public class StructureUtility { if (keyExtractor == null || map == null) { throw new IllegalArgumentException(); } - return new IStructureElementDeferred() { - @Override - public boolean check(T t, World world, int x, int y, int z) { - return map.getOrDefault(keyExtractor.apply(t, null), defaultElem) - .check(t, world, x, y, z); - } - - @Override - public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem) - .placeBlock(t, world, x, y, z, trigger); - } - - @Override - public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem) - .spawnHint(t, world, x, y, z, trigger); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { - return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem) - .survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem) - .survivalPlaceBlock(t, world, x, y, z, trigger, env); - } - }; + return defer(keyExtractor.andThen(key -> map.getOrDefault(key, defaultElem))); } /** @@ -2461,43 +2318,7 @@ public class StructureUtility { if (keyExtractor == null || array == null) { throw new IllegalArgumentException(); } - return new IStructureElementDeferred() { - @Override - public boolean check(T t, World world, int x, int y, int z) { - return array[keyExtractor.apply(t, null)].check(t, world, x, y, z); - } - - @Override - public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { - return array[keyExtractor.apply(t, trigger)].placeBlock(t, world, x, y, z, trigger); - } - - @Override - public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { - return array[keyExtractor.apply(t, trigger)].spawnHint(t, world, x, y, z, trigger); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { - return array[keyExtractor.apply(t, trigger)].survivalPlaceBlock( - t, world, x, y, z, trigger, s, actor, chatter); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - return array[keyExtractor.apply(t, trigger)].survivalPlaceBlock(t, world, x, y, z, trigger, env); - } - }; + return defer(keyExtractor.andThen(i -> array[i])); } /** @@ -2514,10 +2335,9 @@ public class StructureUtility { * @param keyExtractor extract a key from the context object and trigger item * @param array all possible structure element */ - @SuppressWarnings("unchecked") public static IStructureElementDeferred defer( BiFunction keyExtractor, List> array) { - return defer(keyExtractor, array.toArray(new IStructureElement[0])); + return defer(keyExtractor.andThen(array::get)); } /** @@ -2632,43 +2452,7 @@ public class StructureUtility { if (keyExtractor == null || map == null) { throw new IllegalArgumentException(); } - return new IStructureElementDeferred() { - @Override - public boolean check(T t, World world, int x, int y, int z) { - return map.get(keyExtractorCheck.apply(t)).check(t, world, x, y, z); - } - - @Override - public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.get(keyExtractor.apply(t, trigger)).placeBlock(t, world, x, y, z, trigger); - } - - @Override - public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.get(keyExtractor.apply(t, trigger)).spawnHint(t, world, x, y, z, trigger); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { - return map.get(keyExtractor.apply(t, trigger)) - .survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - return map.get(keyExtractor.apply(t, trigger)).survivalPlaceBlock(t, world, x, y, z, trigger, env); - } - }; + return defer(keyExtractorCheck.andThen(map::get), keyExtractor.>andThen(map::get)); } /** @@ -2725,46 +2509,9 @@ public class StructureUtility { if (keyExtractor == null || map == null) { throw new IllegalArgumentException(); } - return new IStructureElementDeferred() { - @Override - public boolean check(T t, World world, int x, int y, int z) { - return map.getOrDefault(keyExtractorCheck.apply(t), defaultElem).check(t, world, x, y, z); - } - - @Override - public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem) - .placeBlock(t, world, x, y, z, trigger); - } - - @Override - public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { - return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem) - .spawnHint(t, world, x, y, z, trigger); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { - return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem) - .survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - return map.getOrDefault(keyExtractor.apply(t, trigger), defaultElem) - .survivalPlaceBlock(t, world, x, y, z, trigger, env); - } - }; + return defer( + keyExtractorCheck.andThen(k -> map.getOrDefault(k, defaultElem)), + keyExtractor.andThen(k -> map.getOrDefault(k, defaultElem))); } /** @@ -2821,44 +2568,7 @@ public class StructureUtility { if (keyExtractor == null || array == null) { throw new IllegalArgumentException(); } - return new IStructureElementDeferred() { - @Override - public boolean check(T t, World world, int x, int y, int z) { - return array[keyExtractorCheck.apply(t)].check(t, world, x, y, z); - } - - @Override - public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) { - return array[keyExtractor.apply(t, trigger)].placeBlock(t, world, x, y, z, trigger); - } - - @Override - public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) { - return array[keyExtractor.apply(t, trigger)].spawnHint(t, world, x, y, z, trigger); - } - - @Override - @Deprecated - public PlaceResult survivalPlaceBlock( - T t, - World world, - int x, - int y, - int z, - ItemStack trigger, - IItemSource s, - EntityPlayerMP actor, - Consumer chatter) { - return array[keyExtractor.apply(t, trigger)].survivalPlaceBlock( - t, world, x, y, z, trigger, s, actor, chatter); - } - - @Override - public PlaceResult survivalPlaceBlock( - T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { - return array[keyExtractor.apply(t, trigger)].survivalPlaceBlock(t, world, x, y, z, trigger, env); - } - }; + return defer(keyExtractorCheck.andThen(i -> array[i]), keyExtractor.andThen(i -> array[i])); } /** @@ -2948,6 +2658,13 @@ public class StructureUtility { return backing.placeBlock(t, world, x, y, z, ChannelDataAccessor.withChannel(trigger, channel)); } + @Nullable + @Override + public BlocksToPlace getBlocksToPlace( + T t, World world, int x, int y, int z, ItemStack trigger, AutoPlaceEnvironment env) { + return backing.getBlocksToPlace(t, world, x, y, z, trigger, env); + } + @Deprecated public PlaceResult survivalPlaceBlock( T t,