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

CyclopsMC / IntegratedDynamics / 19640668712

24 Nov 2025 03:59PM UTC coverage: 53.038% (-0.02%) from 53.061%
19640668712

push

github

rubensworks
Merge remote-tracking branch 'origin/master-1.21-lts' into master-1.21

2876 of 8776 branches covered (32.77%)

Branch coverage included in aggregate %.

17359 of 29376 relevant lines covered (59.09%)

3.07 hits per line

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

64.29
/src/main/java/org/cyclops/integrateddynamics/core/network/Network.java
1
package org.cyclops.integrateddynamics.core.network;
2

3
import com.google.common.collect.Lists;
4
import com.google.common.collect.Maps;
5
import com.google.common.collect.Sets;
6
import it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap;
7
import it.unimi.dsi.fastutil.objects.Object2IntMap;
8
import net.minecraft.core.BlockPos;
9
import net.minecraft.core.Direction;
10
import net.minecraft.world.level.Level;
11
import net.minecraft.world.level.block.entity.BlockEntity;
12
import net.minecraft.world.level.block.state.BlockState;
13
import net.neoforged.fml.ModLoader;
14
import net.neoforged.neoforge.capabilities.ICapabilityProvider;
15
import org.cyclops.cyclopscore.datastructure.DimPos;
16
import org.cyclops.cyclopscore.helper.IModHelpersNeoForge;
17
import org.cyclops.integrateddynamics.Capabilities;
18
import org.cyclops.integrateddynamics.IntegratedDynamics;
19
import org.cyclops.integrateddynamics.api.PartStateException;
20
import org.cyclops.integrateddynamics.api.network.*;
21
import org.cyclops.integrateddynamics.api.network.event.INetworkEvent;
22
import org.cyclops.integrateddynamics.api.network.event.INetworkEventBus;
23
import org.cyclops.integrateddynamics.api.path.IPathElement;
24
import org.cyclops.integrateddynamics.api.path.ISidedPathElement;
25
import org.cyclops.integrateddynamics.capability.path.SidedPathElement;
26
import org.cyclops.integrateddynamics.core.network.diagnostics.NetworkDiagnostics;
27
import org.cyclops.integrateddynamics.core.network.event.NetworkElementAddEvent;
28
import org.cyclops.integrateddynamics.core.network.event.NetworkElementRemoveEvent;
29
import org.cyclops.integrateddynamics.core.network.event.NetworkEventBus;
30
import org.cyclops.integrateddynamics.core.network.event.VariableContentsUpdatedEvent;
31
import org.cyclops.integrateddynamics.core.path.Cluster;
32
import org.cyclops.integrateddynamics.core.path.PathFinder;
33
import org.cyclops.integrateddynamics.core.persist.world.NetworkWorldStorage;
34

35
import java.util.*;
36

37
/**
38
 * A network instance that can hold a set of {@link INetworkElement}s.
39
 * Note that this network only contains references to the relevant data, it does not contain the actual information.
40
 * @author rubensworks
41
 */
42
public class Network implements INetwork {
43

44
    private Cluster baseCluster;
45

46
    private final INetworkEventBus eventBus = new NetworkEventBus();
5✔
47
    private final TreeSet<INetworkElement> elements = Sets.newTreeSet();
3✔
48
    private Object2IntMap<INetworkElement> updateableElementsTicks = null;
3✔
49
    private TreeSet<INetworkElement> invalidatedElements = Sets.newTreeSet();
3✔
50
    private Map<INetworkElement, Long> lastSecondDurations = Maps.newHashMap();
3✔
51

52
    private Map<NetworkCapability<?>, List<ICapabilityProvider<INetwork, Void, ?>>> capabilityProviders;
53
    private IFullNetworkListener[] fullNetworkListeners;
54

55
    private NetworkParams toRead = null;
3✔
56
    private volatile boolean changed = false;
3✔
57
    private volatile boolean killed = false;
3✔
58

59
    private boolean crashed = false;
3✔
60

61
    /**
62
     * Initiate a full network from the given start position.
63
     * @param sidedPathElement The sided path element to start from.
64
     * @return The newly formed network.
65
     */
66
    public static Network initiateNetworkSetup(ISidedPathElement sidedPathElement) {
67
        Network network = new Network(PathFinder.getConnectedCluster(sidedPathElement));
6✔
68
        NetworkWorldStorage.Access.getInstance(IntegratedDynamics._instance).get().addNewNetwork(network);
6✔
69
        return network;
2✔
70
    }
71

72
    /**
73
     * Check if two networks are equal.
74
     * @param networkA A network.
75
     * @param networkB Another network.
76
     * @return If they are equal.
77
     */
78
    public static boolean areNetworksEqual(Network networkA, Network networkB) {
79
        return networkA.elements.containsAll(networkB.elements) && networkA.elements.size() == networkB.elements.size();
×
80
    }
81

82
    /**
83
     * This constructor should not be called, except for the process of constructing networks from NBT.
84
     */
85
    public Network() {
×
86
        this.baseCluster = new Cluster();
×
87
        gatherCapabilities();
×
88
        onConstruct();
×
89
    }
×
90

91
    /**
92
     * Create a new network from a given cluster of path elements.
93
     * Each path element will be checked if it has a {@link INetworkElementProvider} capability at its position
94
     * and will add all its elements to the network in that case.
95
     * Each path element that has an {@link org.cyclops.integrateddynamics.api.part.IPartContainer} capability
96
     * will have the network stored in its part container.
97
     * @param pathElements The path elements that make up the connections in the network which can potentially provide network
98
     *               elements.
99
     */
100
    public Network(Cluster pathElements) {
2✔
101
        this.baseCluster = pathElements;
3✔
102
        gatherCapabilities();
2✔
103
        onConstruct();
2✔
104
        deriveNetworkElements(baseCluster);
4✔
105
    }
1✔
106

107
    protected void gatherCapabilities() {
108
        AttachCapabilitiesEventNetwork event = new AttachCapabilitiesEventNetwork(this);
5✔
109
        ModLoader.postEventWrapContainerInModOrder(event);
2✔
110
        List<IFullNetworkListener> listeners = event.getFullNetworkListeners();
3✔
111
        this.fullNetworkListeners = listeners.toArray(new IFullNetworkListener[listeners.size()]);
8✔
112
        this.capabilityProviders = event.getProviders();
4✔
113
    }
1✔
114

115
    protected IFullNetworkListener[] gatherFullNetworkListeners() {
116
        List<IFullNetworkListener> listeners = Lists.newArrayList();
×
117

118
        return listeners.toArray(new IFullNetworkListener[listeners.size()]);
×
119
    }
120

121
    protected void onConstruct() {
122

123
    }
1✔
124

125
    private void deriveNetworkElements(Cluster pathElements) {
126
        if(!killIfEmpty()) {
3!
127
            for (ISidedPathElement sidedPathElement : pathElements) {
10✔
128
                Level world = sidedPathElement.getPathElement().getPosition().getLevel(true);
6✔
129
                BlockPos pos = sidedPathElement.getPathElement().getPosition().getBlockPos();
5✔
130
                Direction side = sidedPathElement.getSide();
3✔
131
                IModHelpersNeoForge.get().getCapabilityHelpers().getCapability(world, pos, side, Capabilities.NetworkCarrier.BLOCK).ifPresent(networkCarrier -> {
14✔
132
                    // Correctly remove any previously saved network in this carrier
133
                    // and set the new network to this.
134
                    INetwork network = networkCarrier.getNetwork();
3✔
135
                    if (network != null) {
2✔
136
                        network.removePathElement(sidedPathElement.getPathElement(), side, world.getBlockState(pos), world.getBlockEntity(pos));
12✔
137
                    }
138
                    networkCarrier.setNetwork(null);
3✔
139
                    networkCarrier.setNetwork(this);
3✔
140
                });
1✔
141
                IModHelpersNeoForge.get().getCapabilityHelpers().getCapability(world, pos, side, Capabilities.NetworkElementProvider.BLOCK).ifPresent(networkElementProvider -> {
12✔
142
                    for(INetworkElement element : networkElementProvider.createNetworkElements(world, pos)) {
13✔
143
                        addNetworkElement(element, true);
5✔
144
                    }
1✔
145
                });
1✔
146
            }
1✔
147
            onNetworkChanged();
2✔
148
        }
149
    }
1✔
150

151
    @Override
152
    public boolean isInitialized() {
153
        return updateableElementsTicks != null;
6!
154
    }
155

156
    @Override
157
    public INetworkEventBus getEventBus() {
158
        return this.eventBus;
3✔
159
    }
160

161
    /**
162
     * Initialize the network element data.
163
     */
164
    public void initialize() {
165
        initialize(false);
3✔
166
    }
1✔
167

168
    @Override
169
    public boolean equals(Object object) {
170
        return object instanceof Network && areNetworksEqual(this, (Network) object);
×
171
    }
172

173
    public NetworkParams toParams() {
174
        return new NetworkParams(this.baseCluster.toParams(), this.crashed);
9✔
175
    }
176

177
    public void fromParams(NetworkParams params) {
178
        // NBT reading is postponed until the first network tick, to ensure that the game is properly initialized.
179
        // Because other mods may register things such as dimensions at the same time when networks
180
        // are being constructed (as was the case in #349)
181
        this.toRead = params;
×
182
    }
×
183

184
    public void fromParamsEffective(NetworkParams networkParams) {
185
        this.baseCluster.fromParams(networkParams.pathElements());
×
186
        this.crashed = networkParams.crashed();
×
187
        deriveNetworkElements(baseCluster);
×
188
        initialize(true);
×
189
    }
×
190

191
    @Override
192
    public synchronized boolean addNetworkElement(INetworkElement element, boolean networkPreinit) {
193
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
194
            if (!fullNetworkListener.addNetworkElement(element, networkPreinit)) {
5!
195
                return false;
×
196
            }
197
        }
198

199
        if(getEventBus().postCancelable(new NetworkElementAddEvent.Pre(this, element))) {
9!
200
            elements.add(element);
5✔
201
            if (!element.onNetworkAddition(this)) {
4!
202
                elements.remove(element);
×
203
                return false;
×
204
            }
205
            if (!networkPreinit) {
2✔
206
                addNetworkElementUpdateable(element);
3✔
207
            }
208
            if (element instanceof IEventListenableNetworkElement) {
3✔
209
                IEventListenableNetworkElement<?> listenableElement = (IEventListenableNetworkElement<?>) element;
3✔
210
                listenableElement.getNetworkEventListener().ifPresent(listener -> {
6✔
211
                    if (listener.hasEventSubscriptions()) {
3✔
212
                        for (Class<? extends INetworkEvent> eventType : listener.getSubscribedEvents()) {
11✔
213
                            getEventBus().register(listenableElement, eventType);
5✔
214
                        }
1✔
215
                    }
216
                });
1✔
217
            }
218
            getEventBus().post(new NetworkElementAddEvent.Post(this, element));
8✔
219
            onNetworkChanged();
2✔
220
            return true;
2✔
221
        }
222
        return false;
×
223
    }
224

225
    @Override
226
    public void addNetworkElementUpdateable(INetworkElement element) {
227
        if(element.isUpdate()) {
3✔
228
            updateableElementsTicks.put(element, 0);
6✔
229
        }
230
    }
1✔
231

232
    @Override
233
    public boolean removeNetworkElementPre(INetworkElement element) {
234
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
235
            if (!fullNetworkListener.removeNetworkElementPre(element)) {
4!
236
                return false;
×
237
            }
238
        }
239
        return getEventBus().postCancelable(new NetworkElementRemoveEvent.Pre(this, element));
9✔
240
    }
241

242
    @Override
243
    public synchronized void setPriorityAndChannel(INetworkElement element, int priority, int channel) {
244
        elements.remove(element);
×
245
        int oldTickValue = updateableElementsTicks.defaultReturnValue();
×
246
        if (element.isUpdate()) {
×
247
            oldTickValue = updateableElementsTicks.removeInt(element);
×
248
        }
249

250
        //noinspection deprecation
251
        element.setPriorityAndChannel(this, priority, channel);
×
252

253
        elements.add(element);
×
254
        if (element.isUpdate()) {
×
255
            updateableElementsTicks.put(
×
256
                element,
257
                oldTickValue == updateableElementsTicks.defaultReturnValue()
×
258
                    ? element.getUpdateInterval()
×
259
                    : oldTickValue
×
260
            );
261
        }
262
    }
×
263

264
    @Override
265
    public void removeNetworkElementPost(INetworkElement element, BlockState blockState, BlockEntity blockEntity) {
266
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
267
            fullNetworkListener.removeNetworkElementPost(element, blockState, blockEntity);
5✔
268
        }
269
        if (element instanceof IEventListenableNetworkElement) {
3✔
270
            IEventListenableNetworkElement<?> listenableElement = (IEventListenableNetworkElement<?>) element;
3✔
271
            listenableElement.getNetworkEventListener().ifPresent(listener -> {
6✔
272
                if (listener.hasEventSubscriptions()) {
3✔
273
                    getEventBus().unregister(listenableElement);
4✔
274
                }
275
            });
1✔
276
        }
277
        element.beforeNetworkKill(this, blockState, blockEntity);
5✔
278
        element.onNetworkRemoval(this, blockState, blockEntity);
5✔
279
        removeNetworkElementInternal(element);
3✔
280
        getEventBus().post(new NetworkElementRemoveEvent.Post(this, element));
8✔
281
        onNetworkChanged();
2✔
282
    }
1✔
283

284
    public void removeNetworkElementInternal(INetworkElement element) {
285
        elements.remove(element);
5✔
286
        removeNetworkElementUpdateable(element);
3✔
287
        invalidatedElements.remove(element); // The element may be invalidated (like in an unloaded chunk) when it is being removed.
5✔
288
    }
1✔
289

290
    @Override
291
    public synchronized void removeNetworkElementUpdateable(INetworkElement element) {
292
        if (isInitialized()) {
3!
293
            updateableElementsTicks.removeInt(element);
5✔
294
        }
295
    }
1✔
296

297
    /**
298
     * Called when a network is server-loaded or newly created.
299
     * @param silent If the element should not be notified for the network becoming alive.
300
     */
301
    protected void initialize(boolean silent) {
302
        updateableElementsTicks = new Object2IntAVLTreeMap<>();
5✔
303
        updateableElementsTicks.defaultReturnValue(Integer.MIN_VALUE);
4✔
304
        for(INetworkElement element : elements) {
11✔
305
            addNetworkElementUpdateable(element);
3✔
306
            if(!silent) {
2!
307
                element.afterNetworkAlive(this);
3✔
308
            }
309
            element.afterNetworkReAlive(this);
3✔
310
        }
1✔
311

312
        // Once all elements are alive, send a single variable contents updated event.
313
        this.getEventBus().post(new VariableContentsUpdatedEvent(this));
7✔
314
    }
1✔
315

316
    @Override
317
    public void kill() {
318
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
319
            fullNetworkListener.kill();
2✔
320
        }
321
        for(INetworkElement element : elements) {
7!
322
            element.beforeNetworkKill(this, null, null);
×
323
        }
×
324
        killed = true;
3✔
325
    }
1✔
326

327
    @Override
328
    public boolean killIfEmpty() {
329
        if(baseCluster.isEmpty()) {
4✔
330
            kill();
2✔
331
            onNetworkChanged();
2✔
332
            return true;
2✔
333
        }
334
        return false;
2✔
335
    }
336

337
    @Override
338
    public boolean canUpdate(INetworkElement element) {
339
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
340
            if (!fullNetworkListener.canUpdate(element)) {
4!
341
                return false;
×
342
            }
343
        }
344
        return true;
2✔
345
    }
346

347
    @Override
348
    public void postUpdate(INetworkElement element) {
349
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
350
            fullNetworkListener.postUpdate(element);
3✔
351
        }
352
    }
1✔
353

354
    @Override
355
    public void onSkipUpdate(INetworkElement element) {
356
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
×
357
            fullNetworkListener.onSkipUpdate(element);
×
358
        }
359
    }
×
360

361
    @Override
362
    public void updateGuaranteed() {
363
        if (this.toRead != null) {
3!
364
            this.fromParamsEffective(this.toRead);
×
365
            this.toRead = null;
×
366
        }
367
    }
1✔
368

369
    @Override
370
    public final synchronized void update() {
371
        this.changed = false;
3✔
372
        if(killIfEmpty() || killed) {
6!
373
            NetworkWorldStorage.Access.getInstance(IntegratedDynamics._instance).get().removeInvalidatedNetwork(this);
7✔
374
        } else {
375
            onUpdate();
2✔
376

377
            // Update updateable network elements
378
            boolean isBeingDiagnozed = NetworkDiagnostics.getInstance().isBeingDiagnozed();
3✔
379
            if (!isBeingDiagnozed && !lastSecondDurations.isEmpty()) {
6!
380
                // Make sure we aren't using any unnecessary memory.
381
                lastSecondDurations.clear();
×
382
            }
383
            for (Object2IntMap.Entry<INetworkElement> entry : updateableElementsTicks.object2IntEntrySet()) {
12✔
384
                var element = entry.getKey();
4✔
385
                try {
386
                    if (isValid(element)) {
4!
387
                        long startTime = 0;
2✔
388
                        if (isBeingDiagnozed) {
2!
389
                            startTime = System.nanoTime();
×
390
                        }
391
                        int lastElementTick = entry.getIntValue();
3✔
392
                        if (canUpdate(element)) {
4!
393
                            if (lastElementTick <= 0) {
2!
394
                                entry.setValue(element.getUpdateInterval() - 1);
7✔
395
                                element.update(this);
3✔
396
                                postUpdate(element);
4✔
397
                            } else {
398
                                entry.setValue(lastElementTick - 1);
×
399
                            }
400
                        } else {
401
                            onSkipUpdate(element);
×
402
                            entry.setValue(lastElementTick - 1);
×
403
                        }
404
                        if (isBeingDiagnozed) {
2!
405
                            long duration = System.nanoTime() - startTime;
×
406
                            Long lastDuration = lastSecondDurations.get(element);
×
407
                            if (lastDuration != null) {
×
408
                                duration = duration + lastDuration;
×
409
                            }
410
                            lastSecondDurations.put(element, duration);
×
411
                        }
412
                    }
413
                } catch (PartStateException e) {
×
414
                    IntegratedDynamics.clog(org.apache.logging.log4j.Level.WARN, "Attempted to tick a part that was not properly unloaded. " +
×
415
                            "Report this to the Integrated Dynamics issue tracker with details on what you did " +
416
                            "leading up to this stacktrace. The part was forcefully unloaded");
417
                    e.printStackTrace();
×
418
                    element.invalidate(this);
×
419
                }
1✔
420
            }
1✔
421
        }
422
    }
1✔
423

424
    protected void onUpdate() {
425
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
426
            fullNetworkListener.update();
2✔
427
        }
428
    }
1✔
429

430
    @Override
431
    public synchronized boolean removePathElement(IPathElement pathElement, Direction side, BlockState blockState, BlockEntity blockEntity) {
432
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
433
            if (!fullNetworkListener.removePathElement(pathElement, side, blockState, blockEntity)) {
7!
434
                return false;
×
435
            }
436
        }
437
        if(baseCluster.remove(SidedPathElement.of(pathElement, null))) {
7!
438
            DimPos position = pathElement.getPosition();
3✔
439
            Level level = position.getLevel(true);
4✔
440
            INetworkElementProvider networkElementProvider = null;
2✔
441
            if (level != null) {
2!
442
                networkElementProvider = level.getCapability(Capabilities.NetworkElementProvider.BLOCK, position.getBlockPos(), blockState, blockEntity, side);
10✔
443
            }
444
            if (networkElementProvider != null) {
2!
445
                Collection<INetworkElement> networkElements = networkElementProvider.
3✔
446
                        createNetworkElements(position.getLevel(true), position.getBlockPos());
5✔
447
                for (INetworkElement networkElement : networkElements) {
10✔
448
                    if(!removeNetworkElementPre(networkElement)) {
4!
449
                        return false;
×
450
                    }
451
                }
1✔
452
                for (INetworkElement networkElement : networkElements) {
10✔
453
                    removeNetworkElementPost(networkElement, blockState, blockEntity);
5✔
454
                }
1✔
455
                onNetworkChanged();
2✔
456
                return true;
2✔
457
            }
458
        } else {
×
459
            Thread.dumpStack();
×
460
            IntegratedDynamics.clog(org.apache.logging.log4j.Level.WARN, "Tried to remove a path element from a network it was not present in.");
×
461
            System.out.println("Cluster: " + baseCluster);
×
462
            System.out.println("Tried removing element: " + pathElement);
×
463
        }
464
        return false;
×
465
    }
466

467
    @Override
468
    public void afterServerLoad() {
469
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
×
470
            fullNetworkListener.afterServerLoad();
×
471
        }
472
        // All networks start from an invalidated state at server start
473
        for (INetworkElement element : getElements()) {
×
474
            invalidateElement(element);
×
475
        }
×
476

477
    }
×
478

479
    @Override
480
    public void beforeServerStop() {
481
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
482
            fullNetworkListener.beforeServerStop();
2✔
483
        }
484
    }
1✔
485

486
    @Override
487
    public Set<INetworkElement> getElements() {
488
        return this.elements;
3✔
489
    }
490

491
    @Override
492
    public boolean isKilled() {
493
        return this.killed;
×
494
    }
495

496
    protected void onNetworkChanged() {
497
        this.changed = true;
3✔
498
    }
1✔
499

500
    @Override
501
    public boolean hasChanged() {
502
        return this.changed;
×
503
    }
504

505
    @Override
506
    public int getCablesCount() {
507
        return baseCluster.size();
×
508
    }
509

510
    @Override
511
    public long getLastSecondDuration(INetworkElement networkElement) {
512
        Long duration = lastSecondDurations.get(networkElement);
×
513
        return duration == null ? 0 : duration;
×
514
    }
515

516
    @Override
517
    public void resetLastSecondDurations() {
518
        lastSecondDurations.clear();
×
519
    }
×
520

521
    @Override
522
    public boolean isCrashed() {
523
        return crashed;
3✔
524
    }
525

526
    @Override
527
    public void setCrashed(boolean crashed) {
528
        this.crashed = crashed;
×
529
    }
×
530

531
    @Override
532
    public <T> Optional<T> getCapability(NetworkCapability<T> capability) {
533
        return Optional.ofNullable(capability.getCapability(this.capabilityProviders, this));
7✔
534
    }
535

536
    @Override
537
    public void invalidateElement(INetworkElement element) {
538
        if (element.canRevalidate(this)) {
4!
539
            // If this element could already be revalidated,
540
            // this means that the element was not unloaded due to incorrect chunk unload,
541
            // and therefore is corrupted, so let's forcefully remove it.
542
            removeNetworkElementInternal(element);
×
543
        } else {
544
            for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
17✔
545
                fullNetworkListener.invalidateElement(element);
3✔
546
            }
547
            invalidatedElements.add(element);
5✔
548
        }
549
    }
1✔
550

551
    @Override
552
    public void revalidateElement(INetworkElement element) {
553
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
×
554
            fullNetworkListener.revalidateElement(element);
×
555
        }
556
        invalidatedElements.remove(element);
×
557
    }
×
558

559
    @Override
560
    public boolean containsSidedPathElement(ISidedPathElement pathElement) {
561
        return baseCluster.contains(pathElement);
×
562
    }
563

564
    @Override
565
    public IFullNetworkListener[] getFullNetworkListeners() {
566
        return this.fullNetworkListeners;
×
567
    }
568

569
    @Override
570
    public boolean isValid(INetworkElement element) {
571
        if (!element.isLoaded()) {
3!
572
            return false;
×
573
        }
574
        if (invalidatedElements.contains(element)) {
5!
575
            if (element.canRevalidate(this)) {
×
576
                element.revalidate(this);
×
577
                return true;
×
578
            }
579
            return false;
×
580
        }
581
        return true;
2✔
582
    }
583
}
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