diff --git a/src/main/java/gregtech/GTMod.java b/src/main/java/gregtech/GTMod.java index a52a9c2013c..11fecd55000 100644 --- a/src/main/java/gregtech/GTMod.java +++ b/src/main/java/gregtech/GTMod.java @@ -94,6 +94,7 @@ import gregtech.common.misc.spaceprojects.commands.SPMCommand; import gregtech.common.misc.spaceprojects.commands.SpaceProjectCommand; import gregtech.common.tileentities.machines.MTEHatchCraftingInputME; +import gregtech.common.tileentities.machines.multi.nanochip.util.RecipeHandlers; import gregtech.common.tileentities.storage.MTEDigitalChestBase; import gregtech.crossmod.holoinventory.HoloInventory; import gregtech.crossmod.waila.Waila; @@ -389,6 +390,10 @@ public boolean test(ItemStack stack) { GT_FML_LOGGER.debug("Registering SpaceDimensions"); SpaceDimRegisterer.register(); + // This needs to run BEFORE creating any circuit assembler recipes, since the downstream + // recipe map for the assembly matrix relies on doing recipe lookups here. + // I really hope I can put this here without breaking something + RecipeHandlers.populateCircuitComponentRecipeMaps(); GregTechAPI.sLoadFinished = true; GTLog.out.println("GTMod: Load-Phase finished!"); diff --git a/src/main/java/gregtech/api/GregTechAPI.java b/src/main/java/gregtech/api/GregTechAPI.java index 70d1a0c2ce9..ccaecff2214 100644 --- a/src/main/java/gregtech/api/GregTechAPI.java +++ b/src/main/java/gregtech/api/GregTechAPI.java @@ -64,6 +64,7 @@ import gregtech.api.util.item.ItemHolder; import gregtech.api.world.GTWorldgen; import gregtech.common.GTDummyWorld; +import gregtech.common.blocks.BlockCasingsAbstract; import gregtech.common.items.ItemIntegratedCircuit; /** @@ -669,4 +670,18 @@ public static TileEntity createTileEntity(int meta) { if (teCreators[meta] == null) return null; return teCreators[meta].apply(meta); } + + /** + * Get the texture index of a casing block and meta. + * + * @param block Block to check, must extend GT_Block_Casings_Abstract + * @param meta Meta of the block to check + * @return A valid texture index + */ + public static int getCasingTextureIndex(Block block, int meta) { + if (block instanceof BlockCasingsAbstract gtBlock) { + return gtBlock.getTextureIndex(meta); + } + throw new IllegalArgumentException("Passed non-gt casing block to getCasingTextureIndex"); + } } diff --git a/src/main/java/gregtech/api/enums/ItemList.java b/src/main/java/gregtech/api/enums/ItemList.java index 6910c0d72ed..7bf56f9ed14 100644 --- a/src/main/java/gregtech/api/enums/ItemList.java +++ b/src/main/java/gregtech/api/enums/ItemList.java @@ -1515,11 +1515,22 @@ public enum ItemList implements IItemContainer { Casing_Laser, Machine_Multi_IndustrialExtractor, - Machine_Multi_Lathe, Machine_Multi_Autoclave, Casing_Autoclave, + Machine_Multi_NanochipAssemblyComplex, + Hatch_VacuumConveyor_Input, + Hatch_VacuumConveyor_Output, + VacuumConveyorPipe, + NanoChipModule_AssemblyMatrix, + NanoChipModule_SMDProcessor, + NanoChipModule_BoardProcessor, + NanoChipModule_EtchingArray, + NanoChipModule_CuttingChamber, + NanoChipModule_WireTracer, + NanoChipModule_Splitter, + Machine_LV_Miner, Machine_MV_Miner, Machine_HV_Miner, diff --git a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java index 2aa902b8357..be6dfb828c9 100644 --- a/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java +++ b/src/main/java/gregtech/api/enums/MetaTileEntityIDs.java @@ -846,6 +846,17 @@ public enum MetaTileEntityIDs { PURIFICATION_UNIT_DEGASIFIER(9412), HATCH_DEGASIFIER_CONTROL(9413), PURIFICATION_UNIT_PARTICLE_EXTRACTOR(9414), + NANOCHIP_ASSEMBLY_CONTROLLER(9500), + HATCH_VACUUM_CONVEYOR_INPUT(9501), + HATCH_VACUUM_CONVEYOR_OUTPUT(9502), + VACUUM_CONVEYOR_PIPE(9503), + NANOCHIP_MODULE_ASSEMBLY_MATRIX(9504), + NANOCHIP_MODULE_SMD_PROCESSOR(9505), + NANOCHIP_MODULE_BOARD_PROCESSOR(9506), + NANOCHIP_MODULE_ETCHING_ARRAY(9507), + NANOCHIP_MODULE_CUTTING_CHAMBER(9508), + NANOCHIP_MODULE_WIRE_TRACER(9509), + NANOCHIP_MODULE_SPLITTER(9510), PLASMA_GENERATOR_ZPM(10752), PLASMA_GENERATOR_UV(10753), ALLOY_SMELTER_LuV(10760), diff --git a/src/main/java/gregtech/api/items/CircuitComponentFakeItem.java b/src/main/java/gregtech/api/items/CircuitComponentFakeItem.java new file mode 100644 index 00000000000..e8451149eae --- /dev/null +++ b/src/main/java/gregtech/api/items/CircuitComponentFakeItem.java @@ -0,0 +1,50 @@ +package gregtech.api.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import net.minecraft.util.IIcon; + +import java.util.List; + +public class CircuitComponentFakeItem extends GTGenericItem { + + public static CircuitComponentFakeItem INSTANCE = null; + + public CircuitComponentFakeItem() { + super("gt.fakecircuitcomponent", "Fake Circuit Component Item", null); + setMaxDamage(0); + setHasSubtypes(true); + INSTANCE = this; + } + + @Override + public String getUnlocalizedName(ItemStack aStack) { + CircuitComponent component = CircuitComponent.getFromFakeStackUnsafe(aStack); + return component.unlocalizedName; + } + + @Override + public String getItemStackDisplayName(ItemStack stack) { + CircuitComponent component = CircuitComponent.getFromFakeStackUnsafe(stack); + return component.getLocalizedName(); + } + + @Override + public void addInformation(ItemStack aStack, EntityPlayer aPlayer, List aList, boolean aF3_H) { + aList.add("Item in the Nanochip Assembly Complex vacuum pipe system"); + super.addInformation(aStack, aPlayer, aList, aF3_H); + } + + @Override + public IIcon getIconFromDamage(int meta) { + // If the component stores an icon, use that + CircuitComponent component = CircuitComponent.getFromMetaDataUnsafe(meta); + if (component.icon != null) return component.icon; + // Else just use the texture that should be assigned to it + return super.getIconFromDamage(meta); + } + + +} diff --git a/src/main/java/gregtech/api/recipe/RecipeMaps.java b/src/main/java/gregtech/api/recipe/RecipeMaps.java index 31c4ce8b249..9d10980a0a7 100644 --- a/src/main/java/gregtech/api/recipe/RecipeMaps.java +++ b/src/main/java/gregtech/api/recipe/RecipeMaps.java @@ -7,18 +7,11 @@ import static gregtech.api.enums.Mods.Railcraft; import static gregtech.api.enums.TickTime.TICK; import static gregtech.api.util.GTModHandler.getModItem; -import static gregtech.api.util.GTRecipeConstants.ADDITIVE_AMOUNT; -import static gregtech.api.util.GTRecipeConstants.FUEL_VALUE; -import static gregtech.api.util.GTRecipeConstants.SIEVERTS; -import static gregtech.api.util.GTRecipeMapUtil.GTRecipeTemplate; +import static gregtech.api.util.GTRecipeConstants.*; import static gregtech.api.util.GTRecipeMapUtil.asTemplate; import static gregtech.api.util.GTRecipeMapUtil.buildOrEmpty; -import static gregtech.api.util.GTUtility.clamp; -import static gregtech.api.util.GTUtility.copyAmount; -import static gregtech.api.util.GTUtility.getFluidForFilledItem; -import static gregtech.api.util.GTUtility.isArrayEmptyOrNull; -import static gregtech.api.util.GTUtility.isArrayOfLength; -import static gregtech.api.util.GTUtility.multiplyStack; +import static gregtech.api.util.GTUtility.*; +import static gregtech.common.tileentities.machines.multi.nanochip.util.RecipeHandlers.assemblyMatrixRecipeTransformer; import java.util.ArrayList; import java.util.Collection; @@ -74,11 +67,10 @@ import gregtech.api.recipe.metadata.CompressionTierKey; import gregtech.api.recipe.metadata.PCBFactoryTierKey; import gregtech.api.recipe.metadata.PurificationPlantBaseChanceKey; -import gregtech.api.util.GTModHandler; -import gregtech.api.util.GTOreDictUnificator; -import gregtech.api.util.GTRecipe; -import gregtech.api.util.GTRecipeConstants; -import gregtech.api.util.GTUtility; +import gregtech.api.util.*; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyComplex; +import gregtech.common.tileentities.machines.multi.nanochip.modules.*; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; import gregtech.common.tileentities.machines.multi.purification.PurifiedWaterHelpers; import gregtech.nei.formatter.FuelSpecialValueFormatter; import gregtech.nei.formatter.FusionSpecialValueFormatter; @@ -619,7 +611,7 @@ public final class RecipeMaps { return Collections.emptyList(); int aCoalAmount = builder.getMetadataOrDefault(ADDITIVE_AMOUNT, 0); if (aCoalAmount <= 0) return Collections.emptyList(); - GTRecipeTemplate coll = asTemplate(rr.get()); + GTRecipeMapUtil.GTRecipeTemplate coll = asTemplate(rr.get()); for (Materials coal : new Materials[] { Materials.Coal, Materials.Charcoal }) { coll.derive() .setInputs(aInput1, aInput2, coal.getGems(aCoalAmount)) @@ -722,7 +714,7 @@ public final class RecipeMaps { .build(); if (!t.isPresent()) return Collections.emptyList(); ItemStack input = b.getItemInputBasic(0); - GTRecipeTemplate coll = asTemplate(t.get()); + GTRecipeMapUtil.GTRecipeTemplate coll = asTemplate(t.get()); int tExplosives = Math.min(b.getMetadataOrDefault(ADDITIVE_AMOUNT, 0), 64); int tGunpowder = tExplosives << 1; // Worst int tDynamite = Math.max(1, tExplosives >> 1); // good @@ -1195,6 +1187,103 @@ && isArrayEmptyOrNull(b.getFluidOutputs()) .neiHandlerInfo(builder -> builder.setDisplayStack(GTModHandler.getIC2Item("nuclearReactor", 1, null))) .build(); + public static final RecipeMap nanochipConversionRecipes = RecipeMapBuilder + .of("gt.recipe.nanochip.conversion") + .maxIO(1, 1, 0, 0) + .minInputs(1, 0) + .disableOptimize() + .recipeTransformer(recipe -> { + // Register fallback localized name based on input item + ItemStack input = recipe.mInputs[0]; + CircuitComponent output = CircuitComponent.getFromFakeStackUnsafe(recipe.mOutputs[0]); + MTENanochipAssemblyComplex.registerLocalName(input, output); + return recipe; + }) + .build(); + + public static final RecipeMap nanochipAssemblyMatrixRecipes = RecipeMapBuilder + .of("gt.recipe.nanochip.assemblymatrix") + .maxIO(9, 1, 4, 0) + .minInputs(0, 0) + .disableOptimize() + .recipeTransformer(recipe -> { + CircuitComponent output = CircuitComponent.tryGetFromFakeStack(recipe.mOutputs[0]); + // Fake recipes for the assembly matrix may not have this + if (output == null) return recipe; + if (output.realCircuit != null) { + AssemblyMatrix.registerLocalName(output.realCircuit, output); + } + return recipe; + }) + .build(); + + public static final RecipeMap nanochipSMDProcessorRecipes = RecipeMapBuilder + .of("gt.recipe.nanochip.smdprocessor") + .maxIO(2, 1, 2, 0) + .minInputs(0, 0) + .disableOptimize() + .recipeTransformer(recipe -> { + CircuitComponent output = CircuitComponent.getFromFakeStackUnsafe(recipe.mOutputs[0]); + CircuitComponent input = CircuitComponent.getFromFakeStackUnsafe(recipe.mInputs[0]); + SMDProcessor.registerLocalName(input.getLocalizedName(), output); + return recipe; + }) + .build(); + public static final RecipeMap nanochipBoardProcessorRecipes = RecipeMapBuilder + .of("gt.recipe.nanochip.boardprocessor") + .maxIO(2, 1, 2, 0) + .minInputs(0, 0) + .disableOptimize() + .recipeTransformer(recipe -> { + CircuitComponent output = CircuitComponent.getFromFakeStackUnsafe(recipe.mOutputs[0]); + CircuitComponent input = CircuitComponent.getFromFakeStackUnsafe(recipe.mInputs[0]); + BoardProcessor.registerLocalName(input.getLocalizedName(), output); + return recipe; + }) + .build(); + public static final RecipeMap nanochipEtchingArray = RecipeMapBuilder + .of("gt.recipe.nanochip.etchingarray") + .maxIO(2, 1, 2, 0) + .minInputs(0, 0) + .disableOptimize() + .recipeTransformer(recipe -> { + CircuitComponent output = CircuitComponent.getFromFakeStackUnsafe(recipe.mOutputs[0]); + CircuitComponent input = CircuitComponent.getFromFakeStackUnsafe(recipe.mInputs[0]); + EtchingArray.registerLocalName(input.getLocalizedName(), output); + return recipe; + }) + .build(); + public static final RecipeMap nanochipCuttingChamber = RecipeMapBuilder + .of("gt.recipe.nanochip.cuttingchamber") + .maxIO(2, 1, 2, 0) + .minInputs(0, 0) + .disableOptimize() + .recipeTransformer(recipe -> { + CircuitComponent output = CircuitComponent.getFromFakeStackUnsafe(recipe.mOutputs[0]); + CircuitComponent input = CircuitComponent.getFromFakeStackUnsafe(recipe.mInputs[0]); + CuttingChamber.registerLocalName(input.getLocalizedName(), output); + return recipe; + }) + .build(); + public static final RecipeMap nanochipWireTracer = RecipeMapBuilder + .of("gt.recipe.nanochip.wiretracer") + .maxIO(2, 1, 2, 0) + .minInputs(0, 0) + .disableOptimize() + .recipeTransformer(recipe -> { + CircuitComponent output = CircuitComponent.getFromFakeStackUnsafe(recipe.mOutputs[0]); + CircuitComponent input = CircuitComponent.getFromFakeStackUnsafe(recipe.mInputs[0]); + WireTracer.registerLocalName(input.getLocalizedName(), output); + return recipe; + }) + .build(); + public static final RecipeMap nanochipSuperconductorSplitter = RecipeMapBuilder + .of("gt.recipe.nanochip.superconductorsplitter") + .maxIO(2, 1, 2, 0) + .minInputs(0, 0) + .disableOptimize() + .build(); + static { RecipeMaps.dieselFuels.addDownstream( IRecipeMap.newRecipeMap( @@ -1229,5 +1318,8 @@ && isArrayEmptyOrNull(b.getFluidOutputs()) b.copy() .duration(1 * TICK) .eut(TierEU.RECIPE_UEV)))); + + // Add transformer from circuit assembler recipes to nanochip assembly matrix recipe + RecipeMaps.circuitAssemblerRecipes.addDownstream(assemblyMatrixRecipeTransformer); } } diff --git a/src/main/java/gregtech/api/recipe/metadata/NanochipAssemblyRecipeInfo.java b/src/main/java/gregtech/api/recipe/metadata/NanochipAssemblyRecipeInfo.java new file mode 100644 index 00000000000..b48c224b54c --- /dev/null +++ b/src/main/java/gregtech/api/recipe/metadata/NanochipAssemblyRecipeInfo.java @@ -0,0 +1,26 @@ +package gregtech.api.recipe.metadata; + +import javax.annotation.ParametersAreNonnullByDefault; + +import org.jetbrains.annotations.Nullable; + +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.tileentities.machines.multi.nanochip.util.ModuleRecipeInfo; +import gregtech.nei.RecipeDisplayInfo; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class NanochipAssemblyRecipeInfo extends RecipeMetadataKey { + + public static final NanochipAssemblyRecipeInfo INSTANCE = new NanochipAssemblyRecipeInfo(); + + private NanochipAssemblyRecipeInfo() { + super(ModuleRecipeInfo.class, "nanochip_assembly_module_recipe_info"); + } + + @Override + public void drawInfo(RecipeDisplayInfo recipeInfo, @Nullable Object value) { + // TODO: Implement + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/MTENanochipAssemblyComplex.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/MTENanochipAssemblyComplex.java new file mode 100644 index 00000000000..72a3a18cd22 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/MTENanochipAssemblyComplex.java @@ -0,0 +1,569 @@ +package gregtech.common.tileentities.machines.multi.nanochip; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static gregtech.api.enums.HatchElement.Energy; +import static gregtech.api.enums.HatchElement.ExoticEnergy; +import static gregtech.api.enums.HatchElement.InputBus; +import static gregtech.api.enums.HatchElement.OutputBus; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_GLOW; +import static gregtech.api.util.GTRecipeBuilder.SECONDS; +import static gregtech.api.util.GTStructureUtility.ofFrame; +import static gregtech.api.util.GTUtility.filterValidMTEs; +import static gregtech.common.tileentities.machines.multi.nanochip.util.AssemblyComplexStructureString.MAIN_OFFSET_X; +import static gregtech.common.tileentities.machines.multi.nanochip.util.AssemblyComplexStructureString.MAIN_OFFSET_Y; +import static gregtech.common.tileentities.machines.multi.nanochip.util.AssemblyComplexStructureString.MAIN_OFFSET_Z; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import gregtech.api.recipe.RecipeMap; +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import appeng.api.AEApi; +import gregtech.api.GregTechAPI; +import gregtech.api.enums.Materials; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.MTEExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.MTEHatch; +import gregtech.api.metatileentity.implementations.MTEHatchInputBus; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.*; +import gregtech.common.tileentities.machines.MTEHatchCraftingInputME; +import gregtech.common.tileentities.machines.MTEHatchInputBusME; +import gregtech.common.tileentities.machines.multi.nanochip.hatches.MTEHatchVacuumConveyor; +import gregtech.common.tileentities.machines.multi.nanochip.hatches.MTEHatchVacuumConveyorInput; +import gregtech.common.tileentities.machines.multi.nanochip.hatches.MTEHatchVacuumConveyorOutput; +import gregtech.common.tileentities.machines.multi.nanochip.util.AssemblyComplexStructureString; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponentPacket; +import gregtech.common.tileentities.machines.multi.nanochip.util.ItemStackWithSourceBus; +import gregtech.common.tileentities.machines.multi.nanochip.util.VacuumConveyorHatchMap; + +public class MTENanochipAssemblyComplex extends MTEExtendedPowerMultiBlockBase + implements ISurvivalConstructable { + + public static final String STRUCTURE_PIECE_MAIN = "main"; + public static final int CASING_INDEX_BASE = GregTechAPI.getCasingTextureIndex(GregTechAPI.sBlockCasings8, 10); + public static final int CASING_INDEX_WHITE = GregTechAPI.getCasingTextureIndex(GregTechAPI.sBlockCasings8, 5); + + public static final IStructureDefinition STRUCTURE_DEFINITION = StructureDefinition + .builder() + .addShape(STRUCTURE_PIECE_MAIN, AssemblyComplexStructureString.MAIN_STRUCTURE) + // Dimensional Bridge + .addElement('A', ofBlock(GregTechAPI.sBlockCasings1, 14)) + // White casing block + .addElement('B', ofBlock(GregTechAPI.sBlockCasings8, 5)) + // Black casing block + .addElement('C', ofBlock(GregTechAPI.sBlockCasings8, 10)) + .addElement('D', ofFrame(Materials.Naquadah)) + // Tinted glass, for now just black and gray because other options are for psychopaths + .addElement('E', ofChain(ofBlock(GregTechAPI.sBlockTintedGlass, 3), ofBlock(GregTechAPI.sBlockTintedGlass, 2))) + // Module + .addElement( + 'F', + HatchElementBuilder.builder() + .atLeast(AssemblyHatchElement.AssemblyModule) + .casingIndex(CASING_INDEX_WHITE) + .dot(1) + // Base casing or assembly module + .buildAndChain(GregTechAPI.sBlockCasings8, 5)) + // Energy Hatch + .addElement( + 'G', + HatchElementBuilder.builder() + .atLeast(Energy, ExoticEnergy) + .casingIndex(CASING_INDEX_BASE) + .dot(1) + .buildAndChain(GregTechAPI.sBlockCasings8, 10)) + // Vacuum conveyor hatches that the main controller cares about go in specific slots + .addElement( + 'H', + HatchElementBuilder.builder() + .atLeastList(Arrays.asList(AssemblyHatchElement.VacuumConveyorHatch, InputBus, OutputBus)) + .casingIndex(CASING_INDEX_WHITE) + .dot(2) + .buildAndChain(ofBlock(GregTechAPI.sBlockCasings8, 5))) + // Either a white casing block or an ignored hatch (this hatch is on the module) + .addElement( + 'I', + HatchElementBuilder.builder() + .atLeast(AssemblyHatchElement.IgnoredHatch) + .casingIndex(CASING_INDEX_WHITE) + .dot(3) + .buildAndChain(ofBlock(GregTechAPI.sBlockCasings8, 5))) + // Crafting storage block + .addElement('J', ofBlock(getCraftingStorageBlock(), getCraftingStorageMeta())) + .build(); + + public static final int MODULE_CONNECT_INTERVAL = 20; + private static final int INTERNAL_BUFFER_MULTIPLIER = 8; + + private final ArrayList> modules = new ArrayList<>(); + + private final VacuumConveyorHatchMap vacuumConveyors = new VacuumConveyorHatchMap<>(); + + public MTENanochipAssemblyComplex(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected MTENanochipAssemblyComplex(String aName) { + super(aName); + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_MAIN, trigger, hintsOnly, MAIN_OFFSET_X, MAIN_OFFSET_Y, MAIN_OFFSET_Z); + } + + @Override + public int survivalConstruct(ItemStack trigger, int elementBudget, ISurvivalBuildEnvironment env) { + return survivialBuildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + MAIN_OFFSET_X, + MAIN_OFFSET_Y, + MAIN_OFFSET_Z, + elementBudget, + env, + false, + true); + } + + private MTEHatch getEnergyHatch() { + if (this.mExoticEnergyHatches.isEmpty()) { + if (this.mEnergyHatches.isEmpty()) return null; + return this.mEnergyHatches.get(0); + } + return this.mExoticEnergyHatches.get(0); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + fixAllIssues(); + modules.clear(); + vacuumConveyors.clear(); + if (!checkPiece(STRUCTURE_PIECE_MAIN, MAIN_OFFSET_X, MAIN_OFFSET_Y, MAIN_OFFSET_Z)) return false; + // At least most one energy hatch is accepted + if (this.mEnergyHatches.isEmpty()) { + return this.mExoticEnergyHatches.size() == 1; + } else { + return this.mEnergyHatches.size() == 1; + } + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + return new MultiblockTooltipBuilder().toolTipFinisher("GregTech"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTENanochipAssemblyComplex(this.mName); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX_WHITE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX_WHITE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX_WHITE) }; + } + + public boolean addModuleToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) { + return false; + } + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) { + return false; + } + if (aMetaTileEntity instanceof MTENanochipAssemblyModuleBasemodule) { + return modules.add(module); + } + return false; + } + + public boolean addConveyorToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) { + return false; + } + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) { + return false; + } + if (aMetaTileEntity instanceof MTEHatchVacuumConveyor hatch) { + hatch.updateTexture(aBaseCasingIndex); + return vacuumConveyors.addHatch(hatch); + } + return false; + } + + public boolean ignoreAndAcceptHatch(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity instanceof MTEHatch hatch) { + hatch.updateTexture(aBaseCasingIndex); + return true; + } + return false; + } + + private static Block getCraftingStorageBlock() { + // Should never error on get() + return AEApi.instance() + .definitions() + .blocks() + .craftingStorage16384k() + .maybeBlock() + .get(); + } + + private static int getCraftingStorageMeta() { + // Should never error on get() + return AEApi.instance() + .definitions() + .blocks() + .craftingStorage16384k() + .maybeStack(1) + .get() + .getItemDamage(); + } + + /** + * Callback that will be invoked when the controller is removed + */ + @Override + public void onRemoval() { + // On destroying the controller block, all modules should be disconnected + disconnectAll(); + super.onRemoval(); + } + + private void disconnectAll() { + for (MTENanochipAssemblyModuleBase module : modules) { + module.disconnect(); + } + } + + private ArrayList getStoredInputsWithBus() { + // We need to replicate some behaviour of getStoredInputs() here to avoid duplicating items with stocking + // buses, but we cannot call getStoredInputs() directly because the specific hatch the ItemStack is coming + // from matters for routing the created circuit components + + ArrayList inputs = new ArrayList<>(); + Map inputsFromME = new HashMap<>(); + for (MTEHatchInputBus bus : filterValidMTEs(this.mInputBusses)) { + // Ignore crafting input buses + if (bus instanceof MTEHatchCraftingInputME) { + continue; + } + + // Same as the original implementation of getStoredInputs(), but keep track of the bus we found the input + // in. + IGregTechTileEntity te = bus.getBaseMetaTileEntity(); + boolean isMEBus = bus instanceof MTEHatchInputBusME; + for (int i = te.getSizeInventory() - 1; i >= 0; i--) { + ItemStack stack = te.getStackInSlot(i); + if (stack != null) { + if (isMEBus) { + // Prevent the same item from different ME buses from being recognized + inputsFromME.put(GTUtility.ItemId.createNoCopy(stack), new ItemStackWithSourceBus(stack, bus)); + } else { + inputs.add(new ItemStackWithSourceBus(stack, bus)); + } + } + } + } + // Now add all values from the ME input map + inputs.addAll(inputsFromME.values()); + return inputs; + } + + // Route circuit components to a set of hatches. Returns true if the components were routed successfully and the + // stack + // should be consumed + private boolean routeToHatches(List hatches, byte color, CircuitComponent component, + int amount) { + // If no hatches were passed, we can't route + if (hatches == null) return false; + // Find the first hatch that can be used for routing + for (MTEHatchVacuumConveyor hatch : filterValidMTEs(hatches)) { + // Hatch must be an output + if (hatch instanceof MTEHatchVacuumConveyorOutput outputHatch) { + // Ensure that the color matches the expected color, since hatches can be recolored in between rebuilds + // of the hatch map + if (outputHatch.getBaseMetaTileEntity() + .getColorization() != color) { + // If the color did not match, we found an inconsistency in the hatch map, so fix it instead + // of waiting for the next structure check + vacuumConveyors.fixConsistency(); + continue; + } + // Now we can route our components to this hatch + CircuitComponentPacket packet = new CircuitComponentPacket(component, amount); + // Merge with the already existing hatch contents + outputHatch.unifyPacket(packet); + return true; + } + } + return false; + } + + private void processRealItemInputs() { + ArrayList inputs = getStoredInputsWithBus(); + // For each stack in the input, try to find a matching circuit component and if so send it to the correct hatch + for (ItemStackWithSourceBus stack : inputs) { + // Find a conversion recipe + GTRecipe recipe = RecipeMaps.nanochipConversionRecipes.findRecipeQuery() + .items(stack.stack) + .find(); + if (recipe == null) continue; + // If one existed, we have the component now + CircuitComponent component = CircuitComponent.getFromFakeStackUnsafe(recipe.mOutputs[0]); + // Find destination hatch. Note that we already know that this bus is a valid MTE, see + // getStoredInputsWithBus + byte busColor = stack.bus.getBaseMetaTileEntity() + .getColorization(); + ArrayList destinationHatches = vacuumConveyors.findColoredHatches(busColor); + // Try to route to the set of destination hatches + boolean routed = routeToHatches(destinationHatches, busColor, component, stack.stack.stackSize); + // If successful, consume the input + if (routed) { + this.depleteInput(stack.stack); + } + } + } + + private void processComponentInputs() { + // Convert finished circuit CCs to real circuit items and add them as output. + for (ArrayList hatchList : this.vacuumConveyors.allHatches()) { + for (MTEHatchVacuumConveyor hatch : filterValidMTEs(hatchList)) { + // For each vacuum conveyor input, loop over its contents and try to find a circuit component + if (hatch instanceof MTEHatchVacuumConveyorInput) { + // Skip empty hatches + if (hatch.contents == null) continue; + Map contents = hatch.contents.getComponents(); + for (Map.Entry entry : contents.entrySet()) { + CircuitComponent component = entry.getKey(); + Integer amount = entry.getValue(); + // If this entry has a real circuit, we have produced a circuit using the NAC! + if (component.realCircuit != null) { + ItemStack toOutput = GTUtility.copyAmount(amount, component.realCircuit); + // Add output and deplete from hatch + addOutput(toOutput); + contents.remove(component); + } + } + } + } + } + } + + private void tryChargeInternalBuffer() { + MTEHatch hatch = this.getEnergyHatch(); + if (hatch == null) return; + + long eut = this.getMaxInputEu(); + long euToAdd = Math.min(eut, hatch.getEUVar()); + if (hatch.getBaseMetaTileEntity() + .decreaseStoredEnergyUnits(euToAdd, false)) { + setEUVar(getEUVar() + euToAdd); + } + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (aBaseMetaTileEntity.isServerSide()) { + if (isAllowedToWork()) { + // Every running tick, try to charge the buffer in the controller, + // because the MTE base class does not actually do this, but we need to in order to distribute the + // power to the modules. + tryChargeInternalBuffer(); + // If the complex is turned on, periodically reconnect modules. + // This code can be extended to only connect modules based on tiers of the complex or other + // conditions such as energy tier. + if (aTick % MODULE_CONNECT_INTERVAL == 0) { + if (!modules.isEmpty()) { + long eutPerModule = this.getMaxInputEu() / modules.size(); + long euToCharge = eutPerModule * MODULE_CONNECT_INTERVAL; + for (MTENanochipAssemblyModuleBase module : modules) { + module.connect(); + // Set available EU/t for this module, which is the total EU/t divided by the amount of + // modules, + // since each module can draw power equally (no mixed overclocks). + module.setAvailableEUt(eutPerModule); + // Charge the module with power + long availableEnergy = getEUVar(); + if (availableEnergy > 0) { + setEUVar( + Math.max( + 0, + availableEnergy + - module.increaseStoredEU(Math.min(euToCharge, availableEnergy)))); + } + } + } + } + } else { + // If the complex is turned off or unformed, disconnect all modules + disconnectAll(); + } + } + } + + @Override + public @NotNull CheckRecipeResult checkProcessing() { + // Always keep the machine running, it doesn't run recipes directly. + if (isAllowedToWork()) { + mEfficiencyIncrease = 10000; + mMaxProgresstime = 1 * SECONDS; + + // Inside checkProcessing we can safely consume inputs from hatches + processRealItemInputs(); + processComponentInputs(); + + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + mEfficiencyIncrease = 0; + mMaxProgresstime = 0; + return CheckRecipeResultRegistry.NO_RECIPE; + } + + @Override + public RecipeMap getRecipeMap() { + return RecipeMaps.nanochipConversionRecipes; + } + + public static void registerLocalName(ItemStack stack, CircuitComponent component) { + component.fallbackLocalizedName = stack.getDisplayName(); + } + + @Override + public long maxEUStore() { + return INTERNAL_BUFFER_MULTIPLIER * super.maxEUStore(); + } + + // Hatch adder for modules + public enum AssemblyHatchElement implements IHatchElement { + + AssemblyModule(MTENanochipAssemblyComplex::addModuleToMachineList, MTENanochipAssemblyComplex.class) { + + @Override + public long count(MTENanochipAssemblyComplex tileEntity) { + return tileEntity.modules.size(); + } + }, + VacuumConveyorHatch(MTENanochipAssemblyComplex::addConveyorToMachineList, MTENanochipAssemblyComplex.class) { + + @Override + public long count(MTENanochipAssemblyComplex tileEntity) { + return tileEntity.vacuumConveyors.size(); + } + }, + // Hatches are allowed in the module base slots, but the assembly complex ignores these for its base operation, + // so we need a custom adder to not add them to our hatch lists + IgnoredHatch(MTENanochipAssemblyComplex::ignoreAndAcceptHatch, MTENanochipAssemblyComplex.class) { + + @Override + public long count(MTENanochipAssemblyComplex tileEntity) { + return 0; + } + }; + + private final List> mteClasses; + private final IGTHatchAdder adder; + + @SafeVarargs + AssemblyHatchElement(IGTHatchAdder adder, + Class... mteClasses) { + this.mteClasses = Collections.unmodifiableList(Arrays.asList(mteClasses)); + this.adder = adder; + } + + @Override + public List> mteClasses() { + return mteClasses; + } + + public IGTHatchAdder adder() { + return adder; + } + } + + @Override + public boolean doRandomMaintenanceDamage() { + // Does not get have maintenance issues + return true; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/MTENanochipAssemblyModuleBase.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/MTENanochipAssemblyModuleBase.java new file mode 100644 index 00000000000..633d2d5bf2e --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/MTENanochipAssemblyModuleBase.java @@ -0,0 +1,492 @@ +package gregtech.common.tileentities.machines.multi.nanochip; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static gregtech.api.enums.HatchElement.InputBus; +import static gregtech.api.enums.HatchElement.InputHatch; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE_GLOW; +import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_GLOW; +import static gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyComplex.CASING_INDEX_WHITE; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import gregtech.api.util.GTRecipe; +import gregtech.api.util.GTUtility; +import gregtech.api.util.HatchElementBuilder; +import gregtech.api.util.IGTHatchAdder; +import gregtech.api.util.OverclockCalculator; +import gregtech.api.util.ParallelHelper; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.api.GregTechAPI; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.MTEExtendedPowerMultiBlockBase; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.shutdown.ShutDownReasonRegistry; +import gregtech.api.util.shutdown.SimpleShutDownReason; +import gregtech.common.tileentities.machines.multi.nanochip.hatches.MTEHatchVacuumConveyorInput; +import gregtech.common.tileentities.machines.multi.nanochip.hatches.MTEHatchVacuumConveyorOutput; +import gregtech.common.tileentities.machines.multi.nanochip.util.CCInputConsumer; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponentPacket; +import gregtech.common.tileentities.machines.multi.nanochip.util.VacuumConveyorHatchMap; + +public abstract class MTENanochipAssemblyModuleBase> + extends MTEExtendedPowerMultiBlockBase implements ISurvivalConstructable { + + protected static final String STRUCTURE_PIECE_BASE = "base"; + protected static final String[][] base_structure = new String[][] { { " VV~VV ", " ", " VVVVV " }, + { "VVVVVVV", " ZZZZZ ", "VVVVVVV" }, { "VVVVVVV", " ZZZZZ ", "VVVVVVV" }, { "VVVVVVV", " ZZZZZ ", "VVVVVVV" }, + { "VVVVVVV", " ZZZZZ ", "VVVVVVV" }, { "VVVVVVV", " ZZZZZ ", "VVVVVVV" }, { " VVVVV ", " ", " VVVVV " } }; + + protected static final int BASE_STRUCTURE_OFFSET_X = 3; + protected static final int BASE_STRUCTURE_OFFSET_Y = 0; + protected static final int BASE_STRUCTURE_OFFSET_Z = 0; + + private boolean isConnected = false; + + private long availableEUt = 0; + + private final ArrayList inputFakeItems = new ArrayList<>(); + private FluidStack[] fluidInputs = null; + private final ArrayList outputFakeItems = new ArrayList<>(); + private byte outputColor = -1; + private int currentParallel; + + // Something, needs to be tested further what this should really be (probably MUCH higher and scale with hatch tier) + protected static long EU_BUFFER_BASE_SIZE = 160008000L * 1024; + protected final long euBufferSize = EU_BUFFER_BASE_SIZE; + + protected final VacuumConveyorHatchMap vacuumConveyorInputs = new VacuumConveyorHatchMap<>(); + protected final VacuumConveyorHatchMap vacuumConveyorOutputs = new VacuumConveyorHatchMap<>(); + + public static > StructureDefinition.Builder addBaseStructure( + StructureDefinition.Builder structure) { + return structure.addShape(STRUCTURE_PIECE_BASE, base_structure) + .addElement( + 'V', + HatchElementBuilder.builder() + .atLeast(ModuleHatchElement.VacuumConveyorHatch, InputBus, InputHatch) + .casingIndex(CASING_INDEX_WHITE) + .dot(2) + .buildAndChain(ofBlock(GregTechAPI.sBlockCasings8, 5))) + .addElement('Z', ofBlock(GregTechAPI.sBlockCasings8, 10)); + } + + public enum ModuleHatchElement implements IHatchElement> { + + VacuumConveyorHatch(MTENanochipAssemblyModuleBase::addConveyorToMachineList, + MTENanochipAssemblyModuleBase.class) { + + @Override + public long count(MTENanochipAssemblyModuleBase tileEntity) { + return tileEntity.vacuumConveyorInputs.size() + tileEntity.vacuumConveyorOutputs.size(); + } + }; + + private final List> mteClasses; + private final IGTHatchAdder> adder; + + @SafeVarargs + ModuleHatchElement(IGTHatchAdder> adder, + Class... mteClasses) { + this.mteClasses = Collections.unmodifiableList(Arrays.asList(mteClasses)); + this.adder = adder; + } + + @Override + public List> mteClasses() { + return mteClasses; + } + + public IGTHatchAdder> adder() { + return adder; + } + } + + /** + * Create new nanochip assembly module + * + * @param aID ID of this module + * @param aName Name of this module + * @param aNameRegional Localized name of this module + */ + protected MTENanochipAssemblyModuleBase(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected MTENanochipAssemblyModuleBase(String aName) { + super(aName); + } + + // Only checks the base structure piece + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + this.vacuumConveyorInputs.clear(); + this.vacuumConveyorOutputs.clear(); + fixAllIssues(); + return checkPiece( + STRUCTURE_PIECE_BASE, + BASE_STRUCTURE_OFFSET_X, + BASE_STRUCTURE_OFFSET_Y, + BASE_STRUCTURE_OFFSET_Z); + } + + public boolean addConveyorToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) { + return false; + } + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) { + return false; + } + if (aMetaTileEntity instanceof MTEHatchVacuumConveyorInput hatch) { + hatch.updateTexture(aBaseCasingIndex); + return vacuumConveyorInputs.addHatch(hatch); + } + if (aMetaTileEntity instanceof MTEHatchVacuumConveyorOutput hatch) { + hatch.updateTexture(aBaseCasingIndex); + return vacuumConveyorOutputs.addHatch(hatch); + } + return false; + } + + @Override + public boolean supportsBatchMode() { + return false; + } + + @Override + protected boolean supportsCraftingMEBuffer() { + return false; + } + + @Override + public boolean supportsInputSeparation() { + return false; + } + + protected static class ItemInputInformation { + + /** + * A map containing one entry per unique item, with in each entry the color of the last hatch it was seen in. + * This can be used to determine the output color + */ + public final Map colors; + public final Map inputs; + + public ItemInputInformation(Map colors, Map inputs) { + this.colors = colors; + this.inputs = inputs; + } + } + + /** + * Find all inputs stored in the vacuum conveyor inputs. + * Clears inputFakeItems and then adds all fake items to this hatch. Note that different stacks with the same id + * are merged into one entry in this list, which makes lookup and parallel calculation a bit easier. + * + * @return Info about which hatches contained the items, and a full list of item inputs indexed by id to make + * parallel + * calculation easier + */ + private ItemInputInformation refreshInputItems() { + Map itemColorMap = new HashMap<>(); + Map inputs = new HashMap<>(); + // Clear input items before processing + this.inputFakeItems.clear(); + // Refresh fake stacks represented by items in the conveyor hatches. + // Note that we only take the first hatch with items and process it + for (ArrayList conveyorList : this.vacuumConveyorInputs.allHatches()) { + for (MTEHatchVacuumConveyorInput conveyor : conveyorList) { + // Get the contents of this hatch as fake items. + if (conveyor.contents == null) continue; + List itemsInHatch = conveyor.contents.getItemRepresentations(); + // Store the color of this hatch for each ItemStack + byte conveyorColor = conveyor.getColorization(); + for (ItemStack stack : itemsInHatch) { + GTUtility.ItemId id = GTUtility.ItemId.createNoCopy(stack); + // Merge stack into the input map, so we have a list of entries that are all unique. + inputs.merge( + id, + stack, + (a, b) -> new ItemStack(a.getItem(), a.getItemDamage(), a.stackSize + b.stackSize)); + // Also register its color + itemColorMap.put(id, conveyorColor); + // Also add the item to the list of individual input items for recipe checking + this.inputFakeItems.add(stack); + } + } + } + return new ItemInputInformation(itemColorMap, inputs); + } + + /** + * Find the color hatch that we want to use for output of the given recipe. + * + * @param recipe The recipe that we are going to run + * @param itemColors The colors the hatch each ItemStack in the recipe input can be found in + * @return The color that the output needs to end up in. If no hatch with this color exists, the module will report + * that no output space is available. + */ + protected byte findOutputColor(GTRecipe recipe, Map itemColors) { + ItemStack firstInput = recipe.mInputs[0]; + GTUtility.ItemId id = GTUtility.ItemId.createNoCopy(firstInput); + // If this recipe was valid and found, this should never not exist, or we have a bug + return itemColors.get(id); + } + + /** + * Try to find a recipe in the recipe map using the given stored inputs + * + * @return A recipe if one was found, null otherwise + */ + protected GTRecipe findRecipe(ArrayList inputs) { + RecipeMap recipeMap = this.getRecipeMap(); + this.fluidInputs = getStoredFluids().toArray(new FluidStack[] {}); + return recipeMap.findRecipeQuery() + .items(inputs.toArray(new ItemStack[] {})) + .fluids(fluidInputs) + .find(); + } + + /** + * Return a parallel helper, but this should not yet be built, since we will append the item consumer to it first + */ + protected ParallelHelper createParallelHelper(GTRecipe recipe, ItemInputInformation info) { + return new ParallelHelper().setItemInputs(this.inputFakeItems.toArray(new ItemStack[] {})) + .setFluidInputs(fluidInputs) + .setAvailableEUt(this.availableEUt) + .enableBatchMode(0) + .setRecipe(recipe) + .setMachine(this, false, false) + .setMaxParallel(Integer.MAX_VALUE) + .setOutputCalculation(true) + .setCalculator(OverclockCalculator.ofNoOverclock(recipe)); + } + + /** + * Validate if a recipe can be run by this module. By default, always succeeds. + * Override this logic if you want to do recipe validation such as tiering of the module. + * This is called before finding output hatch space or checking parallels. + * + * @param recipe The recipe the module is trying to run + * @return A successful CheckRecipeResult if the recipe should be accepted. + */ + @NotNull + public CheckRecipeResult validateRecipe(@NotNull GTRecipe recipe) { + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @NotNull + @Override + public CheckRecipeResult checkProcessing() { + // Reset output color + outputColor = -1; + currentParallel = 0; + this.lEUt = 0; + + if (!isConnected) { + return CheckRecipeResultRegistry.NO_RECIPE; + } + + // First step in recipe checking is finding all inputs we have to deal with. + // As a result of this process, we also get the colors of the hatch each item is found in, which + // we will use for routing the outputs + ItemInputInformation inputInfo = refreshInputItems(); + + // Now find a recipe with the fake inputs + GTRecipe recipe = findRecipe(this.inputFakeItems); + if (recipe == null) return CheckRecipeResultRegistry.NO_RECIPE; + // Validate it with custom logic, by default does nothing but can be overridden + // by the module + CheckRecipeResult validationResult = validateRecipe(recipe); + if (!validationResult.wasSuccessful()) return validationResult; + + // Now that we know the recipe, we can figure out the color the output hatch should have + outputColor = findOutputColor(recipe, inputInfo.colors); + // Try to find a valid output hatch to see if we have output space available, and error if we don't. + MTEHatchVacuumConveyorOutput outputHatch = this.vacuumConveyorOutputs.findAnyColoredHatch(this.outputColor); + if (outputHatch == null) { + // TODO: Maybe add a custom result for this + return CheckRecipeResultRegistry.ITEM_OUTPUT_FULL; + } + + // Create parallel helper to calculate parallel and consume inputs + ParallelHelper parallelHelper = createParallelHelper(recipe, inputInfo); + // Add item consumer to parallel helper and make it consume the input items while it builds + parallelHelper.setConsumption(true) + .setInputConsumer(new CCInputConsumer(this.vacuumConveyorInputs, this)) + .build(); + CheckRecipeResult result = parallelHelper.getResult(); + if (result.wasSuccessful()) { + // Set item outputs and parallel count. Note that while these outputs are fake, we override + // addOutput to convert these back into CCs in the right hatch + this.currentParallel = parallelHelper.getCurrentParallel(); + this.mOutputItems = parallelHelper.getItemOutputs(); + + mEfficiency = 10000; + mEfficiencyIncrease = 10000; + mMaxProgresstime = recipe.mDuration; + // Needs to be negative obviously to display correctly + this.lEUt = -(long) recipe.mEUt * (long) this.currentParallel; + } + + return result; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide() && isConnected) { + super.onPostTick(aBaseMetaTileEntity, aTick); + if (mEfficiency < 0) mEfficiency = 0; + if (aBaseMetaTileEntity.getStoredEU() <= 0 && mMaxProgresstime > 0) { + stopMachine(ShutDownReasonRegistry.POWER_LOSS); + } + } + } + + @Override + public long maxEUStore() { + return euBufferSize; + } + + @Override + public boolean drainEnergyInput(long aEU) { + // Drain EU from internal buffer in controller. We will need to charge this buffer from the + // Assembly Complex + if (aEU <= this.getEUVar()) { + this.setEUVar(this.getEUVar() - aEU); + return true; + } else { + return false; + } + } + + /** + * Increase the EU stored in the controller buffer + * + * @param maximumIncrease EU that should be added to the buffer + * @return Actually used amount + */ + public long increaseStoredEU(long maximumIncrease) { + if (getBaseMetaTileEntity() == null) { + return 0; + } + connect(); + long increasedEU = Math + .min(getBaseMetaTileEntity().getEUCapacity() - getBaseMetaTileEntity().getStoredEU(), maximumIncrease); + return getBaseMetaTileEntity().increaseStoredEnergyUnits(increasedEU, false) ? increasedEU : 0; + } + + protected MTEHatchVacuumConveyorOutput findOutputHatch(byte color) { + return vacuumConveyorOutputs.findAnyColoredHatch(color); + } + + @Override + public boolean addOutput(ItemStack aStack) { + // We need to override this because outputs are produced in vacuum conveyor outputs, not as real items + if (GTUtility.isStackInvalid(aStack)) return false; + MTEHatchVacuumConveyorOutput hatch = findOutputHatch(this.outputColor); + if (hatch == null) { + stopMachine(SimpleShutDownReason.ofCritical("Colored output hatch disappeared mid-recipe.")); + return false; + } + // Look up component from this output fake stack and unify it with the packet inside the output hatch + CircuitComponent component = CircuitComponent.getFromFakeStackUnsafe(aStack); + CircuitComponentPacket outputPacket = new CircuitComponentPacket(component, aStack.stackSize); + hatch.unifyPacket(outputPacket); + return true; + } + + public void setAvailableEUt(long eut) { + this.availableEUt = eut; + } + + public void connect() { + isConnected = true; + } + + public void disconnect() { + isConnected = false; + this.availableEUt = 0; + } + + public boolean isConnected() { + return this.isConnected; + } + + @Override + public boolean doRandomMaintenanceDamage() { + // Does not get have maintenance issues + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection aFacing, + int colorIndex, boolean aActive, boolean redstoneLevel) { + if (side == aFacing) { + if (aActive) return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX_WHITE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX_WHITE), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_DISTILLATION_TOWER_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { Textures.BlockIcons.getCasingTextureForId(CASING_INDEX_WHITE) }; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/MTEVacuumConveyorPipe.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/MTEVacuumConveyorPipe.java new file mode 100644 index 00000000000..d6371f2f39b --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/MTEVacuumConveyorPipe.java @@ -0,0 +1,298 @@ +package gregtech.common.tileentities.machines.multi.nanochip; + +import static gregtech.api.enums.Dyes.MACHINE_METAL; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import gregtech.GTMod; +import gregtech.api.enums.Dyes; +import gregtech.api.enums.Textures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.BaseMetaPipeEntity; +import gregtech.api.metatileentity.MetaPipeEntity; +import gregtech.api.objects.GTRenderedTexture; +import gregtech.common.GTClient; +import gregtech.common.tileentities.machines.multi.nanochip.util.IConnectsToVacuumConveyor; +import tectech.TecTech; +import tectech.loader.NetworkDispatcher; +import tectech.mechanics.pipe.IActivePipe; +import tectech.mechanics.pipe.PipeActivityMessage; + +public class MTEVacuumConveyorPipe extends MetaPipeEntity implements IConnectsToVacuumConveyor, IActivePipe { + + private static Textures.BlockIcons.CustomIcon EMpipe; + private static Textures.BlockIcons.CustomIcon EMbar, EMbarActive; + public byte connectionCount = 0; + + private boolean active; + + public MTEVacuumConveyorPipe(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional, 0); + } + + public MTEVacuumConveyorPipe(String aName) { + super(aName, 0); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity iGregTechTileEntity) { + return new MTEVacuumConveyorPipe(mName); + } + + @Override + @SideOnly(Side.CLIENT) + public void registerIcons(IIconRegister aBlockIconRegister) { + EMpipe = new Textures.BlockIcons.CustomIcon("iconsets/EM_DATA"); + EMbar = new Textures.BlockIcons.CustomIcon("iconsets/EM_BAR"); + EMbarActive = new Textures.BlockIcons.CustomIcon("iconsets/EM_BAR_ACTIVE"); + super.registerIcons(aBlockIconRegister); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, int aConnections, + int colorIndex, boolean aConnected, boolean aRedstone) { + return new ITexture[] { new GTRenderedTexture(EMpipe), + new GTRenderedTexture( + getActive() ? EMbarActive : EMbar, + Dyes.getModulation(colorIndex, MACHINE_METAL.getRGBA())) }; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity iGregTechTileEntity, int i, ForgeDirection side, + ItemStack itemStack) { + return false; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity iGregTechTileEntity, int i, ForgeDirection side, + ItemStack itemStack) { + return false; + } + + @Override + public void loadNBTData(NBTTagCompound nbtTagCompound) { + active = nbtTagCompound.getBoolean("eActive"); + } + + @Override + public void saveNBTData(NBTTagCompound nbtTagCompound) { + nbtTagCompound.setBoolean("eActive", active); + } + + @Override + public boolean renderInside(ForgeDirection side) { + return false; + } + + @Override + public byte getTileEntityBaseType() { + return 4; + } + + @Override + public String[] getDescription() { + return new String[] {}; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + if (aBaseMetaTileEntity.isClientSide()) { + NetworkDispatcher.INSTANCE.sendToServer(new PipeActivityMessage.PipeActivityQuery(this)); + } + onPostTick(aBaseMetaTileEntity, 31); + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + if ((aTick & 31) == 31) { + if (TecTech.RANDOM.nextInt(15) == 0) { + NetworkDispatcher.INSTANCE.sendToAllAround( + new PipeActivityMessage.PipeActivityData(this), + aBaseMetaTileEntity.getWorld().provider.dimensionId, + aBaseMetaTileEntity.getXCoord(), + aBaseMetaTileEntity.getYCoord(), + aBaseMetaTileEntity.getZCoord(), + 256); + } + if (active) { + active = false; + } + mConnections = 0; + connectionCount = 0; + byte myColor = aBaseMetaTileEntity.getColorization(); + if (aBaseMetaTileEntity.getColorization() < 0) { + return; + } + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + final ForgeDirection oppositeSide = side.getOpposite(); + TileEntity tTileEntity = aBaseMetaTileEntity.getTileEntityAtSide(side); + if (tTileEntity instanceof IConnectsToVacuumConveyor) { + byte tColor = ((IConnectsToVacuumConveyor) tTileEntity).getColorization(); + if (tColor != myColor) { + continue; + } + if (((IConnectsToVacuumConveyor) tTileEntity).canConnect(oppositeSide)) { + mConnections |= 1 << side.ordinal(); + connectionCount++; + } + } else if (tTileEntity instanceof IGregTechTileEntity) { + IMetaTileEntity meta = ((IGregTechTileEntity) tTileEntity).getMetaTileEntity(); + if (meta instanceof IConnectsToVacuumConveyor) { + byte tColor = ((IConnectsToVacuumConveyor) meta).getColorization(); + if (tColor != myColor) { + continue; + } + if (((IConnectsToVacuumConveyor) meta).canConnect(oppositeSide)) { + mConnections |= 1 << side.ordinal(); + connectionCount++; + } + } + } + } + } + } else if (aBaseMetaTileEntity.isClientSide() && GTClient.changeDetected == 4) { + aBaseMetaTileEntity.issueTextureUpdate(); + } + } + + @Override + public boolean canConnect(ForgeDirection side) { + return true; + } + + @Override + public IConnectsToVacuumConveyor getNext(IConnectsToVacuumConveyor source) { + if (connectionCount != 2) { + return null; + } + for (final ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) { + if ((mConnections & 1 << side.ordinal()) == 0) { + continue; // if not connected continue + } + TileEntity next = getBaseMetaTileEntity().getTileEntityAtSide(side); + if (next instanceof IConnectsToVacuumConveyor && next != source) { + if (((IConnectsToVacuumConveyor) next).isComponentsInputFacing(side.getOpposite())) { + return (IConnectsToVacuumConveyor) next; + } + } else if (next instanceof IGregTechTileEntity) { + IMetaTileEntity meta = ((IGregTechTileEntity) next).getMetaTileEntity(); + if (meta instanceof IConnectsToVacuumConveyor connecsToPipe && meta != source) { + if (meta instanceof MTEVacuumConveyorPipe pipeData && pipeData.connectionCount == 2) { + pipeData.markUsed(); + return connecsToPipe; + } + if (connecsToPipe.isComponentsInputFacing(side.getOpposite())) { + return connecsToPipe; + } + } + } + } + return null; + } + + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(World aWorld, int aX, int aY, int aZ) { + float tSpace = (1f - 0.375f) / 2; + float tSide0 = tSpace; + float tSide1 = 1f - tSpace; + float tSide2 = tSpace; + float tSide3 = 1f - tSpace; + float tSide4 = tSpace; + float tSide5 = 1f - tSpace; + + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.DOWN) != 0) { + tSide0 = tSide2 = tSide4 = 0; + tSide3 = tSide5 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.UP) != 0) { + tSide2 = tSide4 = 0; + tSide1 = tSide3 = tSide5 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.NORTH) != 0) { + tSide0 = tSide2 = tSide4 = 0; + tSide1 = tSide5 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.SOUTH) != 0) { + tSide0 = tSide4 = 0; + tSide1 = tSide3 = tSide5 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.WEST) != 0) { + tSide0 = tSide2 = tSide4 = 0; + tSide1 = tSide3 = 1; + } + if (getBaseMetaTileEntity().getCoverIDAtSide(ForgeDirection.EAST) != 0) { + tSide0 = tSide2 = 0; + tSide1 = tSide3 = tSide5 = 1; + } + + byte tConn = ((BaseMetaPipeEntity) getBaseMetaTileEntity()).mConnections; + if ((tConn & 1 << ForgeDirection.DOWN.ordinal()) != 0) { + tSide0 = 0f; + } + if ((tConn & 1 << ForgeDirection.UP.ordinal()) != 0) { + tSide1 = 1f; + } + if ((tConn & 1 << ForgeDirection.NORTH.ordinal()) != 0) { + tSide2 = 0f; + } + if ((tConn & 1 << ForgeDirection.SOUTH.ordinal()) != 0) { + tSide3 = 1f; + } + if ((tConn & 1 << ForgeDirection.WEST.ordinal()) != 0) { + tSide4 = 0f; + } + if ((tConn & 1 << ForgeDirection.EAST.ordinal()) != 0) { + tSide5 = 1f; + } + + return AxisAlignedBB + .getBoundingBox(aX + tSide4, aY + tSide0, aZ + tSide2, aX + tSide5, aY + tSide1, aZ + tSide3); + } + + @Override + public float getThickNess() { + if (GTMod.instance.isClientSide() && GTClient.hideValue == 1) { + return 0.0625F; + } + return 0.375f; + } + + @Override + public boolean isComponentsInputFacing(ForgeDirection side) { + return true; + } + + @Override + public byte getColorization() { + return getBaseMetaTileEntity().getColorization(); + } + + @Override + public void markUsed() { + this.active = true; + } + + @Override + public void setActive(boolean state) { + if (state != active) { + active = state; + getBaseMetaTileEntity().issueTextureUpdate(); + } + } + + @Override + public boolean getActive() { + return active; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/hatches/MTEHatchVacuumConveyor.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/hatches/MTEHatchVacuumConveyor.java new file mode 100644 index 00000000000..cde45c6f084 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/hatches/MTEHatchVacuumConveyor.java @@ -0,0 +1,164 @@ +package gregtech.common.tileentities.machines.multi.nanochip.hatches; + +import static gregtech.api.enums.Dyes.MACHINE_METAL; +import static tectech.thing.metaTileEntity.hatch.MTEHatchDataConnector.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.Dyes; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.MTEHatch; +import gregtech.api.objects.GTRenderedTexture; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponentPacket; +import gregtech.common.tileentities.machines.multi.nanochip.util.IConnectsToVacuumConveyor; + +public abstract class MTEHatchVacuumConveyor extends MTEHatch implements IConnectsToVacuumConveyor { + + public static final int VACUUM_MOVE_TICK = 17; + + public CircuitComponentPacket contents; + + // Identifier used to identify this hatch uniquely inside a multiblock. + public String identifier = null; + + protected MTEHatchVacuumConveyor(int aID, String aName, String aNameRegional, int aTier, String[] descr) { + super(aID, aName, aNameRegional, aTier, 0, descr); + } + + protected MTEHatchVacuumConveyor(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 0, aDescription, aTextures); + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, + new GTRenderedTexture( + EM_D_ACTIVE, + Dyes.getModulation(getBaseMetaTileEntity().getColorization(), MACHINE_METAL.getRGBA())), + new GTRenderedTexture(EM_D_CONN) }; + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return new ITexture[] { aBaseTexture, + new GTRenderedTexture( + EM_D_SIDES, + Dyes.getModulation(getBaseMetaTileEntity().getColorization(), MACHINE_METAL.getRGBA())), + new GTRenderedTexture(EM_D_CONN) }; + } + + public void unifyPacket(CircuitComponentPacket packet) { + if (contents == null) contents = packet; + else contents.unifyWith(packet); + } + + public abstract void moveAround(IGregTechTileEntity aBaseMetaTileEntity); + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + if (aBaseMetaTileEntity.isServerSide()) { + if (aTick % 20 == VACUUM_MOVE_TICK) { + if (contents == null) { + getBaseMetaTileEntity().setActive(false); + } else { + getBaseMetaTileEntity().setActive(true); + moveAround(aBaseMetaTileEntity); + } + } + } + } + + @Override + public boolean isFacingValid(ForgeDirection facing) { + return true; + } + + @Override + public boolean isAccessAllowed(EntityPlayer aPlayer) { + return true; + } + + @Override + public boolean isLiquidInput(ForgeDirection side) { + return false; + } + + @Override + public boolean isFluidInputAllowed(FluidStack aFluid) { + return false; + } + + @Override + public boolean allowPullStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return false; + } + + @Override + public boolean isValidSlot(int aIndex) { + return false; + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public byte getColorization() { + return getBaseMetaTileEntity().getColorization(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + if (this.contents != null) { + aNBT.setTag("vacuumContents", this.contents.writeToNBT()); + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + if (aNBT.hasKey("vacuumContents")) { + this.contents = new CircuitComponentPacket(aNBT.getCompoundTag("vacuumContents")); + } + super.loadNBTData(aNBT); + } + + @Override + public String[] getInfoData() { + ArrayList info = new ArrayList<>(Arrays.asList(super.getInfoData())); + info.add("Contents: "); + if (identifier != null) { + info.add("Hatch ID: " + identifier); + } + if (contents != null) { + // TODO: Would be neat to get a gui that displays these in item form I suppose (using some fake items or + // something) + Map components = contents.getComponents(); + for (Map.Entry component : components.entrySet()) { + info.add( + EnumChatFormatting.YELLOW + component.getKey() + .getLocalizedName() + ": " + EnumChatFormatting.WHITE + component.getValue()); + } + } + return info.toArray(new String[] {}); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/hatches/MTEHatchVacuumConveyorInput.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/hatches/MTEHatchVacuumConveyorInput.java new file mode 100644 index 00000000000..c584e3d783a --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/hatches/MTEHatchVacuumConveyorInput.java @@ -0,0 +1,83 @@ +package gregtech.common.tileentities.machines.multi.nanochip.hatches; + +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.IConnectsToVacuumConveyor; + +public class MTEHatchVacuumConveyorInput extends MTEHatchVacuumConveyor implements IConnectsToVacuumConveyor { + + public MTEHatchVacuumConveyorInput(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier, new String[] {}); + } + + public MTEHatchVacuumConveyorInput(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTEHatchVacuumConveyorInput(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public boolean isComponentsInputFacing(ForgeDirection side) { + return isInputFacing(side); + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return false; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean canConnect(ForgeDirection side) { + return isInputFacing(side); + } + + @Override + public IConnectsToVacuumConveyor getNext(IConnectsToVacuumConveyor source) { + return null; + } + + @Override + public void moveAround(IGregTechTileEntity aBaseMetaTileEntity) {} + + // Try to consume a stack of fake input items from this hatch. Returns the amount of items consumed. + public int tryConsume(ItemStack stack) { + if (contents == null) return 0; + CircuitComponent component = CircuitComponent.getFromFakeStackUnsafe(stack); + Map inventory = contents.getComponents(); + // Find this component in the inventory + Integer amount = inventory.get(component); + if (amount != null) { + // If found, consume as much as possible + int toConsume = Math.min(amount, stack.stackSize); + amount -= toConsume; + if (amount > 0) { + inventory.put(component, amount); + } else { + // Remove component from inventory if it is fully drained + inventory.remove(component); + } + return toConsume; + } + return 0; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/hatches/MTEHatchVacuumConveyorOutput.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/hatches/MTEHatchVacuumConveyorOutput.java new file mode 100644 index 00000000000..08d62202219 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/hatches/MTEHatchVacuumConveyorOutput.java @@ -0,0 +1,92 @@ +package gregtech.common.tileentities.machines.multi.nanochip.hatches; + +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.common.tileentities.machines.multi.nanochip.MTEVacuumConveyorPipe; +import gregtech.common.tileentities.machines.multi.nanochip.util.IConnectsToVacuumConveyor; + +public class MTEHatchVacuumConveyorOutput extends MTEHatchVacuumConveyor { + + public MTEHatchVacuumConveyorOutput(int aID, String aName, String aNameRegional, int aTier) { + super(aID, aName, aNameRegional, aTier, new String[] {}); + } + + public MTEHatchVacuumConveyorOutput(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, aDescription, aTextures); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTEHatchVacuumConveyorOutput(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public boolean isOutputFacing(ForgeDirection side) { + return side == getBaseMetaTileEntity().getFrontFacing(); + } + + @Override + public boolean isInputFacing(ForgeDirection side) { + return false; + } + + @Override + public boolean isSimpleMachine() { + return true; + } + + @Override + public boolean isComponentsInputFacing(ForgeDirection side) { + return isInputFacing(side); + } + + @Override + public void moveAround(IGregTechTileEntity aBaseMetaTileEntity) { + IConnectsToVacuumConveyor current = this, source = this, next; + int range = 0; + while ((next = current.getNext(source)) != null && range++ < 1000) { + if (next instanceof MTEHatchVacuumConveyorInput) { + ((MTEHatchVacuumConveyorInput) next).unifyPacket(contents); + // Only clear contents if we actually moved the packet + contents = null; + break; + } + source = current; + current = next; + } + } + + @Override + public IConnectsToVacuumConveyor getNext(IConnectsToVacuumConveyor source) { + IGregTechTileEntity base = getBaseMetaTileEntity(); + byte color = base.getColorization(); + if (color < 0) { + return null; + } + IGregTechTileEntity next = base.getIGregTechTileEntityAtSide(base.getFrontFacing()); + if (next == null) { + return null; + } + IMetaTileEntity meta = next.getMetaTileEntity(); + if (meta instanceof MTEVacuumConveyorPipe) { + ((MTEVacuumConveyorPipe) meta).markUsed(); + return (IConnectsToVacuumConveyor) meta; + } else if (meta instanceof MTEHatchVacuumConveyorInput + && ((MTEHatchVacuumConveyorInput) meta).getColorization() == color + && ((MTEHatchVacuumConveyorInput) meta).canConnect( + base.getFrontFacing() + .getOpposite())) { + return (IConnectsToVacuumConveyor) meta; + } + return null; + } + + @Override + public boolean canConnect(ForgeDirection side) { + return isOutputFacing(side); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/AssemblyMatrix.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/AssemblyMatrix.java new file mode 100644 index 00000000000..20cc5d0acce --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/AssemblyMatrix.java @@ -0,0 +1,140 @@ +package gregtech.common.tileentities.machines.multi.nanochip.modules; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; + +import net.minecraft.item.ItemStack; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; + +import gregtech.api.GregTechAPI; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.util.GTRecipe; +import gregtech.api.util.GTUtility; +import gregtech.api.util.MultiblockTooltipBuilder; +import gregtech.common.items.IDMetaItem01; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyModuleBase; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.ModuleStructureDefinition; + +public class AssemblyMatrix extends MTENanochipAssemblyModuleBase { + + protected static final int STRUCTURE_OFFSET_X = 3; + protected static final int STRUCTURE_OFFSET_Y = 3; + protected static final int STRUCTURE_OFFSET_Z = -2; + + protected static final String STRUCTURE_PIECE_MAIN = "main"; + private static final String[][] structure = new String[][] { { " AAA ", " AAA ", " AAA " }, + { " AAA ", " A A ", " AAA " }, { " AAA ", " AAA ", " AAA " } }; + + public static final IStructureDefinition STRUCTURE_DEFINITION = ModuleStructureDefinition + .builder() + .addShape(STRUCTURE_PIECE_MAIN, structure) + .addElement('A', ofBlock(GregTechAPI.sBlockCasings4, 0)) + .build(); + + /** + * Create new nanochip assembly module + * + * @param aID ID of this module + * @param aName Name of this module + * @param aNameRegional Localized name of this module + */ + public AssemblyMatrix(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected AssemblyMatrix(String aName) { + super(aName); + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + buildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + hintsOnly, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z); + } + + @Override + public int survivalConstruct(ItemStack trigger, int elementBudget, ISurvivalBuildEnvironment env) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + return survivialBuildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z, + elementBudget, + env, + false, + true); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + // Check base structure + if (!super.checkMachine(aBaseMetaTileEntity, aStack)) return false; + // Now check module structure + return checkPiece(STRUCTURE_PIECE_MAIN, STRUCTURE_OFFSET_X, STRUCTURE_OFFSET_Y, STRUCTURE_OFFSET_Z); + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + return new MultiblockTooltipBuilder().toolTipFinisher("GregTech"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new AssemblyMatrix(this.mName); + } + + @Override + public @NotNull CheckRecipeResult validateRecipe(@NotNull GTRecipe recipe) { + int recipeTier = GTUtility.getTier(recipe.mEUt); + int machineTier = getMachineTier(); + if (machineTier >= recipeTier) return CheckRecipeResultRegistry.SUCCESSFUL; + return CheckRecipeResultRegistry.insufficientMachineTier(recipeTier); + } + + private int getMachineTier() { + // Determine tier of machine based on tier of stack of robot arms in the controller. + ItemStack stack = this.getControllerSlot(); + if (stack == null || stack.stackSize != 64) return 0; + int meta = stack.getItemDamage() - 32000; + // In the ID list, LV-UEV is a separate range from UIV-MAX + if (meta >= IDMetaItem01.Robot_Arm_LV.ID && meta <= IDMetaItem01.Robot_Arm_UEV.ID) { + // LV is tier 1 + return meta - IDMetaItem01.Robot_Arm_LV.ID + 1; + } else if (meta >= IDMetaItem01.Robot_Arm_UIV.ID && meta <= IDMetaItem01.Robot_Arm_MAX.ID) { + // UIV is tier 11 + return meta - IDMetaItem01.Robot_Arm_UIV.ID + 11; + } + return 0; + } + + public static void registerLocalName(ItemStack stack, CircuitComponent component) { + component.fallbackLocalizedName = stack.getDisplayName(); + } + + @Override + public RecipeMap getRecipeMap() { + return RecipeMaps.nanochipAssemblyMatrixRecipes; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/BoardProcessor.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/BoardProcessor.java new file mode 100644 index 00000000000..6f402fc57eb --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/BoardProcessor.java @@ -0,0 +1,102 @@ +package gregtech.common.tileentities.machines.multi.nanochip.modules; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; + +import net.minecraft.item.ItemStack; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; + +import gregtech.api.GregTechAPI; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.util.MultiblockTooltipBuilder; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyModuleBase; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.ModuleStructureDefinition; + +public class BoardProcessor extends MTENanochipAssemblyModuleBase { + + protected static final int STRUCTURE_OFFSET_X = 3; + protected static final int STRUCTURE_OFFSET_Y = 3; + protected static final int STRUCTURE_OFFSET_Z = -2; + + protected static final String STRUCTURE_PIECE_MAIN = "main"; + private static final String[][] structure = new String[][] { { " AAA ", " AAA ", " AAA " }, + { " AAA ", " A A ", " AAA " }, { " AAA ", " AAA ", " AAA " } }; + + public static final IStructureDefinition STRUCTURE_DEFINITION = ModuleStructureDefinition + .builder() + .addShape(STRUCTURE_PIECE_MAIN, structure) + .addElement('A', ofBlock(GregTechAPI.sBlockCasings4, 0)) + .build(); + + public BoardProcessor(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected BoardProcessor(String aName) { + super(aName); + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + buildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + hintsOnly, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z); + } + + @Override + public int survivalConstruct(ItemStack trigger, int elementBudget, ISurvivalBuildEnvironment env) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + return survivialBuildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z, + elementBudget, + env, + false, + true); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + // Check base structure + if (!super.checkMachine(aBaseMetaTileEntity, aStack)) return false; + // Now check module structure + return checkPiece(STRUCTURE_PIECE_MAIN, STRUCTURE_OFFSET_X, STRUCTURE_OFFSET_Y, STRUCTURE_OFFSET_Z); + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + return new MultiblockTooltipBuilder().toolTipFinisher("GregTech"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new BoardProcessor(this.mName); + } + + public static void registerLocalName(String unprocessedName, CircuitComponent component) { + component.fallbackLocalizedName = unprocessedName + " Die"; + } + + @Override + public RecipeMap getRecipeMap() { + return RecipeMaps.nanochipBoardProcessorRecipes; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/CuttingChamber.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/CuttingChamber.java new file mode 100644 index 00000000000..8f0cd1f6c88 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/CuttingChamber.java @@ -0,0 +1,102 @@ +package gregtech.common.tileentities.machines.multi.nanochip.modules; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; + +import net.minecraft.item.ItemStack; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; + +import gregtech.api.GregTechAPI; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.util.MultiblockTooltipBuilder; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyModuleBase; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.ModuleStructureDefinition; + +public class CuttingChamber extends MTENanochipAssemblyModuleBase { + + protected static final int STRUCTURE_OFFSET_X = 3; + protected static final int STRUCTURE_OFFSET_Y = 3; + protected static final int STRUCTURE_OFFSET_Z = -2; + + protected static final String STRUCTURE_PIECE_MAIN = "main"; + private static final String[][] structure = new String[][] { { " AAA ", " AAA ", " AAA " }, + { " AAA ", " A A ", " AAA " }, { " AAA ", " AAA ", " AAA " } }; + + public static final IStructureDefinition STRUCTURE_DEFINITION = ModuleStructureDefinition + .builder() + .addShape(STRUCTURE_PIECE_MAIN, structure) + .addElement('A', ofBlock(GregTechAPI.sBlockCasings4, 0)) + .build(); + + public CuttingChamber(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected CuttingChamber(String aName) { + super(aName); + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + buildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + hintsOnly, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z); + } + + @Override + public int survivalConstruct(ItemStack trigger, int elementBudget, ISurvivalBuildEnvironment env) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + return survivialBuildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z, + elementBudget, + env, + false, + true); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + // Check base structure + if (!super.checkMachine(aBaseMetaTileEntity, aStack)) return false; + // Now check module structure + return checkPiece(STRUCTURE_PIECE_MAIN, STRUCTURE_OFFSET_X, STRUCTURE_OFFSET_Y, STRUCTURE_OFFSET_Z); + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + return new MultiblockTooltipBuilder().toolTipFinisher("GregTech"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new CuttingChamber(this.mName); + } + + public static void registerLocalName(String unprocessedName, CircuitComponent component) { + component.fallbackLocalizedName = "Cut " + unprocessedName; + } + + @Override + public RecipeMap getRecipeMap() { + return RecipeMaps.nanochipCuttingChamber; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/EtchingArray.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/EtchingArray.java new file mode 100644 index 00000000000..ebeb39d531d --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/EtchingArray.java @@ -0,0 +1,102 @@ +package gregtech.common.tileentities.machines.multi.nanochip.modules; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; + +import net.minecraft.item.ItemStack; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; + +import gregtech.api.GregTechAPI; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.util.MultiblockTooltipBuilder; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyModuleBase; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.ModuleStructureDefinition; + +public class EtchingArray extends MTENanochipAssemblyModuleBase { + + protected static final int STRUCTURE_OFFSET_X = 3; + protected static final int STRUCTURE_OFFSET_Y = 3; + protected static final int STRUCTURE_OFFSET_Z = -2; + + protected static final String STRUCTURE_PIECE_MAIN = "main"; + private static final String[][] structure = new String[][] { { " AAA ", " AAA ", " AAA " }, + { " AAA ", " A A ", " AAA " }, { " AAA ", " AAA ", " AAA " } }; + + public static final IStructureDefinition STRUCTURE_DEFINITION = ModuleStructureDefinition + .builder() + .addShape(STRUCTURE_PIECE_MAIN, structure) + .addElement('A', ofBlock(GregTechAPI.sBlockCasings4, 0)) + .build(); + + public EtchingArray(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected EtchingArray(String aName) { + super(aName); + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + buildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + hintsOnly, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z); + } + + @Override + public int survivalConstruct(ItemStack trigger, int elementBudget, ISurvivalBuildEnvironment env) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + return survivialBuildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z, + elementBudget, + env, + false, + true); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + // Check base structure + if (!super.checkMachine(aBaseMetaTileEntity, aStack)) return false; + // Now check module structure + return checkPiece(STRUCTURE_PIECE_MAIN, STRUCTURE_OFFSET_X, STRUCTURE_OFFSET_Y, STRUCTURE_OFFSET_Z); + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + return new MultiblockTooltipBuilder().toolTipFinisher("GregTech"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new EtchingArray(this.mName); + } + + public static void registerLocalName(String unprocessedName, CircuitComponent component) { + component.fallbackLocalizedName = "Etched " + unprocessedName; + } + + @Override + public RecipeMap getRecipeMap() { + return RecipeMaps.nanochipEtchingArray; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/SMDProcessor.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/SMDProcessor.java new file mode 100644 index 00000000000..6a4849681a4 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/SMDProcessor.java @@ -0,0 +1,103 @@ +package gregtech.common.tileentities.machines.multi.nanochip.modules; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; + +import net.minecraft.item.ItemStack; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; + +import gregtech.api.GregTechAPI; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.util.MultiblockTooltipBuilder; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyModuleBase; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.ModuleStructureDefinition; + +public class SMDProcessor extends MTENanochipAssemblyModuleBase { + + protected static final int STRUCTURE_OFFSET_X = 3; + protected static final int STRUCTURE_OFFSET_Y = 3; + protected static final int STRUCTURE_OFFSET_Z = -2; + + protected static final String STRUCTURE_PIECE_MAIN = "main"; + private static final String[][] structure = new String[][] { { " AAA ", " AAA ", " AAA " }, + { " AAA ", " A A ", " AAA " }, { " AAA ", " AAA ", " AAA " } }; + + public static final IStructureDefinition STRUCTURE_DEFINITION = ModuleStructureDefinition + .builder() + .addShape(STRUCTURE_PIECE_MAIN, structure) + .addElement('A', ofBlock(GregTechAPI.sBlockCasings4, 0)) + .build(); + + public SMDProcessor(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected SMDProcessor(String aName) { + super(aName); + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + buildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + hintsOnly, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z); + } + + @Override + public int survivalConstruct(ItemStack trigger, int elementBudget, ISurvivalBuildEnvironment env) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + return survivialBuildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z, + elementBudget, + env, + false, + true); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + // Check base structure + if (!super.checkMachine(aBaseMetaTileEntity, aStack)) return false; + // Now check module structure + return checkPiece(STRUCTURE_PIECE_MAIN, STRUCTURE_OFFSET_X, STRUCTURE_OFFSET_Y, STRUCTURE_OFFSET_Z); + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + return new MultiblockTooltipBuilder().toolTipFinisher("GregTech"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new SMDProcessor(this.mName); + } + + public static void registerLocalName(String unprocessedName, CircuitComponent component) { + // Processed SMDs can be given a name like 'SMD Inductor Tray' + component.fallbackLocalizedName = unprocessedName + " Tray"; + } + + @Override + public RecipeMap getRecipeMap() { + return RecipeMaps.nanochipSMDProcessorRecipes; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/Splitter.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/Splitter.java new file mode 100644 index 00000000000..33279654744 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/Splitter.java @@ -0,0 +1,170 @@ +package gregtech.common.tileentities.machines.multi.nanochip.modules; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static gregtech.api.util.GTRecipeBuilder.SECONDS; + +import java.util.ArrayList; +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; + +import gregtech.api.GregTechAPI; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.util.MultiblockTooltipBuilder; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyModuleBase; +import gregtech.common.tileentities.machines.multi.nanochip.hatches.MTEHatchVacuumConveyorInput; +import gregtech.common.tileentities.machines.multi.nanochip.hatches.MTEHatchVacuumConveyorOutput; +import gregtech.common.tileentities.machines.multi.nanochip.util.ModuleStructureDefinition; + +public class Splitter extends MTENanochipAssemblyModuleBase { + + protected static final int STRUCTURE_OFFSET_X = 3; + protected static final int STRUCTURE_OFFSET_Y = 3; + protected static final int STRUCTURE_OFFSET_Z = -2; + + protected static final String STRUCTURE_PIECE_MAIN = "main"; + private static final String[][] structure = new String[][] { { " AAA ", " AAA ", " AAA " }, + { " AAA ", " A A ", " AAA " }, { " AAA ", " AAA ", " AAA " } }; + + public static final IStructureDefinition STRUCTURE_DEFINITION = ModuleStructureDefinition + .builder() + .addShape(STRUCTURE_PIECE_MAIN, structure) + .addElement('A', ofBlock(GregTechAPI.sBlockCasings4, 0)) + .build(); + + public Splitter(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected Splitter(String aName) { + super(aName); + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + buildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + hintsOnly, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z); + } + + @Override + public int survivalConstruct(ItemStack trigger, int elementBudget, ISurvivalBuildEnvironment env) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + return survivialBuildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z, + elementBudget, + env, + false, + true); + } + + private static EnumChatFormatting getPrefixColor(byte color) { + return switch (color) { + case 0 -> EnumChatFormatting.BLACK; + case 1 -> EnumChatFormatting.RED; + case 2 -> EnumChatFormatting.DARK_GREEN; + case 3 -> EnumChatFormatting.DARK_RED; + case 4 -> EnumChatFormatting.DARK_BLUE; + case 5 -> EnumChatFormatting.DARK_AQUA; + case 6 -> EnumChatFormatting.AQUA; + case 7 -> EnumChatFormatting.GRAY; + case 8 -> EnumChatFormatting.DARK_GRAY; + case 9 -> EnumChatFormatting.LIGHT_PURPLE; + case 10 -> EnumChatFormatting.GREEN; + case 11 -> EnumChatFormatting.YELLOW; + case 12 -> EnumChatFormatting.BLUE; + case 13 -> EnumChatFormatting.DARK_PURPLE; + case 14 -> EnumChatFormatting.GOLD; + case 15 -> EnumChatFormatting.WHITE; + default -> EnumChatFormatting.RESET; + }; + } + + private void assignHatchIdentifiers() { + // Assign ID of all hatches based on their color, index and whether they are an input or an output hatch. + + int hatchID = 0; + for (Map.Entry> inputList : this.vacuumConveyorInputs.hatchMap() + .entrySet()) { + byte color = inputList.getKey(); + EnumChatFormatting colorFormat = getPrefixColor(color); + ArrayList hatches = inputList.getValue(); + for (MTEHatchVacuumConveyorInput hatch : hatches) { + hatch.identifier = colorFormat + "In/" + hatchID; + hatchID += 1; + } + } + + hatchID = 0; + for (Map.Entry> outputList : this.vacuumConveyorOutputs.hatchMap() + .entrySet()) { + byte color = outputList.getKey(); + EnumChatFormatting colorFormat = getPrefixColor(color); + ArrayList hatches = outputList.getValue(); + for (MTEHatchVacuumConveyorOutput hatch : hatches) { + hatch.identifier = colorFormat + "Out/" + hatchID; + hatchID += 1; + } + } + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + // Check base structure + if (!super.checkMachine(aBaseMetaTileEntity, aStack)) return false; + // Now check module structure + if (!checkPiece(STRUCTURE_PIECE_MAIN, STRUCTURE_OFFSET_X, STRUCTURE_OFFSET_Y, STRUCTURE_OFFSET_Z)) { + return false; + } + assignHatchIdentifiers(); + return true; + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + return new MultiblockTooltipBuilder().toolTipFinisher("GregTech"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new Splitter(this.mName); + } + + @Override + public @NotNull CheckRecipeResult checkProcessing() { + // Always keep the machine running, it doesn't run recipes directly. + if (isAllowedToWork()) { + mEfficiencyIncrease = 10000; + mMaxProgresstime = 1 * SECONDS; + + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + mEfficiencyIncrease = 0; + mMaxProgresstime = 0; + return CheckRecipeResultRegistry.NO_RECIPE; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/WireTracer.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/WireTracer.java new file mode 100644 index 00000000000..7ef3411f20e --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/modules/WireTracer.java @@ -0,0 +1,102 @@ +package gregtech.common.tileentities.machines.multi.nanochip.modules; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; + +import net.minecraft.item.ItemStack; + +import com.gtnewhorizon.structurelib.structure.IStructureDefinition; +import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; + +import gregtech.api.GregTechAPI; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.util.MultiblockTooltipBuilder; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyModuleBase; +import gregtech.common.tileentities.machines.multi.nanochip.util.CircuitComponent; +import gregtech.common.tileentities.machines.multi.nanochip.util.ModuleStructureDefinition; + +public class WireTracer extends MTENanochipAssemblyModuleBase { + + protected static final int STRUCTURE_OFFSET_X = 3; + protected static final int STRUCTURE_OFFSET_Y = 3; + protected static final int STRUCTURE_OFFSET_Z = -2; + + protected static final String STRUCTURE_PIECE_MAIN = "main"; + private static final String[][] structure = new String[][] { { " AAA ", " AAA ", " AAA " }, + { " AAA ", " A A ", " AAA " }, { " AAA ", " AAA ", " AAA " } }; + + public static final IStructureDefinition STRUCTURE_DEFINITION = ModuleStructureDefinition + .builder() + .addShape(STRUCTURE_PIECE_MAIN, structure) + .addElement('A', ofBlock(GregTechAPI.sBlockCasings4, 0)) + .build(); + + public WireTracer(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + protected WireTracer(String aName) { + super(aName); + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public void construct(ItemStack trigger, boolean hintsOnly) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + buildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + hintsOnly, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z); + } + + @Override + public int survivalConstruct(ItemStack trigger, int elementBudget, ISurvivalBuildEnvironment env) { + // Should only construct the main structure, since the base structure is built by the nanochip assembly complex. + return survivialBuildPiece( + STRUCTURE_PIECE_MAIN, + trigger, + STRUCTURE_OFFSET_X, + STRUCTURE_OFFSET_Y, + STRUCTURE_OFFSET_Z, + elementBudget, + env, + false, + true); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + // Check base structure + if (!super.checkMachine(aBaseMetaTileEntity, aStack)) return false; + // Now check module structure + return checkPiece(STRUCTURE_PIECE_MAIN, STRUCTURE_OFFSET_X, STRUCTURE_OFFSET_Y, STRUCTURE_OFFSET_Z); + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + return new MultiblockTooltipBuilder().toolTipFinisher("GregTech"); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new WireTracer(this.mName); + } + + public static void registerLocalName(String unprocessedName, CircuitComponent component) { + component.fallbackLocalizedName = "Traced " + unprocessedName; + } + + @Override + public RecipeMap getRecipeMap() { + return RecipeMaps.nanochipWireTracer; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/AssemblyComplexStructureString.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/AssemblyComplexStructureString.java new file mode 100644 index 00000000000..7e56edc5ae3 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/AssemblyComplexStructureString.java @@ -0,0 +1,5031 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +public class AssemblyComplexStructureString { + + public static final int MAIN_OFFSET_X = 31; + public static final int MAIN_OFFSET_Y = 40; + public static final int MAIN_OFFSET_Z = 31; + public static final String[][] MAIN_STRUCTURE = new String[][]{{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CCCC CCCC ", + " CCCCEEECCCC ", + " CCCC CCCC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CCCC CCCC ", + " CCCCEEECEEECEEECCCC ", + " CCCC CCCC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CCC CCC ", + " CCCEEEEEEECEEECEEEEEEECCC ", + " CCC CCC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CC CC ", + " CCEEEEEEEEEECEEECEEEEEEEEEECC ", + " CC CC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CC CC ", + " CCEEEEEEEEEEEECEEECEEEEEEEEEEEECC ", + " CC CC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C IIFII IIFII C ", + " CEEEEEEEEEEEEEECEEECEEEEEEEEEEEEEEC ", + " C IIIII IIIII C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CC CC ", + " CC IBBBBBI IBBBBBI CC ", + " CCEEEEEEECCCCCEEECEEECEEECCCCCEEEEEEECC ", + " CC IBBBBBI IBBBBBI CC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C ", + " C C ", + " C IBBBBBI B B IBBBBBI C ", + " CEEEEEEEEECCCCCECCCCECCCCECCCCCEEEEEEEEEC ", + " C IBBBBBI IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C ", + " C C ", + " C B B C ", + " C IBBBBBICCCC CCCCIBBBBBI C ", + " CEEEEEEEEEECCCCCECCCCECCCCECCCCCEEEEEEEEEEC ", + " C IBBBBBICCCC CCCCIBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " A A ", + " A A ", + " A A ", + " A B B A ", + " A C C A ", + " A IBBBBBI CC CC IBBBBBI A ", + " AEEEEEEEEEEECCCCCECCCCECCCCECCCCCEEEEEEEEEEEA ", + " A IBBBBBI C C IBBBBBI A ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C ", + " C B B C ", + " C C C C ", + " C IBBBBBI C CC IBBBBBI C ", + " CEEEEEEEEEEEECCCCCEEECCECCEEECCCCCEEEEEEEEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C B B C ", + " C C ", + " C IIFII IIIII C C IIIII IIFII C ", + " CEEEEEEEEEEEEEEEEEEEEECCECCEEEEEEEEEEEEEEEEEEEEEC ", + " C IIIII IIIII C C IIIII IIIII C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " C C ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " C C ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " ", + " C IIIIIC C C CIIIII C ", + " CEEEEEEEEEEEEECCEEEEEEEEEECCECCEEEEEEEEEECCEEEEEEEEEEEEEC ", + " C IIIIIC C C CIIIII C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " ", + " C C C C C C ", + " CEEEEEEEEEEEEECCCEEEEEEEEECCECCEEEEEEEEECCCEEEEEEEEEEEEEC ", + " C C C C C C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " ", + " C C C C C C ", + " CEEEEEEEEEEEEEEECCCEEEEEEEECCECCEEEEEEEECCCEEEEEEEEEEEEEEEC ", + " C C C C C C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " B B ", + " C IIIII C BBC CBB C IIIII C ", + " CEEEEEEEEEEEEEEEECCCEEEEEECCCCCCCEEEEEECCCEEEEEEEEEEEEEEEEC ", + " C IIIII C C C C IIIII C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " B B ", + " B B ", + " B B ", + " B B ", + " CCCCCCC ", + " CCCCCCC ", + " C IBBBBBI C BBCCCCCCCBB C IBBBBBI C ", + " CEEECCCCCEEEEEEEEECCCEEECCCCCCCCCCCEEECCCEEEEEEEEECCCCCEEEC ", + " C IBBBBBI C C C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " B B ", + " B B ", + " B B ", + " B B ", + " B B ", + " CCCCCCC ", + " C C ", + " C C ", + " C C ", + " C C ", + " CCC CCC ", + " CC CC ", + " C IBBBBBI C BCCEEEEEEECCB C IBBBBBI C", + " CEEEECCCCCEEEEEEEEEECCCECCC C C CCCECCCEEEEEEEEEECCCCCEEEEC", + " C IBBBBBI C C C C IBBBBBI C", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " BB ", + " B B ", + " BB B ", + " B B ", + " B B ", + " B B ", + " B BB ", + " B B ", + " BBB B ", + " B B ", + " CCCCCCC ", + " CCECECC ", + " CCECECC ", + " CCECECC ", + " CCECECC ", + " CCCCCCC ", + " CC CC ", + " EC CE ", + " EC CE ", + " EC CE ", + " CC CC ", + " CC C C CC ", + " C C ", + " C FBBBBBI CBCEEEEEEEEEEECBC IBBBBBF C", + " CEEEECCCCCEEEEEEEEEEECCCC C C CCCCEEEEEEEEEEECCCCCEEEEC", + " C IBBBBBI C C C C IBBBBBI C", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C ", + " C ", + " C ", + " C ", + " CC ", + " CC ", + " CC ", + " CC ", + " CCC ", + " CCC ", + " CCC ", + " CCC B ", + " CCCC B ", + " BCCCC B ", + " CCCC CC ", + " CCCC CC ", + " CCCC CC ", + " CCCC CC ", + " CCCC CC ", + " CCCCCCCB ", + " CCCCCCC ", + " CCCCCCC ", + " CCCCCCC ", + " CC CC ", + " EC CE ", + " EC CE ", + " EC CE ", + " EC CE ", + " CC CC ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C C C C C ", + " C C ", + " C IBBBBBI BCEEEEEEEEEEEEECB IBBBBBI C", + " CEEEECCCCCEEEEEEEEEEEECC C C CCEEEEEEEEEEEECCCCCEEEEC", + " C IBBBBBI C C C C IBBBBBI C", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B ", + " BC ", + " BC ", + " BC ", + " BC ", + " BCC ", + " BCC ", + " BCC ", + " BCC ", + " BCCC B ", + " BCCC B ", + " BCCC B ", + " BCCC CC ", + " BCJJJ CC ", + " BCJJJ CC ", + " BCJJJ CC ", + " BCJJJ CC ", + " BCJJJ CC ", + " CJJJ CC ", + " CJJJ CC ", + " CJJJ CCCB ", + " CC C CC ", + " CC C CC ", + " CC CC ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C C C C C ", + " C C ", + " C IBBBBBI BCEEEEEEEEEEEEEEECB IBBBBBI C", + " CEEEECCCCCEEEEEEEEEEECC C C CCEEEEEEEEEEECCCCCEEEEC", + " C IBBBBBI C C IBBBBBI C", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C ", + " C ", + " C ", + " C ", + " CC ", + " CC ", + " CC ", + " CC ", + " CCC ", + " CCC ", + " C CCC ", + " C CCC ", + " CC CJJJ D ", + " CC CJJJ ", + " CC CJJJ ", + " CC CJJJDD ", + " CC CJJJ ", + " CC BCJJJ ", + " CC CJJJ ", + " CCCCCJJJ CCCCB ", + " CC C ", + " CC C C ", + " CC C C ", + " C C ", + " E E ", + " E E ", + " E E ", + " E E ", + " C C ", + " C C ", + " E E ", + " E E ", + " E E ", + " C C ", + " CCCCC CCC C ", + " C C ", + "C IIIII BCEEEEEEEEEEEEEEEEECB IIIII ", + "CEEEEEEEEEEEEEEEEEEEECC C C CCEEEEEEEEEEEEEEEEEEEE", + "C IIIII C C IIIII ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C ", + " C ", + " C CC ", + " C CC ", + " C CCC ", + " C CCC ", + " CC CCCC ", + " CC CCCC ", + " CC CCCCC ", + " CC CCCCC ", + " CCC CCCCC ", + " B CCC CCCCC ", + " BCDDDCCC CCCCC ", + " BC CCC CCCCC ", + " BCC CJJJ CCCCC ", + " BCC CJJJ CCCCC ", + " BCC CJJJ CCCCC ", + " BCCDDCJJJ CCCCC ", + " BCC CJJJ CCCCC ", + " BCC CJJJ CCCCC ", + " BCC BCJJJ CCCCC ", + " BCCCCCJJJ CCCCCB ", + " BCC C ", + " BCC C ", + " CC C C ", + " C C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + "C C BCEEEEEEEEEEEEEEEEECB C ", + "CEEEEEECCCEEEEEEEEEEECC C C CCEEEEEEEEEEECCCEEEEEE", + "C C C C C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C ", + " B C ", + " BC CC ", + " BC CC ", + " BCDCCC ", + " BC CCC ", + " BCC CCCC ", + " BCC CCC ", + " BCC JJJCC ", + " BCC JJJCC ", + " BCCC JJJCC ", + " BCCC JJJCC ", + " C BCCC JJJCC ", + " C BCCCDJJJCC ", + " CC BCJJJ JJJCC ", + " CC BCJJJ JJJCC ", + " CC BCJJJ JJJCC ", + " CC BCJJJ JJJCC ", + " CC BCJJJ JJJCC ", + " CC BCJJJ JJJCC ", + " CC BCJJJ JJJCC ", + " CCCCCJJJ JJJCCB ", + " CC C ", + " BC C ", + " C D C ", + " C C C ", + " C C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " CCCCC HHHHHHH CCCCC ", + " C HHHHHHH C ", + "C C BCEEEEEEHHHHHHHEEEEEECB C ", + "CEEEEEECCCEEEEEEEEEECC HHHHHHH CCEEEEEEEEEECCCEEEEEE", + "C C HHHHHHH C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B ", + " CB ", + " CB ", + " C CCB ", + " C CCB ", + " C CCCB ", + " C CCCB ", + " CC CCCCB ", + " CC CCCCB ", + " CC JJJCCB ", + " CC JJJCCB ", + " CCC JJJCCB ", + " CCC JJJCCB ", + " CCC JJJCCB ", + " CCC JJJCCB ", + " CCCC JJJCCB ", + " CCCC JJJCCB ", + " CCCC JJJCCB ", + " CCCC JJJCCB ", + " CCCC JJJCCB ", + " CCCC JJJCCB ", + " BBCCCC JJJCCB ", + " BCCCCCCCJJJCCB ", + " BC CB ", + " BC CB ", + " BC DDDDD CB ", + " BC CB ", + " BC C CB ", + " BC C CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC H H CB ", + " BC HBBBBBH CB ", + "C C BCEEEEEEHBBBBBHEEEEEECB C ", + "CCCCCCCCCCCCCCCCCCCCCC HBBBBBH CCCCCCCCCCCCCCCCCCCCC", + "C C HHHHHHH C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C ", + " C ", + " CC ", + " CC ", + " CCC ", + " CCC ", + " CCCC ", + " CCCC ", + " D JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " D JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " C C JJJCC ", + " C C ", + " C C ", + " C D D C ", + " C C ", + " E E ", + " E DCD E ", + " E CCC E ", + " E DBD E ", + " C D C ", + " C B C ", + " E ~ E ", + " E E ", + " E E ", + " C C ", + " C H H C ", + " C HBJJJBH C ", + " CCCCCCCCCCCCCCEEEEEEHBJJJBHEEEEEECCCCCCCCCCCCCC ", + "EEEEEEECCCCCCCCCCCCCCCCCCCCCHBJJJBHCCCCCCCCCCCCCCCCCCCCCEEEEEE", + " CCCCCCCCCCCCCCCCCCCCHHHHHHHCCCCCCCCCCCCCCCCCCCC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C ", + " C ", + " CC ", + " CC ", + " CCC ", + " CCC ", + " CCCC ", + " CCCC ", + " D JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " D JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " JJJCC ", + " C C JJJCC ", + " C C ", + " CCC CCC ", + " C CCDD DDCC C ", + " C CC CC C ", + " C CC CC C ", + " C CCGCC C ", + " C CCC C ", + " C BCB C ", + " C BBB C ", + " C BBB C ", + " C B C ", + " C C ", + " C C ", + " C C ", + " C H H C ", + " C HBJJJBH C ", + " CEEEEEEHBJJJBHEEEEEEC ", + "EEEEEEEEEEEEEEEEEEEECC HBJJJBH CCEEEEEEEEEEEEEEEEEEE", + " HHHHHHH ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " C ", + " C ", + " CC ", + " CC ", + " CCC ", + " CCC ", + " CCCC ", + " CCCC C ", + " CCCCC C ", + " CCCCC CC ", + " CCCCCC CC ", + " CCCCCC CCC ", + " CCCCCC CCC ", + " CCCCCC CCCC ", + " CCCCC CCCC ", + " CCCCCD JJJCC ", + " CCCCC JJJCC ", + " CCCCC JJJCC ", + " CCCCC JJJCC ", + " CCCCC JJJCC ", + " CCCCC JJJCC ", + " CCCCC JJJCC ", + " CCCCCC JJJCC ", + " CCCCCC JJJCC ", + " CCCCCC JJJCC ", + " CCCCCC JJJCC ", + " CCCCCC JJJCC ", + " CCCCCC JJJCC ", + " CCCCC JJJCC ", + " C C ", + " C C ", + " C D D C ", + " C C ", + " E E ", + " E DCD E ", + " E CCC E ", + " E DBD E ", + " C DBD C ", + " C B C ", + " E E ", + " E E ", + " E E ", + " C C ", + " C H H C ", + " C HBJJJBH C ", + " CCCCCCCCCCCCCCEEEEEEHBJJJBHEEEEEECCCCCCCCCCCCCC ", + "EEEEEEECCCCCCCCCCCCCCCCCCCCCHBJJJBHCCCCCCCCCCCCCCCCCCCCCEEEEEE", + " CCCCCCCCCCCCCCCCCCCCHHHHHHHCCCCCCCCCCCCCCCCCCCC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " B ", + " BC ", + " BC ", + " BCC ", + " BCC ", + " BCCC ", + " BC C ", + " BCC C B ", + " BC C CB ", + " BCC C CB ", + " BC C CCB ", + " BCJJJJC CCB ", + " BCJJJJC CCCB ", + " BCJJJJC CCCB ", + " BCJJJJC CCCCB ", + " BCJJJJ CCCCB ", + " BCJJJJ JJJCCB ", + " BCJJJJ JJJCCB ", + " BCJJJJ JJJCCB ", + " BCJJJJ JJJCCB ", + " BCJJJJ JJJCCB ", + " BCJJJJ JJJCCB ", + " BCJJJJ JJJCCB ", + " BCJJJJC JJJCCB ", + " BCJJJJCDDJJJCCB ", + " BCJJJJC JJJCCB ", + " BCJJJJC JJJCCB ", + " BCJJJJC JJJCCB ", + " BCJJJJC JJJCCB ", + " BCJJJJC JJJCCB ", + " BC CB ", + " BC CB ", + " BC DDDDD CB ", + " BC CB ", + " BC C CB ", + " BC C CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC CB ", + " BC H H CB ", + " BC HBBBBBH CB ", + "C C BCEEEEEEHBBBBBHEEEEEECB C ", + "CCCCCCCCCCCCCCCCCCCCCC HBBBBBH CCCCCCCCCCCCCCCCCCCCC", + "C C HHHHHHH C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " C ", + " C ", + " CC ", + " CC ", + " CCC ", + " C C ", + " CC C ", + " C C C ", + " CC CDDC ", + " C C CC ", + " CJJJJC CC ", + " CJJJJC CCC ", + " CJJJJC CCC ", + " CJJJJC CCCC ", + " CJJJJ CCCC ", + " CJJJJ JJJCC ", + " CJJJJ JJJCC ", + " CJJJJDDDJJJCC ", + " CJJJJ JJJCC ", + " CJJJJ JJJCC ", + " CJJJJ JJJCC ", + " CJJJJ JJJCC ", + " CJJJJC JJJCC ", + " CJJJJC JJJCC ", + " CJJJJC JJJCCB ", + " CJJJJC JJJCC ", + " CJJJJC JJJCC ", + " BCJJJJC JJJCC ", + " CJJJJC JJJCC ", + " C C ", + " C C ", + " C D C ", + " C C C ", + " C C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " CCCCC HHHHHHH CCCCC ", + " C HHHHHHH C ", + "C C BCEEEEEEHHHHHHHEEEEEECB C ", + "CEEEEEECCCEEEEEEEEEECC HHHHHHH CCEEEEEEEEEECCCEEEEEE", + "C C HHHHHHH C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " C ", + " C ", + " CC ", + " CC ", + " CCC ", + " C C ", + " CC C ", + " C C C ", + " CC C C ", + " C C CC ", + " CJJJJC CC ", + " CJJJJC CCC ", + " CJJJJC CCC ", + " CJJJJC CCCC ", + " CJJJJ CCCC ", + " CJJJJ CCCCC ", + " CJJJJ CCCCC ", + " CJJJJ CCCCC ", + " CJJJJ CCCCC ", + " CJJJJ CCCCC ", + " CJJJJ CCCCC ", + " CJJJJ CCCCC ", + " CJJJJC CCCCC ", + " CJJJJC CCCCC ", + " CJJJJC CCCCCB ", + " CJJJJC CCCCC ", + " BCJJJJC CCCCC ", + " CJJJJC CCCCC ", + " CJJJJCCCCCCCC ", + " C C ", + " C C ", + " C C C ", + " C C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + "C C BCEEEEEEEEEEEEEEEEECB C ", + "CEEEEEECCCEEEEEEEEEEECC C C CCEEEEEEEEEEECCCEEEEEE", + "C C C C C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " B ", + " BC ", + " BC ", + " BCC ", + " BCC ", + " BCCC ", + " BC C ", + " BCC C ", + " BC C ", + " BCC C ", + " BC C ", + " BCJJJJC ", + " BCJJJJC ", + " BCJJJJC ", + " BCJJJJC ", + " BCJJJJ ", + " BCJJJJ ", + " BCJJJJ ", + " BCJJJJ ", + " BCJJJJ ", + " BCJJJJ ", + " BCJJJJ B ", + " BCJJJJ B ", + " BCJJJJC B ", + " BCJJJJC B ", + " BCJJJJC BBBBB ", + " BCJJJJC B B ", + " CJJJJC B B ", + " CJJJJC B ", + " CJJJJCCCBCCC ", + " C C ", + " C C ", + " C C C ", + " C C ", + " E E ", + " E E ", + " E E ", + " E E ", + " C C ", + " C C ", + " E E ", + " E E ", + " E E ", + " C C ", + " CCCCC CCCCC ", + " C C ", + "C IIIII BCEEEEEEEEEEEEEEEEECB IIIII ", + "CEEEEEEEEEEEEEEEEEEEECC C C CCEEEEEEEEEEEEEEEEEEEE", + "C IIIII C C IIIII ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " C ", + " C ", + " CC ", + " CC ", + " CCC ", + " CCC ", + " CCCC ", + " CCCC ", + " CCCCC ", + " CCCCC ", + " CCCCCC ", + " CCCCCC ", + " CCCCCC ", + " CCCCCC ", + " CCCCC ", + " CCCCC ", + " CCCCC ", + " CCCCC ", + " CCCCC ", + " CCCCC ", + " CCCCC ", + " CCCCC ", + " CCCCCC ", + " CCCCCC ", + " CCCCCC ", + " BCCCCCC ", + " CCCCCC ", + " CCCCCC ", + " CCCCCCCCBC ", + " CCCCC CC ", + " CCC CC ", + " CCC C CC ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C C C C C ", + " C C ", + " C IBBBBBI BCEEEEEEEEEEEEEEECB IBBBBBI C", + " CEEEECCCCCEEEEEEEEEEECC C C CCEEEEEEEEEEECCCCCEEEEC", + " C IBBBBBI C C IBBBBBI C", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B ", + " B ", + " B ", + " B ", + " B ", + " B B ", + " B B ", + " B B ", + " B B ", + " BBBBB ", + " B B ", + " B B ", + " B B ", + " CC CC ", + " CC CC ", + " CCCCCCC ", + " CC CC ", + " EC CE ", + " EC CE ", + " EC CE ", + " EC CE ", + " CC CC ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C ", + " C C C C C C ", + " C C ", + " C IBBBBBI BCEEEEEEEEEEEEECB IBBBBBI C", + " CEEEECCCCCEEEEEEEEEEEECC C C CCEEEEEEEEEEEECCCCCEEEEC", + " C IBBBBBI C C C C IBBBBBI C", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " B B ", + " B B ", + " CCCCCCC ", + " CCECECC ", + " CCECECC ", + " CCECECC ", + " CCECECC ", + " CCCCCCC ", + " CC CC ", + " EC CE ", + " EC CE ", + " EC CE ", + " CC CC ", + " CC C C CC ", + " C C ", + " C FBBBBBI CBCEEEEEEEEEEECBC IBBBBBF C", + " CEEEECCCCCEEEEEEEEEEECCCC C C CCCCEEEEEEEEEEECCCCCEEEEC", + " C IBBBBBI C C C C IBBBBBI C", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " B B ", + " B B ", + " B B ", + " B B ", + " B B ", + " CCCCCCC ", + " CCECECC ", + " CCECECC ", + " CCECECC ", + " CCCCCCC ", + " CCC CCC ", + " CC CC ", + " C IBBBBBI C BCCEEEEEEECCB C IBBBBBI C", + " CEEEECCCCCEEEEEEEEEECCCECCC C C CCCECCCEEEEEEEEEECCCCCEEEEC", + " C IBBBBBI C C C C IBBBBBI C", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " B B ", + " B B ", + " B B ", + " B B ", + " CCCCCCC ", + " CCCCCCC ", + " C IBBBBBI C BBCCCCCCCBB C IBBBBBI C ", + " CEEECCCCCEEEEEEEEECCCEEECCCCCCCCCCCEEECCCEEEEEEEEECCCCCEEEC ", + " C IBBBBBI C C C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " B B ", + " B B ", + " C IIIII C BBC CBB C IIIII C ", + " CEEEEEEEEEEEEEEEECCCEEEEEECCCCCCCEEEEEECCCEEEEEEEEEEEEEEEEC ", + " C IIIII C C C C IIIII C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C C C C C ", + " CEEEEEEEEEEEEEEECCCEEEEEEEECCECCEEEEEEEECCCEEEEEEEEEEEEEEEC ", + " C C C C C C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C C C C C ", + " CEEEEEEEEEEEEECCCEEEEEEEEECCECCEEEEEEEEECCCEEEEEEEEEEEEEC ", + " C C C C C C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C IIIIIC C C CIIIII C ", + " CEEEEEEEEEEEEECCEEEEEEEEEECCECCEEEEEEEEEECCEEEEEEEEEEEEEC ", + " C IIIIIC C C CIIIII C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEECCCCCEEEEEEEEEEEECCECCEEEEEEEEEEEECCCCCEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C ", + " C C ", + " C IIFII IIIII C C IIIII IIFII C ", + " CEEEEEEEEEEEEEEEEEEEEECCECCEEEEEEEEEEEEEEEEEEEEEC ", + " C IIIII IIIII C C IIIII IIIII C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C ", + " C C ", + " C C ", + " C IBBBBBI C C IBBBBBI C ", + " CEEEEEEEEEEEECCCCCEEECCECCEEECCCCCEEEEEEEEEEEEC ", + " C IBBBBBI C C IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " A A ", + " A A ", + " A A ", + " A A ", + " A A ", + " A IBBBBBI C C IBBBBBI A ", + " AEEEEEEEEEEECCCCCECCCCECCCCECCCCCEEEEEEEEEEEA ", + " A IBBBBBI C C IBBBBBI A ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C ", + " C C ", + " C C ", + " C IBBBBBICCCC CCCCIBBBBBI C ", + " CEEEEEEEEEECCCCCECCCCECCCCECCCCCEEEEEEEEEEC ", + " C IBBBBBICCCC CCCCIBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C C ", + " C C ", + " C IBBBBBI IBBBBBI C ", + " CEEEEEEEEECCCCCECCCCECCCCECCCCCEEEEEEEEEC ", + " C IBBBBBI IBBBBBI C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CC CC ", + " CC IBBBBBI IBBBBBI CC ", + " CCEEEEEEECCCCCEEECEEECEEECCCCCEEEEEEECC ", + " CC IBBBBBI IBBBBBI CC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " C IIFII IIFII C ", + " CEEEEEEEEEEEEEECEEECEEEEEEEEEEEEEEC ", + " C IIIII IIIII C ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CC CC ", + " CCEEEEEEEEEEEECEEECEEEEEEEEEEEECC ", + " CC CC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CC CC ", + " CCEEEEEEEEEECEEECEEEEEEEEEECC ", + " CC CC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + },{ + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " CCC CCC ", + " CCCEEEEEEECEEECEEEEEEECCC ", + " CCC CCC ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " " + }}; +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/CCInputConsumer.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/CCInputConsumer.java new file mode 100644 index 00000000000..a8a0a898fe0 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/CCInputConsumer.java @@ -0,0 +1,54 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.util.GTRecipe; +import gregtech.api.util.ParallelHelper; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyModuleBase; +import gregtech.common.tileentities.machines.multi.nanochip.hatches.MTEHatchVacuumConveyorInput; + +public class CCInputConsumer implements ParallelHelper.InputConsumer { + + private final VacuumConveyorHatchMap inputConveyors; + private final MTENanochipAssemblyModuleBase module; + + public CCInputConsumer(VacuumConveyorHatchMap inputConveyors, + MTENanochipAssemblyModuleBase module) { + this.inputConveyors = inputConveyors; + this.module = module; + } + + @Override + public void consume(GTRecipe recipe, int amountMultiplier, FluidStack[] aFluidInputs, ItemStack[] aInputs) { + // Note that the aInputs[] parameter can be ignored, since this is what the multiblock contains. + // We don't care about this, we just want to consume whatever we can from the input conveyor hatches + for (ItemStack input : recipe.mInputs) { + // Construct a modifiable stack that tracks how much of this item we need to consume + ItemStack toConsumeStack = input.copy(); + toConsumeStack.stackSize *= amountMultiplier; + + for (ArrayList hatchList : inputConveyors.allHatches()) { + boolean done = false; + for (MTEHatchVacuumConveyorInput conveyor : hatchList) { + int consumed = conveyor.tryConsume(toConsumeStack); + toConsumeStack.stackSize -= consumed; + if (toConsumeStack.stackSize <= 0) { + // Break out of both loops... I hate this + // Labeled loops when! + done = true; + break; + } + } + if (done) break; + } + } + + // Consume fluid inputs in recipe + for (FluidStack fluid : aFluidInputs) { + module.depleteInput(fluid); + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/CircuitComponent.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/CircuitComponent.java new file mode 100644 index 00000000000..12a36c6d6bc --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/CircuitComponent.java @@ -0,0 +1,167 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.util.StatCollector; + +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.items.CircuitComponentFakeItem; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.util.GTUtility; + +public enum CircuitComponent { + + // TODO: Consider if this whole fake stack system is overcomplicated and if we can't just use the real stacks + // The main drawback of this is that either we have to override a LOT of things in the NEI display, or simply accept + // that + // the circuit components will be displayed with the same textures and names as the real stacks backing them. + // This also wouldn't work well with components that don't have a 'real' backing ItemStack, such as components + // that are only created through a module in the NAC + + // When adding to this list, PLEASE only add to the end! The ordinals are used as item ids for the fake items, so + // adding in the middle will break saved state! + WireNiobiumTitanium("gt.circuitcomponent.wirenbti", RecipeMaps.nanochipWireTracer, Materials.NiobiumTitanium), + ProcessedWireNiobiumTitanium("gt.circuitcomponent.processed.wirenbti", RecipeMaps.nanochipAssemblyMatrixRecipes, + Materials.NiobiumTitanium), + SMDResistor("gt.circuitcomponent.smd.resistor", RecipeMaps.nanochipSMDProcessorRecipes), + SMDTransistor("gt.circuitcomponent.smd.transistor", RecipeMaps.nanochipSMDProcessorRecipes), + SMDInductor("gt.circuitcomponent.smd.inductor", RecipeMaps.nanochipSMDProcessorRecipes), + SMDCapacitor("gt.circuitcomponent.smd.capacitor", RecipeMaps.nanochipSMDProcessorRecipes), + SMDDiode("gt.circuitcomponent.smd.diode", RecipeMaps.nanochipSMDProcessorRecipes), + AdvSMDResistor("gt.circuitcomponent.asmd.resistor", RecipeMaps.nanochipSMDProcessorRecipes), + AdvSMDTransistor("gt.circuitcomponent.asmd.transistor", RecipeMaps.nanochipSMDProcessorRecipes), + AdvSMDInductor("gt.circuitcomponent.asmd.inductor", RecipeMaps.nanochipSMDProcessorRecipes), + AdvSMDCapacitor("gt.circuitcomponent.asmd.capacitor", RecipeMaps.nanochipSMDProcessorRecipes), + AdvSMDDiode("gt.circuitcomponent.asmd.diode", RecipeMaps.nanochipSMDProcessorRecipes), + OpticalSMDResistor("gt.circuitcomponent.xsmd.resistor", RecipeMaps.nanochipSMDProcessorRecipes), + OpticalSMDTransistor("gt.circuitcomponent.xsmd.transistor", RecipeMaps.nanochipSMDProcessorRecipes), + OpticalSMDInductor("gt.circuitcomponent.xsmd.inductor", RecipeMaps.nanochipSMDProcessorRecipes), + OpticalSMDCapacitor("gt.circuitcomponent.xsmd.capacitor", RecipeMaps.nanochipSMDProcessorRecipes), + OpticalSMDDiode("gt.circuitcomponent.xsmd.diode", RecipeMaps.nanochipSMDProcessorRecipes), + ProcessedSMDResistor("gt.circuitcomponent.processed.smd.resistor", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedSMDTransistor("gt.circuitcomponent.processed.smd.transistor", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedSMDInductor("gt.circuitcomponent.processed.smd.inductor", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedSMDCapacitor("gt.circuitcomponent.processed.smd.capacitor", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedSMDDiode("gt.circuitcomponent.processed.smd.diode", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedAdvSMDResistor("gt.circuitcomponent.processed.asmd.resistor", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedAdvSMDTransistor("gt.circuitcomponent.processed.asmd.transistor", + RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedAdvSMDInductor("gt.circuitcomponent.processed.asmd.inductor", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedAdvSMDCapacitor("gt.circuitcomponent.processed.asmd.capacitor", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedAdvSMDDiode("gt.circuitcomponent.processed.asmd.diode", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedOpticalSMDResistor("gt.circuitcomponent.processed.xsmd.resistor", + RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedOpticalSMDTransistor("gt.circuitcomponent.processed.xsmd.transistor", + RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedOpticalSMDInductor("gt.circuitcomponent.processed.xsmd.inductor", + RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedOpticalSMDCapacitor("gt.circuitcomponent.processed.xsmd.capacitor", + RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedOpticalSMDDiode("gt.circuitcomponent.processed.xsmd.diode", RecipeMaps.nanochipAssemblyMatrixRecipes), + BoardMultifiberglassElite("gt.circuitcomponent.boardmultifiberelite", RecipeMaps.nanochipBoardProcessorRecipes), + ProcessedBoardMultifiberglassElite("gt.circuitcomponent.processed.boardmultifiberelite", + RecipeMaps.nanochipAssemblyMatrixRecipes), + ChipNanoCPU("gt.circuitcomponent.chipnanocpu", RecipeMaps.nanochipCuttingChamber), + ChipRAM("gt.circuitcomponent.chipram", RecipeMaps.nanochipCuttingChamber), + ChipNOR("gt.circuitcomponent.chipnor", RecipeMaps.nanochipCuttingChamber), + ChipNAND("gt.circuitcomponent.chipnand", RecipeMaps.nanochipCuttingChamber), + ChipCrystalCPU("gt.circuitcomponent.chipcrystalcpu", RecipeMaps.nanochipEtchingArray), + ProcessedChipNanoCPU("gt.circuitcomponent.processed.chipnanocpu", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedChipCrystalCPU("gt.circuitcomponent.processed.chipcrystalcpu", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedChipRAM("gt.circuitcomponent.processed.chipram", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedChipNOR("gt.circuitcomponent.processed.chipnor", RecipeMaps.nanochipAssemblyMatrixRecipes), + ProcessedChipNAND("gt.circuitcomponent.processed.chipnand", RecipeMaps.nanochipAssemblyMatrixRecipes), + SuperconductorLuV("gt.circuitcomponent.superconductorluv", RecipeMaps.nanochipSuperconductorSplitter, + Materials.SuperconductorLuV), + ProcessedSuperconductorLuV("gt.circuitcomponent.processed.superconductorluv", + RecipeMaps.nanochipAssemblyMatrixRecipes, Materials.SuperconductorLuV), + FrameboxAluminium("gt.circuitcomponent.frame.aluminium", RecipeMaps.nanochipCuttingChamber, Materials.Aluminium), + ProcessedFrameboxAluminium("gt.circuitcomponent.processed.frame.aluminium", + RecipeMaps.nanochipAssemblyMatrixRecipes), + // The first three circuits in a line can be recursively used in the assembly matrix, and all of them can be turned + // into a physical circuit item + CrystalProcessor("gt.circuitcomponent.crystalprocessor", RecipeMaps.nanochipAssemblyMatrixRecipes, + ItemList.Circuit_Crystalprocessor.get(1)), + CrystalAssembly("gt.circuitcomponent.crystassembly", RecipeMaps.nanochipAssemblyMatrixRecipes, + ItemList.Circuit_Crystalcomputer.get(1)), + CrystalComputer("gt.circuitcomponent.crystalcomputer", RecipeMaps.nanochipAssemblyMatrixRecipes, + ItemList.Circuit_Ultimatecrystalcomputer.get(1)), + CrystalMainframe("gt.circuitcomponent.crystalmainframe", null, ItemList.Circuit_Crystalmainframe.get(1)),; + + public final String unlocalizedName; + public String fallbackLocalizedName = null; + // If this component is a direct conversion of some other item in the NAC main controller, this is the item used for that. + // Otherwise, this is null + public IIcon icon = null; + public final Materials material; + // This is the recipe map that this component is used in as an input item + public final RecipeMap processingMap; + public final ItemStack realCircuit; + + // No need to use a full recipe map for conversions to real circuits, this also makes things a little easier + // since we won't need to match outputs of recipes + public static final Map realCircuitToComponent = new HashMap<>(); + + CircuitComponent(String unlocalizedName, RecipeMap processingMap) { + this(unlocalizedName, processingMap, null, null); + } + + CircuitComponent(String unlocalizedName, RecipeMap processingMap, ItemStack realCircuit) { + this(unlocalizedName, processingMap, realCircuit, null); + } + + CircuitComponent(String unlocalizedName, RecipeMap processingMap, Materials material) { + this(unlocalizedName, processingMap, null, material); + } + + CircuitComponent(String unlocalizedName, RecipeMap processingMap, ItemStack realCircuit, Materials material) { + this.unlocalizedName = unlocalizedName; + // Hide the fake stack in NEI + codechicken.nei.api.API.hideItem(getFakeStack(1)); + this.material = material; + this.processingMap = processingMap; + this.realCircuit = realCircuit; + } + + public String getLocalizedName() { + // If a translation key is set, use it, otherwise use the automatically generated fallback name + if (StatCollector.canTranslate(unlocalizedName)) { + return StatCollector.translateToLocal(unlocalizedName); + } + return fallbackLocalizedName; + } + + // ItemStack of a fake item, only for display and recipe checking purposes + public ItemStack getFakeStack(int amount) { + return new ItemStack(CircuitComponentFakeItem.INSTANCE, amount, this.ordinal()); + } + + public static CircuitComponent tryGetFromFakeStack(ItemStack stack) { + if (stack.getItemDamage() >= CircuitComponent.values().length) return null; + return getFromFakeStackUnsafe(stack); + } + + public static CircuitComponent getFromFakeStackUnsafe(ItemStack stack) { + // If this throws an IndexOutOfBounds exception, there is a bug + return CircuitComponent.values()[stack.getItemDamage()]; + } + + public static CircuitComponent getFromMetaDataUnsafe(int metadata) { + return CircuitComponent.values()[metadata]; + } + + static { + // Populate real circuit conversion hashmap + for (CircuitComponent component : CircuitComponent.values()) { + if (component.realCircuit != null) { + GTUtility.ItemId id = GTUtility.ItemId.createNoCopy(component.realCircuit); + realCircuitToComponent.put(id, component); + } + } + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/CircuitComponentPacket.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/CircuitComponentPacket.java new file mode 100644 index 00000000000..17d074a76c9 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/CircuitComponentPacket.java @@ -0,0 +1,57 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +public class CircuitComponentPacket { + + private final Map components = new HashMap<>(); + + public CircuitComponentPacket(CircuitComponent component, int amount) { + components.put(component, amount); + } + + public CircuitComponentPacket(NBTTagCompound nbt) { + for (String key : nbt.func_150296_c()) { + CircuitComponent component = CircuitComponent.valueOf(key); + int amount = nbt.getInteger(key); + components.put(component, amount); + } + } + + // Accept more circuit components from a new packet + public void unifyWith(CircuitComponentPacket other) { + for (Map.Entry entry : other.components.entrySet()) { + components.merge(entry.getKey(), entry.getValue(), Integer::sum); + } + } + + public NBTTagCompound writeToNBT() { + NBTTagCompound tag = new NBTTagCompound(); + for (Map.Entry entry : components.entrySet()) { + String key = entry.getKey() + .name(); + tag.setInteger(key, entry.getValue()); + } + return tag; + } + + public Map getComponents() { + return components; + } + + public List getItemRepresentations() { + ArrayList stacks = new ArrayList<>(); + for (Map.Entry entry : components.entrySet()) { + ItemStack componentStack = entry.getKey() + .getFakeStack(entry.getValue()); + stacks.add(componentStack); + } + return stacks; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/IConnectsToVacuumConveyor.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/IConnectsToVacuumConveyor.java new file mode 100644 index 00000000000..7d26b315023 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/IConnectsToVacuumConveyor.java @@ -0,0 +1,14 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +import net.minecraftforge.common.util.ForgeDirection; + +public interface IConnectsToVacuumConveyor { + + boolean canConnect(ForgeDirection side); + + IConnectsToVacuumConveyor getNext(IConnectsToVacuumConveyor source); + + boolean isComponentsInputFacing(ForgeDirection side); + + byte getColorization(); +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/ItemStackWithSourceBus.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/ItemStackWithSourceBus.java new file mode 100644 index 00000000000..4b371f87b1c --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/ItemStackWithSourceBus.java @@ -0,0 +1,20 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +import net.minecraft.item.ItemStack; + +import org.jetbrains.annotations.NotNull; + +import gregtech.api.metatileentity.implementations.MTEHatchInputBus; + +public class ItemStackWithSourceBus { + + @NotNull + public final ItemStack stack; + @NotNull + public final MTEHatchInputBus bus; + + public ItemStackWithSourceBus(@NotNull ItemStack stack, @NotNull MTEHatchInputBus bus) { + this.stack = stack; + this.bus = bus; + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/ModuleRecipeInfo.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/ModuleRecipeInfo.java new file mode 100644 index 00000000000..b8368e43c9a --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/ModuleRecipeInfo.java @@ -0,0 +1,22 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +import static gregtech.api.util.GTRecipeBuilder.TICKS; + +public class ModuleRecipeInfo { + public static final int MODULE_RECIPE_TIME = 20 * TICKS; + + public final int recipeProcessingTime; + + public ModuleRecipeInfo(int time) { + this.recipeProcessingTime = time; + } + + public final int getBaseParallel() { + return MODULE_RECIPE_TIME / recipeProcessingTime; + } + + // Some base speeds to keep things simple + public static final ModuleRecipeInfo Fast = new ModuleRecipeInfo(5 * TICKS); + public static final ModuleRecipeInfo Medium = new ModuleRecipeInfo(10 * TICKS); + public static final ModuleRecipeInfo Slow = new ModuleRecipeInfo(20 * TICKS); +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/ModuleStructureDefinition.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/ModuleStructureDefinition.java new file mode 100644 index 00000000000..013e8915359 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/ModuleStructureDefinition.java @@ -0,0 +1,16 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +import com.gtnewhorizon.structurelib.structure.StructureDefinition; + +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyModuleBase; + +/** + * Utility class that implicitly adds the base structure piece of a nanochip assembly module to + * a structure definition. + */ +public class ModuleStructureDefinition { + + public static > StructureDefinition.Builder builder() { + return MTENanochipAssemblyModuleBase.addBaseStructure(StructureDefinition.builder()); + } +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/RecipeHandlers.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/RecipeHandlers.java new file mode 100644 index 00000000000..b4a91da8637 --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/RecipeHandlers.java @@ -0,0 +1,332 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + +import net.minecraft.item.ItemStack; + +import gregtech.api.enums.GTValues; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.TierEU; +import gregtech.api.interfaces.IRecipeMap; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.metadata.NanochipAssemblyRecipeInfo; +import gregtech.api.util.GTOreDictUnificator; +import gregtech.api.util.GTRecipe; +import gregtech.api.util.GTUtility; + +import static gregtech.api.util.GTRecipeBuilder.TICKS; + +public class RecipeHandlers { + + private static void addConversionRecipe(CircuitComponent component, ItemStack stack) { + GTValues.RA.stdBuilder() + .itemInputs(stack) + .itemOutputs(component.getFakeStack(1)) + .duration(1 * TICKS) + .eut(0) + .addTo(RecipeMaps.nanochipConversionRecipes); + component.icon = stack.getIconIndex(); + } + + // Adds a simple processing recipe for circuit components in a module. The recipe map used for processing is + // inferred + // from the map stored by the input component. + private static void addSimpleProcessingRecipe(CircuitComponent input, CircuitComponent output, + ModuleRecipeInfo info, long eut) { + RecipeMap recipeMap = input.processingMap; + if (recipeMap == null) { + throw new IllegalArgumentException( + "Tried to add component processing recipe for a component without an associated recipemap"); + } + GTValues.RA.stdBuilder() + .metadata(NanochipAssemblyRecipeInfo.INSTANCE, info) + .itemInputs(input.getFakeStack(info.getBaseParallel())) + .itemOutputs(output.getFakeStack(info.getBaseParallel())) + .duration(ModuleRecipeInfo.MODULE_RECIPE_TIME) + .eut(eut) + .noOptimize() + .addTo(recipeMap); + } + + public static void populateCircuitComponentRecipeMaps() { + // Note: To correctly generate localized names, currently all conversion recipes need to be registered + // before processing recipes. I'll admit this is a bit messy, so I may try to find a solution for this + // in the future (TODO) + + // Wires + addConversionRecipe( + CircuitComponent.WireNiobiumTitanium, + GTOreDictUnificator.get(OrePrefixes.wireFine, Materials.NiobiumTitanium, 1)); + // SMDs + addConversionRecipe(CircuitComponent.SMDTransistor, ItemList.Circuit_Parts_TransistorSMD.get(1)); + addConversionRecipe(CircuitComponent.SMDInductor, ItemList.Circuit_Parts_InductorSMD.get(1)); + addConversionRecipe(CircuitComponent.SMDCapacitor, ItemList.Circuit_Parts_CapacitorSMD.get(1)); + addConversionRecipe(CircuitComponent.SMDDiode, ItemList.Circuit_Parts_DiodeSMD.get(1)); + addConversionRecipe(CircuitComponent.SMDResistor, ItemList.Circuit_Parts_ResistorSMD.get(1)); + addConversionRecipe(CircuitComponent.AdvSMDTransistor, ItemList.Circuit_Parts_TransistorASMD.get(1)); + addConversionRecipe(CircuitComponent.AdvSMDInductor, ItemList.Circuit_Parts_InductorASMD.get(1)); + addConversionRecipe(CircuitComponent.AdvSMDCapacitor, ItemList.Circuit_Parts_CapacitorASMD.get(1)); + addConversionRecipe(CircuitComponent.AdvSMDDiode, ItemList.Circuit_Parts_DiodeASMD.get(1)); + addConversionRecipe(CircuitComponent.AdvSMDResistor, ItemList.Circuit_Parts_ResistorASMD.get(1)); + addConversionRecipe(CircuitComponent.OpticalSMDTransistor, ItemList.Circuit_Parts_TransistorXSMD.get(1)); + addConversionRecipe(CircuitComponent.OpticalSMDInductor, ItemList.Circuit_Parts_InductorXSMD.get(1)); + addConversionRecipe(CircuitComponent.OpticalSMDCapacitor, ItemList.Circuit_Parts_CapacitorXSMD.get(1)); + addConversionRecipe(CircuitComponent.OpticalSMDDiode, ItemList.Circuit_Parts_DiodeXSMD.get(1)); + addConversionRecipe(CircuitComponent.OpticalSMDResistor, ItemList.Circuit_Parts_ResistorXSMD.get(1)); + // Boards + addConversionRecipe( + CircuitComponent.BoardMultifiberglassElite, + ItemList.Circuit_Board_Multifiberglass_Elite.get(1)); + // CPUs + addConversionRecipe(CircuitComponent.ChipCrystalCPU, ItemList.Circuit_Chip_CrystalCPU.get(1)); + // Cut wafers + addConversionRecipe(CircuitComponent.ChipNanoCPU, ItemList.Circuit_Chip_NanoCPU.get(1)); + addConversionRecipe(CircuitComponent.ChipRAM, ItemList.Circuit_Chip_Ram.get(1)); + addConversionRecipe(CircuitComponent.ChipNOR, ItemList.Circuit_Chip_NOR.get(1)); + addConversionRecipe(CircuitComponent.ChipNAND, ItemList.Circuit_Chip_NAND.get(1)); + // Superconductors + addConversionRecipe( + CircuitComponent.SuperconductorLuV, + GTOreDictUnificator.get(OrePrefixes.wireGt01, Materials.SuperconductorLuV, 1)); + // Frame boxes + addConversionRecipe( + CircuitComponent.FrameboxAluminium, + GTOreDictUnificator.get(OrePrefixes.frameGt, Materials.Aluminium, 1)); + // Wire processing recipes + addSimpleProcessingRecipe( + CircuitComponent.WireNiobiumTitanium, + CircuitComponent.ProcessedWireNiobiumTitanium, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + // SMD processing recipes + addSimpleProcessingRecipe( + CircuitComponent.SMDResistor, + CircuitComponent.ProcessedSMDResistor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.SMDTransistor, + CircuitComponent.ProcessedSMDTransistor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.SMDInductor, + CircuitComponent.ProcessedSMDInductor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.SMDCapacitor, + CircuitComponent.ProcessedSMDCapacitor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.SMDDiode, + CircuitComponent.ProcessedSMDDiode, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.AdvSMDResistor, + CircuitComponent.ProcessedAdvSMDResistor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.AdvSMDTransistor, + CircuitComponent.ProcessedAdvSMDTransistor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.AdvSMDInductor, + CircuitComponent.ProcessedAdvSMDInductor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.AdvSMDCapacitor, + CircuitComponent.ProcessedAdvSMDCapacitor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.AdvSMDDiode, + CircuitComponent.ProcessedAdvSMDDiode, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.OpticalSMDResistor, + CircuitComponent.ProcessedOpticalSMDResistor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.OpticalSMDTransistor, + CircuitComponent.ProcessedOpticalSMDTransistor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.OpticalSMDInductor, + CircuitComponent.ProcessedOpticalSMDInductor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.OpticalSMDCapacitor, + CircuitComponent.ProcessedOpticalSMDCapacitor, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.OpticalSMDDiode, + CircuitComponent.ProcessedOpticalSMDDiode, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + // Board processing recipes + addSimpleProcessingRecipe( + CircuitComponent.BoardMultifiberglassElite, + CircuitComponent.ProcessedBoardMultifiberglassElite, + ModuleRecipeInfo.Fast, + TierEU.RECIPE_LV); + // CPU processing recipes + addSimpleProcessingRecipe( + CircuitComponent.ChipCrystalCPU, + CircuitComponent.ProcessedChipCrystalCPU, + ModuleRecipeInfo.Slow, + TierEU.RECIPE_LV); + // Wafer cutting processing recipes + addSimpleProcessingRecipe( + CircuitComponent.ChipNanoCPU, + CircuitComponent.ProcessedChipNanoCPU, + ModuleRecipeInfo.Medium, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.ChipRAM, + CircuitComponent.ProcessedChipRAM, + ModuleRecipeInfo.Medium, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.ChipNOR, + CircuitComponent.ProcessedChipNOR, + ModuleRecipeInfo.Medium, + TierEU.RECIPE_LV); + addSimpleProcessingRecipe( + CircuitComponent.ChipNAND, + CircuitComponent.ProcessedChipNAND, + ModuleRecipeInfo.Medium, + TierEU.RECIPE_LV); + // Superconductor processing recipes + addSimpleProcessingRecipe( + CircuitComponent.SuperconductorLuV, + CircuitComponent.ProcessedSuperconductorLuV, + ModuleRecipeInfo.Medium, + TierEU.RECIPE_LV); + // Frame box processing recipes + addSimpleProcessingRecipe( + CircuitComponent.FrameboxAluminium, + CircuitComponent.ProcessedFrameboxAluminium, + ModuleRecipeInfo.Medium, + TierEU.RECIPE_LV); + } + + private static GTRecipe findRecipeUsingStack(ItemStack input, RecipeMap map) { + return map.findRecipeQuery() + .dontCheckStackSizes(true) + .items(input) + .find(); + } + + private static ItemStack findResultingStack(ItemStack input, RecipeMap map) { + GTRecipe recipe = findRecipeUsingStack(input, map); + if (recipe == null) return null; + return recipe.mOutputs[0]; + } + + private static ItemStack traverseCircuitRecipes(ItemStack input, RecipeMap inputProcessingMap) { + // TODO: In this algorithm, we might still need to keep track of amount ratios (1 SMD = N Processed SMD = 1/N + // Circuits or something) + + // Special case: if this item is a finished circuit item, we already know the component to use and we don't do + // this full iteration + CircuitComponent circuitComponent = CircuitComponent.realCircuitToComponent + .get(GTUtility.ItemId.createNoCopy(input)); + if (circuitComponent != null) return circuitComponent.getFakeStack(input.stackSize); + // If the recipe map is null, we have a finalized CC (probably, this could also be a bug or missing mappings) + if (inputProcessingMap == null) return input; + // If this map is the nanochip assembly matrix map, return the input as we have finished the process + if (inputProcessingMap.unlocalizedName.equals(RecipeMaps.nanochipAssemblyMatrixRecipes.unlocalizedName)) { + return input; + } + // Find the result of applying the recipe map to this input + ItemStack result = findResultingStack(input, inputProcessingMap); + // If this is null, we cannot process this stack into a finalized circuit (probably some mappings for items are + // missing). + if (result == null) return null; + // This resulting item is a fake stack, so find the circuit component that corresponds to it + CircuitComponent component = CircuitComponent.getFromFakeStackUnsafe(result); + // Process this component further in the next recipe map + return traverseCircuitRecipes(result, component.processingMap); + } + + public static final IRecipeMap assemblyMatrixRecipeTransformer = IRecipeMap.newRecipeMap(builder -> { + // This RecipeMap is added as a downstream of the circuit assembler recipe map. This means that any + // circuit assembler recipe will also be added to this map, so we can process it further. + // One note is that BW also modifies this recipe map, to make the recipes that should go in the CAL 6x more + // expensive and to add its own recipes to the CAL. However, this happens after the recipe map is built already. + // Also, when re-adding recipes, it uses the (deprecated) RecipeMap::add, which bypasses the backend method to + // also + // add recipes to the downstream maps, so this transformer won't be called for the modified recipes. + // This is a good thing, it means we can deal with unmodified circuit assembler recipes here and don't have to + // worry about the CAL recipe transformation code at all. + + // Before we do anything, find the output item, so we can check if this recipe should be touched at all + ItemStack realOutput = builder.getItemOutput(0); + GTUtility.ItemId id = GTUtility.ItemId.createNoCopy(realOutput); + CircuitComponent outputComponent = CircuitComponent.realCircuitToComponent.get(id); + if (outputComponent == null) { + // Not a nanochip assembly recipe because it has no matching fake circuit, return empty list + return Collections.emptyList(); + } + + // Grab a copy of the item input list + ArrayList itemInputs = new ArrayList<>(Arrays.asList(builder.getItemInputsBasic())); + + // For each input, we follow the following procedure + // 1. Find the circuit component produced by this item + // 2. Follow the recipe map processing this circuit component given by CircuitComponent#processingMap to find + // the next step in the process. This gives us a new circuit component in the chain. + // 3. Keep following this chain of circuit components until we arrive at a component that is an input in the + // assembly matrix. + // 4. Use this component as the input of the assembly step. + // Note that this process will only work for the basic circuits, the advanced processing lines using + // the nanochip assembly complex will not be autogenerated by this process. + for (int i = 0; i < itemInputs.size(); ++i) { + ItemStack input = itemInputs.get(i); + // Traverse the recipe map to find the final input needed in the assembly matrix + ItemStack processedFakeInput = traverseCircuitRecipes(input, RecipeMaps.nanochipConversionRecipes); + // If none was found, we simply keep this unchanged in the assembly matrix. Likely some mappings are + // missing, + // so the recipe will be incorrectly generated in this case, but for debugging purposes this is fine. + if (processedFakeInput == null) continue; + // Get the input component, so we can construct a new fake input stack with the correct stack size easily. + // Note that this *is* a roundabout way to copying the processedFakeInput ItemStack, but whatever, this + // does logically make sense and is a bit more explicit. As a bonus, this verifies that processedFakeInput + // is in fact a circuit component, so this is another sanity check that can catch bugs in + // traverseCircuitRecipes. + CircuitComponent componentInput = CircuitComponent.getFromFakeStackUnsafe(processedFakeInput); + ItemStack fakeInputStack = componentInput.getFakeStack(input.stackSize); + itemInputs.set(i, fakeInputStack); + } + + ItemStack fakeOutput = outputComponent.getFakeStack(realOutput.stackSize); + // Add two recipes: A hidden one that outputs the fake circuit CC, and a fake, visible one that outputs the real circuit. + // This is done so we can more easily look them up in NEI + builder = builder.itemInputs(itemInputs.toArray(new ItemStack[] {})); + return GTUtility.concat( + builder.copy() + .itemOutputs(fakeOutput) + .hidden() + .addTo(RecipeMaps.nanochipAssemblyMatrixRecipes), + builder + .fake() + .addTo(RecipeMaps.nanochipAssemblyMatrixRecipes) + ); + }); +} diff --git a/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/VacuumConveyorHatchMap.java b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/VacuumConveyorHatchMap.java new file mode 100644 index 00000000000..c944b73188f --- /dev/null +++ b/src/main/java/gregtech/common/tileentities/machines/multi/nanochip/util/VacuumConveyorHatchMap.java @@ -0,0 +1,98 @@ +package gregtech.common.tileentities.machines.multi.nanochip.util; + +import static gregtech.api.util.GTUtility.filterValidMTEs; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import gregtech.common.tileentities.machines.multi.nanochip.hatches.MTEHatchVacuumConveyor; + +// To keep track of colors of the conveyor hatches for faster routing +public class VacuumConveyorHatchMap { + + // Note that each color can result in multiple conveyor hatches. It's up to the user to determine how to interpret + // this: + // This class does not assume you want to pick the first hatch or distribute the components across all hatches. + private final Map> conveyorsByColor = new HashMap<>(); + private int totalNumHatches = 0; + + private boolean putWithColorUnchecked(byte color, T hatch) { + ArrayList hatches = findColoredHatches(color); + if (hatches != null) { + return hatches.add(hatch); + } + conveyorsByColor.put(color, new ArrayList<>(Collections.singletonList(hatch))); + return true; + } + + /** + * Clear the internal data structure of hatches. This will need to be called on every structure check to avoid + * duplicate entries + */ + public void clear() { + this.conveyorsByColor.clear(); + totalNumHatches = 0; + } + + public boolean addHatch(T hatch) { + totalNumHatches += 1; + byte color = hatch.getColorization(); + return putWithColorUnchecked(color, hatch); + } + + public void fixConsistency() { + // For each valid color, check all entries in the map by that color to ensure they still have their color + for (byte color = 0; color < 16; ++color) { + ArrayList hatches = findColoredHatches(color); + if (hatches == null) continue; + final byte finalColor = color; + hatches.removeIf(hatch -> { + byte realColor = hatch.getColorization(); + // If color doesn't match the real color, put it in the correct entry and remove it from this list + if (finalColor != realColor) { + putWithColorUnchecked(realColor, hatch); + return true; + } + return false; + }); + } + } + + public ArrayList findColoredHatches(byte color) { + return conveyorsByColor.get(color); + } + + public T findAnyColoredHatch(byte color) { + ArrayList hatches = findColoredHatches(color); + if (hatches == null) return null; + for (T hatch : filterValidMTEs(hatches)) { + // Ensure that the color matches the expected color, since hatches can be recolored in between rebuilds + // of the hatch map + if (hatch.getBaseMetaTileEntity() + .getColorization() != color) { + // If the color did not match, we found an inconsistency in the hatch map, so fix it immediately + // and skip this hatch, since it's not a match + fixConsistency(); + continue; + } + return hatch; + } + return null; + } + + public Collection> allHatches() { + return conveyorsByColor.values(); + } + + public Map> hatchMap() { + return this.conveyorsByColor; + } + + // Count all hatches in the map + public int size() { + return totalNumHatches; + } +} diff --git a/src/main/java/gregtech/loaders/postload/recipes/CircuitAssemblerRecipes.java b/src/main/java/gregtech/loaders/postload/recipes/CircuitAssemblerRecipes.java index 90e9b15f56a..c5022c327c1 100644 --- a/src/main/java/gregtech/loaders/postload/recipes/CircuitAssemblerRecipes.java +++ b/src/main/java/gregtech/loaders/postload/recipes/CircuitAssemblerRecipes.java @@ -9,6 +9,9 @@ import static gregtech.loaders.postload.MachineRecipeLoader.solderingMats; import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; import gregtech.api.enums.GTValues; import gregtech.api.enums.ItemList; @@ -26,6 +29,69 @@ public void run() { registerRailcraftRecipes(); registerForestryRecipes(); + // Debugging nanochip assembly complex: Add recipes for crystalprocessor line + Fluid solderIndalloy = FluidRegistry.getFluid("molten.indalloy140") != null + ? FluidRegistry.getFluid("molten.indalloy140") + : FluidRegistry.getFluid("molten.solderingalloy"); + GTValues.RA.stdBuilder() + .itemInputs( + ItemList.Circuit_Board_Multifiberglass_Elite.get(1L), + ItemList.Circuit_Chip_CrystalCPU.get(1L), + ItemList.Circuit_Chip_NanoCPU.get(2L), + ItemList.Circuit_Parts_CapacitorASMD.get(6), + ItemList.Circuit_Parts_TransistorASMD.get(6), + GTOreDictUnificator.get(OrePrefixes.wireFine, Materials.NiobiumTitanium, 8)) + .itemOutputs(ItemList.Circuit_Crystalprocessor.get(1L)) + .fluidInputs(new FluidStack(solderIndalloy, 72)) + .requiresCleanRoom() + .duration(5 * SECONDS) + .eut(9600) + .addTo(circuitAssemblerRecipes); + + GTValues.RA.stdBuilder() + .itemInputs( + ItemList.Circuit_Board_Multifiberglass_Elite.get(1L), + ItemList.Circuit_Crystalprocessor.get(2L), + ItemList.Circuit_Parts_InductorASMD.get(6L), + ItemList.Circuit_Parts_CapacitorASMD.get(8L), + ItemList.Circuit_Chip_Ram.get(24), + GTOreDictUnificator.get(OrePrefixes.wireFine, Materials.NiobiumTitanium, 16)) + .itemOutputs(ItemList.Circuit_Crystalcomputer.get(1L)) + .fluidInputs(new FluidStack(solderIndalloy, 144)) + .requiresCleanRoom() + .duration(10 * SECONDS) + .eut(9600) + .addTo(circuitAssemblerRecipes); + + GTValues.RA.stdBuilder() + .itemInputs( + ItemList.Circuit_Board_Multifiberglass_Elite.get(1L), + ItemList.Circuit_Crystalcomputer.get(2L), + ItemList.Circuit_Chip_Ram.get(4L), + ItemList.Circuit_Chip_NOR.get(32L), + ItemList.Circuit_Chip_NAND.get(64L), + GTOreDictUnificator.get(OrePrefixes.wireFine, Materials.NiobiumTitanium, 32)) + .itemOutputs(ItemList.Circuit_Ultimatecrystalcomputer.get(1L)) + .fluidInputs(new FluidStack(solderIndalloy, 144)) + .requiresCleanRoom() + .duration(20 * SECONDS) + .eut(9600) + .addTo(circuitAssemblerRecipes); + + GTValues.RA.stdBuilder() + .itemInputs( + GTOreDictUnificator.get(OrePrefixes.frameGt, Materials.Aluminium, 2), + ItemList.Circuit_Ultimatecrystalcomputer.get(2L), + ItemList.Circuit_Parts_InductorASMD.get(8L), + ItemList.Circuit_Parts_CapacitorASMD.get(16L), + ItemList.Circuit_Chip_Ram.get(32L), + GTOreDictUnificator.get(OrePrefixes.wireGt01, Materials.SuperconductorLuV, 16)) + .itemOutputs(ItemList.Circuit_Crystalmainframe.get(1L)) + .fluidInputs(new FluidStack(solderIndalloy, 288)) + .requiresCleanRoom() + .duration(40 * SECONDS) + .eut(TierEU.RECIPE_LuV) + .addTo(circuitAssemblerRecipes); } public void registerRailcraftRecipes() { diff --git a/src/main/java/gregtech/loaders/preload/LoaderGTBlockFluid.java b/src/main/java/gregtech/loaders/preload/LoaderGTBlockFluid.java index dfb1c39788b..3779de761a3 100644 --- a/src/main/java/gregtech/loaders/preload/LoaderGTBlockFluid.java +++ b/src/main/java/gregtech/loaders/preload/LoaderGTBlockFluid.java @@ -31,22 +31,9 @@ import cpw.mods.fml.common.registry.GameRegistry; import gregtech.GTMod; import gregtech.api.GregTechAPI; -import gregtech.api.enums.Dyes; -import gregtech.api.enums.GTValues; -import gregtech.api.enums.ItemList; -import gregtech.api.enums.Materials; -import gregtech.api.enums.MaterialsKevlar; -import gregtech.api.enums.MaterialsUEVplus; -import gregtech.api.enums.Mods; -import gregtech.api.enums.OrePrefixes; -import gregtech.api.enums.SubTag; -import gregtech.api.enums.TierEU; +import gregtech.api.enums.*; import gregtech.api.fluid.GTFluidFactory; -import gregtech.api.items.BlockLongDistancePipe; -import gregtech.api.items.GTGenericItem; -import gregtech.api.items.ItemBreederCell; -import gregtech.api.items.ItemCoolantCellIC; -import gregtech.api.items.ItemRadioactiveCellIC; +import gregtech.api.items.*; import gregtech.api.metatileentity.BaseMetaPipeEntity; import gregtech.api.metatileentity.BaseMetaTileEntity; import gregtech.api.util.GTLog; @@ -169,6 +156,7 @@ public void run() { new MetaGeneratedTool01(); new ItemFluidDisplay(); new ItemWirelessHeadphones(); + new CircuitComponentFakeItem(); // Tiered recipe materials actually appear to be set in MTEBasicMachineWithRecipe, making these // unused diff --git a/src/main/java/gregtech/loaders/preload/LoaderMetaTileEntities.java b/src/main/java/gregtech/loaders/preload/LoaderMetaTileEntities.java index b34cd031ea3..ca3778ffa08 100644 --- a/src/main/java/gregtech/loaders/preload/LoaderMetaTileEntities.java +++ b/src/main/java/gregtech/loaders/preload/LoaderMetaTileEntities.java @@ -1,6 +1,8 @@ package gregtech.loaders.preload; +// spotless:off import static gregtech.api.enums.MetaTileEntityIDs.*; +// spotless:on import static gregtech.api.enums.MetaTileEntityIDs.ADVANCED_DATA_ACCESS_HATCH; import static gregtech.api.enums.MetaTileEntityIDs.ADVANCED_DEBUG_STRUCTURE_WRITTER; import static gregtech.api.enums.MetaTileEntityIDs.ADVANCED_SEISMIC_PROSPECTOR_EV; @@ -1083,6 +1085,8 @@ import gregtech.common.tileentities.machines.multi.compressor.MTENeutroniumCompressor; import gregtech.common.tileentities.machines.multi.drone.MTEDroneCentre; import gregtech.common.tileentities.machines.multi.drone.MTEHatchDroneDownLink; +import gregtech.common.tileentities.machines.multi.nanochip.MTENanochipAssemblyComplex; +import gregtech.common.tileentities.machines.multi.nanochip.modules.*; import gregtech.common.tileentities.machines.multi.purification.MTEHatchDegasifierControl; import gregtech.common.tileentities.machines.multi.purification.MTEHatchLensHousing; import gregtech.common.tileentities.machines.multi.purification.MTEHatchLensIndicator; @@ -1633,6 +1637,45 @@ private static void registerMultiblockControllers() { new MTELargeFluidExtractor(LARGE_FLUID_EXTRACTOR.ID, "multimachine.fluidextractor", "Large Fluid Extractor") .getStackForm(1)); + ItemList.Machine_Multi_NanochipAssemblyComplex.set( + new MTENanochipAssemblyComplex( + NANOCHIP_ASSEMBLY_CONTROLLER.ID, + "multimachine.nanochipassemblycomplex", + "Nanochip Assembly Complex").getStackForm(1)); + ItemList.NanoChipModule_AssemblyMatrix.set( + new AssemblyMatrix( + NANOCHIP_MODULE_ASSEMBLY_MATRIX.ID, + "multimachine.nanochipmodule.assemblymatrix", + "Nanochip Assembly Matrix").getStackForm(1)); + ItemList.NanoChipModule_SMDProcessor.set( + new SMDProcessor( + NANOCHIP_MODULE_SMD_PROCESSOR.ID, + "multimachine.nanochipmodule.smdprocessor", + "Part Preparation Apparatus").getStackForm(1)); + ItemList.NanoChipModule_BoardProcessor.set( + new BoardProcessor( + NANOCHIP_MODULE_BOARD_PROCESSOR.ID, + "multimachine.nanochipmodule.boadprocessor", + "Full-Board Immersion Device").getStackForm(1)); + ItemList.NanoChipModule_EtchingArray.set( + new EtchingArray( + NANOCHIP_MODULE_ETCHING_ARRAY.ID, + "multimachine.nanochipmodule.etchingarray", + "Ultra-high Energy Etching Array").getStackForm(1)); + ItemList.NanoChipModule_CuttingChamber.set( + new CuttingChamber( + NANOCHIP_MODULE_CUTTING_CHAMBER.ID, + "multimachine.nanochipmodule.cuttingchamber", + "Nanoprecision Cutting Chamber").getStackForm(1)); + ItemList.NanoChipModule_WireTracer.set( + new WireTracer( + NANOCHIP_MODULE_WIRE_TRACER.ID, + "multimachine.nanochipmodule.wiretracer", + "Nanoprecision Wire Tracer").getStackForm(1)); + ItemList.NanoChipModule_Splitter.set( + new Splitter(NANOCHIP_MODULE_SPLITTER.ID, "multimachine.nanochipmodule.splitter", "Nanopart Splitter") + .getStackForm(1)); + if (Thaumcraft.isModLoaded()) { ItemList.ResearchCompleter.set( new MTEResearchCompleter(ResearchCompleter.ID, "Research Completer", "Research Completer")