diff --git a/gradle/forge.versions.toml b/gradle/forge.versions.toml index 8cc8154749d..8682399d7ea 100644 --- a/gradle/forge.versions.toml +++ b/gradle/forge.versions.toml @@ -7,7 +7,7 @@ jei = "15.20.0.115" rei = "12.1.785" emi = "1.1.22+1.20.1" ae2 = "15.0.18" -mui = "3.3.0-SNAPSHOT" +mui = "3.3.1-SNAPSHOT" kubejs = "2001.6.5-build.16" rhino = "2001.2.3-build.10" architectury = "9.2.14" diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/schema/MutableSchema.java b/src/main/java/com/gregtechceu/gtceu/client/mui/schema/MutableSchema.java index 370fc1ea215..0ea506c2853 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/schema/MutableSchema.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/schema/MutableSchema.java @@ -30,6 +30,7 @@ public class MutableSchema implements ISchema { protected final Level level = new SchemaLevel(); @Getter protected @NotNull BlockPos origin = BlockPos.ZERO; + @Getter protected @NotNull Vector3f center = new Vector3f(); @Getter private BlockPos controllerPos = BlockPos.ZERO; diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java index fda07d22569..949cd3d745e 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/behavior/TerminalBehavior.java @@ -133,7 +133,7 @@ public InteractionResultHolder use(Item item, Level level, Player pla private ModularPanel clientPanel() { MultiblockPreviewWidget previewWidget = new MultiblockPreviewWidget(this.multiblockDefinition, - this.multiblockSchemaInfo) + this.multiblockSchemaInfo, 200, 200) .setControllerPos(this.controllerPos) .setFrontFacing(this.frontFacing).setUpFacing(this.upFacing).setFlipped(this.isFlipped); previewWidget.refreshSchema(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java index bb84e52914b..8f92d9b58e7 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CleanroomMachine.java @@ -313,7 +313,7 @@ private static boolean isAllFloorBlocks(Level level, BlockPos.MutableBlockPos po public static Function getPattern() { return (definition) -> { - PatternPredicate wallPredicate = getValidFloorBlocks().or(states(getCasingState(), getGlassState())); + PatternPredicate wallPredicate = states(getCasingState(), getGlassState()).or(getValidFloorBlocks()); PatternPredicate energyPredicate = autoAbilities(true, false, false).or(abilities(PartAbility.INPUT_ENERGY) .setMinGlobalLimited(1).setMaxGlobalLimited(3)); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/emi/MultiblockInfoEmiCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/emi/MultiblockInfoEmiCategory.java index f97732716cb..6e278b99c02 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/emi/MultiblockInfoEmiCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/emi/MultiblockInfoEmiCategory.java @@ -2,23 +2,40 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; +import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; +import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; +import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; +import com.gregtechceu.gtceu.api.multiblock.util.AbstractStructureHelper; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.registry.GTRegistries; import com.gregtechceu.gtceu.common.data.machines.GTMultiMachines; import com.gregtechceu.gtceu.integration.recipeviewer.widgets.MultiblockPreviewWidget; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; import brachy.modularui.integration.emi.recipe.ModularUIEmiRecipe; import dev.emi.emi.api.EmiRegistry; import dev.emi.emi.api.recipe.EmiRecipeCategory; import dev.emi.emi.api.stack.EmiIngredient; import dev.emi.emi.api.stack.EmiStack; -import dev.emi.emi.api.widget.SlotWidget; import dev.emi.emi.api.widget.WidgetHolder; +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; + +import static com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine.DEFAULT_STRUCTURE; public class MultiblockInfoEmiCategory extends EmiRecipeCategory { @@ -45,22 +62,48 @@ public Component getName() { public static class MultiblockInfoEmiWrapper extends ModularUIEmiRecipe { private final MultiblockMachineDefinition definition; - private SlotWidget slotWidget; + private final List containedBlocks = new ArrayList<>(); public MultiblockInfoEmiWrapper(MultiblockMachineDefinition definition) { - super(definition.getId(), () -> new MultiblockPreviewWidget(definition, null)); + super(definition.getId(), () -> new MultiblockPreviewWidget(definition, null, 200, 180)); this.definition = definition; + initializeContainedBlocks(); + } + + private void initializeContainedBlocks() { + Map resultStructure = new HashMap<>(); + IBlockPattern pattern = definition.getStructurePatterns().get(DEFAULT_STRUCTURE).get(); + AbstractStructureHelper structureHelper = null; + if (pattern instanceof BlockPattern blockPattern) { + var sliceRepeats = new Int2IntArrayMap(); + for (int i = 0; i < blockPattern.getSlices().length; i++) { + sliceRepeats.put(i, blockPattern.getSlices()[i].getMinRepeats()); + } + structureHelper = AbstractStructureHelper.blockPattern(sliceRepeats); + } else if (pattern instanceof ExpandablePattern expandablePattern) { + var userDimensions = new IntArrayList(); + expandablePattern.getBoundsConstraints().apply().stream() + .mapToInt(Pair::left) + .forEach(userDimensions::add); + structureHelper = AbstractStructureHelper.expandable(userDimensions); + } + if (structureHelper != null) { + structureHelper.populate(resultStructure, pattern, null, + definition.getRotationState().defaultDirection, switch (definition.getRotationState()) { + case Y_AXIS -> Direction.NORTH; + case ALL, NON_Y_AXIS, NONE -> Direction.UP; + }, false); + + Object2IntMap blockCount = new Object2IntOpenHashMap<>(); + resultStructure.forEach( + (pos, state) -> blockCount.mergeInt(state.getBlockState().getBlock(), 1, Integer::sum)); + blockCount.forEach((block, count) -> containedBlocks.add(EmiStack.of(block.asItem(), count))); + } } @Override public void addWidgets(WidgetHolder widgets) { super.addWidgets(widgets); - // numbers gotten from the size of the widget - slotWidget = new SlotWidget(EmiStack.of(definition.getItem().asItem()), 138, 12) - .recipeContext(this) - .drawBack(false); - - widgets.add(slotWidget); } @Override @@ -75,12 +118,12 @@ public EmiRecipeCategory getCategory() { @Override public List getInputs() { - return List.of(); + return containedBlocks; } @Override public List getOutputs() { - return List.of(EmiStack.of(definition.getItem())); + return List.of(EmiStack.of(definition.getBlock())); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/jei/MultiblockInfoJeiCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/jei/MultiblockInfoJeiCategory.java index eeb358d82c8..75aa99e349f 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/jei/MultiblockInfoJeiCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/jei/MultiblockInfoJeiCategory.java @@ -43,7 +43,7 @@ public class MultiblockInfoJeiCategory extends private final IDrawable icon; public MultiblockInfoJeiCategory(IJeiHelpers helpers) { - super(v -> new MultiblockPreviewWidget(v.definition, null), v -> v.definition.getId()); + super(v -> new MultiblockPreviewWidget(v.definition, null, 200, 180), v -> v.definition.getId()); IGuiHelper guiHelper = helpers.getGuiHelper(); this.background = guiHelper.createBlankDrawable(160, 160); this.icon = guiHelper.createDrawableItemStack(GTMultiMachines.ELECTRIC_BLAST_FURNACE.asStack()); diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/rei/MultiblockInfoReiCategory.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/rei/MultiblockInfoReiCategory.java index 8fe0ba24ec8..42c96d49e5a 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/rei/MultiblockInfoReiCategory.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/rei/MultiblockInfoReiCategory.java @@ -2,19 +2,41 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; +import com.gregtechceu.gtceu.api.multiblock.pattern.BlockPattern; +import com.gregtechceu.gtceu.api.multiblock.pattern.ExpandablePattern; +import com.gregtechceu.gtceu.api.multiblock.pattern.IBlockPattern; +import com.gregtechceu.gtceu.api.multiblock.util.AbstractStructureHelper; +import com.gregtechceu.gtceu.api.multiblock.util.BlockInfo; import com.gregtechceu.gtceu.api.registry.GTRegistries; import com.gregtechceu.gtceu.common.data.machines.GTMultiMachines; import com.gregtechceu.gtceu.integration.recipeviewer.widgets.MultiblockPreviewWidget; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Block; import brachy.modularui.integration.rei.recipe.ModularUIREIDisplay; import brachy.modularui.integration.rei.recipe.ModularUIREIDisplayCategory; +import it.unimi.dsi.fastutil.Pair; +import it.unimi.dsi.fastutil.ints.Int2IntArrayMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import me.shedaniel.rei.api.client.gui.Renderer; import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; import me.shedaniel.rei.api.common.category.CategoryIdentifier; +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import me.shedaniel.rei.api.common.util.EntryIngredients; import me.shedaniel.rei.api.common.util.EntryStacks; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.gregtechceu.gtceu.api.machine.multiblock.MultiblockControllerMachine.DEFAULT_STRUCTURE; + public class MultiblockInfoReiCategory extends ModularUIREIDisplayCategory { @@ -62,8 +84,55 @@ public Renderer getIcon() { public static class MultiblockInfoDisplay extends ModularUIREIDisplay { + private final MultiblockMachineDefinition definition; + private final List containedBlocks = new ArrayList<>(); + public MultiblockInfoDisplay(MultiblockMachineDefinition definition) { - super(definition.getId(), () -> new MultiblockPreviewWidget(definition, null), CATEGORY); + super(definition.getId(), () -> new MultiblockPreviewWidget(definition, null, 200, 180), CATEGORY); + this.definition = definition; + initializeContainedBlocks(); + } + + private void initializeContainedBlocks() { + Map resultStructure = new HashMap<>(); + IBlockPattern pattern = definition.getStructurePatterns().get(DEFAULT_STRUCTURE).get(); + AbstractStructureHelper structureHelper = null; + if (pattern instanceof BlockPattern blockPattern) { + var sliceRepeats = new Int2IntArrayMap(); + for (int i = 0; i < blockPattern.getSlices().length; i++) { + sliceRepeats.put(i, blockPattern.getSlices()[i].getMinRepeats()); + } + structureHelper = AbstractStructureHelper.blockPattern(sliceRepeats); + } else if (pattern instanceof ExpandablePattern expandablePattern) { + var userDimensions = new IntArrayList(); + expandablePattern.getBoundsConstraints().apply().stream() + .mapToInt(Pair::left) + .forEach(userDimensions::add); + structureHelper = AbstractStructureHelper.expandable(userDimensions); + } + if (structureHelper != null) { + structureHelper.populate(resultStructure, pattern, null, + definition.getRotationState().defaultDirection, switch (definition.getRotationState()) { + case Y_AXIS -> Direction.NORTH; + case ALL, NON_Y_AXIS, NONE -> Direction.UP; + }, false); + + Object2IntMap blockCount = new Object2IntOpenHashMap<>(); + resultStructure.forEach( + (pos, state) -> blockCount.mergeInt(state.getBlockState().getBlock(), 1, Integer::sum)); + + blockCount.forEach((block, count) -> containedBlocks.add(EntryIngredients.of(block.asItem(), count))); + } + } + + @Override + public List getInputEntries() { + return containedBlocks; + } + + @Override + public List getOutputEntries() { + return List.of(EntryIngredients.of(definition.getBlock())); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java index 81cef0ad8f1..780bbf6f179 100644 --- a/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/integration/recipeviewer/widgets/MultiblockPreviewWidget.java @@ -1,5 +1,6 @@ package com.gregtechceu.gtceu.integration.recipeviewer.widgets; +import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.machine.MultiblockMachineDefinition; import com.gregtechceu.gtceu.api.mui.MultiblockSchemaInfo; import com.gregtechceu.gtceu.api.multiblock.PatternPredicate; @@ -29,6 +30,8 @@ import brachy.modularui.drawable.ItemDrawable; import brachy.modularui.drawable.SchemaRenderer; import brachy.modularui.drawable.schema.BlockHighlight; +import brachy.modularui.integration.recipeviewer.RecipeSlotRole; +import brachy.modularui.integration.recipeviewer.RecipeViewerSlotWidget; import brachy.modularui.utils.Alignment; import brachy.modularui.utils.Color; import brachy.modularui.value.BoolValue; @@ -85,8 +88,10 @@ public class MultiblockPreviewWidget extends ParentWidget Direction.NORTH; @@ -116,11 +121,15 @@ public MultiblockPreviewWidget(MultiblockMachineDefinition definition, Multibloc // NOTE wrapped flows require a fixed size in their axis, relative/coverChildren does not work .wrap() .coverChildrenWidth(20) - .height(200) + .height(height) .children(this.multiblockSchemaInfo.getBlockCounts().reference2IntEntrySet(), e -> { ItemStack stack = new ItemStack(e.getKey(), e.getIntValue()); - return new ItemDrawable(stack) - .asWidget().size(18).margin(1) + return RecipeViewerSlotWidget.create() + .recipeSlotRole(RecipeSlotRole.OUTPUT) + .value(stack) + .background(IDrawable.EMPTY) + .size(16) + .margin(1) .tooltip(r -> r.addFromItem(stack)); })); @@ -148,7 +157,9 @@ public MultiblockPreviewWidget(MultiblockMachineDefinition definition, Multibloc List> patterns = multiblockDefinition.getStructurePatterns() .entrySet().stream().map(e -> Map.entry(e.getKey(), e.getValue().get())).toList(); - this.multiblockSchemaInfo.setMultiSchema(this.multiblockSchemaInfo.getRenderer().asWidget() + this.multiblockSchemaInfo.getRenderer().camera().setPosAndLookAt(0, 0, -10, + this.multiblockSchemaInfo.getMapSchema().getCenter()); + SchemaWidget schema = this.multiblockSchemaInfo.getRenderer().asWidget() .listenGuiAction(setBlockOnClick) .tooltipDynamic(text -> { BlockHitResult hit = this.multiblockSchemaInfo.getRenderer().lastRayTrace(); @@ -161,7 +172,9 @@ public MultiblockPreviewWidget(MultiblockMachineDefinition definition, Multibloc text.addFromItem(pickedItem); } }).tooltipAutoUpdate(true) - .size(200)); + .size(width, height); + + this.multiblockSchemaInfo.setMultiSchema(schema); this.multiblockSchemaInfo.getMultiSchema().getSchemaRenderer().updateRenderFilter((pos, state) -> { if (yLevel == -1) { return true;