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

CyclopsMC / IntegratedCrafting / #479011828

30 Dec 2025 09:05AM UTC coverage: 24.324% (-0.06%) from 24.387%
#479011828

push

github

rubensworks
Fix reusable ingredients not being extracted from storage if consumed once

0 of 31 new or added lines in 4 files covered. (0.0%)

1 existing line in 1 file now uncovered.

756 of 3108 relevant lines covered (24.32%)

0.24 hits per line

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

32.41
/src/main/java/org/cyclops/integratedcrafting/api/crafting/CraftingJob.java
1
package org.cyclops.integratedcrafting.api.crafting;
2

3
import com.google.common.collect.Maps;
4
import it.unimi.dsi.fastutil.ints.IntArrayList;
5
import it.unimi.dsi.fastutil.ints.IntList;
6
import net.minecraft.nbt.CompoundTag;
7
import net.minecraft.nbt.IntArrayTag;
8
import net.minecraft.nbt.Tag;
9
import org.apache.commons.compress.utils.Lists;
10
import org.cyclops.commoncapabilities.api.capability.recipehandler.IRecipeDefinition;
11
import org.cyclops.commoncapabilities.api.ingredient.IIngredientMatcher;
12
import org.cyclops.commoncapabilities.api.ingredient.IMixedIngredients;
13
import org.cyclops.commoncapabilities.api.ingredient.IngredientComponent;
14
import org.cyclops.commoncapabilities.api.ingredient.MixedIngredients;
15
import org.cyclops.cyclopscore.ingredient.collection.IngredientList;
16
import org.cyclops.cyclopscore.ingredient.storage.IngredientComponentStorageSlottedCollectionWrapper;
17
import org.cyclops.integratedcrafting.core.CraftingHelpers;
18
import org.cyclops.integratedcrafting.core.MissingIngredients;
19

20
import javax.annotation.Nullable;
21
import java.util.List;
22
import java.util.Map;
23
import java.util.Objects;
24

25
/**
26
 * @author rubensworks
27
 */
28
public class CraftingJob {
29

30
    private final int id;
31
    private final int channel;
32
    private final IRecipeDefinition recipe;
33
    private final IntList dependencyCraftingJobs;
34
    private final IntList dependentCraftingJobs;
35
    private int amount;
36
    private IMixedIngredients ingredientsStorage; // Total to extract from storage (simulated and immutable)
37
    private IMixedIngredients ingredientsStorageBuffer; // The actual ingredients from storage, which are consumed over time.
38
    private Map<IngredientComponent<?, ?>, MissingIngredients<?, ?>> lastMissingIngredients;
39
    private long startTick;
40
    private boolean invalidInputs;
41
    @Nullable
42
    private String initiatorUuid;
43
    private boolean ignoreDependencyCheck;
44

45
    public CraftingJob(int id, int channel, IRecipeDefinition recipe, int amount, IMixedIngredients ingredientsStorage) {
1✔
46
        this.id = id;
1✔
47
        this.channel = channel;
1✔
48
        this.recipe = recipe;
1✔
49
        this.amount = amount;
1✔
50
        this.ingredientsStorage = ingredientsStorage;
1✔
51
        this.ingredientsStorageBuffer = new MixedIngredients(Maps.newIdentityHashMap());
1✔
52
        this.lastMissingIngredients = Maps.newIdentityHashMap();
1✔
53
        this.dependencyCraftingJobs = new IntArrayList();
1✔
54
        this.dependentCraftingJobs = new IntArrayList();
1✔
55
        this.invalidInputs = false;
1✔
56
        this.ignoreDependencyCheck = false;
1✔
57
    }
1✔
58

59
    public int getId() {
60
        return id;
1✔
61
    }
62

63
    public int getChannel() {
64
        return this.channel;
1✔
65
    }
66

67
    public IRecipeDefinition getRecipe() {
68
        return this.recipe;
1✔
69
    }
70

71
    public IntList getDependencyCraftingJobs() {
72
        return dependencyCraftingJobs;
1✔
73
    }
74

75
    public IntList getDependentCraftingJobs() {
76
        return dependentCraftingJobs;
1✔
77
    }
78

79
    public int getAmount() {
80
        return amount;
1✔
81
    }
82

83
    public void setAmount(int amount) {
84
        this.amount = amount;
1✔
85
    }
1✔
86

87
    public void addDependency(CraftingJob dependency) {
88
        dependencyCraftingJobs.add(dependency.getId());
1✔
89
        dependency.dependentCraftingJobs.add(this.getId());
1✔
90
    }
1✔
91

92
    public void removeDependency(CraftingJob dependency) {
93
        dependencyCraftingJobs.rem(dependency.getId());
1✔
94
        dependency.dependentCraftingJobs.rem(this.getId());
1✔
95
    }
1✔
96

97
    /**
98
     * @return The ingredients that will be taken from storage
99
     *         The amount of this job is already taken into account.
100
     */
101
    public IMixedIngredients getIngredientsStorage() {
102
        return ingredientsStorage;
1✔
103
    }
104

105
    public void setIngredientsStorage(IMixedIngredients ingredientsStorage) {
106
        this.ingredientsStorage = ingredientsStorage;
1✔
107
    }
1✔
108

109
    public IMixedIngredients getIngredientsStorageBuffer() {
110
        return ingredientsStorageBuffer;
1✔
111
    }
112

113
    public void setIngredientsStorageBuffer(IMixedIngredients ingredientsStorageBuffer) {
114
        this.ingredientsStorageBuffer = ingredientsStorageBuffer;
×
115
    }
×
116

117
    public <T, M> void addToIngredientsStorageBuffer(IngredientComponent<T, M> ingredientComponent, T instance) {
NEW
118
        IIngredientMatcher<T, M> matcher = ingredientComponent.getMatcher();
×
NEW
119
        IMixedIngredients buffer = this.getIngredientsStorageBuffer();
×
NEW
120
        if (!buffer.getComponents().contains(ingredientComponent)) {
×
NEW
121
            Map<IngredientComponent<?, ?>, List<?>> mixedIngredientsRaw = Maps.newIdentityHashMap();
×
NEW
122
            for (IngredientComponent<?, ?> component : buffer.getComponents()) {
×
NEW
123
                mixedIngredientsRaw.put(component, buffer.getInstances(component));
×
NEW
124
            }
×
NEW
125
            List<T> list = Lists.newArrayList();
×
NEW
126
            mixedIngredientsRaw.put(ingredientComponent, list);
×
NEW
127
            list.add(instance);
×
NEW
128
            buffer = new MixedIngredients(mixedIngredientsRaw);
×
NEW
129
            this.setIngredientsStorageBuffer(buffer);
×
NEW
130
        } else {
×
NEW
131
            List<T> instances = buffer.getInstances(ingredientComponent);
×
NEW
132
            if (!instances.stream().anyMatch(matcher::isEmpty)) {
×
133
                // Make sure we have at least one empty slot available, to guarantee insertion can succeed.
NEW
134
                instances.add(matcher.getEmptyInstance());
×
135
            }
NEW
136
            T remaining = new IngredientComponentStorageSlottedCollectionWrapper<>(new IngredientList<>(ingredientComponent, instances), Integer.MAX_VALUE, Integer.MAX_VALUE).insert(instance, false);
×
NEW
137
            if (!matcher.isEmpty(remaining)) {
×
NEW
138
                throw new IllegalStateException(String.format("Unable to insert %s into the crafting job buffer, remaining: ", instances, remaining));
×
139
            }
140
        }
NEW
141
    }
×
142

143
    /**
144
     * @return The ingredients that were missing for 1 job amount. This will mostly be an empty map.
145
     */
146
    public Map<IngredientComponent<?, ?>, MissingIngredients<?, ?>> getLastMissingIngredients() {
147
        return lastMissingIngredients;
×
148
    }
149

150
    public void setLastMissingIngredients(Map<IngredientComponent<?, ?>, MissingIngredients<?, ?>> lastMissingIngredients) {
151
        this.lastMissingIngredients = lastMissingIngredients;
×
152
    }
×
153

154
    public long getStartTick() {
155
        return startTick;
×
156
    }
157

158
    public void setStartTick(long startTick) {
159
        this.startTick = startTick;
×
160
    }
×
161

162
    public boolean isInvalidInputs() {
163
        return invalidInputs;
×
164
    }
165

166
    public void setInvalidInputs(boolean invalidInputs) {
167
        this.invalidInputs = invalidInputs;
×
168
    }
×
169

170
    @Nullable
171
    public String getInitiatorUuid() {
172
        return initiatorUuid;
×
173
    }
174

175
    public void setInitiatorUuid(String initiatorUuid) {
176
        this.initiatorUuid = initiatorUuid;
×
177
    }
×
178

179
    public void setIgnoreDependencyCheck(boolean ignoreDependencyCheck) {
180
        this.ignoreDependencyCheck = ignoreDependencyCheck;
×
181
    }
×
182

183
    public boolean isIgnoreDependencyCheck() {
184
        return ignoreDependencyCheck;
×
185
    }
186

187
    public static CompoundTag serialize(CraftingJob craftingJob) {
188
        CompoundTag tag = new CompoundTag();
×
189
        tag.putInt("id", craftingJob.id);
×
190
        tag.putInt("channel", craftingJob.channel);
×
191
        tag.put("recipe", IRecipeDefinition.serialize(craftingJob.recipe));
×
192
        tag.put("dependencies", new IntArrayTag(craftingJob.getDependencyCraftingJobs()));
×
193
        tag.put("dependents", new IntArrayTag(craftingJob.getDependentCraftingJobs()));
×
194
        tag.putInt("amount", craftingJob.amount);
×
195
        tag.put("ingredientsStorage", IMixedIngredients.serialize(craftingJob.ingredientsStorage));
×
196
        tag.put("ingredientsStorageBuffer", IMixedIngredients.serialize(craftingJob.ingredientsStorageBuffer));
×
197
        tag.put("lastMissingIngredients", MissingIngredients.serialize(craftingJob.lastMissingIngredients));
×
198
        tag.putLong("startTick", craftingJob.startTick);
×
199
        tag.putBoolean("invalidInputs", craftingJob.invalidInputs);
×
200
        if (craftingJob.initiatorUuid != null) {
×
201
            tag.putString("initiatorUuid", craftingJob.initiatorUuid);
×
202
        }
203
        tag.putBoolean("ignoreDependencyCheck", craftingJob.ignoreDependencyCheck);
×
204
        return tag;
×
205
    }
206

207
    public static CraftingJob deserialize(CompoundTag tag) {
208
        if (!tag.contains("id", Tag.TAG_INT)) {
×
209
            throw new IllegalArgumentException("Could not find an id entry in the given tag");
×
210
        }
211
        if (!tag.contains("channel", Tag.TAG_INT)) {
×
212
            throw new IllegalArgumentException("Could not find a channel entry in the given tag");
×
213
        }
214
        if (!tag.contains("recipe", Tag.TAG_COMPOUND)) {
×
215
            throw new IllegalArgumentException("Could not find a recipe entry in the given tag");
×
216
        }
217
        if (!tag.contains("dependencies", Tag.TAG_INT_ARRAY)) {
×
218
            throw new IllegalArgumentException("Could not find a dependencies entry in the given tag");
×
219
        }
220
        if (!tag.contains("dependents", Tag.TAG_INT_ARRAY)) {
×
221
            throw new IllegalArgumentException("Could not find a dependents entry in the given tag");
×
222
        }
223
        if (!tag.contains("amount", Tag.TAG_INT)) {
×
224
            throw new IllegalArgumentException("Could not find a amount entry in the given tag");
×
225
        }
226
        if (!tag.contains("ingredientsStorage", Tag.TAG_COMPOUND)) {
×
227
            throw new IllegalArgumentException("Could not find a ingredientsStorage entry in the given tag");
×
228
        }
229
        if (!tag.contains("lastMissingIngredients", Tag.TAG_COMPOUND)) {
×
230
            throw new IllegalArgumentException("Could not find a lastMissingIngredients entry in the given tag");
×
231
        }
232
        if (!tag.contains("startTick", Tag.TAG_LONG)) {
×
233
            throw new IllegalArgumentException("Could not find a startTick entry in the given tag");
×
234
        }
235
        if (!tag.contains("invalidInputs", Tag.TAG_BYTE)) {
×
236
            throw new IllegalArgumentException("Could not find an invalidInputs entry in the given tag");
×
237
        }
238
        int id = tag.getInt("id");
×
239
        int channel = tag.getInt("channel");
×
240
        IRecipeDefinition recipe = IRecipeDefinition.deserialize(tag.getCompound("recipe"));
×
241
        int amount = tag.getInt("amount");
×
242
        IMixedIngredients ingredientsStorage = IMixedIngredients.deserialize(tag.getCompound("ingredientsStorage"));
×
243
        IMixedIngredients ingredientsStorageBuffer = IMixedIngredients.deserialize(tag.contains("ingredientsStorageBuffer") ? tag.getCompound("ingredientsStorageBuffer") : new CompoundTag()); // TODO: rm backwards-compat in nextmajor
×
244
        CraftingJob craftingJob = new CraftingJob(id, channel, recipe, amount, ingredientsStorage);
×
245
        for (int dependency : tag.getIntArray("dependencies")) {
×
246
            craftingJob.dependencyCraftingJobs.add(dependency);
×
247
        }
248
        for (int dependent : tag.getIntArray("dependents")) {
×
249
            craftingJob.dependentCraftingJobs.add(dependent);
×
250
        }
251
        Map<IngredientComponent<?, ?>, MissingIngredients<?, ?>> lastMissingIngredients = MissingIngredients
×
252
                .deserialize(tag.getCompound("lastMissingIngredients"));
×
253
        craftingJob.setLastMissingIngredients(lastMissingIngredients);
×
254
        craftingJob.setStartTick(tag.getLong("startTick"));
×
255
        craftingJob.setInvalidInputs(tag.getBoolean("invalidInputs"));
×
256
        if (tag.contains("initiatorUuid", Tag.TAG_STRING)) {
×
257
            craftingJob.setInitiatorUuid(tag.getString("initiatorUuid"));
×
258
        }
259
        craftingJob.setIgnoreDependencyCheck(tag.getBoolean("ignoreDependencyCheck"));
×
260
        craftingJob.setIngredientsStorageBuffer(ingredientsStorageBuffer);
×
261
        return craftingJob;
×
262
    }
263

264
    @Override
265
    public String toString() {
266
        return String.format("[Crafting Job id: %s, channel: %s, recipe: %s, dependencies: %s, dependents: %s, amount: %s, storage: %s]",
×
267
                getId(), getChannel(), getRecipe(), getDependencyCraftingJobs(), getDependentCraftingJobs(), getAmount(), getIngredientsStorage());
×
268
    }
269

270
    @Override
271
    public boolean equals(Object obj) {
272
        if (!(obj instanceof CraftingJob)) {
1✔
273
            return false;
×
274
        }
275
        CraftingJob that = (CraftingJob) obj;
1✔
276
        return this.getId() == that.getId()
1✔
277
                && this.getChannel() == that.getChannel()
1✔
278
                && Objects.equals(this.getRecipe(), that.getRecipe())
1✔
279
                && this.getDependencyCraftingJobs().equals(that.getDependencyCraftingJobs())
1✔
280
                && this.getDependentCraftingJobs().equals(that.getDependentCraftingJobs())
1✔
281
                && this.getAmount() == that.getAmount()
1✔
282
                && this.getIngredientsStorage().equals(that.getIngredientsStorage());
1✔
283
    }
284

285
    public CraftingJob clone(CraftingHelpers.IIdentifierGenerator identifierGenerator) {
286
        if (!this.getIngredientsStorageBuffer().isEmpty()) {
1✔
287
            throw new IllegalStateException("Cloning a job with an ingredient buffer is illegal");
×
288
        }
289
        return new CraftingJob(
1✔
290
                identifierGenerator.getNext(),
1✔
291
                getChannel(),
1✔
292
                getRecipe(),
1✔
293
                getAmount(),
1✔
294
                getIngredientsStorage()
1✔
295
        );
296
    }
297
}
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

© 2025 Coveralls, Inc