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

CyclopsMC / IntegratedDynamics / 19640651880

24 Nov 2025 03:59PM UTC coverage: 44.824% (-0.3%) from 45.13%
19640651880

push

github

rubensworks
Bump mod version

2581 of 8552 branches covered (30.18%)

Branch coverage included in aggregate %.

11789 of 23507 relevant lines covered (50.15%)

2.38 hits per line

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

51.53
/src/main/java/org/cyclops/integrateddynamics/core/blockentity/BlockEntityMultipartTicking.java
1
package org.cyclops.integrateddynamics.core.blockentity;
2

3
import lombok.Getter;
4
import lombok.Setter;
5
import net.minecraft.core.BlockPos;
6
import net.minecraft.core.Direction;
7
import net.minecraft.core.HolderLookup;
8
import net.minecraft.nbt.CompoundTag;
9
import net.minecraft.nbt.Tag;
10
import net.minecraft.world.level.Level;
11
import net.minecraft.world.level.block.entity.BlockEntityType;
12
import net.minecraft.world.level.block.state.BlockState;
13
import net.neoforged.fml.ModLoader;
14
import net.neoforged.neoforge.capabilities.BlockCapability;
15
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
16
import net.neoforged.neoforge.client.model.data.ModelData;
17
import org.cyclops.cyclopscore.blockentity.BlockEntityTickerDelayed;
18
import org.cyclops.cyclopscore.blockentity.CyclopsBlockEntity;
19
import org.cyclops.cyclopscore.datastructure.DimPos;
20
import org.cyclops.cyclopscore.datastructure.EnumFacingMap;
21
import org.cyclops.cyclopscore.helper.BlockHelpers;
22
import org.cyclops.cyclopscore.persist.nbt.NBTPersist;
23
import org.cyclops.integrateddynamics.Capabilities;
24
import org.cyclops.integrateddynamics.RegistryEntries;
25
import org.cyclops.integrateddynamics.api.block.IFacadeable;
26
import org.cyclops.integrateddynamics.api.block.cable.ICableFakeable;
27
import org.cyclops.integrateddynamics.api.network.INetwork;
28
import org.cyclops.integrateddynamics.api.network.INetworkCarrier;
29
import org.cyclops.integrateddynamics.api.network.INetworkElement;
30
import org.cyclops.integrateddynamics.api.network.IPartNetwork;
31
import org.cyclops.integrateddynamics.api.part.PartCapability;
32
import org.cyclops.integrateddynamics.api.part.PartPos;
33
import org.cyclops.integrateddynamics.api.part.PartRenderPosition;
34
import org.cyclops.integrateddynamics.api.part.PartTarget;
35
import org.cyclops.integrateddynamics.block.BlockCable;
36
import org.cyclops.integrateddynamics.capability.cable.CableFakeableMultipartTicking;
37
import org.cyclops.integrateddynamics.capability.cable.CableTileMultipartTicking;
38
import org.cyclops.integrateddynamics.capability.dynamiclight.DynamicLightTileMultipartTicking;
39
import org.cyclops.integrateddynamics.capability.dynamicredstone.DynamicRedstoneTileMultipartTicking;
40
import org.cyclops.integrateddynamics.capability.facadeable.FacadeableDefault;
41
import org.cyclops.integrateddynamics.capability.facadeable.FacadeableTileMultipartTicking;
42
import org.cyclops.integrateddynamics.capability.network.NetworkCarrierDefault;
43
import org.cyclops.integrateddynamics.capability.networkelementprovider.NetworkElementProviderPartContainer;
44
import org.cyclops.integrateddynamics.capability.partcontainer.PartContainerTileMultipartTicking;
45
import org.cyclops.integrateddynamics.capability.path.PathElementTileMultipartTicking;
46
import org.cyclops.integrateddynamics.client.model.CableRenderState;
47
import org.cyclops.integrateddynamics.core.helper.CableHelpers;
48
import org.cyclops.integrateddynamics.core.helper.NetworkHelpers;
49
import org.cyclops.integrateddynamics.core.helper.PartHelpers;
50
import org.cyclops.integrateddynamics.core.part.event.RegisterPartCapabilitiesEvent;
51

52
import java.util.Map;
53
import java.util.Objects;
54
import java.util.Optional;
55

56
/**
57
 * A ticking part entity which is made up of different parts.
58
 * @author Ruben Taelman
59
 */
60
public class BlockEntityMultipartTicking extends CyclopsBlockEntity implements PartHelpers.IPartStateHolderCallback {
61

62
    @Getter
4✔
63
    @NBTPersist private EnumFacingMap<Boolean> connected = EnumFacingMap.newMap();
2✔
64
    @NBTPersist private EnumFacingMap<Boolean> forceDisconnected = EnumFacingMap.newMap();
3✔
65
    @Getter
4✔
66
    @NBTPersist private EnumFacingMap<Integer> redstoneLevels = EnumFacingMap.newMap();
2✔
67
    @Getter
4✔
68
    @NBTPersist private EnumFacingMap<Boolean> redstoneInputs = EnumFacingMap.newMap();
2✔
69
    @Getter
4✔
70
    @NBTPersist private EnumFacingMap<Boolean> redstoneStrong = EnumFacingMap.newMap();
2✔
71
    @Getter
4✔
72
    @NBTPersist private EnumFacingMap<Integer> lastRedstonePulses = EnumFacingMap.newMap();
2✔
73
    @Getter
4✔
74
    @NBTPersist private EnumFacingMap<Integer> lightLevels = EnumFacingMap.newMap();
2✔
75
    private EnumFacingMap<Integer> previousLightLevels;
76
    @Getter
6✔
77
    @Setter
4✔
78
    @NBTPersist private CompoundTag facadeBlockTag = null;
79

80
    @Getter
3✔
81
    private final PartContainerTileMultipartTicking partContainer;
82
    @Getter
3✔
83
    private final CableTileMultipartTicking cable;
84
    @Getter
3✔
85
    private final INetworkCarrier networkCarrier;
86
    @Getter
3✔
87
    private final ICableFakeable cableFakeable;
88
    @NBTPersist
89
    @Setter
4✔
90
    private boolean forceLightCheckAtClient;
91

92
    private ModelData cachedState = null;
3✔
93

94
    public BlockEntityMultipartTicking(BlockPos blockPos, BlockState blockState) {
95
        super(RegistryEntries.BLOCK_ENTITY_MULTIPART_TICKING.get(), blockPos, blockState);
7✔
96
        partContainer = new PartContainerTileMultipartTicking(this);
6✔
97
        cable = new CableTileMultipartTicking(this);
6✔
98
        networkCarrier = new NetworkCarrierDefault();
5✔
99
        cableFakeable = new CableFakeableMultipartTicking(this);
6✔
100
    }
1✔
101

102
    public static void registerMultipartTickingCapabilities(RegisterCapabilitiesEvent event, BlockEntityType<? extends BlockEntityMultipartTicking> blockEntityType) {
103
        event.registerBlockEntity(
5✔
104
                Capabilities.PartContainer.BLOCK,
105
                blockEntityType,
106
                (blockEntity, context) -> blockEntity.getPartContainer()
3✔
107
        );
108
        event.registerBlockEntity(
5✔
109
                Capabilities.NetworkElementProvider.BLOCK,
110
                blockEntityType,
111
                (blockEntity, context) -> new NetworkElementProviderPartContainer(blockEntity.getPartContainer())
6✔
112
        );
113
        event.registerBlockEntity(
5✔
114
                Capabilities.Facadeable.BLOCK,
115
                blockEntityType,
116
                (blockEntity, context) -> new FacadeableTileMultipartTicking(blockEntity)
5✔
117
        );
118
        event.registerBlockEntity(
5✔
119
                Capabilities.Cable.BLOCK,
120
                blockEntityType,
121
                (blockEntity, context) -> blockEntity.getCable()
3✔
122
        );
123
        event.registerBlockEntity(
5✔
124
                Capabilities.NetworkCarrier.BLOCK,
125
                blockEntityType,
126
                (blockEntity, context) -> blockEntity.getNetworkCarrier()
3✔
127
        );
128
        event.registerBlockEntity(
5✔
129
                Capabilities.CableFakeable.BLOCK,
130
                blockEntityType,
131
                (blockEntity, context) -> blockEntity.getCableFakeable()
3✔
132
        );
133
        event.registerBlockEntity(
5✔
134
                Capabilities.PathElement.BLOCK,
135
                blockEntityType,
136
                (blockEntity, context) -> new PathElementTileMultipartTicking(blockEntity, blockEntity.getCable())
7✔
137
        );
138
        registerPartCapabilityAsBlockCapability(event, blockEntityType, Capabilities.ValueInterface.BLOCK, Capabilities.ValueInterface.PART);
5✔
139
        registerPartCapabilityAsBlockCapability(event, blockEntityType, Capabilities.VariableContainer.BLOCK, Capabilities.VariableContainer.PART);
5✔
140
        ModLoader.postEventWrapContainerInModOrder(new RegisterPartCapabilitiesEvent(event, blockEntityType));
6✔
141

142
        event.registerBlockEntity(
5✔
143
                Capabilities.DynamicLight.BLOCK,
144
                blockEntityType,
145
                DynamicLightTileMultipartTicking::new
146
        );
147
        event.registerBlockEntity(
5✔
148
                Capabilities.DynamicRedstone.BLOCK,
149
                blockEntityType,
150
                DynamicRedstoneTileMultipartTicking::new
151
        );
152
    }
1✔
153

154
    public static <T> void registerPartCapabilityAsBlockCapability(RegisterCapabilitiesEvent event, BlockEntityType<? extends BlockEntityMultipartTicking> blockEntityType, BlockCapability<T, Direction> blockCapability, PartCapability<T> partCapability) {
155
        event.registerBlockEntity(
6✔
156
                blockCapability,
157
                blockEntityType,
158
                (blockEntity, context) -> {
159
                    INetwork network = blockEntity.getNetwork();
3✔
160
                    if (network != null) {
2!
161
                        IPartNetwork partNetwork = NetworkHelpers.getPartNetworkChecked(network);
3✔
162
                        return blockEntity.getPartContainer()
7✔
163
                                .getCapability(partCapability, network, partNetwork, PartTarget.fromCenter(PartPos.of(blockEntity.getLevel(), blockEntity.getBlockPos(), context)))
8✔
164
                                .orElse(null);
1✔
165
                    }
166
                    return null;
×
167
                }
168
        );
169
    }
1✔
170

171
    @Override
172
    public void saveAdditional(CompoundTag tag, HolderLookup.Provider provider) {
173
        super.saveAdditional(tag, provider);
4✔
174
        forceLightCheckAtClient = false;
3✔
175
        tag.put("partContainer", partContainer.serializeNBT(provider));
8✔
176
        tag.putBoolean("realCable", cableFakeable.isRealCable());
6✔
177
    }
1✔
178

179
    @Override
180
    public void read(CompoundTag tag, HolderLookup.Provider provider) {
181
        EnumFacingMap<Boolean> lastConnected = EnumFacingMap.newMap(connected);
×
182
        Tag lastFacadeBlock = facadeBlockTag;
×
183
        boolean lastRealCable = cableFakeable.isRealCable();
×
184
        partContainer.deserializeNBT(provider, tag.getCompound("partContainer"));
×
185
        boolean wasLightTransparent = getLevel() != null && CableHelpers.isLightTransparent(getLevel(), getBlockPos(), null);
×
186

187
        super.read(tag, provider);
×
188
        cableFakeable.setRealCable(tag.getBoolean("realCable"));
×
189
        boolean isLightTransparent = getLevel() != null && CableHelpers.isLightTransparent(getLevel(), getBlockPos(), null);
×
190
        if (getLevel() != null && (lastConnected == null || connected == null || !lastConnected.equals(connected)
×
191
                || !Objects.equals(lastFacadeBlock, facadeBlockTag)
×
192
                || lastRealCable != cableFakeable.isRealCable() || wasLightTransparent != isLightTransparent)) {
×
193
            BlockHelpers.markForUpdate(getLevel(), getBlockPos());
×
194
        }
195
    }
×
196

197
    @Override
198
    public void onUpdateReceived() {
199
        if(!lightLevels.equals(previousLightLevels)) {
×
200
            previousLightLevels = lightLevels;
×
201
        }
202
        cachedState = null;
×
203
        BlockHelpers.markForUpdate(getLevel(), getBlockPos());
×
204
        if (forceLightCheckAtClient) {
×
205
            getLevel().getLightEngine().checkBlock(getBlockPos());
×
206
        }
207
    }
×
208

209
    public ModelData getConnectionState() {
210
        if (cachedState != null) {
×
211
            return cachedState;
×
212
        }
213
        ModelData.Builder builder = ModelData.builder();
×
214
        if (partContainer.getPartData() != null) { // Can be null in rare cases where rendering happens before data sync
×
215
            builder.with(BlockCable.REALCABLE, cableFakeable.isRealCable());
×
216
            if (connected.isEmpty()) {
×
217
                getCable().updateConnections(false);
×
218
            }
219
            for (Direction side : Direction.values()) {
×
220
                builder.with(BlockCable.CONNECTED[side.ordinal()],
×
221
                        !cable.isForceDisconnected(side) && connected.get(side));
×
222
                builder.with(BlockCable.PART_RENDERPOSITIONS[side.ordinal()],
×
223
                        partContainer.hasPart(side) ? partContainer.getPart(side).getPartRenderPosition() : PartRenderPosition.NONE);
×
224
            }
225
            IFacadeable facadeable = Optional.ofNullable(level.getCapability(Capabilities.Facadeable.BLOCK, getBlockPos(), getBlockState(), this, null))
×
226
                    .orElseGet(FacadeableDefault::new);
×
227
            builder.with(BlockCable.FACADE, facadeable.hasFacade() ? Optional.of(facadeable.getFacade()) : Optional.empty());
×
228
            builder.with(BlockCable.PARTCONTAINER, partContainer);
×
229
            builder.with(BlockCable.RENDERSTATE, new CableRenderState(
×
230
                    this.cableFakeable.isRealCable(),
×
231
                    EnumFacingMap.newMap(this.connected),
×
232
                    EnumFacingMap.newMap(this.partContainer.getPartData()),
×
233
                    facadeBlockTag
234
                    ));
235
        }
236
        return cachedState = builder.build();
×
237
    }
238

239
    public void updateRedstoneInfo(Direction side, boolean strongPower) {
240
        this.setChanged();
2✔
241
        if (getLevel().isLoaded(getBlockPos().relative(side))) {
8!
242
            getLevel().neighborChanged(getBlockPos().relative(side), getBlockState().getBlock(), getBlockPos());
12✔
243
            if (strongPower) {
2✔
244
                // When we are emitting a strong power, also update all neighbours of the target
245
                getLevel().updateNeighborsAt(getBlockPos().relative(side), getBlockState().getBlock());
10✔
246
            }
247
        }
248
    }
1✔
249

250
    public void updateLightInfo() {
251
        sendUpdate();
×
252
    }
×
253

254
    public INetwork getNetwork() {
255
        return networkCarrier.getNetwork();
4✔
256
    }
257

258
    @Override
259
    public void onSet(PartHelpers.PartStateHolder<?, ?> partStateHolder) {
260

261
    }
×
262

263
    /**
264
     * @return The raw force disconnection data.
265
     */
266
    public EnumFacingMap<Boolean> getForceDisconnected() {
267
        return this.forceDisconnected;
3✔
268
    }
269

270
    public void setForceDisconnected(EnumFacingMap<Boolean> forceDisconnected) {
271
        this.forceDisconnected.clear();
×
272
        this.forceDisconnected.putAll(forceDisconnected);
×
273
    }
×
274

275
    @Override
276
    public void onChunkUnloaded() {
277
        super.onChunkUnloaded();
2✔
278
        invalidateParts();
2✔
279
    }
1✔
280

281
    protected void invalidateParts() {
282
        if (getLevel() != null && !getLevel().isClientSide) {
7!
283
            INetwork network = getNetwork();
3✔
284
            if (network != null) {
2✔
285
                for (Map.Entry<Direction, PartHelpers.PartStateHolder<?, ?>> entry : partContainer.getPartData().entrySet()) {
13✔
286
                    INetworkElement element = entry.getValue().getPart().createNetworkElement(getPartContainer(), DimPos.of(getLevel(), getBlockPos()), entry.getKey());
16✔
287
                    element.invalidate(network);
3✔
288
                }
1✔
289
            }
290
        }
291
    }
1✔
292

293
    @Override
294
    protected Direction transformFacingForRotation(Direction facing) {
295
        // Ignore rotations on this tile
296
        return facing;
×
297
    }
298

299
    public static class Ticker<T extends BlockEntityMultipartTicking> extends BlockEntityTickerDelayed<T> {
3✔
300
        @Override
301
        protected void update(Level level, BlockPos pos, BlockState blockState, T blockEntity) {
302
            super.update(level, pos, blockState, blockEntity);
6✔
303

304
            if (blockEntity.getConnected().isEmpty()) {
4✔
305
                blockEntity.getCable().updateConnections();
3✔
306
            }
307
            blockEntity.getPartContainer().update();
3✔
308

309
            // Revalidate network if that hasn't happened yet
310
            if (blockEntity.getNetwork() == null) {
3✔
311
                NetworkHelpers.revalidateNetworkElements(level, pos);
4✔
312
            }
313
        }
1✔
314
    }
315
}
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