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

CyclopsMC / IntegratedCrafting / #479011822

29 Dec 2025 01:56PM UTC coverage: 24.23% (-0.6%) from 24.876%
#479011822

push

github

rubensworks
Add dedicated storage per crafting job

When a crafting job is started, ingredients are immediately moved from
general storage to the new storage buffers per crafting job. This avoids
issues where ingredients can be consumed elsewhere (e.g. exporters or
other crafting jobs) before it is used by the crafting job.

Closes #112

3 of 104 new or added lines in 7 files covered. (2.88%)

3 existing lines in 3 files now uncovered.

755 of 3116 relevant lines covered (24.23%)

0.24 hits per line

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

37.6
/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.cyclops.commoncapabilities.api.capability.recipehandler.IRecipeDefinition;
10
import org.cyclops.commoncapabilities.api.ingredient.IMixedIngredients;
11
import org.cyclops.commoncapabilities.api.ingredient.IngredientComponent;
12
import org.cyclops.commoncapabilities.api.ingredient.MixedIngredients;
13
import org.cyclops.integratedcrafting.core.CraftingHelpers;
14
import org.cyclops.integratedcrafting.core.MissingIngredients;
15

16
import javax.annotation.Nullable;
17
import java.util.Map;
18
import java.util.Objects;
19

20
/**
21
 * @author rubensworks
22
 */
23
public class CraftingJob {
24

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

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

54
    public int getId() {
55
        return id;
1✔
56
    }
57

58
    public int getChannel() {
59
        return this.channel;
1✔
60
    }
61

62
    public IRecipeDefinition getRecipe() {
63
        return this.recipe;
1✔
64
    }
65

66
    public IntList getDependencyCraftingJobs() {
67
        return dependencyCraftingJobs;
1✔
68
    }
69

70
    public IntList getDependentCraftingJobs() {
71
        return dependentCraftingJobs;
1✔
72
    }
73

74
    public int getAmount() {
75
        return amount;
1✔
76
    }
77

78
    public void setAmount(int amount) {
79
        this.amount = amount;
1✔
80
    }
1✔
81

82
    public void addDependency(CraftingJob dependency) {
83
        dependencyCraftingJobs.add(dependency.getId());
1✔
84
        dependency.dependentCraftingJobs.add(this.getId());
1✔
85
    }
1✔
86

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

92
    /**
93
     * @return The ingredients that will be taken from storage
94
     *         The amount of this job is already taken into account.
95
     */
96
    public IMixedIngredients getIngredientsStorage() {
97
        return ingredientsStorage;
1✔
98
    }
99

100
    public void setIngredientsStorage(IMixedIngredients ingredientsStorage) {
101
        this.ingredientsStorage = ingredientsStorage;
1✔
102
    }
1✔
103

104
    public IMixedIngredients getIngredientsStorageBuffer() {
105
        return ingredientsStorageBuffer;
1✔
106
    }
107

108
    public void setIngredientsStorageBuffer(IMixedIngredients ingredientsStorageBuffer) {
NEW
109
        this.ingredientsStorageBuffer = ingredientsStorageBuffer;
×
NEW
110
    }
×
111

112
    /**
113
     * @return The ingredients that were missing for 1 job amount. This will mostly be an empty map.
114
     */
115
    public Map<IngredientComponent<?, ?>, MissingIngredients<?, ?>> getLastMissingIngredients() {
116
        return lastMissingIngredients;
×
117
    }
118

119
    public void setLastMissingIngredients(Map<IngredientComponent<?, ?>, MissingIngredients<?, ?>> lastMissingIngredients) {
120
        this.lastMissingIngredients = lastMissingIngredients;
×
121
    }
×
122

123
    public long getStartTick() {
124
        return startTick;
×
125
    }
126

127
    public void setStartTick(long startTick) {
128
        this.startTick = startTick;
×
129
    }
×
130

131
    public boolean isInvalidInputs() {
132
        return invalidInputs;
×
133
    }
134

135
    public void setInvalidInputs(boolean invalidInputs) {
136
        this.invalidInputs = invalidInputs;
×
137
    }
×
138

139
    @Nullable
140
    public String getInitiatorUuid() {
141
        return initiatorUuid;
×
142
    }
143

144
    public void setInitiatorUuid(String initiatorUuid) {
145
        this.initiatorUuid = initiatorUuid;
×
146
    }
×
147

148
    public void setIgnoreDependencyCheck(boolean ignoreDependencyCheck) {
149
        this.ignoreDependencyCheck = ignoreDependencyCheck;
×
150
    }
×
151

152
    public boolean isIgnoreDependencyCheck() {
153
        return ignoreDependencyCheck;
×
154
    }
155

156
    public static CompoundTag serialize(CraftingJob craftingJob) {
157
        CompoundTag tag = new CompoundTag();
×
158
        tag.putInt("id", craftingJob.id);
×
159
        tag.putInt("channel", craftingJob.channel);
×
160
        tag.put("recipe", IRecipeDefinition.serialize(craftingJob.recipe));
×
161
        tag.put("dependencies", new IntArrayTag(craftingJob.getDependencyCraftingJobs()));
×
162
        tag.put("dependents", new IntArrayTag(craftingJob.getDependentCraftingJobs()));
×
163
        tag.putInt("amount", craftingJob.amount);
×
164
        tag.put("ingredientsStorage", IMixedIngredients.serialize(craftingJob.ingredientsStorage));
×
NEW
165
        tag.put("ingredientsStorageBuffer", IMixedIngredients.serialize(craftingJob.ingredientsStorageBuffer));
×
166
        tag.put("lastMissingIngredients", MissingIngredients.serialize(craftingJob.lastMissingIngredients));
×
167
        tag.putLong("startTick", craftingJob.startTick);
×
168
        tag.putBoolean("invalidInputs", craftingJob.invalidInputs);
×
169
        if (craftingJob.initiatorUuid != null) {
×
170
            tag.putString("initiatorUuid", craftingJob.initiatorUuid);
×
171
        }
172
        tag.putBoolean("ignoreDependencyCheck", craftingJob.ignoreDependencyCheck);
×
173
        return tag;
×
174
    }
175

176
    public static CraftingJob deserialize(CompoundTag tag) {
177
        if (!tag.contains("id", Tag.TAG_INT)) {
×
178
            throw new IllegalArgumentException("Could not find an id entry in the given tag");
×
179
        }
180
        if (!tag.contains("channel", Tag.TAG_INT)) {
×
181
            throw new IllegalArgumentException("Could not find a channel entry in the given tag");
×
182
        }
183
        if (!tag.contains("recipe", Tag.TAG_COMPOUND)) {
×
184
            throw new IllegalArgumentException("Could not find a recipe entry in the given tag");
×
185
        }
186
        if (!tag.contains("dependencies", Tag.TAG_INT_ARRAY)) {
×
187
            throw new IllegalArgumentException("Could not find a dependencies entry in the given tag");
×
188
        }
189
        if (!tag.contains("dependents", Tag.TAG_INT_ARRAY)) {
×
190
            throw new IllegalArgumentException("Could not find a dependents entry in the given tag");
×
191
        }
192
        if (!tag.contains("amount", Tag.TAG_INT)) {
×
193
            throw new IllegalArgumentException("Could not find a amount entry in the given tag");
×
194
        }
195
        if (!tag.contains("ingredientsStorage", Tag.TAG_COMPOUND)) {
×
196
            throw new IllegalArgumentException("Could not find a ingredientsStorage entry in the given tag");
×
197
        }
198
        if (!tag.contains("lastMissingIngredients", Tag.TAG_COMPOUND)) {
×
199
            throw new IllegalArgumentException("Could not find a lastMissingIngredients entry in the given tag");
×
200
        }
201
        if (!tag.contains("startTick", Tag.TAG_LONG)) {
×
202
            throw new IllegalArgumentException("Could not find a startTick entry in the given tag");
×
203
        }
204
        if (!tag.contains("invalidInputs", Tag.TAG_BYTE)) {
×
205
            throw new IllegalArgumentException("Could not find an invalidInputs entry in the given tag");
×
206
        }
207
        int id = tag.getInt("id");
×
208
        int channel = tag.getInt("channel");
×
209
        IRecipeDefinition recipe = IRecipeDefinition.deserialize(tag.getCompound("recipe"));
×
210
        int amount = tag.getInt("amount");
×
211
        IMixedIngredients ingredientsStorage = IMixedIngredients.deserialize(tag.getCompound("ingredientsStorage"));
×
NEW
212
        IMixedIngredients ingredientsStorageBuffer = IMixedIngredients.deserialize(tag.contains("ingredientsStorageBuffer") ? tag.getCompound("ingredientsStorageBuffer") : new CompoundTag()); // TODO: rm backwards-compat in nextmajor
×
213
        CraftingJob craftingJob = new CraftingJob(id, channel, recipe, amount, ingredientsStorage);
×
214
        for (int dependency : tag.getIntArray("dependencies")) {
×
215
            craftingJob.dependencyCraftingJobs.add(dependency);
×
216
        }
217
        for (int dependent : tag.getIntArray("dependents")) {
×
218
            craftingJob.dependentCraftingJobs.add(dependent);
×
219
        }
220
        Map<IngredientComponent<?, ?>, MissingIngredients<?, ?>> lastMissingIngredients = MissingIngredients
×
221
                .deserialize(tag.getCompound("lastMissingIngredients"));
×
222
        craftingJob.setLastMissingIngredients(lastMissingIngredients);
×
223
        craftingJob.setStartTick(tag.getLong("startTick"));
×
224
        craftingJob.setInvalidInputs(tag.getBoolean("invalidInputs"));
×
225
        if (tag.contains("initiatorUuid", Tag.TAG_STRING)) {
×
226
            craftingJob.setInitiatorUuid(tag.getString("initiatorUuid"));
×
227
        }
228
        craftingJob.setIgnoreDependencyCheck(tag.getBoolean("ignoreDependencyCheck"));
×
NEW
229
        craftingJob.setIngredientsStorageBuffer(ingredientsStorageBuffer);
×
UNCOV
230
        return craftingJob;
×
231
    }
232

233
    @Override
234
    public String toString() {
235
        return String.format("[Crafting Job id: %s, channel: %s, recipe: %s, dependencies: %s, dependents: %s, amount: %s, storage: %s]",
×
236
                getId(), getChannel(), getRecipe(), getDependencyCraftingJobs(), getDependentCraftingJobs(), getAmount(), getIngredientsStorage());
×
237
    }
238

239
    @Override
240
    public boolean equals(Object obj) {
241
        if (!(obj instanceof CraftingJob)) {
1✔
242
            return false;
×
243
        }
244
        CraftingJob that = (CraftingJob) obj;
1✔
245
        return this.getId() == that.getId()
1✔
246
                && this.getChannel() == that.getChannel()
1✔
247
                && Objects.equals(this.getRecipe(), that.getRecipe())
1✔
248
                && this.getDependencyCraftingJobs().equals(that.getDependencyCraftingJobs())
1✔
249
                && this.getDependentCraftingJobs().equals(that.getDependentCraftingJobs())
1✔
250
                && this.getAmount() == that.getAmount()
1✔
251
                && this.getIngredientsStorage().equals(that.getIngredientsStorage());
1✔
252
    }
253

254
    public CraftingJob clone(CraftingHelpers.IIdentifierGenerator identifierGenerator) {
255
        if (!this.getIngredientsStorageBuffer().isEmpty()) {
1✔
NEW
256
            throw new IllegalStateException("Cloning a job with an ingredient buffer is illegal");
×
257
        }
258
        return new CraftingJob(
1✔
259
                identifierGenerator.getNext(),
1✔
260
                getChannel(),
1✔
261
                getRecipe(),
1✔
262
                getAmount(),
1✔
263
                getIngredientsStorage()
1✔
264
        );
265
    }
266
}
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