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

CyclopsMC / IntegratedDynamics / 30758491470

02 Aug 2026 05:15PM UTC coverage: 45.534% (-0.1%) from 45.649%
30758491470

push

github

rubensworks
Add base compatibility with Create Aeronautics

This allows ray trace handlers for cables to be registered, which will
be done in the compat mod for Create Aeronautics.
Furthermore, this commits ensures that no items are dropped when the
isMoving flag is false within Block#onRemove.

Closes #1674

2803 of 8926 branches covered (31.4%)

Branch coverage included in aggregate %.

12311 of 24267 relevant lines covered (50.73%)

2.42 hits per line

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

80.16
/src/main/java/org/cyclops/integrateddynamics/core/helper/CableHelpers.java
1
package org.cyclops.integrateddynamics.core.helper;
2

3
import com.google.common.collect.Lists;
4
import com.google.common.collect.Sets;
5
import net.minecraft.core.BlockPos;
6
import net.minecraft.core.Direction;
7
import net.minecraft.world.InteractionResult;
8
import net.minecraft.world.entity.LivingEntity;
9
import net.minecraft.world.entity.player.Player;
10
import net.minecraft.world.item.ItemStack;
11
import net.minecraft.world.level.BlockGetter;
12
import net.minecraft.world.level.Level;
13
import net.minecraft.world.level.block.Block;
14
import net.minecraft.world.level.block.state.BlockState;
15
import net.neoforged.neoforge.common.NeoForge;
16
import net.neoforged.neoforge.common.extensions.ILevelExtension;
17
import org.cyclops.cyclopscore.helper.BlockEntityHelpers;
18
import org.cyclops.cyclopscore.helper.IModHelpers;
19
import org.cyclops.cyclopscore.helper.ItemStackHelpers;
20
import org.cyclops.integrateddynamics.Capabilities;
21
import org.cyclops.integrateddynamics.api.block.IFacadeable;
22
import org.cyclops.integrateddynamics.api.block.cable.ICable;
23
import org.cyclops.integrateddynamics.api.block.cable.ICableFakeable;
24
import org.cyclops.integrateddynamics.api.network.INetwork;
25
import org.cyclops.integrateddynamics.api.network.INetworkCarrier;
26
import org.cyclops.integrateddynamics.api.network.INetworkElement;
27
import org.cyclops.integrateddynamics.api.network.INetworkElementProvider;
28
import org.cyclops.integrateddynamics.api.part.IPartContainer;
29
import org.cyclops.integrateddynamics.api.part.IPartType;
30
import org.cyclops.integrateddynamics.api.path.IPathElement;
31
import org.cyclops.integrateddynamics.capability.facadeable.FacadeableTileMultipartTicking;
32
import org.cyclops.integrateddynamics.core.blockentity.BlockEntityMultipartTicking;
33
import org.cyclops.integrateddynamics.core.network.event.NetworkInitializedEvent;
34
import org.cyclops.integrateddynamics.item.ItemBlockCable;
35

36
import javax.annotation.Nullable;
37
import java.lang.ref.WeakReference;
38
import java.util.Collection;
39
import java.util.List;
40
import java.util.Map;
41
import java.util.Optional;
42

43
/**
44
 * Helpers related to cables.
45
 * @author rubensworks
46
 */
47
public class CableHelpers {
×
48

49
    public static final Collection<Direction> ALL_SIDES = Sets.newIdentityHashSet();
2✔
50
    static {
51
        for (Direction side : Direction.values()) {
16✔
52
            ALL_SIDES.add(side);
4✔
53
        }
54
    }
55

56
    /**
57
     * Get the cable capability at the given position.
58
     * @param world The world.
59
     * @param pos The position.
60
     * @param side The side.
61
     * @return The optional cable capability.
62
     */
63
    @Deprecated // TODO: attempt to migrate all calls to method with BlockState param
64
    public static Optional<ICable> getCable(ILevelExtension world, BlockPos pos, @Nullable Direction side) {
65
        return BlockEntityHelpers.getCapability(world, pos, side, Capabilities.Cable.BLOCK);
6✔
66
    }
67

68
    /**
69
     * Get the cable capability at the given position.
70
     * @param world The world.
71
     * @param pos The position.
72
     * @param side The side.
73
     * @param blockState The block state.
74
     * @return The optional cable capability.
75
     */
76
    public static Optional<ICable> getCable(ILevelExtension world, BlockPos pos, @Nullable Direction side, @Nullable BlockState blockState) {
77
        return Optional.ofNullable(world.getCapability(Capabilities.Cable.BLOCK, pos, blockState, null, side));
10✔
78
    }
79

80
    /**
81
     * Get the fakeable cable capability at the given position.
82
     * @param world The world.
83
     * @param pos The position.
84
     * @param side The side.
85
     * @return The optional fakeable cable capability.
86
     */
87
    @Deprecated // TODO: attempt to migrate all calls to method with BlockState param
88
    public static Optional<ICableFakeable> getCableFakeable(ILevelExtension world, BlockPos pos, @Nullable Direction side) {
89
        return BlockEntityHelpers.getCapability(world, pos, side, Capabilities.CableFakeable.BLOCK);
6✔
90
    }
91

92
    /**
93
     * Get the fakeable cable capability at the given position.
94
     * @param world The world.
95
     * @param pos The position.
96
     * @param side The side.
97
     * @param blockState The block state.
98
     * @return The optional fakeable cable capability.
99
     */
100
    public static Optional<ICableFakeable> getCableFakeable(ILevelExtension world, BlockPos pos, @Nullable Direction side, BlockState blockState) {
101
        return Optional.ofNullable(world.getCapability(Capabilities.CableFakeable.BLOCK, pos, blockState, null, side));
10✔
102
    }
103

104
    /**
105
     * Get the path element capability at the given position.
106
     * @param world The world.
107
     * @param pos The position.
108
     * @param side The side.
109
     * @return The optional path element capability.
110
     */
111
    @Deprecated // TODO: attempt to migrate all calls to method with BlockState param
112
    public static Optional<IPathElement> getPathElement(ILevelExtension world, BlockPos pos, @Nullable Direction side) {
113
        return BlockEntityHelpers.getCapability(world, pos, side, Capabilities.PathElement.BLOCK);
×
114
    }
115

116
    /**
117
     * Get the path element capability at the given position.
118
     * @param world The world.
119
     * @param pos The position.
120
     * @param side The side.
121
     * @return The optional path element capability.
122
     */
123
    public static Optional<IPathElement> getPathElement(ILevelExtension world, BlockPos pos, @Nullable Direction side, BlockState blockState) {
124
        return Optional.ofNullable(world.getCapability(Capabilities.PathElement.BLOCK, pos, blockState, null, side));
10✔
125
    }
126

127
    /**
128
     * Request to update the cable connections of all neighbours of the given position.
129
     * @param world The world.
130
     * @param pos The center position.
131
     * @param sides The sides to update connections for.
132
     */
133
    public static void updateConnectionsNeighbours(ILevelExtension world, BlockPos pos, Collection<Direction> sides) {
134
        for(Direction side : sides) {
10✔
135
            updateConnections(world, pos.relative(side), side.getOpposite());
7✔
136
        }
1✔
137
    }
1✔
138

139
    /**
140
     * Request to update the cable connections at the given position.
141
     * @param world The world.
142
     * @param pos The position.
143
     * @param side The side.
144
     */
145
    public static void updateConnections(ILevelExtension world, BlockPos pos, @Nullable Direction side) {
146
        getCable(world, pos, side)
5✔
147
                .ifPresent(ICable::updateConnections);
1✔
148
    }
1✔
149

150
    /**
151
     * Check if there is a cable at the given position AND if it is connected for the given side.
152
     * @param world The world.
153
     * @param pos The position.
154
     * @param side The side to check a connection for.
155
     * @return If there is a cable that is connected.
156
     */
157
    @Deprecated // TODO: attempt to migrate all calls to method with BlockState param
158
    public static boolean isCableConnected(ILevelExtension world, BlockPos pos, Direction side) {
159
        return getCable(world, pos, side)
×
160
                .map(cable -> cable.isConnected(side))
×
161
                .orElse(false);
×
162
    }
163

164
    /**
165
     * Check if there is a cable at the given position AND if it is connected for the given side.
166
     * @param world The world.
167
     * @param pos The position.
168
     * @param side The side to check a connection for.
169
     * @param blockState The block state.
170
     * @return If there is a cable that is connected.
171
     */
172
    public static boolean isCableConnected(ILevelExtension world, BlockPos pos, Direction side, BlockState blockState) {
173
        return getCable(world, pos, side, blockState)
8✔
174
                .map(cable -> cable.isConnected(side))
7✔
175
                .orElse(false);
4✔
176
    }
177

178
    /**
179
     * Check if one side of the given cable at the given position can connect to the given side.
180
     * To be used when the cable connections are being updated.
181
     * This will check if the origin cable can connect to that side,
182
     * if there is a cable at the target side and if that cable can connect with this side.
183
     * This ignores any current cable connections.
184
     * @param world The world.
185
     * @param pos The center position.
186
     * @param side The side from the center position to check.
187
     * @param originCable The cable at the center position.
188
     * @return If it can connect.
189
     */
190
    public static boolean canCableConnectTo(ILevelExtension world, BlockPos pos, Direction side, ICable originCable) {
191
        BlockPos neighbourPos = pos.relative(side);
4✔
192
        return getCable(world, neighbourPos, side.getOpposite())
9✔
193
                .map(neighbourCable -> originCable.canConnect(neighbourCable, side)
12✔
194
                        && neighbourCable.canConnect(originCable, side.getOpposite()))
6✔
195
                .orElse(false);
4✔
196
    }
197

198
    /**
199
     * Check if the given position is not a fake cable.
200
     * This can mean that there is no cable at all!
201
     * But if there is a cable, this method will return true only if it is a real cable.
202
     * @param world The world.
203
     * @param pos The position.
204
     * @param side The side.
205
     * @return If there is no fake cable.
206
     */
207
    @Deprecated // TODO: attempt to migrate all calls to method with BlockState param
208
    public static boolean isNoFakeCable(ILevelExtension world, BlockPos pos, @Nullable Direction side) {
209
        return getCableFakeable(world, pos, side)
6✔
210
                .map(ICableFakeable::isRealCable)
2✔
211
                .orElse(true);
4✔
212
    }
213

214
    /**
215
     * Check if the given position is not a fake cable.
216
     * This can mean that there is no cable at all!
217
     * But if there is a cable, this method will return true only if it is a real cable.
218
     * @param world The world.
219
     * @param pos The position.
220
     * @param side The side.
221
     * @param blockState The block state.
222
     * @return If there is no fake cable.
223
     */
224
    public static boolean isNoFakeCable(ILevelExtension world, BlockPos pos, @Nullable Direction side, BlockState blockState) {
225
        return getCableFakeable(world, pos, side, blockState)
7✔
226
                .map(ICableFakeable::isRealCable)
2✔
227
                .orElse(true);
4✔
228
    }
229

230
    /**
231
     * Disconnect a cable's side.
232
     * @param world The cable world.
233
     * @param pos The cable position.
234
     * @param side The cable side.
235
     * @param cable The cable to disconnect.
236
     * @param disconnectSide The side to disconnect.
237
     */
238
    public static void disconnectCable(Level world, BlockPos pos, Direction side, ICable cable, Direction disconnectSide) {
239
        // Store the disconnection in the part entity
240
        cable.disconnect(disconnectSide);
3✔
241

242
        // Signal changes
243
        cable.updateConnections();
2✔
244
        Collection<Direction> sidesToUpdate = getCableConnections(cable);
3✔
245
        sidesToUpdate.add(disconnectSide);
4✔
246
        CableHelpers.updateConnectionsNeighbours(world, pos, sidesToUpdate);
4✔
247

248
        // Reinit the networks for this block and the disconnected neighbour.
249
        NetworkHelpers.initNetwork(world, pos, side);
5✔
250
        NetworkHelpers.initNetwork(world, pos.relative(disconnectSide), side.getOpposite());
8✔
251
    }
1✔
252

253
    /**
254
     * Actions to be performed when a player right clicks on a cable.
255
     * @param world The world  of the cable.
256
     * @param pos The position of the cable.
257
     * @param state The blockstate of the cable.
258
     * @param player The player activating the cable.
259
     * @param heldItem The item with which the player is right-clicking.
260
     * @param side The side of the block the player right-clicked on.
261
     * @param cableConnectionHit The side identifying the cable connection that is being activated,
262
     *                           this will be null if the center part of the cable is activated.
263
     * @return Action result.
264
     */
265
    public static InteractionResult onCableActivated(Level world, BlockPos pos, BlockState state, Player player,
266
                                                    ItemStack heldItem, Direction side, @Nullable Direction cableConnectionHit) {
267
        ICable cable = CableHelpers.getCable(world, pos, side).orElse(null);
8✔
268
        if (cable == null) {
2!
269
            return InteractionResult.PASS;
×
270
        }
271

272
        if(WrenchHelpers.isWrench(player, heldItem, world, pos, side)) {
7!
273
            if (world.isClientSide()) {
3!
274
                return InteractionResult.SUCCESS; // Don't do anything client-side
×
275
            }
276
            if (player.isSecondaryUseActive()) {
3✔
277
                removeCable(world, pos, player);
5✔
278
            } else if (cableConnectionHit != null) {
2✔
279
                disconnectCable(world, pos, side, cable, cableConnectionHit);
7✔
280
            } else if (cableConnectionHit == null) {
2!
281
                // Reconnect cable side
282
                BlockPos neighbourPos = pos.relative(side);
4✔
283
                ICable neighbourCable = CableHelpers.getCable(world, neighbourPos, side.getOpposite()).orElse(null);
9✔
284
                if(neighbourCable != null && !cable.isConnected(side) &&
9!
285
                        (cable.canConnect(neighbourCable, side) || neighbourCable.canConnect(cable, side.getOpposite()))
8!
286
                        ) {
287
                    // Notify the reconnection in the part entity of this and the neighbour block,
288
                    // since we don't know in which one the disconnection was made.
289
                    cable.reconnect(side);
3✔
290
                    neighbourCable.reconnect(side.getOpposite());
4✔
291

292
                    // Signal changes
293
                    cable.updateConnections();
2✔
294
                    Collection<Direction> sidesToUpdate = getCableConnections(cable);
3✔
295
                    sidesToUpdate.add(side);
4✔
296
                    CableHelpers.updateConnectionsNeighbours(world, pos, sidesToUpdate);
4✔
297

298
                    // Reinit the networks for this block and the connected neighbour.
299
                    NetworkHelpers.initNetwork(world, pos, side);
5✔
300
                    NetworkHelpers.initNetwork(world, neighbourPos, side.getOpposite());
6✔
301
                }
302
            }
303
            return InteractionResult.SUCCESS;
2✔
304
        }
305
        return InteractionResult.PASS;
×
306
    }
307

308
    private static WeakReference<LivingEntity> CABLE_PLACER_SNAPSHOT = new WeakReference<>(null);
5✔
309

310
    /**
311
     * This should be called when a cable is added.
312
     * This method automatically notifies the neighbours and (re-)initializes the network if this cable carries one.
313
     * This should in most cases only be called server-side.
314
     * @param world The world.
315
     * @param pos The position.
316
     */
317
    public static void onCableAdded(Level world, BlockPos pos) {
318
        LivingEntity placer = CABLE_PLACER_SNAPSHOT.get();
4✔
319
        if (placer != null) {
2✔
320
            CableHelpers.onCableAddedByPlayer(world, pos, placer);
4✔
321
            CABLE_PLACER_SNAPSHOT = new WeakReference<>(null);
6✔
322
        } else {
323
            onCableAddedByPlayerActual(world, pos, null);
4✔
324
        }
325
    }
1✔
326

327
    /**
328
     * This should be called when a cable was added by a player.
329
     * This should be called after {@link CableHelpers#onCableAdded(Level, BlockPos)}.
330
     * It simply emits an player-sensitive init event on the network bus.
331
     * @param world The world.
332
     * @param pos The position.
333
     * @param placer The entity who placed the cable.
334
     */
335
    public static void onCableAddedByPlayer(Level world, BlockPos pos, @Nullable LivingEntity placer) {
336
        if (world.captureBlockSnapshots) {
3✔
337
            CABLE_PLACER_SNAPSHOT = new WeakReference<>(placer);
6✔
338
        } else {
339
            onCableAddedByPlayerActual(world, pos, placer);
4✔
340
        }
341
    }
1✔
342

343
    /**
344
     * This should be called when a cable was added by a player.
345
     * This should be called after {@link CableHelpers#onCableAdded(Level, BlockPos)}.
346
     * It simply emits an player-sensitive init event on the network bus.
347
     * @param world The world.
348
     * @param pos The position.
349
     * @param placer The entity who placed the cable.
350
     */
351
    public static void onCableAddedByPlayerActual(Level world, BlockPos pos, @Nullable LivingEntity placer) {
352
        CableHelpers.updateConnectionsNeighbours(world, pos, CableHelpers.ALL_SIDES);
4✔
353
        if(!world.isClientSide()) {
3!
354
            NetworkHelpers.initNetwork(world, pos, null)
8✔
355
                    .ifPresent(network -> NeoForge.EVENT_BUS.post(new NetworkInitializedEvent(network, world, pos, placer)));
12✔
356
        }
357
    }
1✔
358

359
    /**
360
     * This should be called when a cable is being removed, while the part entity is still present.
361
     * This method won't do anything when called client-side.
362
     * @param world The world.
363
     * @param pos The position.
364
     * @param dropMainElement If the main part element should be dropped.
365
     * @param saveState If the element state should be saved in the item.
366
     * @return If the cable was removed from the network.
367
     */
368
    @Deprecated // TODO: rm in next major
369
    public static boolean onCableRemoving(Level world, BlockPos pos, boolean dropMainElement, boolean saveState, BlockState blockState) {
370
        return onCableRemoving(world, pos, dropMainElement, saveState, blockState, false);
×
371
    }
372

373
    /**
374
     * This should be called when a cable is being removed, while the part entity is still present.
375
     * This method won't do anything when called client-side.
376
     * @param world The world.
377
     * @param pos The position.
378
     * @param dropMainElement If the main part element should be dropped.
379
     * @param saveState If the element state should be saved in the item.
380
     * @param isMoving If the cable is being moved to another location. If false, items won't be dropped.
381
     * @return If the cable was removed from the network.
382
     */
383
    public static boolean onCableRemoving(Level world, BlockPos pos, boolean dropMainElement, boolean saveState, BlockState blockState, boolean isMoving) {
384
        if (!world.isClientSide() && CableHelpers.isNoFakeCable(world, pos, null)) {
8!
385
            INetworkCarrier networkCarrier = NetworkHelpers.getNetworkCarrier(world, pos, null, blockState).orElse(null);
9✔
386

387
            // Get all drops from the network elements this cable provides.
388
            if (!isMoving) {
2!
389
                List<ItemStack> itemStacks = Lists.newLinkedList();
2✔
390
                INetworkElementProvider networkElementProvider = NetworkHelpers.getNetworkElementProvider(world, pos, null, blockState).orElse(null);
9✔
391
                if (networkElementProvider != null) {
2!
392
                    for (INetworkElement networkElement : networkElementProvider.createNetworkElements(world, pos)) {
13✔
393
                        networkElement.addDrops(blockState, itemStacks, dropMainElement, saveState);
6✔
394
                    }
1✔
395
                    for (ItemStack itemStack : itemStacks) {
10✔
396
                        Block.popResource(world, pos, itemStack);
4✔
397
                    }
1✔
398
                }
399
            }
400

401
            // If the cable has a network, remove it from the network.
402
            if(networkCarrier != null && networkCarrier.getNetwork() != null) {
5!
403
                IPathElement pathElement = getPathElement(world, pos, null, blockState)
6✔
404
                        .orElseThrow(() -> new IllegalStateException("Could not find a valid path element capability"));
3✔
405
                INetwork network = networkCarrier.getNetwork();
3✔
406
                networkCarrier.setNetwork(null);
3✔
407
                return network.removePathElement(pathElement, null, blockState);
6✔
408
            }
409
        }
410
        return true;
2✔
411
    }
412

413
    /**
414
     * This should be called AFTER a cable is removed, at this stage the part entity will not exist anymore.
415
     * This method won't do anything when called client-side.
416
     * @param world The world.
417
     * @param pos The position.
418
     * @param sides The sides to update connections for.
419
     * @return If the cable was removed from the network.
420
     */
421
    public static boolean onCableRemoved(Level world, BlockPos pos, Collection<Direction> sides) {
422
        updateConnectionsNeighbours(world, pos, sides);
4✔
423
        if (!world.isClientSide()) {
3!
424
            // Reinit neighbouring networks.
425
            for(Direction side : sides) {
10✔
426
                BlockPos sidePos = pos.relative(side);
4✔
427
                NetworkHelpers.initNetwork(world, sidePos, side.getOpposite());
6✔
428
            }
1✔
429
        }
430
        return true;
2✔
431
    }
432

433
    private static boolean removingCable = false;
3✔
434
    /**
435
     * @return If {@link #removeCable} is currently being called.
436
     */
437
    public static boolean isRemovingCable() {
438
        return removingCable;
2✔
439
    }
440
    /**
441
     * @param removingCable If the removing cable flag should be set
442
     */
443
    public static void setRemovingCable(boolean removingCable) {
444
        CableHelpers.removingCable = removingCable;
2✔
445
    }
1✔
446

447
    /**
448
     * Remove a cable.
449
     * This will automatically handle sounds, drops,
450
     * fakeable cables, network element removal and network (re)intialization.
451
     * @param world The world.
452
     * @param pos The position.
453
     * @param player The player removing the cable or null.
454
     */
455
    public static void removeCable(Level world, BlockPos pos, @Nullable Player player) {
456
        removingCable = true;
2✔
457
        ICable cable = getCable(world, pos, null).orElse(null);
8✔
458
        ICableFakeable cableFakeable = getCableFakeable(world, pos, null).orElse(null);
8✔
459
        IPartContainer partContainer = PartHelpers.getPartContainer(world, pos, null).orElse(null);
8✔
460
        BlockState blockState = world.getBlockState(pos);
4✔
461
        if (cable == null) {
2!
462
            removingCable = false;
×
463
            return;
×
464
        }
465

466
        Collection<Direction> connectedCables = getCableConnections(cable);
3✔
467
        CableHelpers.onCableRemoving(world, pos, false, false, blockState, false);
8✔
468
        // If the cable has no parts or is not fakeable, remove the block,
469
        // otherwise mark the cable as being fake.
470
        if (cableFakeable == null || partContainer == null || !partContainer.hasParts()) {
7!
471
            cable.destroy();
3✔
472
        } else {
473
            cableFakeable.setRealCable(false);
3✔
474
        }
475
        if (player == null) {
2!
476
            ItemStackHelpers.spawnItemStack(world, pos, cable.getItemStack());
×
477
        } else if (!player.isCreative()) {
3!
478
            ItemStackHelpers.spawnItemStackToPlayer(world, pos, cable.getItemStack(), player);
6✔
479
        }
480
        CableHelpers.onCableRemoved(world, pos, connectedCables);
5✔
481

482
        ItemBlockCable.playBreakSound(world, pos, blockState);
4✔
483

484
        removingCable = false;
2✔
485
    }
1✔
486

487
    /**
488
     * Check if the target has a facade.
489
     * @param world The world.
490
     * @param pos The position.
491
     * @return If it has a facade.
492
     */
493
    @Deprecated // TODO: attempt to migrate all calls to method with BlockState param
494
    public static boolean hasFacade(ILevelExtension world, BlockPos pos) {
495
        return BlockEntityHelpers.getCapability(world, pos, null, Capabilities.Facadeable.BLOCK)
×
496
                .map(IFacadeable::hasFacade)
×
497
                .orElse(false);
×
498
    }
499

500
    /**
501
     * Check if the target has a facade.
502
     * @param world The world.
503
     * @param pos The position.
504
     * @param blockState The block state.
505
     * @return If it has a facade.
506
     */
507
    public static boolean hasFacade(ILevelExtension world, BlockPos pos, BlockState blockState) {
508
        return Optional.ofNullable(world.getCapability(Capabilities.Facadeable.BLOCK, pos, blockState, null, null))
11✔
509
                .map(IFacadeable::hasFacade)
2✔
510
                .orElse(false);
4✔
511
    }
512

513
    /**
514
     * Get the target's facade
515
     * @param world The world.
516
     * @param pos The position.
517
     * @return The optional facade.
518
     */
519
    @Deprecated // TODO: attempt to migrate all calls to method with BlockState param
520
    public static Optional<BlockState> getFacade(ILevelExtension world, BlockPos pos) {
521
        return BlockEntityHelpers.getCapability(world, pos, null, Capabilities.Facadeable.BLOCK)
7✔
522
                .flatMap(facadeable -> Optional.ofNullable(facadeable.getFacade()));
5✔
523
    }
524

525
    /**
526
     * Get the target's facade
527
     * @param world The world.
528
     * @param pos The position.
529
     * @param blockState The block state.
530
     * @return The optional facade.
531
     */
532
    public static Optional<BlockState> getFacade(ILevelExtension world, BlockPos pos, BlockState blockState) {
533
        return Optional.ofNullable(world.getCapability(Capabilities.Facadeable.BLOCK, pos, blockState, null, null))
11✔
534
                .flatMap(facadeable -> Optional.ofNullable(facadeable.getFacade()));
5✔
535
    }
536

537
    /**
538
     * Get the target's facade from {@link BlockEntityMultipartTicking} without going through capabilities.
539
     * This is necessary because some BlockColor's rely on BlockGetter, which do not support capabilities.
540
     * @param world The world.
541
     * @param pos The position.
542
     * @return The optional facade.
543
     */
544
    public static Optional<BlockState> getFacadeMultipartTicking(BlockGetter world, BlockPos pos) {
545
        return IModHelpers.get().getBlockEntityHelpers().get(world, pos, BlockEntityMultipartTicking.class)
×
546
                .flatMap(blockEntity -> Optional.ofNullable(new FacadeableTileMultipartTicking(blockEntity).getFacade()));
×
547
    }
548

549
    @Deprecated // TODO: attempt to migrate all calls to method with BlockState param
550
    public static boolean isLightTransparent(Level world, BlockPos pos, @Nullable Direction side) {
551
        return PartHelpers.getPartContainer(world, pos, side)
×
552
                .map(partContainer -> {
×
553
                    for (Map.Entry<Direction, IPartType<?, ?>> entry : partContainer.getParts().entrySet()) {
×
554
                        IPartType part = entry.getValue();
×
555
                        if (part.forceLightTransparency(partContainer.getPartState(entry.getKey()))) {
×
556
                            return true;
×
557
                        }
558
                    }
×
559
                    return false;
×
560
                })
561
                .orElse(false);
×
562
    }
563

564
    public static boolean isLightTransparent(Level world, BlockPos pos, @Nullable Direction side, BlockState blockState) {
565
        return PartHelpers.getPartContainer(world, pos, side, blockState)
7✔
566
                .map(partContainer -> {
2✔
567
                    for (Map.Entry<Direction, IPartType<?, ?>> entry : partContainer.getParts().entrySet()) {
12✔
568
                        IPartType part = entry.getValue();
4✔
569
                        if (part.forceLightTransparency(partContainer.getPartState(entry.getKey()))) {
8!
570
                            return true;
×
571
                        }
572
                    }
1✔
573
                    return false;
3✔
574
                })
575
                .orElse(false);
4✔
576
    }
577

578
    /**
579
     * Get the sides the cable is currently connected to.
580
     * @param cable A cable.
581
     * @return The cable connections.
582
     */
583
    public static Collection<Direction> getCableConnections(ICable cable) {
584
        Collection<Direction> sides = Sets.newIdentityHashSet();
2✔
585
        for (Direction side : Direction.values()) {
16✔
586
            if (cable.isConnected(side)) {
4✔
587
                sides.add(side);
4✔
588
            }
589
        }
590
        return sides;
2✔
591
    }
592

593
    /**
594
     * Get the sides that are externally connected to the given position.
595
     * @param world The world.
596
     * @param pos The position.
597
     * @return The sides.
598
     */
599
    public static Collection<Direction> getExternallyConnectedCables(Level world, BlockPos pos) {
600
        Collection<Direction> sides = Sets.newIdentityHashSet();
2✔
601
        for (Direction side : Direction.values()) {
16✔
602
            if (CableHelpers.isCableConnected(world, pos.relative(side), side.getOpposite(), null)) {
9✔
603
                sides.add(side);
4✔
604
            }
605
        }
606
        return sides;
2✔
607
    }
608
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc