From d75067976a48c7d2335b18c1cf07250a7c9999ef Mon Sep 17 00:00:00 2001 From: Glease <4586901+Glease@users.noreply.github.com> Date: Tue, 9 Aug 2022 14:13:53 +0800 Subject: autoplace integration (#1117) --- .../java/gregtech/api/enums/GT_HatchElement.java | 100 +++++ .../gregtech/api/interfaces/IHatchElement.java | 134 ++++++ .../GT_MetaTileEntity_CubicMultiBlockBase.java | 32 +- .../GT_MetaTileEntity_EnhancedMultiBlockBase.java | 22 +- .../GT_MetaTileEntity_MultiBlockBase.java | 48 ++- .../api/util/GT_ExoticEnergyInputHelper.java | 12 +- .../gregtech/api/util/GT_HatchElementBuilder.java | 303 +++++++++++++ .../gregtech/api/util/GT_StructureUtility.java | 476 ++++++++++++++------- .../java/gregtech/api/util/IGT_HatchAdder.java | 12 + 9 files changed, 961 insertions(+), 178 deletions(-) create mode 100644 src/main/java/gregtech/api/enums/GT_HatchElement.java create mode 100644 src/main/java/gregtech/api/interfaces/IHatchElement.java create mode 100644 src/main/java/gregtech/api/util/GT_HatchElementBuilder.java (limited to 'src/main/java/gregtech/api') diff --git a/src/main/java/gregtech/api/enums/GT_HatchElement.java b/src/main/java/gregtech/api/enums/GT_HatchElement.java new file mode 100644 index 0000000000..5e26c43f80 --- /dev/null +++ b/src/main/java/gregtech/api/enums/GT_HatchElement.java @@ -0,0 +1,100 @@ +package gregtech.api.enums; + +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Dynamo; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Energy; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Maintenance; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Muffler; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_OutputBus; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.util.GT_ExoticEnergyInputHelper; +import gregtech.api.util.IGT_HatchAdder; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public enum GT_HatchElement implements IHatchElement> { + Muffler(GT_MetaTileEntity_MultiBlockBase::addMufflerToMachineList, GT_MetaTileEntity_Hatch_Muffler.class) { + @Override + public long count(GT_MetaTileEntity_EnhancedMultiBlockBase t) { + return t.mMufflerHatches.size(); + } + }, + Maintenance(GT_MetaTileEntity_MultiBlockBase::addMaintenanceToMachineList, GT_MetaTileEntity_Hatch_Maintenance.class) { + @Override + public long count(GT_MetaTileEntity_EnhancedMultiBlockBase t) { + return t.mMaintenanceHatches.size(); + } + }, + InputHatch(GT_MetaTileEntity_MultiBlockBase::addInputHatchToMachineList, GT_MetaTileEntity_Hatch_Input.class) { + @Override + public long count(GT_MetaTileEntity_EnhancedMultiBlockBase t) { + return t.mInputHatches.size(); + } + }, + InputBus(GT_MetaTileEntity_MultiBlockBase::addInputBusToMachineList, GT_MetaTileEntity_Hatch_InputBus.class) { + @Override + public long count(GT_MetaTileEntity_EnhancedMultiBlockBase t) { + return t.mInputBusses.size(); + } + }, + OutputHatch(GT_MetaTileEntity_MultiBlockBase::addOutputHatchToMachineList, GT_MetaTileEntity_Hatch_Output.class) { + @Override + public long count(GT_MetaTileEntity_EnhancedMultiBlockBase t) { + return t.mOutputHatches.size(); + } + }, + OutputBus(GT_MetaTileEntity_MultiBlockBase::addOutputBusToMachineList, GT_MetaTileEntity_Hatch_OutputBus.class) { + @Override + public long count(GT_MetaTileEntity_EnhancedMultiBlockBase t) { + return t.mOutputBusses.size(); + } + }, + Energy(GT_MetaTileEntity_MultiBlockBase::addEnergyInputToMachineList, GT_MetaTileEntity_Hatch_Energy.class) { + @Override + public long count(GT_MetaTileEntity_EnhancedMultiBlockBase t) { + return t.mEnergyHatches.size(); + } + }, + Dynamo(GT_MetaTileEntity_MultiBlockBase::addDynamoToMachineList, GT_MetaTileEntity_Hatch_Dynamo.class) { + @Override + public long count(GT_MetaTileEntity_EnhancedMultiBlockBase t) { + return t.mDynamoHatches.size(); + } + }, + ExoticEnergy(GT_MetaTileEntity_MultiBlockBase::addExoticEnergyInputToMachineList) { + @Override + public List> mteClasses() { + return GT_ExoticEnergyInputHelper.getAllClasses(); + } + + @Override + public long count(GT_MetaTileEntity_EnhancedMultiBlockBase t) { + return t.getExoticEnergyHatches().size(); + } + }, + ; + private final List> mteClasses; + private final IGT_HatchAdder> adder; + + @SafeVarargs + GT_HatchElement(IGT_HatchAdder> adder, Class... mteClasses) { + this.mteClasses = Collections.unmodifiableList(Arrays.asList(mteClasses)); + this.adder = adder; + } + + @Override + public List> mteClasses() { + return mteClasses; + } + + public IGT_HatchAdder> adder() { + return adder; + } +} diff --git a/src/main/java/gregtech/api/interfaces/IHatchElement.java b/src/main/java/gregtech/api/interfaces/IHatchElement.java new file mode 100644 index 0000000000..b93cbeacbc --- /dev/null +++ b/src/main/java/gregtech/api/interfaces/IHatchElement.java @@ -0,0 +1,134 @@ +package gregtech.api.interfaces; + +import com.gtnewhorizon.structurelib.structure.IStructureElement; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_EnhancedMultiBlockBase; +import gregtech.api.util.GT_StructureUtility; +import gregtech.api.util.IGT_HatchAdder; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.BiPredicate; +import java.util.function.ToLongFunction; + +public interface IHatchElement> { + List> mteClasses(); + + IGT_HatchAdder adder(); + + String name(); + + long count(T t); + + default IHatchElement withMteClass(Class aClass) { + if (aClass == null) throw new IllegalArgumentException(); + return withMteClasses(Collections.singletonList(aClass)); + } + + @SuppressWarnings("unchecked") // can't set SafeVarargs :( + default IHatchElement withMteClasses(Class... aClasses) { + if (aClasses == null) throw new IllegalArgumentException(); + return withMteClasses(Arrays.asList(aClasses)); + } + + default IHatchElement withMteClasses(List> aClasses) { + if (aClasses == null) throw new IllegalArgumentException(); + return new HatchElement<>(aClasses, null, null, null, this); + } + + default IHatchElement withAdder(IGT_HatchAdder aAdder) { + if (aAdder == null) throw new IllegalArgumentException(); + return new HatchElement<>(null, aAdder, null, null, this); + } + + default IHatchElement withName(String aName) { + if (aName == null) throw new IllegalArgumentException(); + return new HatchElement<>(null, null, aName, null, this); + } + + default IHatchElement withCount(ToLongFunction aCount) { + if (aCount == null) throw new IllegalArgumentException(); + return new HatchElement<>(null, null, null, aCount, this); + } + + default IStructureElement newAny(int aCasingIndex, int aDot) { + if (aCasingIndex < 0 || aDot < 0) throw new IllegalArgumentException(); + return GT_StructureUtility.buildHatchAdder() + .anyOf(this) + .casingIndex(aCasingIndex) + .dot(aDot) + .build(); + } + + default IStructureElement newAny(int aCasingIndex, int aDot, BiPredicate aShouldSkip) { + if (aCasingIndex < 0 || aDot < 0 || aShouldSkip == null) throw new IllegalArgumentException(); + return GT_StructureUtility.buildHatchAdder() + .anyOf(this) + .casingIndex(aCasingIndex) + .dot(aDot) + .shouldSkip(aShouldSkip) + .build(); + } +} + +class HatchElement> implements IHatchElement { + private final List> mClasses; + private final IGT_HatchAdder mAdder; + private final String mName; + private final IHatchElement mBacking; + private final ToLongFunction mCount; + + public HatchElement(List> aMteClasses, IGT_HatchAdder aAdder, String aName, ToLongFunction aCount, IHatchElement aBacking) { + this.mClasses = aMteClasses; + this.mAdder = aAdder; + this.mName = aName; + this.mCount = aCount; + this.mBacking = aBacking; + } + + @Override + public List> mteClasses() { + return mClasses == null ? mBacking.mteClasses() : mClasses; + } + + @Override + public IGT_HatchAdder adder() { + return mAdder == null ? mBacking.adder() : mAdder; + } + + @Override + public String name() { + return mName == null ? mBacking.name() : mName; + } + + @Override + public long count(T t) { + return mCount == null ? mBacking.count(t) : mCount.applyAsLong(t); + } + + @Override + public IHatchElement withMteClasses(List> aClasses) { + if (aClasses == null) throw new IllegalArgumentException(); + return new HatchElement<>(aClasses, mAdder, mName, mCount, mBacking); + } + + @Override + public IHatchElement withAdder(IGT_HatchAdder aAdder) { + if (aAdder == null) throw new IllegalArgumentException(); + return new HatchElement<>(mClasses, aAdder, mName, mCount, mBacking); + } + + @Override + public IHatchElement withName(String aName) { + if (aName == null) throw new IllegalArgumentException(); + return new HatchElement<>(mClasses, mAdder, aName, mCount, mBacking); + } + + @Override + public IHatchElement withCount(ToLongFunction aCount) { + if (aCount == null) throw new IllegalArgumentException(); + return new HatchElement<>(mClasses, mAdder, mName, aCount, mBacking); + } +} diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_CubicMultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_CubicMultiBlockBase.java index 3854a96cda..c2212e331e 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_CubicMultiBlockBase.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_CubicMultiBlockBase.java @@ -1,16 +1,24 @@ package gregtech.api.metatileentity.implementations; +import com.google.common.collect.ImmutableList; +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IItemSource; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.IStructureElement; import com.gtnewhorizon.structurelib.structure.StructureDefinition; +import gregtech.api.interfaces.IHatchElement; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.util.GT_StructureUtility; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; +import java.util.List; + import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy; import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; -import static gregtech.api.util.GT_StructureUtility.ofHatchAdder; +import static gregtech.api.enums.GT_HatchElement.*; /** * A simple 3x3x3 hollow cubic multiblock, that can be arbitrarily rotated, made of a single type of machine casing and accepts hatches everywhere. @@ -27,7 +35,7 @@ import static gregtech.api.util.GT_StructureUtility.ofHatchAdder; * * @param */ -public abstract class GT_MetaTileEntity_CubicMultiBlockBase> extends GT_MetaTileEntity_EnhancedMultiBlockBase { +public abstract class GT_MetaTileEntity_CubicMultiBlockBase> extends GT_MetaTileEntity_EnhancedMultiBlockBase implements ISurvivalConstructable { protected static final String STRUCTURE_PIECE_MAIN = "main"; protected static final ClassValue>> STRUCTURE_DEFINITION = new ClassValue>>() { @Override @@ -39,7 +47,13 @@ public abstract class GT_MetaTileEntity_CubicMultiBlockBase ofHatchAdder(GT_MetaTileEntity_CubicMultiBlockBase::addToMachineList, t.getHatchTextureIndex(), 1)), + lazy( + t -> GT_StructureUtility.>buildHatchAdder() + .atLeastList(t.getAllowedHatches()) + .casingIndex(t.getHatchTextureIndex()) + .dot(1) + .build() + ), onElementPass( GT_MetaTileEntity_CubicMultiBlockBase::onCorrectCasingAdded, lazy(GT_MetaTileEntity_CubicMultiBlockBase::getCasingElement) @@ -74,7 +88,13 @@ public abstract class GT_MetaTileEntity_CubicMultiBlockBase> getCasingElement(); + protected List>> getAllowedHatches() { + return ImmutableList.of(InputHatch, OutputHatch, InputBus, OutputBus, Muffler, Maintenance, Energy); + } + /** * The hatch's texture index. */ diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_EnhancedMultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_EnhancedMultiBlockBase.java index e5a48f706d..1e85933522 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_EnhancedMultiBlockBase.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_EnhancedMultiBlockBase.java @@ -8,12 +8,13 @@ import com.gtnewhorizon.structurelib.alignment.constructable.IConstructable; import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; import com.gtnewhorizon.structurelib.alignment.enumerable.Flip; import com.gtnewhorizon.structurelib.alignment.enumerable.Rotation; +import com.gtnewhorizon.structurelib.structure.IItemSource; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import cpw.mods.fml.common.network.NetworkRegistry; -import gregtech.api.interfaces.ISecondaryDescribable; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraftforge.common.util.ForgeDirection; @@ -150,10 +151,21 @@ public abstract class GT_MetaTileEntity_EnhancedMultiBlockBase 0) checkStructure(true, getBaseMetaTileEntity()); + return built; + } @Override public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { diff --git a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java index 87d2c65df5..a31be046b3 100644 --- a/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java +++ b/src/main/java/gregtech/api/metatileentity/implementations/GT_MetaTileEntity_MultiBlockBase.java @@ -1004,14 +1004,19 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity { } public boolean addInputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + return addInputBusToMachineList(aTileEntity, aBaseCasingIndex) || + addInputHatchToMachineList(aTileEntity, aBaseCasingIndex); + } + + public boolean addOutputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + return addOutputBusToMachineList(aTileEntity, aBaseCasingIndex) || + addOutputHatchToMachineList(aTileEntity, aBaseCasingIndex); + } + + public boolean addInputBusToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { if (aTileEntity == null) return false; IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); if (aMetaTileEntity == null) return false; - if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) { - ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); - ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mRecipeMap = getRecipeMap(); - return mInputHatches.add((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity); - } if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_InputBus) { ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); ((GT_MetaTileEntity_Hatch_InputBus) aMetaTileEntity).mRecipeMap = getRecipeMap(); @@ -1020,14 +1025,10 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity { return false; } - public boolean addOutputToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + public boolean addOutputBusToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { if (aTileEntity == null) return false; IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); if (aMetaTileEntity == null) return false; - if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output) { - ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); - return mOutputHatches.add((GT_MetaTileEntity_Hatch_Output) aMetaTileEntity); - } if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_OutputBus) { ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); return mOutputBusses.add((GT_MetaTileEntity_Hatch_OutputBus) aMetaTileEntity); @@ -1035,6 +1036,29 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity { return false; } + public boolean addInputHatchToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Input) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + ((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity).mRecipeMap = getRecipeMap(); + return mInputHatches.add((GT_MetaTileEntity_Hatch_Input) aMetaTileEntity); + } + return false; + } + + public boolean addOutputHatchToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof GT_MetaTileEntity_Hatch_Output) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + return mOutputHatches.add((GT_MetaTileEntity_Hatch_Output) aMetaTileEntity); + } + return false; + } + @Override public String[] getInfoData() { int mPollutionReduction=0; @@ -1160,4 +1184,8 @@ public abstract class GT_MetaTileEntity_MultiBlockBase extends MetaTileEntity { tag.setBoolean("incompleteStructure", (getBaseMetaTileEntity().getErrorDisplayID() & 64) != 0); } + + public List getExoticEnergyHatches() { + return mExoticEnergyHatches; + } } 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> sExoticEnergyHatchType = new ArrayList<>(); + private static final List> 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) clazz); } public static boolean drainEnergy(long aEU, Collection hatches) { @@ -68,4 +70,8 @@ public class GT_ExoticEnergyInputHelper { if (isValidMetaTileEntity(tHatch)) rAmp += tHatch.getBaseMetaTileEntity().getInputAmperage(); return rAmp; } + + public static List> 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> { + private interface Builtin { + } + + private IGT_HatchAdder mAdder; + private int mCasingIndex = -1; + private int mDot = -1; + private BiPredicate mShouldSkip; + private Function> mHatchItemFilter; + private Supplier mHatchItemType; + private Predicate mReject, mBuiltinReject; + private boolean mCacheHint; + + private GT_HatchElementBuilder() { + } + + public static > GT_HatchElementBuilder 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 anyOf(IHatchElement... 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. + *

+ * Will rotate through all elements + * TODO add doc + */ + @SafeVarargs + public final GT_HatchElementBuilder atLeast(IHatchElement... 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. + *

+ * Will rotate through all elements + * TODO add doc + */ + public final GT_HatchElementBuilder atLeastList(List> 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 atLeast(Map, ? extends Number> elements) { + if (elements == null || elements.isEmpty() || elements.containsKey(null) || elements.containsValue(null)) + throw new IllegalArgumentException(); + List> 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 & 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 adder(IGT_HatchAdder aAdder) { + if (aAdder == null) throw new IllegalArgumentException(); + mAdder = aAdder; + return this; + } + + public GT_HatchElementBuilder casingIndex(int aCasingIndex) { + if (aCasingIndex <= 0) throw new IllegalArgumentException(); + mCasingIndex = aCasingIndex; + return this; + } + + public GT_HatchElementBuilder dot(int aDot) { + if (aDot <= 0) throw new IllegalArgumentException(); + mDot = aDot; + return this; + } + + public GT_HatchElementBuilder shouldSkip(BiPredicate 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

& Builtin> GT_HatchElementBuilder shouldSkipInternal(P aShouldSkip) { + // if (mShouldSkip == null) mShouldSkip = aShouldSkip; + // return this; + // } + // turns out javac doesn't like this... so... + + public GT_HatchElementBuilder shouldReject(Predicate aShouldReject) { + if (aShouldReject == null) throw new IllegalArgumentException(); + mReject = aShouldReject; + return this; + } + + public GT_HatchElementBuilder hatchItemFilter(Function> aHatchItemFilter) { + if (aHatchItemFilter == null) throw new IllegalArgumentException(); + mHatchItemFilter = aHatchItemFilter; + return this; + } + + public GT_HatchElementBuilder hatchItemFilterAnd(Function> aHatchItemFilter) { + if (aHatchItemFilter == null) throw new IllegalArgumentException(); + Function> tOldFilter = mHatchItemFilter; + mHatchItemFilter = t -> tOldFilter.apply(t).and(aHatchItemFilter.apply(t)); + return this; + } + + // region hint + public GT_HatchElementBuilder hint(Supplier aSupplier) { + if (aSupplier == null) throw new IllegalArgumentException(); + mHatchItemType = aSupplier; + mCacheHint = false; + return this; + } + + public GT_HatchElementBuilder cacheHint(Supplier aSupplier) { + if (aSupplier == null) throw new IllegalArgumentException(); + mHatchItemType = aSupplier; + mCacheHint = true; + return this; + } + + public GT_HatchElementBuilder cacheHint() { + if (mHatchItemType == null) throw new IllegalStateException(); + mCacheHint = true; + return this; + } + // endregion + // endregion + + // region intermediate + public GT_HatchElementBuilder hatchClass(Class clazz) { + return hatchItemFilter(c -> is -> clazz.isInstance(GT_Item_Machines.getMetaTileEntity(is))) + .cacheHint(() -> "of class " + clazz.getSimpleName()); + } + + @SafeVarargs + public final GT_HatchElementBuilder hatchClasses(Class... classes) { + return hatchClasses(Arrays.asList(classes)); + } + + public final GT_HatchElementBuilder hatchClasses(List> classes) { + List> 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 & Builtin) (c, t) -> t != null && list.stream().anyMatch(clazz -> clazz.isInstance(t.getMetaTileEntity()))); + } + + public GT_HatchElementBuilder 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 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 buildAndChain(IStructureElement... elements) { + List> l = new ArrayList<>(); + l.add(build()); + l.addAll(Arrays.asList(elements)); + IStructureElement[] array = l.toArray(new IStructureElement[0]); + return () -> array; + } + + public final IStructureElementChain buildAndChain(Block block, int meta) { + return buildAndChain(ofBlock(block, meta)); + } + + public IStructureElement build() { + if (mAdder == null || mCasingIndex == -1 || mDot == -1) { + throw new IllegalArgumentException(); + } + if (mHatchItemFilter == null) { + // no item filter -> no placement + return new IStructureElementNoPlacement() { + @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() { + 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 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 IStructureElementNoPlacement ofHatchAdder(IGT_HatchAdder aHatchAdder, int aTextureIndex, int aDots) { - return ofHatchAdder(aHatchAdder, aTextureIndex, StructureLibAPI.getBlockHint(), aDots - 1); - } - - public static IStructureElement ofFrame(Materials aFrameMaterial) { - if (aFrameMaterial == null) throw new IllegalArgumentException(); - return new IStructureElement() { - - 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 IStructureElementNoPlacement ofHatchAdder(IGT_HatchAdder aHatchAdder, int aTextureIndex, Block aHintBlock, int aHintMeta) { - if (aHatchAdder == null || aHintBlock == 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); - 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 IStructureElement ofHatchAdderOptional(IGT_HatchAdder aHatchAdder, int textureIndex, int dots, Block placeCasing, int placeCasingMeta) { - return ofHatchAdderOptional(aHatchAdder, textureIndex, StructureLibAPI.getBlockHint(), dots - 1, placeCasing, placeCasingMeta); - } - - public static IStructureElement ofHatchAdderOptional(IGT_HatchAdder aHatchAdder, int aTextureIndex, Block aHintBlock, int hintMeta, Block placeCasing, int placeCasingMeta) { - if (aHatchAdder == null || aHintBlock == null) { - throw new IllegalArgumentException(); - } - return new IStructureElement() { - @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 IStructureElement ofCoil(BiConsumer aHeatingCoilSetter, Function 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 IStructureElement ofCoil(BiPredicate aHeatingCoilSetter, Function aHeatingCoilGetter) { - if (aHeatingCoilSetter == null || aHeatingCoilGetter == null) { - throw new IllegalArgumentException(); - } - return new IStructureElement() { - @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, String> customNames = new HashMap<>(); + private GT_StructureUtility() { + throw new AssertionError("Not instantiable"); + } + + public static boolean hasMTE(IGregTechTileEntity aTile, Class clazz) { + return aTile != null && clazz.isInstance(aTile.getMetaTileEntity()); + } + + public static IStructureElementNoPlacement ofHatchAdder(IGT_HatchAdder aHatchAdder, int aTextureIndex, int aDots) { + return ofHatchAdder(aHatchAdder, aTextureIndex, StructureLibAPI.getBlockHint(), aDots - 1); + } + + public static IStructureElement ofFrame(Materials aFrameMaterial) { + if (aFrameMaterial == null) throw new IllegalArgumentException(); + return new IStructureElement() { + + 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 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 > GT_HatchElementBuilder buildHatchAdder() { + return GT_HatchElementBuilder.builder(); + } + + /** + * Completely equivalent to {@link #buildHatchAdder()}, except it plays nicer with type inference when statically imported + */ + public static > GT_HatchElementBuilder buildHatchAdder(Class typeToken) { + return GT_HatchElementBuilder.builder(); + } + + public static IStructureElementNoPlacement ofHatchAdder(IGT_HatchAdder aHatchAdder, int aTextureIndex, Block aHintBlock, int aHintMeta) { + if (aHatchAdder == null || aHintBlock == 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); + 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 IStructureElement ofHatchAdder(IGT_HatchAdder aHatchAdder, int aTextureIndex, Block aHintBlock, int aHintMeta, BiPredicate shouldSkip, Function> aMetaId, final IStructureElement.PlaceResult acceptType) { + if (aHatchAdder == null) { + throw new IllegalArgumentException(); + } + return new IStructureElement() { + @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 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 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 IStructureElement ofHatchAdder(IGT_HatchAdder aHatchAdder, int aTextureIndex, Block aHintBlock, int aHintMeta, BiPredicate shouldSkip, ToIntFunction aMetaId) { + if (aHatchAdder == null) { + throw new IllegalArgumentException(); + } + return new IStructureElement() { + @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 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 IStructureElement ofHatchAdderOptional(IGT_HatchAdder aHatchAdder, int textureIndex, int dots, Block placeCasing, int placeCasingMeta) { + return ofHatchAdderOptional(aHatchAdder, textureIndex, StructureLibAPI.getBlockHint(), dots - 1, placeCasing, placeCasingMeta); + } + + public static IStructureElement ofHatchAdderOptional(IGT_HatchAdder aHatchAdder, int aTextureIndex, Block aHintBlock, int hintMeta, Block placeCasing, int placeCasingMeta) { + if (aHatchAdder == null || aHintBlock == null) { + throw new IllegalArgumentException(); + } + return new IStructureElement() { + @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 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 IStructureElement ofCoil(BiConsumer aHeatingCoilSetter, Function 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 IStructureElement ofCoil(BiPredicate aHeatingCoilSetter, Function aHeatingCoilGetter) { + if (aHeatingCoilSetter == null || aHeatingCoilGetter == null) { + throw new IllegalArgumentException(); + } + return new IStructureElement() { + @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 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 filterByMTEClass(List> list) { + return is -> { + IMetaTileEntity tile = GT_Item_Machines.getMetaTileEntity(is); + return tile != null && list.stream().anyMatch(c -> c.isInstance(tile)); + }; + } + + @Nonnull + public static Predicate 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 { * @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 IGT_HatchAdder rebrand() { + return (IGT_HatchAdder) this; + } + + default IGT_HatchAdder orElse(IGT_HatchAdder fallback) { + return (t, iGregTechTileEntity, aShort) -> IGT_HatchAdder.this.apply(t, iGregTechTileEntity, aShort) || fallback.apply(t, iGregTechTileEntity, aShort); + } } -- cgit