package com.gtnewhorizon.structurelib.structure;
import static com.gtnewhorizon.structurelib.StructureLib.DEBUG_MODE;
import static java.lang.Integer.MIN_VALUE;
import com.gtnewhorizon.structurelib.StructureLib;
import com.gtnewhorizon.structurelib.StructureLibAPI;
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.NBTMode;
import com.gtnewhorizon.structurelib.util.Vec3Impl;
import cpw.mods.fml.common.registry.GameRegistry;
import java.util.*;
import java.util.function.*;
import javax.annotation.Nullable;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.IIcon;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
/**
* Fluent API for structure checking!
*
* (Just import static this class to have a nice fluent syntax while defining structure definitions)
*/
public class StructureUtility {
private static final String NICE_CHARS =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz=|!@#$%&()[]{};:<>/?_,.*^'`";
@SuppressWarnings("rawtypes")
private static final Map STEP = new HashMap<>();
@SuppressWarnings("rawtypes")
private static final IStructureElement AIR = new IStructureElement() {
@Override
public boolean check(Object t, World world, int x, int y, int z) {
return world.isAirBlock(x, y, z);
}
@Override
public boolean spawnHint(Object o, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), 13);
return true;
}
@Override
public boolean placeBlock(Object o, World world, int x, int y, int z, ItemStack trigger) {
world.setBlock(x, y, z, Blocks.air, 0, 2);
return false;
}
@Override
public PlaceResult survivalPlaceBlock(
Object o,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(o, world, x, y, z)) return PlaceResult.SKIP;
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) 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() {
@Override
public boolean check(Object t, World world, int x, int y, int z) {
return !world.isAirBlock(x, y, z);
}
@Override
public boolean spawnHint(Object o, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), 14);
return true;
}
@Override
public boolean placeBlock(Object o, World world, int x, int y, int z, ItemStack trigger) {
world.setBlock(x, y, z, StructureLibAPI.getBlockHint(), 14, 2);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
Object o,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
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)) {
world.setBlock(x, y, z, Blocks.cobblestone, 0, 2);
}
return PlaceResult.REJECT;
}
};
@SuppressWarnings("rawtypes")
private static final IStructureElement ERROR = new IStructureElement() {
@Override
public boolean check(Object t, World world, int x, int y, int z) {
return false;
}
@Override
public boolean spawnHint(Object o, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), 15);
return true;
}
@Override
public boolean placeBlock(Object o, World world, int x, int y, int z, ItemStack trigger) {
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
Object o,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
return PlaceResult.REJECT;
}
};
private StructureUtility() {}
/**
* This method assume block at given coord is NOT acceptable, but may or may not be trivially replaceable
*/
public static PlaceResult survivalPlaceBlock(
Block block, int meta, World world, int x, int y, int z, IItemSource s, EntityPlayerMP actor) {
return survivalPlaceBlock(block, meta, world, x, y, z, s, actor, null);
}
/**
* This method assume block at given coord is NOT acceptable, but may or may not be trivially replaceable
*/
public static PlaceResult survivalPlaceBlock(
Block block,
int meta,
World world,
int x,
int y,
int z,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (block == null) throw new NullPointerException();
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) return PlaceResult.REJECT;
Item itemBlock = Item.getItemFromBlock(block);
int itemMeta = itemBlock instanceof ISpecialItemBlock
? ((ISpecialItemBlock) itemBlock).getItemMetaFromBlockMeta(block, meta)
: meta;
if (!s.takeOne(new ItemStack(itemBlock, 1, itemMeta), false)) {
if (chatter != null)
chatter.accept(new ChatComponentTranslation(
"structurelib.autoplace.error.no_simple_block",
new ItemStack(itemBlock, 1, itemMeta).func_151000_E()));
return PlaceResult.REJECT;
}
if (block instanceof ICustomBlockSetting) {
ICustomBlockSetting block2 = (ICustomBlockSetting) block;
block2.setBlock(world, x, y, z, meta);
} else {
world.setBlock(x, y, z, block, meta, 2);
}
return PlaceResult.ACCEPT;
}
/**
* This method assume block at given coord is NOT acceptable, but may or may not be trivially replaceable
*
* @param stack a valid stack with stack size of exactly 1. Must be of an ItemBlock!
*/
public static PlaceResult survivalPlaceBlock(
ItemStack stack,
NBTMode nbtMode,
NBTTagCompound tag,
boolean assumeStackPresent,
World world,
int x,
int y,
int z,
IItemSource s,
EntityPlayerMP actor) {
return survivalPlaceBlock(stack, nbtMode, tag, assumeStackPresent, world, x, y, z, s, actor, null);
}
/**
* This method assume block at given coord is NOT acceptable, but may or may not be trivially replaceable
*
* @param stack a valid stack with stack size of exactly 1. Must be of an ItemBlock!
* @param chatter pass in null to suppress error output, or just use the other overload
*/
public static PlaceResult survivalPlaceBlock(
ItemStack stack,
NBTMode nbtMode,
NBTTagCompound tag,
boolean assumeStackPresent,
World world,
int x,
int y,
int z,
IItemSource s,
EntityPlayerMP actor,
@Nullable Consumer chatter) {
if (stack == null) throw new NullPointerException();
if (stack.stackSize != 1) throw new IllegalArgumentException();
if (!(stack.getItem() instanceof ItemBlock)) throw new IllegalArgumentException();
if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor)) return PlaceResult.REJECT;
if (!assumeStackPresent && !s.takeOne(stack, true)) {
if (chatter != null)
chatter.accept(new ChatComponentTranslation(
"structurelib.autoplace.error.no_item_stack", stack.func_151000_E()));
return PlaceResult.REJECT;
}
if (!stack.copy().tryPlaceItemIntoWorld(actor, world, x, y, z, ForgeDirection.UP.ordinal(), 0.5f, 0.5f, 0.5f))
return PlaceResult.REJECT;
if (!s.takeOne(stack, false))
// this is bad! probably an exploit somehow. Let's nullify the block we just placed instead
world.setBlockToAir(x, y, z);
return PlaceResult.ACCEPT;
}
@SuppressWarnings("unchecked")
public static IStructureElement isAir() {
return AIR;
}
@SuppressWarnings("unchecked")
public static IStructureElement notAir() {
return NOT_AIR;
}
/**
* Check returns false.
* Placement is always handled by this and does nothing.
* Makes little to no use it in fallback chain.
*/
@SuppressWarnings("unchecked")
public static IStructureElement error() {
return ERROR;
}
// region hint only
/**
* Check always returns: true.
*/
public static IStructureElementNoPlacement ofHint(int dots) {
int meta = dots - 1;
return new IStructureElementNoPlacement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), meta);
return false;
}
};
}
/**
* Check always returns: true.
*/
public static IStructureElementNoPlacement ofHintDeferred(Supplier icons) {
return new IStructureElementNoPlacement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, icons.get());
return false;
}
};
}
/**
* Check always returns: true.
*/
public static IStructureElementNoPlacement ofHintDeferred(Supplier icons, short[] RGBa) {
return new IStructureElementNoPlacement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticleTinted(world, x, y, z, icons.get(), RGBa);
return false;
}
};
}
// endregion
// region block
/**
* A more primitive variant of {@link #ofBlocksTiered(ITierConverter, List, Object, BiConsumer, Function)}
* Main difference is this one is check only.
*
* @see #ofBlocksTiered(ITierConverter, Object, BiConsumer, Function)
*/
public static IStructureElementCheckOnly ofBlocksTiered(
ITierConverter tierExtractor,
@Nullable TIER notSet,
BiConsumer setter,
Function getter) {
if (tierExtractor == null) throw new IllegalArgumentException();
if (setter == null) throw new IllegalArgumentException();
if (getter == null) throw new IllegalArgumentException();
return (t, world, x, y, z) -> {
Block block = world.getBlock(x, y, z);
int meta = world.getBlockMetadata(x, y, z);
TIER tier = tierExtractor.convert(block, meta);
TIER current = getter.apply(t);
if (Objects.equals(notSet, current)) {
setter.accept(t, tier);
return true;
}
return Objects.equals(current, tier);
};
}
/**
* Element representing a component with different tiers. Player can use more blueprint to get hints denoting more
* advanced components.
*
* There is yet no TileEntity counter part of this utility. Feel free to submit a PR to add it.
*
* @param allKnownTiers All known tiers as of calling. Can be empty or null. No hint will be spawned if empty or null. Cannot have null elements.
* First element denotes the most primitive tier. Last element denotes the most advanced tier.
* If not all tiers are available at definition construction time, use {@link #lazy(Supplier)} or its overloads to delay a little bit.
* @param notSet The value returned from {@code getter} when there were no tier info found in T yet. Can be null.
* @param getter a function to retrieve the current tier from T
* @param setter a function to set the current tier into T
* @param tierExtractor a function to extract tier info from a block.
*/
public static IStructureElement ofBlocksTiered(
ITierConverter tierExtractor,
@Nullable List> allKnownTiers,
@Nullable TIER notSet,
BiConsumer setter,
Function getter) {
List> hints = allKnownTiers == null ? Collections.emptyList() : allKnownTiers;
if (hints.stream().anyMatch(Objects::isNull)) throw new IllegalArgumentException();
IStructureElementCheckOnly check = ofBlocksTiered(tierExtractor, notSet, setter, getter);
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return check.check(t, world, x, y, z);
}
private Pair getHint(ItemStack trigger) {
return hints.get(Math.min(Math.max(trigger.stackSize, 1), hints.size()) - 1);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
Pair hint = getHint(trigger);
if (hint == null) return false;
StructureLibAPI.hintParticle(world, x, y, z, hint.getKey(), hint.getValue());
return true;
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
Pair hint = getHint(trigger);
if (hint == null) return false;
if (hint.getKey() instanceof ICustomBlockSetting) {
ICustomBlockSetting block = (ICustomBlockSetting) hint.getKey();
block.setBlock(world, x, y, z, hint.getValue());
} else {
world.setBlock(x, y, z, hint.getKey(), hint.getValue(), 2);
}
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
Pair hint = getHint(trigger);
if (hint == null) return PlaceResult.REJECT; // TODO or SKIP?
Block block = world.getBlock(x, y, z);
int meta = world.getBlockMetadata(x, y, z);
TIER tier = tierExtractor.convert(block, meta);
if (!Objects.equals(tier, notSet)) {
return Objects.equals(tier, tierExtractor.convert(hint.getKey(), hint.getValue()))
? PlaceResult.SKIP
: PlaceResult.REJECT;
}
return StructureUtility.survivalPlaceBlock(
hint.getKey(), hint.getValue(), world, x, y, z, s, actor, chatter);
}
};
}
/**
* Denote a block using unlocalized names. This can be useful to get around mod loading order issues.
*
* While no immediate error will be thrown, client code should ensure said mod is loaded and
* said mod is present, otherwise bad things will happen later!
*/
public static IStructureElement ofBlockUnlocalizedName(String modid, String unlocalizedName, int meta) {
return ofBlockUnlocalizedName(modid, unlocalizedName, meta, false);
}
/**
* Denote a block using unlocalized names. This can be useful to get around mod loading order issues.
*
* While no immediate error will be thrown, client code should ensure said mod is loaded and
* said mod is present, otherwise bad things will happen later!
*
* Will place block or hint using the given meta if wildcard is true.
*/
public static IStructureElement ofBlockUnlocalizedName(
String modid, String unlocalizedName, int meta, boolean wildcard) {
if (StringUtils.isBlank(unlocalizedName)) throw new IllegalArgumentException();
if (meta < 0) throw new IllegalArgumentException();
if (meta > 15) throw new IllegalArgumentException();
if (StringUtils.isBlank(modid)) throw new IllegalArgumentException();
return new IStructureElement() {
private Block block;
private Block getBlock() {
if (block == null) block = GameRegistry.findBlock(modid, unlocalizedName);
return block;
}
@Override
public boolean check(T t, World world, int x, int y, int z) {
return world.getBlock(x, y, z) == getBlock() && (wildcard || world.getBlockMetadata(x, y, z) == meta);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
if (getBlock() == null) return error().spawnHint(t, world, x, y, z, trigger);
StructureLibAPI.hintParticle(world, x, y, z, getBlock(), meta);
return true;
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
if (getBlock() == null) return error().placeBlock(t, world, x, y, z, trigger);
world.setBlock(x, y, z, getBlock(), meta, 2);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
if (getBlock() == null) return PlaceResult.REJECT;
return StructureUtility.survivalPlaceBlock(getBlock(), meta, world, x, y, z, s, actor, chatter);
}
};
}
/**
* Similiar to the other overload, but allows client code to specify a fallback in case said block was not found later
* when the element got called.
*
* This is slightly different to using the other overload and another element in a {@link #ofChain(IStructureElement[])},
* as that combination would cause crash, where this won't.
*/
public static IStructureElement ofBlockUnlocalizedName(
String modid, String unlocalizedName, int meta, IStructureElement fallback) {
if (StringUtils.isBlank(unlocalizedName)) throw new IllegalArgumentException();
if (meta < 0) throw new IllegalArgumentException();
if (meta > 15) throw new IllegalArgumentException();
if (StringUtils.isBlank(modid)) throw new IllegalArgumentException();
if (fallback == null) throw new IllegalArgumentException();
return new IStructureElement() {
private Block block;
private boolean initialized;
private boolean init() {
if (!initialized) {
block = GameRegistry.findBlock(modid, unlocalizedName);
initialized = true;
}
return block != null;
}
@Override
public boolean check(T t, World world, int x, int y, int z) {
if (init()) return world.getBlock(x, y, z) != block && world.getBlockMetadata(x, y, z) == meta;
else return fallback.check(t, world, x, y, z);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
if (init()) {
StructureLibAPI.hintParticle(world, x, y, z, block, meta);
return true;
} else return fallback.spawnHint(t, world, x, y, z, trigger);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
if (init()) {
world.setBlock(x, y, z, block, meta, 2);
return true;
} else return fallback.placeBlock(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) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
if (init()) return StructureUtility.survivalPlaceBlock(block, meta, world, x, y, z, s, actor, chatter);
return fallback.survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
}
};
}
/**
* Does not allow Block duplicates (with different meta)
*/
public static IStructureElementNoPlacement ofBlocksFlatHint(
Map blocsMap, Block hintBlock, int hintMeta) {
if (blocsMap == null || blocsMap.isEmpty() || hintBlock == null) {
throw new IllegalArgumentException();
}
return new IStructureElementNoPlacement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return blocsMap.getOrDefault(worldBlock, MIN_VALUE) == worldBlock.getDamageValue(world, x, y, z);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta);
return true;
}
};
}
/**
* Allows block duplicates (with different meta)
*/
public static IStructureElementNoPlacement ofBlocksMapHint(
Map> blocsMap, Block hintBlock, int hintMeta) {
if (blocsMap == null || blocsMap.isEmpty() || hintBlock == null) {
throw new IllegalArgumentException();
}
for (Collection value : blocsMap.values()) {
if (value.isEmpty()) {
throw new IllegalArgumentException();
}
}
return new IStructureElementNoPlacement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return blocsMap.getOrDefault(worldBlock, Collections.emptySet())
.contains(worldBlock.getDamageValue(world, x, y, z));
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta);
return true;
}
};
}
public static IStructureElementNoPlacement ofBlockHint(
Block block, int meta, Block hintBlock, int hintMeta) {
if (block == null || hintBlock == null) {
throw new IllegalArgumentException();
}
return new IStructureElementNoPlacement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return block == worldBlock && meta == worldBlock.getDamageValue(world, x, y, z);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta);
return true;
}
};
}
public static IStructureElementNoPlacement ofBlockHint(Block block, int meta) {
return ofBlockHint(block, meta, block, meta);
}
public static IStructureElementNoPlacement ofBlockAdderHint(
IBlockAdder iBlockAdder, Block hintBlock, int hintMeta) {
if (iBlockAdder == null || hintBlock == null) {
throw new IllegalArgumentException();
}
return new IStructureElementNoPlacement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return iBlockAdder.apply(t, worldBlock, worldBlock.getDamageValue(world, x, y, z));
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta);
return true;
}
};
}
/**
* Does not allow Block duplicates (with different meta)
*/
public static IStructureElement ofBlocksFlat(
Map blocsMap, Block defaultBlock, int defaultMeta) {
if (blocsMap == null || blocsMap.isEmpty() || defaultBlock == null) {
throw new IllegalArgumentException();
}
if (defaultBlock instanceof ICustomBlockSetting) {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return blocsMap.getOrDefault(worldBlock, MIN_VALUE) == worldBlock.getDamageValue(world, x, y, z);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
} else {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return blocsMap.getOrDefault(worldBlock, MIN_VALUE) == worldBlock.getDamageValue(world, x, y, z);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
world.setBlock(x, y, z, defaultBlock, defaultMeta, 2);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
}
}
/**
* Allows block duplicates (with different meta)
*/
public static IStructureElement ofBlocksMap(
Map> blocsMap, Block defaultBlock, int defaultMeta) {
if (blocsMap == null || blocsMap.isEmpty() || defaultBlock == null) {
throw new IllegalArgumentException();
}
for (Collection value : blocsMap.values()) {
if (value.isEmpty()) {
throw new IllegalArgumentException();
}
}
if (defaultBlock instanceof ICustomBlockSetting) {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return blocsMap.getOrDefault(worldBlock, Collections.emptySet())
.contains(worldBlock.getDamageValue(world, x, y, z));
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
} else {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return blocsMap.getOrDefault(worldBlock, Collections.emptySet())
.contains(worldBlock.getDamageValue(world, x, y, z));
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
world.setBlock(x, y, z, defaultBlock, defaultMeta, 2);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
}
}
public static IStructureElement ofBlock(Block block, int meta, Block defaultBlock, int defaultMeta) {
if (block == null || defaultBlock == null) {
throw new IllegalArgumentException();
}
if (block instanceof ICustomBlockSetting) {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return block == worldBlock && meta == worldBlock.getDamageValue(world, x, y, z);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
} else {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return block == worldBlock && meta == worldBlock.getDamageValue(world, x, y, z);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
world.setBlock(x, y, z, defaultBlock, defaultMeta, 2);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
}
}
/**
* Same as above but ignores target meta id
*/
public static IStructureElement ofBlockAnyMeta(Block block, Block defaultBlock, int defaultMeta) {
if (block == null || defaultBlock == null) {
throw new IllegalArgumentException();
}
if (block instanceof ICustomBlockSetting) {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return block == world.getBlock(x, y, z);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
} else {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return block == world.getBlock(x, y, z);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
world.setBlock(x, y, z, defaultBlock, defaultMeta, 2);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
if (check(t, world, x, y, z)) return PlaceResult.SKIP;
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
}
}
public static IStructureElement ofBlock(Block block, int meta) {
return ofBlock(block, meta, block, meta);
}
/**
* Same as above but ignores target meta id
*/
public static IStructureElement ofBlockAnyMeta(Block block) {
return ofBlockAnyMeta(block, block, 0);
}
/**
* Same as above but allows to set hint particle render
*/
public static IStructureElement ofBlockAnyMeta(Block block, int defaultMeta) {
return ofBlockAnyMeta(block, block, defaultMeta);
}
// endregion
// region adders
public static IStructureElement ofBlockAdder(
IBlockAdder iBlockAdder, Block defaultBlock, int defaultMeta) {
if (iBlockAdder == null || defaultBlock == null) {
throw new IllegalArgumentException();
}
if (defaultBlock instanceof ICustomBlockSetting) {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return iBlockAdder.apply(t, worldBlock, worldBlock.getDamageValue(world, x, y, z));
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
((ICustomBlockSetting) defaultBlock).setBlock(world, x, y, z, defaultMeta);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
} else {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
Block worldBlock = world.getBlock(x, y, z);
return iBlockAdder.apply(t, worldBlock, worldBlock.getDamageValue(world, x, y, z));
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
world.setBlock(x, y, z, defaultBlock, defaultMeta, 2);
return true;
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, defaultBlock, defaultMeta);
return true;
}
@Override
public PlaceResult survivalPlaceBlock(
T t,
World world,
int x,
int y,
int z,
ItemStack trigger,
IItemSource s,
EntityPlayerMP actor,
Consumer chatter) {
return StructureUtility.survivalPlaceBlock(
defaultBlock, defaultMeta, world, x, y, z, s, actor, chatter);
}
};
}
}
public static IStructureElement ofBlockAdder(IBlockAdder iBlockAdder, int dots) {
return ofBlockAdder(iBlockAdder, StructureLibAPI.getBlockHint(), dots - 1);
}
public static IStructureElementNoPlacement ofTileAdder(
ITileAdder iTileAdder, Block hintBlock, int hintMeta) {
if (iTileAdder == null || hintBlock == null) {
throw new IllegalArgumentException();
}
return new IStructureElementNoPlacement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
TileEntity tileEntity = world.getTileEntity(x, y, z);
// This used to check if it's a GT tile. Since this is now an standalone mod we no longer do this
return iTileAdder.apply(t, tileEntity);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta);
return true;
}
};
}
public static IStructureElementNoPlacement ofSpecificTileAdder(
BiPredicate iTileAdder, Class tileClass, Block hintBlock, int hintMeta) {
if (iTileAdder == null || hintBlock == null || tileClass == null) {
throw new IllegalArgumentException();
}
return new IStructureElementNoPlacement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
TileEntity tileEntity = world.getTileEntity(x, y, z);
// This used to check if it's a GT tile. Since this is now an standalone mod we no longer do this
return tileClass.isInstance(tileEntity) && iTileAdder.test(t, tileClass.cast(tileEntity));
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
StructureLibAPI.hintParticle(world, x, y, z, hintBlock, hintMeta);
return true;
}
};
}
// No more hatch adder. Implement it via tile adder. We could of course add a wrapper around it in gregtech, but not
// any more in this standalone mod.
// endregion
// region side effects
public static , T> IStructureElement onElementPass(
Consumer onCheckPass, B element) {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
boolean check = element.check(t, world, x, y, z);
if (check) {
onCheckPass.accept(t);
}
return check;
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
return element.placeBlock(t, world, x, y, z, trigger);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return element.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 element.survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
}
};
}
public static , T> IStructureElement onElementFail(
Consumer onFail, B element) {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
boolean check = element.check(t, world, x, y, z);
if (!check) {
onFail.accept(t);
}
return check;
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
return element.placeBlock(t, world, x, y, z, trigger);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return element.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 element.survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
}
};
}
// endregion
/**
* Enable this structure element only if given predicate returns true.
*/
public static IStructureElement onlyIf(
Predicate super T> predicate, IStructureElement super T> downstream) {
return onlyIf(predicate, downstream, PlaceResult.SKIP);
}
/**
* Enable this structure element only if given predicate returns true.
*/
public static IStructureElement onlyIf(
Predicate super T> predicate,
IStructureElement super T> downstream,
PlaceResult placeResultWhenDisabled) {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return predicate.test(t) && downstream.check(t, world, x, y, z);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return predicate.test(t) && downstream.spawnHint(t, world, x, y, z, trigger);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
return predicate.test(t) && downstream.placeBlock(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) {
if (predicate.test(t))
return downstream.survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
return placeResultWhenDisabled;
}
};
}
/**
* Take care while chaining, as it will try to call every structure element until it returns true.
* If none does it will finally return false.
*/
@SafeVarargs
public static IStructureElementChain ofChain(IStructureElement... elementChain) {
if (elementChain == null || elementChain.length == 0) {
throw new IllegalArgumentException();
}
for (IStructureElement iStructureElement : elementChain) {
if (iStructureElement == null) {
throw new IllegalArgumentException();
}
}
return () -> elementChain;
}
/**
* Take care while chaining, as it will try to call every structure element until it returns true.
* If none does it will finally return false.
*/
@SuppressWarnings("unchecked")
public static IStructureElementChain ofChain(List> elementChain) {
return ofChain(elementChain.toArray(new IStructureElement[0]));
}
// region context
public static , E extends IStructureElement>
IStructureElement withContext(E elem) {
return new IStructureElement() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return elem.check(t.getCurrentContext(), world, x, y, z);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return elem.spawnHint(t.getCurrentContext(), world, x, y, z, trigger);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
return elem.placeBlock(t.getCurrentContext(), 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 elem.survivalPlaceBlock(t.getCurrentContext(), world, x, y, z, trigger, s, actor, chatter);
}
};
}
// endregion
// region defer
/**
* Similar to defer, but caches the first returned element returned and won't call it again.
* Initialization is not thread safe.
*/
public static IStructureElementDeferred lazy(Supplier> to) {
if (to == null) {
throw new IllegalArgumentException();
}
return new LazyStructureElement<>(t -> to.get());
}
/**
* Similar to defer, but caches the first returned element returned and won't call it again.
* Initialization is not thread safe.
*/
public static IStructureElementDeferred lazy(Function> to) {
if (to == null) {
throw new IllegalArgumentException();
}
return new LazyStructureElement<>(to);
}
public static IStructureElementDeferred defer(Supplier> to) {
if (to == null) {
throw new IllegalArgumentException();
}
return new IStructureElementDeferred() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return to.get().check(t, world, x, y, z);
}
@Override
public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
return to.get().placeBlock(t, world, x, y, z, trigger);
}
@Override
public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
return to.get().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 to.get().survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
}
};
}
public static IStructureElementDeferred defer(Function> to) {
if (to == null) {
throw new IllegalArgumentException();
}
return new IStructureElementDeferred() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return to.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 to.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 to.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 to.apply(t).survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
}
};
}
public static IStructureElementDeferred defer(
Function keyExtractor, Map> map) {
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);
}
};
}
public static IStructureElementDeferred defer(
Function keyExtractor, Map> map, IStructureElement defaultElem) {
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);
}
};
}
@SafeVarargs
public static IStructureElementDeferred defer(
Function keyExtractor, IStructureElement... array) {
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);
}
};
}
@SuppressWarnings("unchecked")
public static IStructureElementDeferred defer(
Function keyExtractor, List> array) {
return defer(keyExtractor, array.toArray(new IStructureElement[0]));
}
public static IStructureElementDeferred defer(BiFunction> to) {
if (to == null) {
throw new IllegalArgumentException();
}
return new IStructureElementDeferred() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return to.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 to.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 to.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 to.apply(t, trigger).survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
}
};
}
public static IStructureElementDeferred defer(
BiFunction keyExtractor, Map> map) {
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);
}
};
}
public static IStructureElementDeferred defer(
BiFunction keyExtractor,
Map> map,
IStructureElement defaultElem) {
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);
}
};
}
@SafeVarargs
public static IStructureElementDeferred defer(
BiFunction keyExtractor, IStructureElement... array) {
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);
}
};
}
@SuppressWarnings("unchecked")
public static IStructureElementDeferred defer(
BiFunction keyExtractor, List> array) {
return defer(keyExtractor, array.toArray(new IStructureElement[0]));
}
public static IStructureElementDeferred defer(
Function> toCheck, BiFunction> to) {
if (to == null) {
throw new IllegalArgumentException();
}
return new IStructureElementDeferred() {
@Override
public boolean check(T t, World world, int x, int y, int z) {
return toCheck.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 to.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 to.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 to.apply(t, trigger).survivalPlaceBlock(t, world, x, y, z, trigger, s, actor, chatter);
}
};
}
public static IStructureElementDeferred defer(
Function keyExtractorCheck,
BiFunction keyExtractor,
Map> map) {
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);
}
};
}
public static IStructureElementDeferred defer(
Function keyExtractorCheck,
BiFunction keyExtractor,
Map> map,
IStructureElement defaultElem) {
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);
}
};
}
@SafeVarargs
public static IStructureElementDeferred defer(
Function keyExtractorCheck,
BiFunction keyExtractor,
IStructureElement... array) {
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
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);
}
};
}
@SuppressWarnings("unchecked")
public static IStructureElementDeferred defer(
Function keyExtractorCheck,
BiFunction keyExtractor,
List> array) {
return defer(keyExtractorCheck, keyExtractor, array.toArray(new IStructureElement[0]));
}
// endregion
/**
* Used internally, to generate skips for structure definitions
*/
public static