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

CyclopsMC / IntegratedDynamics / 20210191346

14 Dec 2025 03:32PM UTC coverage: 19.514% (-33.5%) from 53.061%
20210191346

push

github

rubensworks
Remove deprecations

663 of 8728 branches covered (7.6%)

Branch coverage included in aggregate %.

6786 of 29445 relevant lines covered (23.05%)

1.09 hits per line

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

0.0
/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();
×
47
    private final TreeSet<INetworkElement> elements = Sets.newTreeSet();
×
48
    private Object2IntMap<INetworkElement> updateableElementsTicks = null;
×
49
    private TreeSet<INetworkElement> invalidatedElements = Sets.newTreeSet();
×
50
    private Map<INetworkElement, Long> lastSecondDurations = Maps.newHashMap();
×
51

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

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

59
    private boolean crashed = false;
×
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));
×
68
        NetworkWorldStorage.Access.getInstance(IntegratedDynamics._instance).get().addNewNetwork(network);
×
69
        return network;
×
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) {
×
101
        this.baseCluster = pathElements;
×
102
        gatherCapabilities();
×
103
        onConstruct();
×
104
        deriveNetworkElements(baseCluster);
×
105
    }
×
106

107
    protected void gatherCapabilities() {
108
        AttachCapabilitiesEventNetwork event = new AttachCapabilitiesEventNetwork(this);
×
109
        ModLoader.postEventWrapContainerInModOrder(event);
×
110
        List<IFullNetworkListener> listeners = event.getFullNetworkListeners();
×
111
        this.fullNetworkListeners = listeners.toArray(new IFullNetworkListener[listeners.size()]);
×
112
        this.capabilityProviders = event.getProviders();
×
113
    }
×
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
    }
×
124

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

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

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

161
    /**
162
     * Initialize the network element data.
163
     */
164
    public void initialize() {
165
        initialize(false);
×
166
    }
×
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);
×
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) {
×
194
            if (!fullNetworkListener.addNetworkElement(element, networkPreinit)) {
×
195
                return false;
×
196
            }
197
        }
198

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

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

232
    @Override
233
    public boolean removeNetworkElementPre(INetworkElement element) {
234
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
×
235
            if (!fullNetworkListener.removeNetworkElementPre(element)) {
×
236
                return false;
×
237
            }
238
        }
239
        return getEventBus().postCancelable(new NetworkElementRemoveEvent.Pre(this, element));
×
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) {
×
267
            fullNetworkListener.removeNetworkElementPost(element, blockState, blockEntity);
×
268
        }
269
        if (element instanceof IEventListenableNetworkElement) {
×
270
            IEventListenableNetworkElement<?> listenableElement = (IEventListenableNetworkElement<?>) element;
×
271
            listenableElement.getNetworkEventListener().ifPresent(listener -> {
×
272
                if (listener.hasEventSubscriptions()) {
×
273
                    getEventBus().unregister(listenableElement);
×
274
                }
275
            });
×
276
        }
277
        element.beforeNetworkKill(this, blockState, blockEntity);
×
278
        element.onNetworkRemoval(this, blockState, blockEntity);
×
279
        removeNetworkElementInternal(element);
×
280
        getEventBus().post(new NetworkElementRemoveEvent.Post(this, element));
×
281
        onNetworkChanged();
×
282
    }
×
283

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

290
    @Override
291
    public synchronized void removeNetworkElementUpdateable(INetworkElement element) {
292
        if (isInitialized()) {
×
293
            updateableElementsTicks.removeInt(element);
×
294
        }
295
    }
×
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<>();
×
303
        updateableElementsTicks.defaultReturnValue(Integer.MIN_VALUE);
×
304
        for(INetworkElement element : elements) {
×
305
            addNetworkElementUpdateable(element);
×
306
            if(!silent) {
×
307
                element.afterNetworkAlive(this);
×
308
            }
309
            element.afterNetworkReAlive(this);
×
310
        }
×
311

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

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

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

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

347
    @Override
348
    public void postUpdate(INetworkElement element) {
349
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
×
350
            fullNetworkListener.postUpdate(element);
×
351
        }
352
    }
×
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) {
×
364
            this.fromParamsEffective(this.toRead);
×
365
            this.toRead = null;
×
366
        }
367
    }
×
368

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

377
            // Update updateable network elements
378
            boolean isBeingDiagnozed = NetworkDiagnostics.getInstance().isBeingDiagnozed();
×
379
            if (!isBeingDiagnozed && !lastSecondDurations.isEmpty()) {
×
380
                // Make sure we aren't using any unnecessary memory.
381
                lastSecondDurations.clear();
×
382
            }
383
            for (Object2IntMap.Entry<INetworkElement> entry : updateableElementsTicks.object2IntEntrySet()) {
×
384
                var element = entry.getKey();
×
385
                try {
386
                    if (isValid(element)) {
×
387
                        long startTime = 0;
×
388
                        if (isBeingDiagnozed) {
×
389
                            startTime = System.nanoTime();
×
390
                        }
391
                        int lastElementTick = entry.getIntValue();
×
392
                        if (canUpdate(element)) {
×
393
                            if (lastElementTick <= 0) {
×
394
                                entry.setValue(element.getUpdateInterval() - 1);
×
395
                                element.update(this);
×
396
                                postUpdate(element);
×
397
                            } else {
398
                                entry.setValue(lastElementTick - 1);
×
399
                            }
400
                        } else {
401
                            onSkipUpdate(element);
×
402
                            entry.setValue(lastElementTick - 1);
×
403
                        }
404
                        if (isBeingDiagnozed) {
×
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
                }
×
420
            }
×
421
        }
422
    }
×
423

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

430
    @Override
431
    public synchronized boolean removePathElement(IPathElement pathElement, Direction side, BlockState blockState, BlockEntity blockEntity) {
432
        for (IFullNetworkListener fullNetworkListener : this.fullNetworkListeners) {
×
433
            if (!fullNetworkListener.removePathElement(pathElement, side, blockState, blockEntity)) {
×
434
                return false;
×
435
            }
436
        }
437
        if(baseCluster.remove(SidedPathElement.of(pathElement, null))) {
×
438
            DimPos position = pathElement.getPosition();
×
439
            Level level = position.getLevel(true);
×
440
            INetworkElementProvider networkElementProvider = null;
×
441
            if (level != null) {
×
442
                networkElementProvider = level.getCapability(Capabilities.NetworkElementProvider.BLOCK, position.getBlockPos(), blockState, blockEntity, side);
×
443
            }
444
            if (networkElementProvider != null) {
×
445
                Collection<INetworkElement> networkElements = networkElementProvider.
×
446
                        createNetworkElements(position.getLevel(true), position.getBlockPos());
×
447
                for (INetworkElement networkElement : networkElements) {
×
448
                    if(!removeNetworkElementPre(networkElement)) {
×
449
                        return false;
×
450
                    }
451
                }
×
452
                for (INetworkElement networkElement : networkElements) {
×
453
                    removeNetworkElementPost(networkElement, blockState, blockEntity);
×
454
                }
×
455
                onNetworkChanged();
×
456
                return true;
×
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) {
×
482
            fullNetworkListener.beforeServerStop();
×
483
        }
484
    }
×
485

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

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

496
    protected void onNetworkChanged() {
497
        this.changed = true;
×
498
    }
×
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;
×
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));
×
534
    }
535

536
    @Override
537
    public void invalidateElement(INetworkElement element) {
538
        if (element.canRevalidate(this)) {
×
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) {
×
545
                fullNetworkListener.invalidateElement(element);
×
546
            }
547
            invalidatedElements.add(element);
×
548
        }
549
    }
×
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()) {
×
572
            return false;
×
573
        }
574
        if (invalidatedElements.contains(element)) {
×
575
            if (element.canRevalidate(this)) {
×
576
                element.revalidate(this);
×
577
                return true;
×
578
            }
579
            return false;
×
580
        }
581
        return true;
×
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