• 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

7.08
/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.nbt.CompoundTag;
8
import net.minecraft.nbt.Tag;
9
import net.minecraft.network.Connection;
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.minecraft.world.level.redstone.ExperimentalRedstoneUtils;
14
import net.minecraft.world.level.redstone.Orientation;
15
import net.minecraft.world.level.storage.ValueInput;
16
import net.minecraft.world.level.storage.ValueOutput;
17
import net.neoforged.fml.ModLoader;
18
import net.neoforged.neoforge.capabilities.BlockCapability;
19
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
20
import net.neoforged.neoforge.model.data.ModelData;
21
import org.cyclops.cyclopscore.blockentity.BlockEntityTickerDelayed;
22
import org.cyclops.cyclopscore.blockentity.CyclopsBlockEntity;
23
import org.cyclops.cyclopscore.datastructure.DimPos;
24
import org.cyclops.cyclopscore.datastructure.EnumFacingMap;
25
import org.cyclops.cyclopscore.helper.IModHelpers;
26
import org.cyclops.cyclopscore.persist.nbt.NBTPersist;
27
import org.cyclops.integrateddynamics.Capabilities;
28
import org.cyclops.integrateddynamics.RegistryEntries;
29
import org.cyclops.integrateddynamics.api.block.IFacadeable;
30
import org.cyclops.integrateddynamics.api.block.cable.ICableFakeable;
31
import org.cyclops.integrateddynamics.api.network.INetwork;
32
import org.cyclops.integrateddynamics.api.network.INetworkCarrier;
33
import org.cyclops.integrateddynamics.api.network.INetworkElement;
34
import org.cyclops.integrateddynamics.api.network.IPartNetwork;
35
import org.cyclops.integrateddynamics.api.part.PartCapability;
36
import org.cyclops.integrateddynamics.api.part.PartPos;
37
import org.cyclops.integrateddynamics.api.part.PartRenderPosition;
38
import org.cyclops.integrateddynamics.api.part.PartTarget;
39
import org.cyclops.integrateddynamics.block.BlockCable;
40
import org.cyclops.integrateddynamics.capability.cable.CableFakeableMultipartTicking;
41
import org.cyclops.integrateddynamics.capability.cable.CableTileMultipartTicking;
42
import org.cyclops.integrateddynamics.capability.dynamiclight.DynamicLightTileMultipartTicking;
43
import org.cyclops.integrateddynamics.capability.dynamicredstone.DynamicRedstoneTileMultipartTicking;
44
import org.cyclops.integrateddynamics.capability.facadeable.FacadeableDefault;
45
import org.cyclops.integrateddynamics.capability.facadeable.FacadeableTileMultipartTicking;
46
import org.cyclops.integrateddynamics.capability.network.NetworkCarrierDefault;
47
import org.cyclops.integrateddynamics.capability.networkelementprovider.NetworkElementProviderPartContainer;
48
import org.cyclops.integrateddynamics.capability.partcontainer.PartContainerTileMultipartTicking;
49
import org.cyclops.integrateddynamics.capability.path.PathElementTileMultipartTicking;
50
import org.cyclops.integrateddynamics.client.model.CableRenderState;
51
import org.cyclops.integrateddynamics.core.helper.CableHelpers;
52
import org.cyclops.integrateddynamics.core.helper.NetworkHelpers;
53
import org.cyclops.integrateddynamics.core.helper.PartHelpers;
54
import org.cyclops.integrateddynamics.core.part.event.RegisterPartCapabilitiesEvent;
55

56
import java.util.Map;
57
import java.util.Objects;
58
import java.util.Optional;
59

60
/**
61
 * A ticking part entity which is made up of different parts.
62
 * @author Ruben Taelman
63
 */
64
public class BlockEntityMultipartTicking extends CyclopsBlockEntity implements PartHelpers.IPartStateHolderCallback {
65

66
    @Getter
×
67
    @NBTPersist private EnumFacingMap<Boolean> connected = EnumFacingMap.newMap();
×
68
    @NBTPersist private EnumFacingMap<Boolean> forceDisconnected = EnumFacingMap.newMap();
×
69
    @Getter
×
70
    @NBTPersist private EnumFacingMap<Integer> redstoneLevels = EnumFacingMap.newMap();
×
71
    @Getter
×
72
    @NBTPersist private EnumFacingMap<Boolean> redstoneInputs = EnumFacingMap.newMap();
×
73
    @Getter
×
74
    @NBTPersist private EnumFacingMap<Boolean> redstoneStrong = EnumFacingMap.newMap();
×
75
    @Getter
×
76
    @NBTPersist private EnumFacingMap<Integer> lastRedstonePulses = EnumFacingMap.newMap();
×
77
    @Getter
×
78
    @NBTPersist private EnumFacingMap<Integer> lightLevels = EnumFacingMap.newMap();
×
79
    private EnumFacingMap<Integer> previousLightLevels;
80
    @Getter
×
81
    @Setter
×
82
    @NBTPersist private CompoundTag facadeBlockTag = null;
83

84
    @Getter
×
85
    private final PartContainerTileMultipartTicking partContainer;
86
    @Getter
×
87
    private final CableTileMultipartTicking cable;
88
    @Getter
×
89
    private final INetworkCarrier networkCarrier;
90
    @Getter
×
91
    private final ICableFakeable cableFakeable;
92
    @NBTPersist
93
    @Setter
×
94
    private boolean forceLightCheckAtClient;
95

96
    private ModelData cachedState = null;
×
97

98
    public BlockEntityMultipartTicking(BlockPos blockPos, BlockState blockState) {
99
        super(RegistryEntries.BLOCK_ENTITY_MULTIPART_TICKING.get(), blockPos, blockState);
×
100
        partContainer = new PartContainerTileMultipartTicking(this);
×
101
        cable = new CableTileMultipartTicking(this);
×
102
        networkCarrier = new NetworkCarrierDefault();
×
103
        cableFakeable = new CableFakeableMultipartTicking(this);
×
104
    }
×
105

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

146
        event.registerBlockEntity(
5✔
147
                Capabilities.DynamicLight.BLOCK,
148
                blockEntityType,
149
                DynamicLightTileMultipartTicking::new
150
        );
151
        event.registerBlockEntity(
5✔
152
                Capabilities.DynamicRedstone.BLOCK,
153
                blockEntityType,
154
                DynamicRedstoneTileMultipartTicking::new
155
        );
156
    }
1✔
157

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

175
    @Override
176
    public void saveAdditional(ValueOutput output) {
177
        super.saveAdditional(output);
×
178
        forceLightCheckAtClient = false;
×
179
        partContainer.toValueOutput(output.child("partContainer"));
×
180
        output.putBoolean("realCable", cableFakeable.isRealCable());
×
181
    }
×
182

183
    @Override
184
    public void read(ValueInput input) {
185
        EnumFacingMap<Boolean> lastConnected = EnumFacingMap.newMap(connected);
×
186
        Tag lastFacadeBlock = facadeBlockTag;
×
187
        boolean lastRealCable = cableFakeable.isRealCable();
×
188
        partContainer.fromValueInput(input.child("partContainer").orElseThrow());
×
189
        boolean wasLightTransparent = getLevel() != null && CableHelpers.isLightTransparent(getLevel(), getBlockPos(), null, getBlockState());
×
190

191
        super.read(input);
×
192
        cableFakeable.setRealCable(input.getBooleanOr("realCable", false));
×
193
        boolean isLightTransparent = getLevel() != null && CableHelpers.isLightTransparent(getLevel(), getBlockPos(), null, getBlockState());
×
194
        if (getLevel() != null && (lastConnected == null || connected == null || !lastConnected.equals(connected)
×
195
                || !Objects.equals(lastFacadeBlock, facadeBlockTag)
×
196
                || lastRealCable != cableFakeable.isRealCable() || wasLightTransparent != isLightTransparent)) {
×
197
            IModHelpers.get().getBlockHelpers().markForUpdate(getLevel(), getBlockPos());
×
198
        }
199
    }
×
200

201
    @Override
202
    public void onDataPacket(Connection net, ValueInput valueInput) {
203
        super.onDataPacket(net, valueInput);
×
204
        onUpdateReceived();
×
205
    }
×
206

207
    protected void onUpdateReceived() {
208
        if(!lightLevels.equals(previousLightLevels)) {
×
209
            previousLightLevels = lightLevels;
×
210
        }
211
        cachedState = null;
×
212
        IModHelpers.get().getBlockHelpers().markForUpdate(getLevel(), getBlockPos());
×
213
        if (forceLightCheckAtClient) {
×
214
            getLevel().getLightEngine().checkBlock(getBlockPos());
×
215
        }
216
    }
×
217

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

248
    public void updateRedstoneInfo(Direction side, boolean strongPower) {
249
        this.setChanged();
×
250
        if (getLevel().isLoaded(getBlockPos().relative(side))) {
×
251
            Orientation orientation = ExperimentalRedstoneUtils.initialOrientation(level, side.getOpposite(), null);
×
252
            getLevel().neighborChanged(getBlockPos().relative(side), getBlockState().getBlock(), orientation);
×
253
            if (strongPower) {
×
254
                // When we are emitting a strong power, also update all neighbours of the target
255
                getLevel().updateNeighborsAt(getBlockPos().relative(side), getBlockState().getBlock());
×
256
            }
257
        }
258
    }
×
259

260
    public void updateLightInfo() {
261
        sendUpdate();
×
262
    }
×
263

264
    public INetwork getNetwork() {
265
        return networkCarrier.getNetwork();
×
266
    }
267

268
    @Override
269
    public void onSet(PartHelpers.PartStateHolder<?, ?> partStateHolder) {
270

271
    }
×
272

273
    /**
274
     * @return The raw force disconnection data.
275
     */
276
    public EnumFacingMap<Boolean> getForceDisconnected() {
277
        return this.forceDisconnected;
×
278
    }
279

280
    public void setForceDisconnected(EnumFacingMap<Boolean> forceDisconnected) {
281
        this.forceDisconnected.clear();
×
282
        this.forceDisconnected.putAll(forceDisconnected);
×
283
    }
×
284

285
    @Override
286
    public void onChunkUnloaded() {
287
        super.onChunkUnloaded();
×
288
        invalidateParts();
×
289
    }
×
290

291
    protected void invalidateParts() {
292
        if (getLevel() != null && !getLevel().isClientSide()) {
×
293
            INetwork network = getNetwork();
×
294
            if (network != null) {
×
295
                for (Map.Entry<Direction, PartHelpers.PartStateHolder<?, ?>> entry : partContainer.getPartData().entrySet()) {
×
296
                    INetworkElement element = entry.getValue().getPart().createNetworkElement(getPartContainer(), DimPos.of(getLevel(), getBlockPos()), entry.getKey());
×
297
                    element.invalidate(network);
×
298
                }
×
299
            }
300
        }
301
    }
×
302

303
    @Override
304
    protected Direction transformFacingForRotation(Direction facing) {
305
        // Ignore rotations on this tile
306
        return facing;
×
307
    }
308

309
    @Override
310
    public void preRemoveSideEffects(BlockPos pos, BlockState state) {
311
        super.preRemoveSideEffects(pos, state);
×
312

313
        if (!CableHelpers.isRemovingCable()) {
×
314
            CableHelpers.onCableRemoving(level, pos, false, false, state, this);
×
315
        }
316
    }
×
317

318
    @Override
319
    public void setRemoved() {
320
        // Only required for cases where cables are moved by commands or cleared after game tests.
321
        if (getNetworkCarrier().getNetwork() != null) {
×
322
            CableHelpers.onCableRemovingNetwork(getBlockState(), this, getNetworkCarrier(), new PathElementTileMultipartTicking(this, this.getCable()));
×
323
        }
324

325
        super.setRemoved();
×
326
    }
×
327

328
    public static class Ticker<T extends BlockEntityMultipartTicking> extends BlockEntityTickerDelayed<T> {
×
329
        @Override
330
        protected void update(Level level, BlockPos pos, BlockState blockState, T blockEntity) {
331
            super.update(level, pos, blockState, blockEntity);
×
332

333
            if (blockEntity.getConnected().isEmpty()) {
×
334
                blockEntity.getCable().updateConnections();
×
335
            }
336
            blockEntity.getPartContainer().update();
×
337

338
            // Revalidate network if that hasn't happened yet
339
            if (blockEntity.getNetwork() == null) {
×
340
                NetworkHelpers.revalidateNetworkElements(level, pos);
×
341
            }
342
        }
×
343
    }
344
}
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