aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/util
diff options
context:
space:
mode:
authorGlease <4586901+Glease@users.noreply.github.com>2022-08-09 14:13:53 +0800
committerGitHub <noreply@github.com>2022-08-09 08:13:53 +0200
commitd75067976a48c7d2335b18c1cf07250a7c9999ef (patch)
treeac62845da371b0c761bd8a66611da8bf6b5cfefd /src/main/java/gregtech/api/util
parent843ad84357ee0902ab1c3901852460e263983ec9 (diff)
downloadGT5-Unofficial-d75067976a48c7d2335b18c1cf07250a7c9999ef.tar.gz
GT5-Unofficial-d75067976a48c7d2335b18c1cf07250a7c9999ef.tar.bz2
GT5-Unofficial-d75067976a48c7d2335b18c1cf07250a7c9999ef.zip
autoplace integration (#1117)
Diffstat (limited to 'src/main/java/gregtech/api/util')
-rw-r--r--src/main/java/gregtech/api/util/GT_ExoticEnergyInputHelper.java12
-rw-r--r--src/main/java/gregtech/api/util/GT_HatchElementBuilder.java303
-rw-r--r--src/main/java/gregtech/api/util/GT_StructureUtility.java476
-rw-r--r--src/main/java/gregtech/api/util/IGT_HatchAdder.java12
4 files changed, 644 insertions, 159 deletions
diff --git a/src/main/java/gregtech/api/util/GT_ExoticEnergyInputHelper.java b/src/main/java/gregtech/api/util/GT_ExoticEnergyInputHelper.java
index 3de3d42f14..01614a0704 100644
--- a/src/main/java/gregtech/api/util/GT_ExoticEnergyInputHelper.java
+++ b/src/main/java/gregtech/api/util/GT_ExoticEnergyInputHelper.java
@@ -5,6 +5,7 @@ import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import static gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase.isValidMetaTileEntity;
@@ -13,7 +14,7 @@ public class GT_ExoticEnergyInputHelper {
/**
* The Valid Types of TecTech Hatch List.
*/
- private static final List<Class<?>> sExoticEnergyHatchType = new ArrayList<>();
+ private static final List<Class<? extends GT_MetaTileEntity_Hatch>> sExoticEnergyHatchType = new ArrayList<>();
static {
tryRegister("com.github.technus.tectech.thing.metaTileEntity.hatch.GT_MetaTileEntity_Hatch_EnergyMulti");
@@ -26,7 +27,8 @@ public class GT_ExoticEnergyInputHelper {
sExoticEnergyHatchType.add(clazz);
}
- public static void tryRegister(String className) {
+ @SuppressWarnings("unchecked")
+ public static void tryRegister(String className) {
Class<?> clazz;
try {
clazz = Class.forName(className);
@@ -35,7 +37,7 @@ public class GT_ExoticEnergyInputHelper {
}
if (!GT_MetaTileEntity_Hatch.class.isAssignableFrom(clazz))
throw new IllegalArgumentException(clazz.getName() + " is not a subclass of " + GT_MetaTileEntity_Hatch.class.getName());
- sExoticEnergyHatchType.add(clazz);
+ sExoticEnergyHatchType.add((Class<? extends GT_MetaTileEntity_Hatch>) clazz);
}
public static boolean drainEnergy(long aEU, Collection<? extends GT_MetaTileEntity_Hatch> hatches) {
@@ -68,4 +70,8 @@ public class GT_ExoticEnergyInputHelper {
if (isValidMetaTileEntity(tHatch)) rAmp += tHatch.getBaseMetaTileEntity().getInputAmperage();
return rAmp;
}
+
+ public static List<Class<? extends GT_MetaTileEntity_Hatch>> getAllClasses() {
+ return Collections.unmodifiableList(sExoticEnergyHatchType);
+ }
}
diff --git a/src/main/java/gregtech/api/util/GT_HatchElementBuilder.java b/src/main/java/gregtech/api/util/GT_HatchElementBuilder.java
new file mode 100644
index 0000000000..94b5f626c1
--- /dev/null
+++ b/src/main/java/gregtech/api/util/GT_HatchElementBuilder.java
@@ -0,0 +1,303 @@
+package gregtech.api.util;
+
+import com.gtnewhorizon.structurelib.StructureLibAPI;
+import com.gtnewhorizon.structurelib.structure.*;
+import com.gtnewhorizon.structurelib.util.ItemStackPredicate;
+import gnu.trove.TIntCollection;
+import gnu.trove.list.array.TIntArrayList;
+import gnu.trove.set.hash.TIntHashSet;
+import gregtech.api.interfaces.IHatchElement;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase;
+import gregtech.common.blocks.GT_Item_Machines;
+import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.item.ItemStack;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ChatComponentTranslation;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.world.World;
+
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock;
+import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain;
+
+public class GT_HatchElementBuilder<T extends GT_MetaTileEntity_EnhancedMultiBlockBase<?>> {
+ private interface Builtin {
+ }
+
+ private IGT_HatchAdder<? super T> mAdder;
+ private int mCasingIndex = -1;
+ private int mDot = -1;
+ private BiPredicate<? super T, ? super IGregTechTileEntity> mShouldSkip;
+ private Function<? super T, ? extends Predicate<ItemStack>> mHatchItemFilter;
+ private Supplier<String> mHatchItemType;
+ private Predicate<? super T> mReject, mBuiltinReject;
+ private boolean mCacheHint;
+
+ private GT_HatchElementBuilder() {
+ }
+
+ public static <T extends GT_MetaTileEntity_EnhancedMultiBlockBase<?>> GT_HatchElementBuilder<T> builder() {
+ return new GT_HatchElementBuilder<>();
+ }
+
+ // region composite
+
+ /**
+ * Set all of adder, hint and hatchItemFilter. Provide a reasonable default for shouldSkip.
+ * TODO add doc
+ */
+ @SafeVarargs
+ public final GT_HatchElementBuilder<T> anyOf(IHatchElement<? super T>... elements) {
+ if (elements == null || elements.length == 0) throw new IllegalArgumentException();
+ return adder(Arrays.stream(elements).map(e -> e.adder().rebrand()).reduce(IGT_HatchAdder::orElse).get())
+ .hatchClasses(Arrays.stream(elements).map(IHatchElement::mteClasses).flatMap(Collection::stream).collect(Collectors.toList()))
+ .cacheHint(() -> Arrays.stream(elements).map(IHatchElement::name).collect(Collectors.joining(" or ", "of type ", "")));
+ }
+
+ /**
+ * Set all of adder, hint and hatchItemFilter. Provide a reasonable default for shouldSkip.
+ * <p>
+ * Will rotate through all elements
+ * TODO add doc
+ */
+ @SafeVarargs
+ public final GT_HatchElementBuilder<T> atLeast(IHatchElement<? super T>... elements) {
+ if (elements == null || elements.length == 0) throw new IllegalArgumentException();
+ return atLeast(Arrays.stream(elements).collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting())));
+ }
+
+ /**
+ * Set all of adder, hint and hatchItemFilter. Provide a reasonable default for shouldSkip.
+ * <p>
+ * Will rotate through all elements
+ * TODO add doc
+ */
+ public final GT_HatchElementBuilder<T> atLeastList(List<IHatchElement<? super T>> elements) {
+ if (elements == null || elements.isEmpty()) throw new IllegalArgumentException();
+ return atLeast(elements.stream().collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting())));
+ }
+
+ /**
+ * Set all of adder, hint and hatchItemFilter. Provide a reasonable default for shouldSkip.
+ * TODO add doc
+ */
+ public final GT_HatchElementBuilder<T> atLeast(Map<IHatchElement<? super T>, ? extends Number> elements) {
+ if (elements == null || elements.isEmpty() || elements.containsKey(null) || elements.containsValue(null))
+ throw new IllegalArgumentException();
+ List<Class<? extends IMetaTileEntity>> list = elements.keySet().stream().map(IHatchElement::mteClasses).flatMap(Collection::stream).collect(Collectors.toList());
+ // map cannot be null or empty, so assert Optional isPresent
+ return adder(elements.keySet().stream().map(e -> e.adder().rebrand()).reduce(IGT_HatchAdder::orElse).orElseThrow(AssertionError::new))
+ .hatchItemFilter(obj -> GT_StructureUtility.filterByMTEClass(elements.entrySet().stream()
+ .filter(entry -> entry.getKey().count(obj) < entry.getValue().longValue())
+ .flatMap(entry -> entry.getKey().mteClasses().stream())
+ .collect(Collectors.toList())))
+ .shouldReject(obj -> elements.entrySet().stream().allMatch(e-> e.getKey().count(obj) >= e.getValue().longValue()))
+ .shouldSkip((BiPredicate<? super T, ? super IGregTechTileEntity> & Builtin) (c, t) -> t != null && list.stream().anyMatch(clazz -> clazz.isInstance(t.getMetaTileEntity())))
+ .cacheHint(() -> elements.keySet().stream().map(IHatchElement::name).collect(Collectors.joining(" or ", "of type ", "")));
+ }
+ //endregion
+
+ //region primitives
+
+ public GT_HatchElementBuilder<T> adder(IGT_HatchAdder<? super T> aAdder) {
+ if (aAdder == null) throw new IllegalArgumentException();
+ mAdder = aAdder;
+ return this;
+ }
+
+ public GT_HatchElementBuilder<T> casingIndex(int aCasingIndex) {
+ if (aCasingIndex <= 0) throw new IllegalArgumentException();
+ mCasingIndex = aCasingIndex;
+ return this;
+ }
+
+ public GT_HatchElementBuilder<T> dot(int aDot) {
+ if (aDot <= 0) throw new IllegalArgumentException();
+ mDot = aDot;
+ return this;
+ }
+
+ public GT_HatchElementBuilder<T> shouldSkip(BiPredicate<? super T, ? super IGregTechTileEntity> aShouldSkip) {
+ if (!(aShouldSkip instanceof Builtin) || mShouldSkip != null) {
+ if (!(mShouldSkip instanceof Builtin) && mShouldSkip != null) throw new IllegalStateException();
+ if (aShouldSkip == null) throw new IllegalArgumentException();
+ }
+ mShouldSkip = aShouldSkip;
+ return this;
+ }
+
+ // avoid loooooong lines like
+ // shouldSkip((BiPredicate<.....> & Builtin) (c, t) -> ....)
+ // private <P extends BiPredicate<? super T, ? super IGregTechTileEntity> & Builtin> GT_HatchElementBuilder<T> shouldSkipInternal(P aShouldSkip) {
+ // if (mShouldSkip == null) mShouldSkip = aShouldSkip;
+ // return this;
+ // }
+ // turns out javac doesn't like this... so...
+
+ public GT_HatchElementBuilder<T> shouldReject(Predicate<? super T> aShouldReject) {
+ if (aShouldReject == null) throw new IllegalArgumentException();
+ mReject = aShouldReject;
+ return this;
+ }
+
+ public GT_HatchElementBuilder<T> hatchItemFilter(Function<? super T, ? extends Predicate<ItemStack>> aHatchItemFilter) {
+ if (aHatchItemFilter == null) throw new IllegalArgumentException();
+ mHatchItemFilter = aHatchItemFilter;
+ return this;
+ }
+
+ public GT_HatchElementBuilder<T> hatchItemFilterAnd(Function<? super T, ? extends Predicate<ItemStack>> aHatchItemFilter) {
+ if (aHatchItemFilter == null) throw new IllegalArgumentException();
+ Function<? super T, ? extends Predicate<ItemStack>> tOldFilter = mHatchItemFilter;
+ mHatchItemFilter = t -> tOldFilter.apply(t).and(aHatchItemFilter.apply(t));
+ return this;
+ }
+
+ // region hint
+ public GT_HatchElementBuilder<T> hint(Supplier<String> aSupplier) {
+ if (aSupplier == null) throw new IllegalArgumentException();
+ mHatchItemType = aSupplier;
+ mCacheHint = false;
+ return this;
+ }
+
+ public GT_HatchElementBuilder<T> cacheHint(Supplier<String> aSupplier) {
+ if (aSupplier == null) throw new IllegalArgumentException();
+ mHatchItemType = aSupplier;
+ mCacheHint = true;
+ return this;
+ }
+
+ public GT_HatchElementBuilder<T> cacheHint() {
+ if (mHatchItemType == null) throw new IllegalStateException();
+ mCacheHint = true;
+ return this;
+ }
+ // endregion
+ // endregion
+
+ // region intermediate
+ public GT_HatchElementBuilder<T> hatchClass(Class<? extends IMetaTileEntity> clazz) {
+ return hatchItemFilter(c -> is -> clazz.isInstance(GT_Item_Machines.getMetaTileEntity(is)))
+ .cacheHint(() -> "of class " + clazz.getSimpleName());
+ }
+
+ @SafeVarargs
+ public final GT_HatchElementBuilder<T> hatchClasses(Class<? extends IMetaTileEntity>... classes) {
+ return hatchClasses(Arrays.asList(classes));
+ }
+
+ public final GT_HatchElementBuilder<T> hatchClasses(List<? extends Class<? extends IMetaTileEntity>> classes) {
+ List<? extends Class<? extends IMetaTileEntity>> list = new ArrayList<>(classes);
+ return hatchItemFilter(obj -> GT_StructureUtility.filterByMTEClass(list))
+ .cacheHint(() -> list.stream().map(Class::getSimpleName).collect(Collectors.joining(" or ", "of class ", "")))
+ .shouldSkip((BiPredicate<? super T, ? super IGregTechTileEntity> & Builtin) (c, t) -> t != null && list.stream().anyMatch(clazz -> clazz.isInstance(t.getMetaTileEntity())));
+ }
+
+ public GT_HatchElementBuilder<T> hatchId(int aId) {
+ return hatchItemFilter(c -> is -> GT_Utility.isStackValid(is) && is.getItem() instanceof GT_Item_Machines && is.getItemDamage() == aId)
+ .cacheHint(() -> "of id " + aId);
+ }
+
+ public GT_HatchElementBuilder<T> hatchIds(int... aIds) {
+ if (aIds == null || aIds.length == 0) throw new IllegalArgumentException();
+ if (aIds.length == 1) return hatchId(aIds[0]);
+ TIntCollection coll = aIds.length < 16 ? new TIntArrayList(aIds) : new TIntHashSet(aIds);
+ return hatchItemFilter(c -> is -> GT_Utility.isStackValid(is) && is.getItem() instanceof GT_Item_Machines && coll.contains(is.getItemDamage()))
+ .cacheHint(() -> Arrays.stream(coll.toArray()).mapToObj(String::valueOf).collect(Collectors.joining(" or ", "of id ", "")));
+ }
+
+ //endregion
+
+ @SuppressWarnings("unchecked")
+ @SafeVarargs
+ public final IStructureElementChain<T> buildAndChain(IStructureElement<T>... elements) {
+ List<IStructureElement<T>> l = new ArrayList<>();
+ l.add(build());
+ l.addAll(Arrays.asList(elements));
+ IStructureElement<T>[] array = l.toArray(new IStructureElement[0]);
+ return () -> array;
+ }
+
+ public final IStructureElementChain<T> buildAndChain(Block block, int meta) {
+ return buildAndChain(ofBlock(block, meta));
+ }
+
+ public IStructureElement<T> build() {
+ if (mAdder == null || mCasingIndex == -1 || mDot == -1) {
+ throw new IllegalArgumentException();
+ }
+ if (mHatchItemFilter == null) {
+ // no item filter -> no placement
+ return new IStructureElementNoPlacement<T>() {
+ @Override
+ public boolean check(T t, World world, int x, int y, int z) {
+ TileEntity tileEntity = world.getTileEntity(x, y, z);
+ return tileEntity instanceof IGregTechTileEntity && mAdder.apply(t, (IGregTechTileEntity) tileEntity, (short) mCasingIndex);
+ }
+
+ @Override
+ public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
+ StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), mDot - 1);
+ return true;
+ }
+ };
+ }
+ return new IStructureElement<T>() {
+ private String mHint = mHatchItemType == null ? "unspecified GT hatch" : mHatchItemType.get();
+
+ @Override
+ public boolean check(T t, World world, int x, int y, int z) {
+ TileEntity tileEntity = world.getTileEntity(x, y, z);
+ return tileEntity instanceof IGregTechTileEntity && mAdder.apply(t, (IGregTechTileEntity) tileEntity, (short) mCasingIndex);
+ }
+
+ @Override
+ public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
+ StructureLibAPI.hintParticle(world, x, y, z, StructureLibAPI.getBlockHint(), mDot);
+ return true;
+ }
+
+ @Override
+ public boolean placeBlock(T t, World world, int i, int i1, int i2, ItemStack itemStack) {
+ // TODO
+ return false;
+ }
+
+ private String getHint() {
+ if (mHint != null) return mHint;
+ String tHint = mHatchItemType.get();
+ if (mCacheHint)
+ mHint = tHint;
+ return tHint;
+ }
+
+ @Override
+ public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
+ if (mShouldSkip != null) {
+ TileEntity tileEntity = world.getTileEntity(x, y, z);
+ if (tileEntity instanceof IGregTechTileEntity && mShouldSkip.test(t, (IGregTechTileEntity) tileEntity))
+ return PlaceResult.SKIP;
+ }
+ if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor))
+ return PlaceResult.REJECT;
+ if (mReject != null && mReject.test(t)) return PlaceResult.REJECT;
+ ItemStack taken = s.takeOne(mHatchItemFilter.apply(t), true);
+ if (GT_Utility.isStackInvalid(taken)) {
+ String type = getHint();
+ chatter.accept(new ChatComponentTranslation("GT5U.autoplace.error.no_hatch", type));
+ return PlaceResult.REJECT;
+ }
+ return StructureUtility.survivalPlaceBlock(taken, ItemStackPredicate.NBTMode.IGNORE, null, true, world, x, y, z, s, actor) == PlaceResult.ACCEPT ? PlaceResult.ACCEPT_STOP : PlaceResult.REJECT;
+ }
+ };
+ }
+}
diff --git a/src/main/java/gregtech/api/util/GT_StructureUtility.java b/src/main/java/gregtech/api/util/GT_StructureUtility.java
index d211dad43d..7938214319 100644
--- a/src/main/java/gregtech/api/util/GT_StructureUtility.java
+++ b/src/main/java/gregtech/api/util/GT_StructureUtility.java
@@ -1,182 +1,346 @@
package gregtech.api.util;
import com.gtnewhorizon.structurelib.StructureLibAPI;
+import com.gtnewhorizon.structurelib.structure.IItemSource;
import com.gtnewhorizon.structurelib.structure.IStructureElement;
import com.gtnewhorizon.structurelib.structure.IStructureElementNoPlacement;
+import com.gtnewhorizon.structurelib.structure.StructureUtility;
+import com.gtnewhorizon.structurelib.util.ItemStackPredicate;
import gregtech.api.GregTech_API;
import gregtech.api.enums.HeatingCoilLevel;
import gregtech.api.enums.Materials;
import gregtech.api.enums.OrePrefixes;
import gregtech.api.interfaces.IHeatingCoil;
+import gregtech.api.interfaces.metatileentity.IMetaTileEntity;
import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
import gregtech.api.metatileentity.BaseMetaPipeEntity;
import gregtech.api.metatileentity.implementations.GT_MetaPipeEntity_Frame;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase;
+import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TieredMachineBlock;
import gregtech.common.blocks.GT_Block_Casings5;
+import gregtech.common.blocks.GT_Item_Machines;
import net.minecraft.block.Block;
+import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
+import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
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 javax.annotation.Nonnull;
import java.util.Arrays;
-import java.util.function.BiConsumer;
-import java.util.function.BiPredicate;
-import java.util.function.Function;
+import java.util.List;
+import java.util.function.*;
public class GT_StructureUtility {
- private GT_StructureUtility() {
- throw new AssertionError("Not instantiable");
- }
-
- public static <T> IStructureElementNoPlacement<T> ofHatchAdder(IGT_HatchAdder<T> aHatchAdder, int aTextureIndex, int aDots) {
- return ofHatchAdder(aHatchAdder, aTextureIndex, StructureLibAPI.getBlockHint(), aDots - 1);
- }
-
- public static <T> IStructureElement<T> ofFrame(Materials aFrameMaterial) {
- if (aFrameMaterial == null) throw new IllegalArgumentException();
- return new IStructureElement<T>() {
-
- private IIcon[] mIcons;
-
- @Override
- public boolean check(T t, World world, int x, int y, int z) {
- TileEntity tBase = world.getTileEntity(x, y, z);
- if (tBase instanceof BaseMetaPipeEntity) {
- BaseMetaPipeEntity tPipeBase = (BaseMetaPipeEntity) tBase;
- if (tPipeBase.isInvalidTileEntity()) return false;
- if (tPipeBase.getMetaTileEntity() instanceof GT_MetaPipeEntity_Frame)
- return aFrameMaterial == ((GT_MetaPipeEntity_Frame) tPipeBase.getMetaTileEntity()).mMaterial;
- }
- return false;
- }
-
- @Override
- public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
- if (mIcons == null) {
- mIcons = new IIcon[6];
- Arrays.fill(mIcons, aFrameMaterial.mIconSet.mTextures[OrePrefixes.frameGt.mTextureIndex].getIcon());
- }
- StructureLibAPI.hintParticleTinted(world, x, y, z, mIcons, aFrameMaterial.mRGBa);
- return true;
- }
-
- @Override
- public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
- ItemStack tFrameStack = GT_OreDictUnificator.get(OrePrefixes.frameGt, aFrameMaterial, 1);
- if (tFrameStack.getItem() instanceof ItemBlock) {
- ItemBlock tFrameStackItem = (ItemBlock) tFrameStack.getItem();
- return tFrameStackItem.placeBlockAt(tFrameStack, null, world, x, y, z, 6, 0, 0, 0, Items.feather.getDamage(tFrameStack));
- }
- return false;
- }
- };
- }
-
- public static <T> IStructureElementNoPlacement<T> ofHatchAdder(IGT_HatchAdder<T> aHatchAdder, int aTextureIndex, Block aHintBlock, int aHintMeta) {
- if (aHatchAdder == null || aHintBlock == null) {
- throw new IllegalArgumentException();
- }
- return new IStructureElementNoPlacement<T>() {
- @Override
- public boolean check(T t, World world, int x, int y, int z) {
- TileEntity tileEntity = world.getTileEntity(x, y, z);
- return tileEntity instanceof IGregTechTileEntity && aHatchAdder.apply(t, (IGregTechTileEntity) tileEntity, (short) aTextureIndex);
- }
-
- @Override
- public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
- StructureLibAPI.hintParticle(world, x, y, z, aHintBlock, aHintMeta);
- return true;
- }
- };
- }
-
- public static <T> IStructureElement<T> ofHatchAdderOptional(IGT_HatchAdder<T> aHatchAdder, int textureIndex, int dots, Block placeCasing, int placeCasingMeta) {
- return ofHatchAdderOptional(aHatchAdder, textureIndex, StructureLibAPI.getBlockHint(), dots - 1, placeCasing, placeCasingMeta);
- }
-
- public static <T> IStructureElement<T> ofHatchAdderOptional(IGT_HatchAdder<T> aHatchAdder, int aTextureIndex, Block aHintBlock, int hintMeta, Block placeCasing, int placeCasingMeta) {
- if (aHatchAdder == null || aHintBlock == null) {
- throw new IllegalArgumentException();
- }
- return new IStructureElement<T>() {
- @Override
- public boolean check(T t, World world, int x, int y, int z) {
- TileEntity tileEntity = world.getTileEntity(x, y, z);
- Block worldBlock = world.getBlock(x, y, z);
- return (tileEntity instanceof IGregTechTileEntity &&
- aHatchAdder.apply(t, (IGregTechTileEntity) tileEntity, (short) aTextureIndex)) ||
- (worldBlock == placeCasing && worldBlock.getDamageValue(world, x, y, z) == placeCasingMeta);
- }
-
- @Override
- public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
- StructureLibAPI.hintParticle(world, x, y, z, aHintBlock, hintMeta);
- return true;
- }
-
- @Override
- public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
- world.setBlock(x, y, z, placeCasing, placeCasingMeta, 2);
- return true;
- }
- };
- }
-
- /**
- * Assume all coils accepted.
- * @see #ofCoil(BiPredicate, Function)
- */
- public static <T> IStructureElement<T> ofCoil(BiConsumer<T, HeatingCoilLevel> aHeatingCoilSetter, Function<T, HeatingCoilLevel> aHeatingCoilGetter) {
- return ofCoil((t, l) -> {
- aHeatingCoilSetter.accept(t, l);
- return true;
- }, aHeatingCoilGetter);
- }
-
- /**
- * Heating coil structure element.
- * @param aHeatingCoilSetter Notify the controller of this new coil.
- * Got called exactly once per coil.
- * Might be called less times if structure test fails.
- * If the setter returns false then it assumes the coil is rejected.
- * @param aHeatingCoilGetter Get the current heating level. Null means no coil recorded yet.
- */
- public static <T> IStructureElement<T> ofCoil(BiPredicate<T, HeatingCoilLevel> aHeatingCoilSetter, Function<T, HeatingCoilLevel> aHeatingCoilGetter) {
- if (aHeatingCoilSetter == null || aHeatingCoilGetter == null) {
- throw new IllegalArgumentException();
- }
- return new IStructureElement<T>() {
- @Override
- public boolean check(T t, World world, int x, int y, int z) {
- Block block = world.getBlock(x, y, z);
- if (!(block instanceof IHeatingCoil))
- return false;
- HeatingCoilLevel existingLevel = aHeatingCoilGetter.apply(t),
- newLevel = ((IHeatingCoil) block).getCoilHeat(world.getBlockMetadata(x, y, z));
- if (existingLevel == null || existingLevel == HeatingCoilLevel.None) {
- return aHeatingCoilSetter.test(t, newLevel);
- } else {
- return newLevel == existingLevel;
- }
- }
-
- @Override
- public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
- StructureLibAPI.hintParticle(world, x, y, z, GregTech_API.sBlockCasings5, getMeta(trigger));
- return true;
- }
-
- private int getMeta(ItemStack trigger) {
- return GT_Block_Casings5.getMetaFromCoilHeat(HeatingCoilLevel.getFromTier((byte) Math.min(HeatingCoilLevel.getMaxTier(), Math.max(0, trigger.stackSize - 1))));
- }
-
- @Override
- public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
- return world.setBlock(x, y, z, GregTech_API.sBlockCasings5, getMeta(trigger), 3);
- }
- };
- }
+ // private static final Map<Class<?>, String> customNames = new HashMap<>();
+ private GT_StructureUtility() {
+ throw new AssertionError("Not instantiable");
+ }
+
+ public static boolean hasMTE(IGregTechTileEntity aTile, Class<? extends IMetaTileEntity> clazz) {
+ return aTile != null && clazz.isInstance(aTile.getMetaTileEntity());
+ }
+
+ public static <T> IStructureElementNoPlacement<T> ofHatchAdder(IGT_HatchAdder<T> aHatchAdder, int aTextureIndex, int aDots) {
+ return ofHatchAdder(aHatchAdder, aTextureIndex, StructureLibAPI.getBlockHint(), aDots - 1);
+ }
+
+ public static <T> IStructureElement<T> ofFrame(Materials aFrameMaterial) {
+ if (aFrameMaterial == null) throw new IllegalArgumentException();
+ return new IStructureElement<T>() {
+
+ private IIcon[] mIcons;
+
+ @Override
+ public boolean check(T t, World world, int x, int y, int z) {
+ TileEntity tBase = world.getTileEntity(x, y, z);
+ if (tBase instanceof BaseMetaPipeEntity) {
+ BaseMetaPipeEntity tPipeBase = (BaseMetaPipeEntity) tBase;
+ if (tPipeBase.isInvalidTileEntity()) return false;
+ if (tPipeBase.getMetaTileEntity() instanceof GT_MetaPipeEntity_Frame)
+ return aFrameMaterial == ((GT_MetaPipeEntity_Frame) tPipeBase.getMetaTileEntity()).mMaterial;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
+ if (mIcons == null) {
+ mIcons = new IIcon[6];
+ Arrays.fill(mIcons, aFrameMaterial.mIconSet.mTextures[OrePrefixes.frameGt.mTextureIndex].getIcon());
+ }
+ StructureLibAPI.hintParticleTinted(world, x, y, z, mIcons, aFrameMaterial.mRGBa);
+ return true;
+ }
+
+ @Override
+ public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
+ ItemStack tFrameStack = GT_OreDictUnificator.get(OrePrefixes.frameGt, aFrameMaterial, 1);
+ if (!GT_Utility.isStackValid(tFrameStack) || !(tFrameStack.getItem() instanceof ItemBlock))
+ return false;
+ ItemBlock tFrameStackItem = (ItemBlock) tFrameStack.getItem();
+ return tFrameStackItem.placeBlockAt(tFrameStack, null, world, x, y, z, 6, 0, 0, 0, Items.feather.getDamage(tFrameStack));
+ }
+
+ @Override
+ public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
+ if (check(t, world, x, y, z)) return PlaceResult.SKIP;
+ ItemStack tFrameStack = GT_OreDictUnificator.get(OrePrefixes.frameGt, aFrameMaterial, 1);
+ if (!GT_Utility.isStackValid(tFrameStack) || !(tFrameStack.getItem() instanceof ItemBlock))
+ return PlaceResult.REJECT; // honestly, this is more like a programming error or pack issue
+ return StructureUtility.survivalPlaceBlock(tFrameStack, ItemStackPredicate.NBTMode.IGNORE_KNOWN_INSIGNIFICANT_TAGS, null, false, world, x, y, z, s, actor, chatter);
+ }
+ };
+ }
+
+ public static <T extends GT_MetaTileEntity_EnhancedMultiBlockBase<?>> GT_HatchElementBuilder<T> buildHatchAdder() {
+ return GT_HatchElementBuilder.builder();
+ }
+
+ /**
+ * Completely equivalent to {@link #buildHatchAdder()}, except it plays nicer with type inference when statically imported
+ */
+ public static <T extends GT_MetaTileEntity_EnhancedMultiBlockBase<?>> GT_HatchElementBuilder<T> buildHatchAdder(Class<T> typeToken) {
+ return GT_HatchElementBuilder.builder();
+ }
+
+ public static <T> IStructureElementNoPlacement<T> ofHatchAdder(IGT_HatchAdder<T> aHatchAdder, int aTextureIndex, Block aHintBlock, int aHintMeta) {
+ if (aHatchAdder == null || aHintBlock == null) {
+ throw new IllegalArgumentException();
+ }
+ return new IStructureElementNoPlacement<T>() {
+ @Override
+ public boolean check(T t, World world, int x, int y, int z) {
+ TileEntity tileEntity = world.getTileEntity(x, y, z);
+ return tileEntity instanceof IGregTechTileEntity && aHatchAdder.apply(t, (IGregTechTileEntity) tileEntity, (short) aTextureIndex);
+ }
+
+ @Override
+ public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
+ StructureLibAPI.hintParticle(world, x, y, z, aHintBlock, aHintMeta);
+ return true;
+ }
+ };
+ }
+
+ public static <T> IStructureElement<T> ofHatchAdder(IGT_HatchAdder<T> aHatchAdder, int aTextureIndex, Block aHintBlock, int aHintMeta, BiPredicate<T, IGregTechTileEntity> shouldSkip, Function<T, Class<? extends IMetaTileEntity>> aMetaId, final IStructureElement.PlaceResult acceptType) {
+ if (aHatchAdder == null) {
+ throw new IllegalArgumentException();
+ }
+ return new IStructureElement<T>() {
+ @Override
+ public boolean check(T t, World world, int x, int y, int z) {
+ TileEntity tileEntity = world.getTileEntity(x, y, z);
+ return tileEntity instanceof IGregTechTileEntity && aHatchAdder.apply(t, (IGregTechTileEntity) tileEntity, (short) aTextureIndex);
+ }
+
+ @Override
+ public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
+ StructureLibAPI.hintParticle(world, x, y, z, aHintBlock, aHintMeta);
+ return true;
+ }
+
+ @Override
+ public boolean placeBlock(T t, World world, int i, int i1, int i2, ItemStack itemStack) {
+ // TODO
+ return false;
+ }
+
+ @Override
+ public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
+ if (shouldSkip != null) {
+ TileEntity tileEntity = world.getTileEntity(x, y, z);
+ if (tileEntity instanceof IGregTechTileEntity && shouldSkip.test(t, (IGregTechTileEntity) tileEntity))
+ return PlaceResult.SKIP;
+ }
+ if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor))
+ return PlaceResult.REJECT;
+ Class<? extends IMetaTileEntity> clazz = aMetaId.apply(t);
+ if (clazz == null) return PlaceResult.REJECT;
+ ItemStack taken = s.takeOne(is -> clazz.isInstance(GT_Item_Machines.getMetaTileEntity(is)), true);
+ if (GT_Utility.isStackInvalid(taken)) {
+ chatter.accept(new ChatComponentTranslation("GT5U.autoplace.error.no_mte.class_name", clazz.getSimpleName()));
+ return PlaceResult.REJECT;
+ }
+ if (StructureUtility.survivalPlaceBlock(taken, ItemStackPredicate.NBTMode.IGNORE, null, true, world, x, y, z, s, actor) == PlaceResult.ACCEPT)
+ return acceptType;
+ return PlaceResult.REJECT;
+ }
+ };
+ }
+
+ public static <T> IStructureElement<T> ofHatchAdder(IGT_HatchAdder<T> aHatchAdder, int aTextureIndex, Block aHintBlock, int aHintMeta, BiPredicate<T, IGregTechTileEntity> shouldSkip, ToIntFunction<T> aMetaId) {
+ if (aHatchAdder == null) {
+ throw new IllegalArgumentException();
+ }
+ return new IStructureElement<T>() {
+ @Override
+ public boolean check(T t, World world, int x, int y, int z) {
+ TileEntity tileEntity = world.getTileEntity(x, y, z);
+ return tileEntity instanceof IGregTechTileEntity && aHatchAdder.apply(t, (IGregTechTileEntity) tileEntity, (short) aTextureIndex);
+ }
+
+ @Override
+ public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
+ StructureLibAPI.hintParticle(world, x, y, z, aHintBlock, aHintMeta);
+ return true;
+ }
+
+ @Override
+ public boolean placeBlock(T t, World world, int i, int i1, int i2, ItemStack itemStack) {
+ // TODO
+ return false;
+ }
+
+ @Override
+ public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
+ if (shouldSkip != null) {
+ TileEntity tileEntity = world.getTileEntity(x, y, z);
+ if (tileEntity instanceof IGregTechTileEntity && shouldSkip.test(t, (IGregTechTileEntity) tileEntity))
+ return PlaceResult.SKIP;
+ }
+ if (!StructureLibAPI.isBlockTriviallyReplaceable(world, x, y, z, actor))
+ return PlaceResult.REJECT;
+ GT_Item_Machines item = (GT_Item_Machines) Item.getItemFromBlock(GregTech_API.sBlockMachines);
+ int meta = aMetaId.applyAsInt(t);
+ if (meta < 0) return PlaceResult.REJECT;
+ ItemStack taken = s.takeOne(ItemStackPredicate.from(item).setMeta(meta), true);
+ if (GT_Utility.isStackInvalid(taken)) {
+ chatter.accept(new ChatComponentTranslation("GT5U.autoplace.error.no_mte.id", meta));
+ return PlaceResult.REJECT;
+ }
+ return StructureUtility.survivalPlaceBlock(taken, ItemStackPredicate.NBTMode.IGNORE, null, true, world, x, y, z, s, actor) == PlaceResult.ACCEPT ? PlaceResult.ACCEPT_STOP : PlaceResult.REJECT;
+ }
+ };
+ }
+
+ public static <T> IStructureElement<T> ofHatchAdderOptional(IGT_HatchAdder<T> aHatchAdder, int textureIndex, int dots, Block placeCasing, int placeCasingMeta) {
+ return ofHatchAdderOptional(aHatchAdder, textureIndex, StructureLibAPI.getBlockHint(), dots - 1, placeCasing, placeCasingMeta);
+ }
+
+ public static <T> IStructureElement<T> ofHatchAdderOptional(IGT_HatchAdder<T> aHatchAdder, int aTextureIndex, Block aHintBlock, int hintMeta, Block placeCasing, int placeCasingMeta) {
+ if (aHatchAdder == null || aHintBlock == null) {
+ throw new IllegalArgumentException();
+ }
+ return new IStructureElement<T>() {
+ @Override
+ public boolean check(T t, World world, int x, int y, int z) {
+ TileEntity tileEntity = world.getTileEntity(x, y, z);
+ Block worldBlock = world.getBlock(x, y, z);
+ return (tileEntity instanceof IGregTechTileEntity &&
+ aHatchAdder.apply(t, (IGregTechTileEntity) tileEntity, (short) aTextureIndex)) ||
+ (worldBlock == placeCasing && worldBlock.getDamageValue(world, x, y, z) == placeCasingMeta);
+ }
+
+ @Override
+ public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
+ StructureLibAPI.hintParticle(world, x, y, z, aHintBlock, hintMeta);
+ return true;
+ }
+
+ @Override
+ public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
+ world.setBlock(x, y, z, placeCasing, placeCasingMeta, 2);
+ return true;
+ }
+
+ @Override
+ public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
+ if (check(t, world, x, y, z)) return PlaceResult.SKIP;
+ return StructureUtility.survivalPlaceBlock(placeCasing, placeCasingMeta, world, x, y, z, s, actor, chatter);
+ }
+ };
+ }
+
+ /**
+ * Assume all coils accepted.
+ *
+ * @see #ofCoil(BiPredicate, Function)
+ */
+ public static <T> IStructureElement<T> ofCoil(BiConsumer<T, HeatingCoilLevel> aHeatingCoilSetter, Function<T, HeatingCoilLevel> aHeatingCoilGetter) {
+ return ofCoil((t, l) -> {
+ aHeatingCoilSetter.accept(t, l);
+ return true;
+ }, aHeatingCoilGetter);
+ }
+
+ /**
+ * Heating coil structure element.
+ *
+ * @param aHeatingCoilSetter Notify the controller of this new coil.
+ * Got called exactly once per coil.
+ * Might be called less times if structure test fails.
+ * If the setter returns false then it assumes the coil is rejected.
+ * @param aHeatingCoilGetter Get the current heating level. Null means no coil recorded yet.
+ */
+ public static <T> IStructureElement<T> ofCoil(BiPredicate<T, HeatingCoilLevel> aHeatingCoilSetter, Function<T, HeatingCoilLevel> aHeatingCoilGetter) {
+ if (aHeatingCoilSetter == null || aHeatingCoilGetter == null) {
+ throw new IllegalArgumentException();
+ }
+ return new IStructureElement<T>() {
+ @Override
+ public boolean check(T t, World world, int x, int y, int z) {
+ Block block = world.getBlock(x, y, z);
+ if (!(block instanceof IHeatingCoil))
+ return false;
+ HeatingCoilLevel existingLevel = aHeatingCoilGetter.apply(t),
+ newLevel = ((IHeatingCoil) block).getCoilHeat(world.getBlockMetadata(x, y, z));
+ if (existingLevel == null || existingLevel == HeatingCoilLevel.None) {
+ return aHeatingCoilSetter.test(t, newLevel);
+ } else {
+ return newLevel == existingLevel;
+ }
+ }
+
+ @Override
+ public boolean spawnHint(T t, World world, int x, int y, int z, ItemStack trigger) {
+ StructureLibAPI.hintParticle(world, x, y, z, GregTech_API.sBlockCasings5, getMetaFromHint(trigger));
+ return true;
+ }
+
+ private int getMetaFromHint(ItemStack trigger) {
+ return GT_Block_Casings5.getMetaFromCoilHeat(getHeatFromHint(trigger));
+ }
+
+ private HeatingCoilLevel getHeatFromHint(ItemStack trigger) {
+ return HeatingCoilLevel.getFromTier((byte) Math.min(HeatingCoilLevel.getMaxTier() , Math.max(0, trigger.stackSize - 1)));
+ }
+
+ @Override
+ public boolean placeBlock(T t, World world, int x, int y, int z, ItemStack trigger) {
+ return world.setBlock(x, y, z, GregTech_API.sBlockCasings5, getMetaFromHint(trigger), 3);
+ }
+
+ @Override
+ public PlaceResult survivalPlaceBlock(T t, World world, int x, int y, int z, ItemStack trigger, IItemSource s, EntityPlayerMP actor, Consumer<IChatComponent> chatter) {
+ Block block = world.getBlock(x, y, z);
+ boolean isCoil = block instanceof IHeatingCoil && ((IHeatingCoil) block).getCoilHeat(world.getBlockMetadata(x, y, z)) == getHeatFromHint(trigger);
+ if (isCoil) return PlaceResult.SKIP;
+ return StructureUtility.survivalPlaceBlock(GregTech_API.sBlockCasings5, getMetaFromHint(trigger), world, x, y, z, s, actor, chatter);
+ }
+ };
+ }
+
+ @Nonnull
+ public static Predicate<ItemStack> filterByMTEClass(List<? extends Class<? extends IMetaTileEntity>> list) {
+ return is -> {
+ IMetaTileEntity tile = GT_Item_Machines.getMetaTileEntity(is);
+ return tile != null && list.stream().anyMatch(c -> c.isInstance(tile));
+ };
+ }
+
+ @Nonnull
+ public static Predicate<ItemStack> filterByMTETier(int aMinTier, int aMaxTier) {
+ return is -> {
+ IMetaTileEntity tile = GT_Item_Machines.getMetaTileEntity(is);
+ return tile instanceof GT_MetaTileEntity_TieredMachineBlock &&
+ ((GT_MetaTileEntity_TieredMachineBlock) tile).mTier <= aMaxTier &&
+ ((GT_MetaTileEntity_TieredMachineBlock) tile).mTier >= aMinTier;
+ };
+ }
}
diff --git a/src/main/java/gregtech/api/util/IGT_HatchAdder.java b/src/main/java/gregtech/api/util/IGT_HatchAdder.java
index 362fddaf1f..16fdd90e62 100644
--- a/src/main/java/gregtech/api/util/IGT_HatchAdder.java
+++ b/src/main/java/gregtech/api/util/IGT_HatchAdder.java
@@ -12,4 +12,16 @@ public interface IGT_HatchAdder<T> {
* @return managed to add hatch (structure still valid)
*/
boolean apply(T t, IGregTechTileEntity iGregTechTileEntity, Short aShort);
+
+ /**
+ * hack to work around java generic issues.
+ */
+ @SuppressWarnings("unchecked")
+ default <T2 extends T> IGT_HatchAdder<T2> rebrand() {
+ return (IGT_HatchAdder<T2>) this;
+ }
+
+ default IGT_HatchAdder<T> orElse(IGT_HatchAdder<? super T> fallback) {
+ return (t, iGregTechTileEntity, aShort) -> IGT_HatchAdder.this.apply(t, iGregTechTileEntity, aShort) || fallback.apply(t, iGregTechTileEntity, aShort);
+ }
}