• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

CyclopsMC / IntegratedDynamics / 24034486947

06 Apr 2026 01:51PM UTC coverage: 53.645% (-0.08%) from 53.721%
24034486947

push

github

rubensworks
Update to MC 26.1.1

3052 of 8931 branches covered (34.17%)

Branch coverage included in aggregate %.

18680 of 31580 relevant lines covered (59.15%)

3.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.26
/src/main/java/org/cyclops/integrateddynamics/blockentity/BlockEntityMechanicalDryingBasin.java
1
package org.cyclops.integrateddynamics.blockentity;
2

3
import net.minecraft.core.BlockPos;
4
import net.minecraft.core.Direction;
5
import net.minecraft.core.NonNullList;
6
import net.minecraft.network.chat.Component;
7
import net.minecraft.world.MenuProvider;
8
import net.minecraft.world.entity.player.Inventory;
9
import net.minecraft.world.entity.player.Player;
10
import net.minecraft.world.inventory.AbstractContainerMenu;
11
import net.minecraft.world.item.ItemStack;
12
import net.minecraft.world.item.crafting.RecipeHolder;
13
import net.minecraft.world.item.crafting.RecipeType;
14
import net.minecraft.world.level.block.entity.BlockEntityType;
15
import net.minecraft.world.level.block.state.BlockState;
16
import net.minecraft.world.level.storage.ValueInput;
17
import net.minecraft.world.level.storage.ValueOutput;
18
import net.neoforged.neoforge.fluids.FluidStack;
19
import net.neoforged.neoforge.transfer.fluid.FluidResource;
20
import net.neoforged.neoforge.transfer.transaction.Transaction;
21
import org.apache.commons.lang3.tuple.Pair;
22
import org.cyclops.cyclopscore.datastructure.SingleCache;
23
import org.cyclops.cyclopscore.fluid.SingleUseTank;
24
import org.cyclops.cyclopscore.helper.IModHelpers;
25
import org.cyclops.cyclopscore.helper.IModHelpersNeoForge;
26
import org.cyclops.cyclopscore.recipe.type.IInventoryFluid;
27
import org.cyclops.cyclopscore.recipe.type.InventoryFluid;
28
import org.cyclops.integrateddynamics.RegistryEntries;
29
import org.cyclops.integrateddynamics.block.BlockMechanicalDryingBasin;
30
import org.cyclops.integrateddynamics.block.BlockMechanicalDryingBasinConfig;
31
import org.cyclops.integrateddynamics.core.blockentity.BlockEntityMechanicalMachine;
32
import org.cyclops.integrateddynamics.core.recipe.handler.RecipeHandlerDryingBasin;
33
import org.cyclops.integrateddynamics.core.recipe.type.RecipeMechanicalDryingBasin;
34
import org.cyclops.integrateddynamics.inventory.container.ContainerMechanicalDryingBasin;
35

36
import javax.annotation.Nullable;
37
import java.util.Optional;
38
import java.util.function.Supplier;
39

40
/**
41
 * A part entity for the mechanical drying basin.
42
 * @author rubensworks
43
 */
44
public class BlockEntityMechanicalDryingBasin extends BlockEntityMechanicalMachine<Pair<ItemStack, FluidStack>, RecipeMechanicalDryingBasin>
45
        implements MenuProvider {
46

47
    public static final int INVENTORY_SIZE = 5;
48

49
    private static final int SLOT_INPUT = 0;
50
    private static final int[] SLOTS_OUTPUT = {1, 2, 3, 4};
20✔
51

52
    private final SingleUseTank tankIn = new SingleUseTank(IModHelpersNeoForge.get().getFluidHelpers().getBucketVolume() * 10);
10✔
53
    private final SingleUseTank tankOut = new SingleUseTank(IModHelpersNeoForge.get().getFluidHelpers().getBucketVolume() * 100);
10✔
54

55
    public BlockEntityMechanicalDryingBasin(BlockPos blockPos, BlockState blockState) {
56
        super(RegistryEntries.BLOCK_ENTITY_MECHANICAL_DRYING_BASIN.get(), blockPos, blockState, INVENTORY_SIZE);
8✔
57

58
        // Add tank update listeners
59
        tankIn.addDirtyMarkListener(this::onTankChanged);
5✔
60
        tankOut.addDirtyMarkListener(this::onTankChanged);
5✔
61
    }
1✔
62

63
    public static class CapabilityRegistrar extends BlockEntityMechanicalMachine.CapabilityRegistrar<BlockEntityMechanicalDryingBasin> {
64
        public CapabilityRegistrar(Supplier<BlockEntityType<? extends BlockEntityMechanicalDryingBasin>> blockEntityType) {
65
            super(blockEntityType);
3✔
66
        }
1✔
67

68
        @Override
69
        public void populate() {
70
            super.populate();
2✔
71

72
            add(
4✔
73
                    net.neoforged.neoforge.capabilities.Capabilities.Fluid.BLOCK,
74
                    (blockEntity, direction) -> direction == Direction.DOWN ? blockEntity.getTankOutput() : blockEntity.getTankInput()
×
75
            );
76
            add(
4✔
77
                    org.cyclops.commoncapabilities.api.capability.Capabilities.RecipeHandler.BLOCK,
78
                    (blockEntity, direction) -> new RecipeHandlerDryingBasin<>(blockEntity::getLevel, RegistryEntries.RECIPETYPE_MECHANICAL_DRYING_BASIN.get())
×
79
            );
80
        }
1✔
81
    }
82

83
    @Override
84
    protected SingleCache.ICacheUpdater<Pair<ItemStack, FluidStack>, Optional<RecipeHolder<RecipeMechanicalDryingBasin>>> createCacheUpdater() {
85
        return new SingleCache.ICacheUpdater<Pair<ItemStack, FluidStack>, Optional<RecipeHolder<RecipeMechanicalDryingBasin>>>() {
14✔
86
            @Override
87
            public Optional<RecipeHolder<RecipeMechanicalDryingBasin>> getNewValue(Pair<ItemStack, FluidStack> key) {
88
                IInventoryFluid recipeInput = new InventoryFluid(
8✔
89
                        NonNullList.of(ItemStack.EMPTY, key.getLeft()),
10✔
90
                        NonNullList.of(FluidStack.EMPTY, key.getRight()));
6✔
91
                return IModHelpers.get().getCraftingHelpers().findRecipe(getRecipeRegistry(), recipeInput, getLevel());
11✔
92
            }
93

94
            @Override
95
            public boolean isKeyEqual(Pair<ItemStack, FluidStack> cacheKey, Pair<ItemStack, FluidStack> newKey) {
96
                return cacheKey == null || newKey == null ||
6!
97
                        (ItemStack.matches(cacheKey.getLeft(), newKey.getLeft()) &&
8!
98
                                FluidStack.matches(cacheKey.getRight(), newKey.getRight()));
10✔
99
            }
100
        };
101
    }
102

103
    @Override
104
    public int[] getInputSlots() {
105
        return new int[]{SLOT_INPUT};
×
106
    }
107

108
    @Override
109
    public int[] getOutputSlots() {
110
        return SLOTS_OUTPUT;
×
111
    }
112

113
    @Override
114
    public boolean wasWorking() {
115
        return getLevel().getBlockState(getBlockPos()).getValue(BlockMechanicalDryingBasin.LIT);
10✔
116
    }
117

118
    @Override
119
    public void setWorking(boolean working) {
120
        getLevel().setBlockAndUpdate(getBlockPos(), getLevel().getBlockState(getBlockPos())
13✔
121
                .setValue(BlockMechanicalDryingBasin.LIT, working));
3✔
122
    }
1✔
123

124
    public SingleUseTank getTankInput() {
125
        return tankIn;
3✔
126
    }
127

128
    public SingleUseTank getTankOutput() {
129
        return tankOut;
3✔
130
    }
131

132
    @Override
133
    public void read(ValueInput input) {
134
        super.read(input);
×
135
        getTankInput().deserialize(input, "tankIn");
×
136
        getTankOutput().deserialize(input, "tankOut");
×
137
    }
×
138

139
    @Override
140
    public void saveAdditional(ValueOutput output) {
141
        getTankInput().serialize(output, "tankIn");
5✔
142
        getTankOutput().serialize(output, "tankOut");
5✔
143
        super.saveAdditional(output);
3✔
144
    }
1✔
145

146
    @Override
147
    protected RecipeType<RecipeMechanicalDryingBasin> getRecipeRegistry() {
148
        return RegistryEntries.RECIPETYPE_MECHANICAL_DRYING_BASIN.get();
4✔
149
    }
150

151
    @Override
152
    protected Pair<ItemStack, FluidStack> getCurrentRecipeCacheKey() {
153
        return Pair.of(getInventory().getItem(SLOT_INPUT).copy(), IModHelpersNeoForge.get().getFluidHelpers().copy(getTankInput().getFluid()));
13✔
154
    }
155

156
    @Override
157
    public int getRecipeDuration(RecipeHolder<RecipeMechanicalDryingBasin> recipe) {
158
        return recipe.value().getDuration();
5✔
159
    }
160

161
    @Override
162
    protected boolean finalizeRecipe(RecipeMechanicalDryingBasin recipe, boolean simulate) {
163
        // Output items
164
        ItemStack outputStack = recipe.getOutputItemFirst().orElse(ItemStack.EMPTY).copy();
7✔
165
        if (!outputStack.isEmpty()) {
3!
166
            if (!IModHelpers.get().getInventoryHelpers().addToInventory(getInventory(), SLOTS_OUTPUT, NonNullList.withSize(1, outputStack), simulate).isEmpty()) {
12!
167
                return false;
×
168
            }
169
        }
170

171
        // Output fluid
172
        Optional<FluidStack> outputFluid = recipe.getOutputFluid();
3✔
173
        if (outputFluid.isPresent()) {
3!
174
            try (var tx = Transaction.openRoot()) {
×
175
                int inserted = getTankOutput().insert(FluidResource.of(outputFluid.get()), outputFluid.get().getAmount(), tx);
×
176
                if (!simulate) {
×
177
                    tx.commit();
×
178
                }
179
                if (inserted != outputFluid.get().getAmount()) {
×
180
                    return false;
×
181
                }
182
            }
×
183
        }
184

185
        // Only consume items if we are not simulating
186
        if (!simulate) {
2✔
187
            if (!recipe.getInputIngredient().isEmpty()) {
4!
188
                getInventory().removeItem(SLOT_INPUT, 1);
×
189
            }
190
        }
191

192
        // Consume fluid
193
        Optional<FluidStack> inputFluid = recipe.getInputFluid();
3✔
194
        if (inputFluid.isPresent()) {
3!
195
            try (var tx = Transaction.openRoot()) {
2✔
196
                int extracted = getTankInput().extract(FluidResource.of(inputFluid.get()), inputFluid.get().getAmount(), tx);
13✔
197
                if (!simulate) {
2✔
198
                    tx.commit();
2✔
199
                }
200
                if (extracted != inputFluid.get().getAmount()) {
6!
201
                    return false;
×
202
                }
203
            }
×
204
        }
205

206
        return true;
2✔
207
    }
208

209
    @Override
210
    public int getEnergyConsumptionRate() {
211
        return BlockMechanicalDryingBasinConfig.consumptionRate;
2✔
212
    }
213

214
    @Override
215
    public int getMaxEnergyStored() {
216
        return BlockMechanicalDryingBasinConfig.capacity;
2✔
217
    }
218

219
    @Nullable
220
    @Override
221
    public AbstractContainerMenu createMenu(int id, Inventory playerInventory, Player playerEntity) {
222
        return new ContainerMechanicalDryingBasin(id, playerInventory, this.getInventory(), Optional.of(this));
×
223
    }
224

225
    @Override
226
    public Component getDisplayName() {
227
        return Component.translatable("block.integrateddynamics.mechanical_drying_basin");
×
228
    }
229
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc