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

CyclopsMC / IntegratedDynamics / 16574353307

28 Jul 2025 04:15PM UTC coverage: 53.239% (+0.03%) from 53.206%
16574353307

push

github

rubensworks
Bump CommonCaps version

2890 of 8740 branches covered (33.07%)

Branch coverage included in aggregate %.

17352 of 29281 relevant lines covered (59.26%)

3.08 hits per line

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

0.0
/src/main/java/org/cyclops/integrateddynamics/inventory/container/ContainerLogicProgrammerBase.java
1
package org.cyclops.integrateddynamics.inventory.container;
2

3
import com.google.common.collect.Lists;
4
import net.minecraft.core.component.DataComponents;
5
import net.minecraft.network.chat.Component;
6
import net.minecraft.resources.ResourceLocation;
7
import net.minecraft.util.StringUtil;
8
import net.minecraft.world.Container;
9
import net.minecraft.world.SimpleContainer;
10
import net.minecraft.world.entity.player.Inventory;
11
import net.minecraft.world.entity.player.Player;
12
import net.minecraft.world.inventory.ClickType;
13
import net.minecraft.world.inventory.MenuType;
14
import net.minecraft.world.inventory.Slot;
15
import net.minecraft.world.item.ItemStack;
16
import org.apache.commons.lang3.tuple.Pair;
17
import org.cyclops.cyclopscore.helper.IModHelpers;
18
import org.cyclops.cyclopscore.inventory.SimpleInventory;
19
import org.cyclops.cyclopscore.inventory.container.ScrollingInventoryContainer;
20
import org.cyclops.cyclopscore.inventory.slot.SlotSingleItem;
21
import org.cyclops.cyclopscore.persist.IDirtyMarkListener;
22
import org.cyclops.integrateddynamics.IntegratedDynamics;
23
import org.cyclops.integrateddynamics.RegistryEntries;
24
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueType;
25
import org.cyclops.integrateddynamics.api.evaluate.variable.ValueDeseralizationContext;
26
import org.cyclops.integrateddynamics.api.item.IVariableFacade;
27
import org.cyclops.integrateddynamics.api.item.IVariableFacadeHandlerRegistry;
28
import org.cyclops.integrateddynamics.api.logicprogrammer.ILogicProgrammerElement;
29
import org.cyclops.integrateddynamics.api.logicprogrammer.ILogicProgrammerElementType;
30
import org.cyclops.integrateddynamics.client.gui.container.ContainerScreenLogicProgrammerBase;
31
import org.cyclops.integrateddynamics.core.helper.Helpers;
32
import org.cyclops.integrateddynamics.core.inventory.container.slot.SlotVariable;
33
import org.cyclops.integrateddynamics.core.logicprogrammer.LogicProgrammerElementTypes;
34
import org.cyclops.integrateddynamics.core.logicprogrammer.client.RenderPattern;
35
import org.cyclops.integrateddynamics.core.persist.world.LabelsWorldStorage;
36

37
import javax.annotation.Nullable;
38
import java.util.List;
39

40
/**
41
 * Base container for the logic programmer.
42
 * @author rubensworks
43
 */
44
public abstract class ContainerLogicProgrammerBase extends ScrollingInventoryContainer<ILogicProgrammerElement<RenderPattern, ContainerScreenLogicProgrammerBase<?>, ContainerLogicProgrammerBase, ?>> implements IDirtyMarkListener {
45

46
    public static final int OUTPUT_X = 232;
47
    public static final int OUTPUT_Y = 110;
48

49
    public static final int BASE_X = 88;
50
    public static final int BASE_Y = 18;
51
    public static final int MAX_WIDTH = 160;
52
    public static final int MAX_HEIGHT = 87;
53

54
    protected static final IItemPredicate<ILogicProgrammerElement<RenderPattern, ContainerScreenLogicProgrammerBase<?>, ContainerLogicProgrammerBase, ?>> FILTERER =
×
55
            (item, pattern) -> pattern.matcher(item.getMatchString()).matches()
×
56
                    || pattern.matcher(item.getSymbol()).matches();
×
57

58
    private final SimpleInventory writeSlot;
59
    private final SimpleInventory filterSlots;
60
    private ILogicProgrammerElement activeElement = null;
×
61
    private ILogicProgrammerElement temporarySlotsElement = null;
×
62
    private SimpleInventory temporaryInputSlots = null;
×
63
    private Component lastError;
64
    private LoadConfigListener loadConfigListener;
65

66
    private IValueType filterIn1 = null;
×
67
    private IValueType filterIn2 = null;
×
68
    private IValueType filterOut = null;
×
69

70
    private ScreenCallbackHandler screenCallbackHandler;
71

72
    private String lastLabel = "";
×
73

74
    public ContainerLogicProgrammerBase(@Nullable MenuType<?> type, int id, Inventory playerInventory) {
75
        super(type, id, playerInventory, new SimpleContainer(0), getElements(), FILTERER);
×
76
        this.writeSlot = new SimpleInventory(1, 1);
×
77
        this.filterSlots = new SimpleInventory(3, 1);
×
78
        this.filterSlots.addDirtyMarkListener(new FilterSlotListener(ValueDeseralizationContext.of(playerInventory.player.level())));
×
79
        this.writeSlot.addDirtyMarkListener(this);
×
80
        this.writeSlot.addDirtyMarkListener(loadConfigListener = new LoadConfigListener());
×
81
        this.temporaryInputSlots = new SimpleInventory(0, 1);
×
82
        initializeSlotsPre();
×
83
        initializeSlotsPost();
×
84
    }
×
85

86
    protected static List<ILogicProgrammerElement<RenderPattern, ContainerScreenLogicProgrammerBase<?>, ContainerLogicProgrammerBase, ?>> getElements() {
87
        List<ILogicProgrammerElement<RenderPattern, ContainerScreenLogicProgrammerBase<?>, ContainerLogicProgrammerBase, ?>> elements = Lists.newLinkedList();
×
88
        for(ILogicProgrammerElementType type: LogicProgrammerElementTypes.REGISTRY.getTypes()) {
×
89
            elements.addAll(type.createElements());
×
90
        }
×
91
        return elements;
×
92
    }
93

94
    public void setScreenCallbackHandler(ScreenCallbackHandler screenCallbackHandler) {
95
        this.screenCallbackHandler = screenCallbackHandler;
×
96
    }
×
97

98
    public ScreenCallbackHandler getGui() {
99
        return this.screenCallbackHandler;
×
100
    }
101

102
    protected void initializeSlotsPre() {
103
        addSlot(new SlotVariable(writeSlot, 0, OUTPUT_X, OUTPUT_Y));
×
104
        SlotSingleItem filterSlotIn1 = new SlotVariable(filterSlots, 0, 6, 218);
×
105
        SlotSingleItem filterSlotIn2 = new SlotVariable(filterSlots, 1, 24, 218);
×
106
        SlotSingleItem filterSlotOut = new SlotVariable(filterSlots, 2, 58, 218);
×
107
        filterSlotIn1.setPhantom(true);
×
108
        filterSlotIn2.setPhantom(true);
×
109
        filterSlotOut.setPhantom(true);
×
110
        addSlot(filterSlotIn1);
×
111
        addSlot(filterSlotIn2);
×
112
        addSlot(filterSlotOut);
×
113
    }
×
114

115
    protected void initializeSlotsPost() {
116
        addPlayerInventory((Inventory) getPlayerIInventory(), 88, 131);
×
117
    }
×
118

119
    @Override
120
    public int getPageSize() {
121
        return 10;
×
122
    }
123

124
    @Override
125
    protected boolean isAssertInventorySize() {
126
        return false;
×
127
    }
128

129
    @Override
130
    protected int getSizeInventory() {
131
        return 1;
×
132
    }
133

134
    public void setActiveElementById(ResourceLocation typeId, ResourceLocation elementId) {
135
        ILogicProgrammerElementType type = LogicProgrammerElementTypes.REGISTRY.getType(typeId);
×
136
        if (type != null) {
×
137
            ILogicProgrammerElement element = type.getByName(elementId);
×
138
            if(!LogicProgrammerElementTypes.areEqual(getActiveElement(), element)) {
×
139
                setActiveElement(element, 0, 0);
×
140
                onDirty();
×
141
            }
142
        } else {
×
143
            setActiveElement(null, 0, 0);
×
144
        }
145
    }
×
146

147
    /**
148
     * Set the new active element.
149
     * @param activeElement The new element.
150
     * @param baseX The slots X coordinate
151
     * @param baseY The slots Y coordinate
152
     */
153
    public void setActiveElement(final ILogicProgrammerElement activeElement, int baseX, int baseY) {
154
        if(this.activeElement != null) {
×
155
            this.activeElement.deactivate();
×
156
        }
157
        this.activeElement = activeElement;
×
158

159
        this.lastError = null;
×
160
        this.activeElement = activeElement;
×
161

162
        this.setElementInventory(this.activeElement, baseX, baseY);
×
163

164
        if(activeElement != null) {
×
165
            activeElement.activate();
×
166
        }
167
    }
×
168

169
    /**
170
     * Set the new active element.
171
     * @param element The new element.
172
     * @param baseX The slots X coordinate
173
     * @param baseY The slots Y coordinate
174
     */
175
    public void setElementInventory(final ILogicProgrammerElement element, int baseX, int baseY) {
176
        this.lastError = null;
×
177

178
        // This assumes that there is only one other slot, the remaining slots will be erased!
179
        // (We can do this because they are all ghost slots)
180
        lastSlots.clear();
×
181
        slots.clear();
×
182
        remoteSlots.clear();
×
183
        initializeSlotsPre();
×
184
        this.temporaryInputSlots.removeDirtyMarkListener(this);
×
185
        this.temporaryInputSlots = new SimpleInventory(element == null ? 0 : element.getRenderPattern().getSlotPositions().length, element == null ? 0 : element.getItemStackSizeLimit());
×
186
        temporaryInputSlots.addDirtyMarkListener(this);
×
187
        this.temporarySlotsElement = element;
×
188
        if(element != null) {
×
189
            Pair<Integer, Integer>[] slotPositions = element.getRenderPattern().getSlotPositions();
×
190
            for (int i = 0; i < temporaryInputSlots.getContainerSize(); i++) {
×
191
                Slot slot = addSlot(element.createSlot(temporaryInputSlots, i, 1 + baseX + slotPositions[i].getLeft(),
×
192
                        1 + baseY + slotPositions[i].getRight()));
×
193

194
                // Init remote slot as empty, as the server may otherwise unnecessarily overwrite the client-side-only value.
195
                remoteSlots.get(slot.index).force(ItemStack.EMPTY);
×
196
            }
197
        }
198
        initializeSlotsPost();
×
199
        this.lastLabel = "";
×
200
    }
×
201

202
    public boolean canWriteActiveElementPre() {
203
        if(activeElement != null) {
×
204
            return activeElement.canWriteElementPre();
×
205
        }
206
        return false;
×
207
    }
208

209
    public boolean canWriteActiveElement() {
210
        if(!canWriteActiveElementPre()) {
×
211
            return false;
×
212
        }
213
        lastError = activeElement.validate();
×
214
        return lastError == null;
×
215
    }
216

217
    public ILogicProgrammerElement<RenderPattern, ContainerScreenLogicProgrammerBase<?>, ContainerLogicProgrammerBase, ?> getActiveElement() {
218
        return activeElement;
×
219
    }
220

221
    @Override
222
    public void removed(Player player) {
223
        super.removed(player);
×
224
        if (!player.level().isClientSide()) {
×
225
            returnWriteItemToPlayer();
×
226
        }
227
    }
×
228

229
    public void onLabelPacket(String label) {
230
        this.lastLabel = label;
×
231
        labelCurrent();
×
232
    }
×
233

234
    protected void labelCurrent() {
235
        ItemStack itemStack = writeSlot.getItem(0);
×
236
        if(!itemStack.isEmpty()) {
×
237
            IVariableFacade variableFacade = RegistryEntries.ITEM_VARIABLE.get().getVariableFacade(ValueDeseralizationContext.of(player.level()), itemStack);
×
238
            if(this.lastLabel != null && variableFacade.isValid()) {
×
239
                LabelsWorldStorage.Access.getInstance(IntegratedDynamics._instance).get().put(variableFacade.getId(), this.lastLabel);
×
240
            }
241
        }
242
    }
×
243

244
    protected ItemStack writeElementInfo() {
245
        ItemStack itemStack = writeSlot.getItem(0);
×
246
        ItemStack result = getActiveElement().writeElement(player, itemStack.copy());
×
247
        return result;
×
248
    }
249

250
    @Override
251
    public void onDirty() {
252
        ILogicProgrammerElement activeElement = getActiveElement();
×
253
        if(activeElement != null) {
×
254
            for (int i = 0; i < temporaryInputSlots.getContainerSize(); i++) {
×
255
                ItemStack itemStack = temporaryInputSlots.getItem(i);
×
256
                temporarySlotsElement.onInputSlotUpdated(player, i, itemStack);
×
257
            }
258
        }
259

260
        ItemStack itemStack = writeSlot.getItem(0);
×
261
        if(canWriteActiveElement() && !itemStack.isEmpty()) {
×
262
            // If the variable has a vanilla custom name, make sure we inherit it as variable label
263
            if (itemStack.has(DataComponents.CUSTOM_NAME)) {
×
264
                this.lastLabel = itemStack.getHoverName().getString();
×
265
            }
266

267
            ItemStack outputStack = writeElementInfo();
×
268
            writeSlot.removeDirtyMarkListener(this);
×
269
            writeSlot.removeDirtyMarkListener(loadConfigListener);
×
270
            writeSlot.setItem(0, outputStack);
×
271
            if(!StringUtil.isNullOrEmpty(this.lastLabel)) {
×
272
                labelCurrent();
×
273
            }
274
            writeSlot.addDirtyMarkListener(this);
×
275
            writeSlot.addDirtyMarkListener(loadConfigListener);
×
276
        }
277
    }
×
278

279
    protected void loadConfigFrom(ItemStack itemStack) {
280
        IVariableFacadeHandlerRegistry registry = IntegratedDynamics._instance.getRegistryManager().getRegistry(IVariableFacadeHandlerRegistry.class);
×
281
        IVariableFacade variableFacade = registry.handle(ValueDeseralizationContext.of(player.level()), itemStack);
×
282
        for(ILogicProgrammerElement<RenderPattern, ContainerScreenLogicProgrammerBase<?>, ContainerLogicProgrammerBase, ?> element : getUnfilteredItems()) {
×
283
            if(element.isFor(variableFacade)) {
×
284
                writeSlot.removeDirtyMarkListener(this);
×
285
                writeSlot.removeDirtyMarkListener(loadConfigListener);
×
286
                if (IModHelpers.get().getMinecraftHelpers().isClientSideThread()) {
×
287
                    getGui().handleElementActivation(element, false);
×
288
                } else {
289
                    setActiveElement(element, 0, 0);
×
290
                }
291
                temporaryInputSlots.removeDirtyMarkListener(this);
×
292
                element.loadElement(variableFacade);
×
293
                if (IModHelpers.get().getMinecraftHelpers().isClientSideThread()) {
×
294
                    element.getClient().setValueInGui(getGui().getOperatorConfigPattern());
×
295
                } else {
296
                    element.setValueInContainer(this);
×
297
                }
298
                writeSlot.addDirtyMarkListener(this);
×
299
                writeSlot.addDirtyMarkListener(loadConfigListener);
×
300
                temporaryInputSlots.addDirtyMarkListener(this);
×
301
            }
302
        }
×
303
    }
×
304

305
    public Component getLastError() {
306
        return this.lastError;
×
307
    }
308

309
    public SimpleInventory getTemporaryInputSlots() {
310
        return this.temporaryInputSlots;
×
311
    }
312

313
    public boolean hasWriteItemInSlot() {
314
        return !this.writeSlot.getItem(0).isEmpty();
×
315
    }
316

317
    public void returnWriteItemToPlayer() {
318
        if (hasWriteItemInSlot()) {
×
319
            ItemStack itemStack = writeSlot.getItem(0);
×
320
            Helpers.returnItemToPlayer(player, itemStack);
×
321
            writeSlot.setItem(0, ItemStack.EMPTY);
×
322
        }
323
    }
×
324

325
    @Override
326
    protected boolean additionalApplies(ILogicProgrammerElement item) {
327
        return (
×
328
                ((filterIn1 == null || item.matchesInput(filterIn1)) && (filterIn2 == null || item.matchesInput(filterIn2))) || (filterIn1 == null && filterIn2 == null))
×
329
                && (filterOut == null || item.matchesOutput(filterOut));
×
330
    }
331

332
    @Override
333
    public void clicked(int slotId, int mouseButton, ClickType clickType, Player player) {
334
        // Handle cases where the client may have more (phantom) slots than the server.
335
        if (slotId >= this.slots.size() || (this.activeElement != null
×
336
                && this.slots.size() > slotId && slotId >= 0
×
337
                && this.activeElement.slotClick(slotId, this.getSlot(slotId), mouseButton, clickType, player))) {
×
338
            return;
×
339
        }
340
        super.clicked(slotId, mouseButton, clickType, player);
×
341
    }
×
342

343
    /**
344
     * Load existing operator data when a variable card is inserted into the write slot
345
     */
346
    protected class LoadConfigListener implements IDirtyMarkListener {
×
347

348
        @Override
349
        public void onDirty() {
350
            if (activeElement == null) {
×
351
                ItemStack itemStack = writeSlot.getItem(0);
×
352
                if (!itemStack.isEmpty()) {
×
353
                    ContainerLogicProgrammerBase.this.loadConfigFrom(itemStack);
×
354
                }
355
            }
356
        }
×
357

358
    }
359

360
    /**
361
     * Filter LP elements based on the filter value types.
362
     */
363
    protected class FilterSlotListener implements IDirtyMarkListener {
364

365
        private final ValueDeseralizationContext valueDeseralizationContext;
366

367
        public FilterSlotListener(ValueDeseralizationContext valueDeseralizationContext) {
×
368
            this.valueDeseralizationContext = valueDeseralizationContext;
×
369
        }
×
370

371
        protected IValueType getValueType(Container inventory, int slot) {
372
            IVariableFacadeHandlerRegistry handler = IntegratedDynamics._instance.getRegistryManager().getRegistry(IVariableFacadeHandlerRegistry.class);
×
373
            if(inventory.getItem(slot) != null) {
×
374
                IVariableFacade variableFacade = handler.handle(valueDeseralizationContext, inventory.getItem(slot));
×
375
                if(variableFacade.isValid()) {
×
376
                    return variableFacade.getOutputType();
×
377
                }
378
            }
379
            return null;
×
380
        }
381

382
        @Override
383
        public void onDirty() {
384
            IValueType filterIn1Prev = filterIn1;
×
385
            IValueType filterIn2Prev = filterIn2;
×
386
            IValueType filterOutPrev = filterOut;
×
387

388
            filterIn1 = getValueType(filterSlots, 0);
×
389
            filterIn2 = getValueType(filterSlots, 1);
×
390
            filterOut = getValueType(filterSlots, 2);
×
391
            if (filterIn1Prev != filterIn1 || filterIn2Prev != filterIn2 || filterOutPrev != filterOut) {
×
392
                refreshFilter();
×
393
            }
394
        }
×
395

396
    }
397

398
    public static interface ScreenCallbackHandler {
399
        public boolean handleElementActivation(ILogicProgrammerElement element, boolean sendToServer);
400
        public RenderPattern getOperatorConfigPattern();
401
    }
402

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