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

CyclopsMC / IntegratedCrafting / #479011716

10 Oct 2023 02:56PM UTC coverage: 25.089% (-0.009%) from 25.098%
#479011716

push

github-actions

rubensworks
Bump mod version

706 of 2814 relevant lines covered (25.09%)

0.25 hits per line

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

0.0
/src/main/java/org/cyclops/integratedcrafting/core/PendingCraftingJobResultIndexObserver.java
1
package org.cyclops.integratedcrafting.core;
2

3
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
4
import it.unimi.dsi.fastutil.objects.ObjectIterator;
5
import org.cyclops.commoncapabilities.api.ingredient.IIngredientMatcher;
6
import org.cyclops.commoncapabilities.api.ingredient.IPrototypedIngredient;
7
import org.cyclops.commoncapabilities.api.ingredient.IngredientComponent;
8
import org.cyclops.commoncapabilities.api.ingredient.PrototypedIngredient;
9
import org.cyclops.commoncapabilities.api.ingredient.storage.IIngredientComponentStorage;
10
import org.cyclops.cyclopscore.ingredient.collection.IIngredientCollection;
11
import org.cyclops.cyclopscore.ingredient.collection.IngredientCollectionPrototypeMap;
12
import org.cyclops.cyclopscore.ingredient.storage.IngredientComponentStorageCollectionWrapper;
13
import org.cyclops.integratedcrafting.api.crafting.CraftingJob;
14
import org.cyclops.integratedcrafting.api.network.ICraftingNetwork;
15
import org.cyclops.integrateddynamics.api.ingredient.IIngredientComponentStorageObservable;
16
import org.cyclops.integrateddynamics.api.network.IPositionedAddonsNetwork;
17

18
import java.util.Iterator;
19
import java.util.List;
20
import java.util.ListIterator;
21
import java.util.Map;
22

23
/**
24
 * An ingredient index observer that tracks crafting job outputs for a certain ingredient component type.
25
 *
26
 * It will observe changes and (partially) resolve awaiting crafting job outputs when applicable.
27
 *
28
 * @author rubensworks
29
 */
30
public class PendingCraftingJobResultIndexObserver<T, M>
31
        implements IIngredientComponentStorageObservable.IIndexChangeObserver<T, M> {
32

33
    private final IngredientComponent<T, M> ingredientComponent;
34
    private final CraftingJobHandler handler;
35
    private final ICraftingNetwork craftingNetwork;
36

37
    public PendingCraftingJobResultIndexObserver(IngredientComponent<T, M> ingredientComponent, CraftingJobHandler handler, ICraftingNetwork craftingNetwork) {
×
38
        this.ingredientComponent = ingredientComponent;
×
39
        this.handler = handler;
×
40
        this.craftingNetwork = craftingNetwork;
×
41
    }
×
42

43
    @Override
44
    public void onChange(IIngredientComponentStorageObservable.StorageChangeEvent<T, M> event) {
45
        if (event.getChangeType() == IIngredientComponentStorageObservable.Change.ADDITION
×
46
                // If we're still initializing the network, skip addition events.
47
                // Otherwise, we could incorrectly mark running crafting jobs as finished.
48
                && !event.isInitialChange()) {
×
49
            IIngredientCollection<T, M> addedIngredients = event.getInstances();
×
50
            IIngredientComponentStorage<T, M> ingredientsHayStack = null; // A mutable copy of addedIngredients (lazily created)
×
51
            IIngredientMatcher<T, M> matcher = ingredientComponent.getMatcher();
×
52

53
            Int2ObjectMap<List<Map<IngredientComponent<?, ?>, List<IPrototypedIngredient<?, ?>>>>> processingJobs = handler.getProcessingCraftingJobsPendingIngredients();
×
54
            ObjectIterator<Int2ObjectMap.Entry<List<Map<IngredientComponent<?, ?>, List<IPrototypedIngredient<?, ?>>>>>> jobsEntryIt = processingJobs.int2ObjectEntrySet().iterator();
×
55
            while (jobsEntryIt.hasNext()) {
×
56
                Int2ObjectMap.Entry<List<Map<IngredientComponent<?, ?>, List<IPrototypedIngredient<?, ?>>>>> jobsEntry = jobsEntryIt.next();
×
57
                int craftingJobId = jobsEntry.getIntKey();
×
58
                // Only check jobs that have a matching channel with the event
59
                CraftingJob craftingJob = handler.getAllCraftingJobs().get(jobsEntry.getIntKey());
×
60
                if (craftingJob != null
×
61
                        && (craftingJob.getChannel() == IPositionedAddonsNetwork.WILDCARD_CHANNEL || craftingJob.getChannel() == event.getChannel())) {
×
62
                    Iterator<Map<IngredientComponent<?, ?>, List<IPrototypedIngredient<?, ?>>>> jobEntryIt = jobsEntry.getValue().iterator();
×
63
                    while (jobEntryIt.hasNext()) {
×
64
                        Map<IngredientComponent<?, ?>, List<IPrototypedIngredient<?, ?>>> jobEntry = jobEntryIt.next();
×
65
                        List<IPrototypedIngredient<?, ?>> pendingIngredientsUnsafe = jobEntry.get(ingredientComponent);
×
66
                        if (pendingIngredientsUnsafe != null) {
×
67
                            // Remove pending ingredients that were added in the event
68
                            List<IPrototypedIngredient<T, M>> pendingIngredients = (List<IPrototypedIngredient<T, M>>) (Object) pendingIngredientsUnsafe;
×
69

70
                            // Iterate over all pending ingredients for this ingredient component
71
                            ListIterator<IPrototypedIngredient<T, M>> it = pendingIngredients.listIterator();
×
72
                            while (it.hasNext()) {
×
73
                                IPrototypedIngredient<T, M> prototypedIngredient = it.next();
×
74
                                final long initialQuantity = matcher.getQuantity(prototypedIngredient.getPrototype());
×
75
                                long remainingQuantity = initialQuantity;
×
76

77
                                // Lazily create ingredientsHayStack only when needed,
78
                                // because we need to copy all ingredients from addedIngredients,
79
                                // which can get expensive
80
                                // We need to make a copy because multiple crafting jobs can have the same pending instances,
81
                                // so each instance may only be consumed by a single crafting job.
82
                                if (ingredientsHayStack == null) {
×
83
                                    if (addedIngredients.contains(prototypedIngredient.getPrototype(),
×
84
                                            prototypedIngredient.getCondition())) {
×
85
                                        IngredientCollectionPrototypeMap<T, M> prototypeMap = new IngredientCollectionPrototypeMap<>(ingredientComponent);
×
86
                                        ingredientsHayStack = new IngredientComponentStorageCollectionWrapper<>(prototypeMap);
×
87
                                        prototypeMap.addAll(addedIngredients);
×
88
                                    } else {
89
                                        continue;
90
                                    }
91
                                }
92

93
                                // Iteratively extract the pending ingredient from the hay stack.
94
                                T extracted;
95
                                do {
96
                                    extracted = ingredientsHayStack.extract(prototypedIngredient.getPrototype(),
×
97
                                            prototypedIngredient.getCondition(), false);
×
98

99
                                    if (matcher.isEmpty(extracted)) {
×
100
                                        // Quickly break when no matches are available anymore
101
                                        break;
×
102
                                    }
103

104
                                    remainingQuantity -= matcher.getQuantity(extracted);
×
105
                                } while (!matcher.isEmpty(extracted) && remainingQuantity > 0);
×
106

107
                                // Update the list if the prototype has changed.
108
                                if (remainingQuantity <= 0) {
×
109
                                    it.remove();
×
110
                                } else if (initialQuantity != remainingQuantity) {
×
111
                                    it.set(new PrototypedIngredient<>(ingredientComponent,
×
112
                                            matcher.withQuantity(prototypedIngredient.getPrototype(), remainingQuantity),
×
113
                                            prototypedIngredient.getCondition()));
×
114
                                }
115
                            }
×
116

117
                            // If no prototypes for this component type for this crafting job for this job entry are pending.
118
                            if (pendingIngredients.isEmpty()) {
×
119
                                // Remove observer (in next tick) when all pending ingredients are resolved
120
                                handler.getObserversPendingDeletion().add(ingredientComponent);
×
121

122
                                // Remove crafting job if needed.
123
                                // No ingredients of this ingredient component type are pending
124
                                jobEntry.remove(ingredientComponent);
×
125
                                if (jobEntry.isEmpty()) {
×
126
                                    // No ingredients are pending for this non-blocking-mode-entry are pending
127
                                    handler.onCraftingJobEntryFinished(this.craftingNetwork, craftingJobId);
×
128
                                    jobEntryIt.remove();
×
129
                                }
130
                                if (jobsEntry.getValue().isEmpty()) {
×
131
                                    // No more entries for this crafting job are pending
132
                                    handler.onCraftingJobFinished(handler.getAllCraftingJobs().get(craftingJobId));
×
133
                                    handler.getProcessingCraftingJobsRaw().remove(craftingJobId);
×
134
                                    jobsEntryIt.remove();
×
135
                                }
136
                            }
137
                        }
138
                    }
×
139
                }
140
            }
×
141
        }
142
    }
×
143

144

145
}
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