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

CyclopsMC / IntegratedDynamics / 13739195914

08 Mar 2025 03:58PM UTC coverage: 39.059% (+0.06%) from 39.002%
13739195914

push

github

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

1966 of 8373 branches covered (23.48%)

Branch coverage included in aggregate %.

10307 of 23049 relevant lines covered (44.72%)

2.1 hits per line

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

38.07
/src/main/java/org/cyclops/integrateddynamics/core/part/panel/PartTypePanelVariableDriven.java
1
package org.cyclops.integrateddynamics.core.part.panel;
2

3
import com.google.common.collect.Lists;
4
import lombok.Getter;
5
import lombok.Setter;
6
import net.minecraft.ChatFormatting;
7
import net.minecraft.core.BlockPos;
8
import net.minecraft.core.Direction;
9
import net.minecraft.nbt.CompoundTag;
10
import net.minecraft.nbt.Tag;
11
import net.minecraft.network.RegistryFriendlyByteBuf;
12
import net.minecraft.network.chat.Component;
13
import net.minecraft.network.chat.MutableComponent;
14
import net.minecraft.resources.ResourceLocation;
15
import net.minecraft.server.level.ServerPlayer;
16
import net.minecraft.world.InteractionHand;
17
import net.minecraft.world.InteractionResult;
18
import net.minecraft.world.MenuProvider;
19
import net.minecraft.world.entity.player.Inventory;
20
import net.minecraft.world.entity.player.Player;
21
import net.minecraft.world.inventory.AbstractContainerMenu;
22
import net.minecraft.world.item.ItemStack;
23
import net.minecraft.world.level.Level;
24
import net.minecraft.world.level.block.Block;
25
import net.minecraft.world.level.block.state.BlockBehaviour;
26
import net.minecraft.world.level.block.state.BlockState;
27
import net.minecraft.world.phys.BlockHitResult;
28
import org.apache.commons.lang3.tuple.Triple;
29
import org.cyclops.cyclopscore.config.extendedconfig.BlockConfigCommon;
30
import org.cyclops.cyclopscore.helper.IModHelpers;
31
import org.cyclops.integrateddynamics.IntegratedDynamics;
32
import org.cyclops.integrateddynamics.api.evaluate.EvaluationException;
33
import org.cyclops.integrateddynamics.api.evaluate.variable.IValue;
34
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueType;
35
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueTypeListProxy;
36
import org.cyclops.integrateddynamics.api.evaluate.variable.IVariable;
37
import org.cyclops.integrateddynamics.api.evaluate.variable.ValueDeseralizationContext;
38
import org.cyclops.integrateddynamics.api.network.INetwork;
39
import org.cyclops.integrateddynamics.api.network.IPartNetwork;
40
import org.cyclops.integrateddynamics.api.network.event.INetworkEvent;
41
import org.cyclops.integrateddynamics.api.part.IPartContainer;
42
import org.cyclops.integrateddynamics.api.part.IPartTypeActiveVariable;
43
import org.cyclops.integrateddynamics.api.part.PartPos;
44
import org.cyclops.integrateddynamics.api.part.PartTarget;
45
import org.cyclops.integrateddynamics.core.block.IgnoredBlock;
46
import org.cyclops.integrateddynamics.core.block.IgnoredBlockStatus;
47
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueHelpers;
48
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeList;
49
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypes;
50
import org.cyclops.integrateddynamics.core.helper.L10NValues;
51
import org.cyclops.integrateddynamics.core.helper.NetworkHelpers;
52
import org.cyclops.integrateddynamics.core.helper.PartHelpers;
53
import org.cyclops.integrateddynamics.core.helper.WrenchHelpers;
54
import org.cyclops.integrateddynamics.core.network.event.VariableContentsUpdatedEvent;
55
import org.cyclops.integrateddynamics.core.part.PartStateActiveVariableBase;
56
import org.cyclops.integrateddynamics.core.part.PartTypeBase;
57
import org.cyclops.integrateddynamics.inventory.container.ContainerPartPanelVariableDriven;
58

59
import javax.annotation.Nullable;
60
import java.util.List;
61
import java.util.Map;
62
import java.util.Optional;
63

64
/**
65
 * A panel part that is driven by a contained variable.
66
 * @author rubensworks
67
 */
68
public abstract class PartTypePanelVariableDriven<P extends PartTypePanelVariableDriven<P, S>, S extends PartTypePanelVariableDriven.State<P, S>> extends PartTypePanel<P, S> implements IPartTypeActiveVariable<P, S> {
69

70
    public PartTypePanelVariableDriven(String name) {
71
        super(name);
3✔
72
    }
1✔
73

74
    @Override
75
    protected Block createBlock(BlockConfigCommon<?> blockConfig, BlockBehaviour.Properties properties) {
76
        return new IgnoredBlockStatus(properties);
×
77
    }
78

79
    @Override
80
    protected Map<Class<? extends INetworkEvent>, IEventAction> constructNetworkEventActions() {
81
        Map<Class<? extends INetworkEvent>, IEventAction> actions = super.constructNetworkEventActions();
3✔
82
        IEventAction<P, S, INetworkEvent> updateEventListener = (network, target, state, event) -> NetworkHelpers
5✔
83
                .getPartNetwork(network).ifPresent(partNetwork -> onVariableContentsUpdated(partNetwork, target, state));
12✔
84
        actions.put(VariableContentsUpdatedEvent.class, updateEventListener);
5✔
85
        return actions;
2✔
86
    }
87

88
    @Override
89
    public void addDrops(PartTarget target, S state, List<ItemStack> itemStacks, boolean dropMainElement, boolean saveState) {
90
        for(int i = 0; i < state.getInventory().getContainerSize(); i++) {
×
91
            ItemStack itemStack = state.getInventory().getItem(i);
×
92
            if(!itemStack.isEmpty()) {
×
93
                itemStacks.add(itemStack);
×
94
            }
95
        }
96
        state.getInventory().clearContent();
×
97
        state.onVariableContentsUpdated((P) this, target);
×
98
        super.addDrops(target, state, itemStacks, dropMainElement, saveState);
×
99
    }
×
100

101
    @Override
102
    public boolean isUpdate(S state) {
103
        return true;
2✔
104
    }
105

106
    @Override
107
    public void update(INetwork network, IPartNetwork partNetwork, PartTarget target, S state) {
108
        super.update(network, partNetwork, target, state);
6✔
109
        IValue lastValue = state.getDisplayValue();
3✔
110
        IValue newValue = null;
2✔
111
        Level level = target.getCenter().getPos().getLevel(true);
6✔
112
        if(state.hasVariable()) {
3✔
113
            try {
114
                IVariable variable = state.getVariable(network, partNetwork, ValueDeseralizationContext.of(level));
7✔
115
                if(variable != null) {
2✔
116
                    newValue = variable.getValue();
3✔
117

118
                    if (state.isRetryEvaluation()) {
3!
119
                        state.setRetryEvaluation(false);
×
120
                        state.addGlobalError(null);
×
121
                    }
122
                }
123
            } catch (EvaluationException e) {
×
124
                if (!state.isRetryEvaluation()) {
×
125
                    state.addGlobalError(e.getErrorMessage());
×
126
                    if (e.isRetryEvaluation()) {
×
127
                        state.setRetryEvaluation(true);
×
128
                    } else {
129
                        e.addResolutionListeners(() -> state.onVariableContentsUpdated((P) this, target));
×
130
                    }
131
                }
132
            }
1✔
133
        }
134
        if(!ValueHelpers.areValuesEqual(lastValue, newValue)) {
4✔
135
            onValueChanged(network, partNetwork, target, state, lastValue, newValue);
8✔
136

137
            // We can't call state.sendUpdate() here, so we must trigger a block update manually.
138
            // This was the cause of issue #46 which made it so that values that change after one tick are
139
            // NOT sent to the client.
140
            // This was because in each server tick, all tiles are first updated and then the networks.
141
            // Since sendUpdate marks a flag for the part to update, this caused a loss of one tick.
142
            // For example:
143
            // tick-0: Tile tick
144
            // tick-0: Part tick: update a value, and mark part to invalidate
145
            // tick-0: -- send all block updates to client ---
146
            // tick-1: Tile tick: notices and update, marks a block invalidate
147
            // tick-1: Part tick: update the value again, the old value has still not been sent here!
148
            // tick-1: -- send all block updates to client --- This will contain the value that was set in tick-1.
149
            state.onDirty();
2✔
150
            IModHelpers.get().getBlockHelpers().markForUpdate(level, target.getCenter().getPos().getBlockPos());
8✔
151
        }
152
    }
1✔
153

154
    @Override
155
    public boolean hasActiveVariable(IPartNetwork network, PartTarget target, S partState) {
156
        return partState.hasVariable();
×
157
    }
158

159
    @Override
160
    public <V extends IValue> IVariable<V> getActiveVariable(INetwork network, IPartNetwork partNetwork, PartTarget target, S partState) {
161
        return partState.getVariable(network, partNetwork, ValueDeseralizationContext.of(target.getCenter().getPos().getLevel(true)));
×
162
    }
163

164
    protected void onValueChanged(INetwork network, IPartNetwork partNetwork, PartTarget target, S state,
165
                                  IValue lastValue, IValue newValue) {
166
        if (newValue == null) {
2✔
167
            state.setDisplayValue(null);
4✔
168
        } else {
169
            IValue materializedValue = null;
2✔
170
            try {
171
                if (newValue.getType() == ValueTypes.LIST) {
4!
172
                    IValueTypeListProxy<IValueType<IValue>, IValue> original = ((ValueTypeList.ValueList) newValue).getRawValue();
×
173
                    if (original.getLength() > ValueTypeList.MAX_RENDER_LINES) {
×
174
                        List<IValue> list = Lists.newArrayList();
×
175
                        for (int i = 0; i < ValueTypeList.MAX_RENDER_LINES; i++) {
×
176
                            list.add(original.get(i));
×
177
                        }
178
                        newValue = ValueTypeList.ValueList.ofList(original.getValueType(), list);
×
179
                    }
180
                }
181
                materializedValue = newValue.getType().materialize(newValue);
5✔
182
            } catch (EvaluationException e) {
×
183
                state.addGlobalError(e.getErrorMessage());
×
184
                e.addResolutionListeners(() -> state.addGlobalError(null));
×
185
            }
1✔
186
            state.setDisplayValue(materializedValue);
3✔
187
        }
188
    }
1✔
189

190
    @Override
191
    public Optional<MenuProvider> getContainerProvider(PartPos pos) {
192
        return Optional.of(new MenuProvider() {
×
193
            @Override
194
            public Component getDisplayName() {
195
                return Component.translatable(getTranslationKey());
×
196
            }
197

198
            @Nullable
199
            @Override
200
            public AbstractContainerMenu createMenu(int id, Inventory playerInventory, Player playerEntity) {
201
                Triple<IPartContainer, PartTypeBase, PartTarget> data = PartHelpers.getContainerPartConstructionData(pos);
×
202
                PartTypePanelVariableDriven.State partState = (PartTypePanelVariableDriven.State) data.getLeft().getPartState(data.getRight().getCenter().getSide());
×
203
                return new ContainerPartPanelVariableDriven(id, playerInventory, partState.getInventory(),
×
204
                        Optional.of(data.getRight()), Optional.of(data.getLeft()), (PartTypePanelVariableDriven<?, ?>) data.getMiddle());
×
205
            }
206
        });
207
    }
208

209
    @Override
210
    public void writeExtraGuiData(RegistryFriendlyByteBuf packetBuffer, PartPos pos, ServerPlayer player) {
211
        // Write inventory size
212
        IPartContainer partContainer = PartHelpers.getPartContainerChecked(pos);
×
213
        PartTypePanelVariableDriven.State partState = (PartTypePanelVariableDriven.State) partContainer.getPartState(pos.getSide());
×
214
        packetBuffer.writeInt(partState.getInventory().getContainerSize());
×
215

216
        super.writeExtraGuiData(packetBuffer, pos, player);
×
217
    }
×
218

219
    protected IgnoredBlockStatus.Status getStatus(PartTypePanelVariableDriven.State state) {
220
        IgnoredBlockStatus.Status status = IgnoredBlockStatus.Status.INACTIVE;
2✔
221
        if (state != null && !state.getInventory().isEmpty()) {
6!
222
            if (state.hasVariable() && state.isEnabled()) {
6!
223
                status = IgnoredBlockStatus.Status.ACTIVE;
3✔
224
            } else {
225
                status = IgnoredBlockStatus.Status.ERROR;
2✔
226
            }
227
        }
228
        return status;
2✔
229
    }
230

231
    @Override
232
    public BlockState getBlockState(IPartContainer partContainer,
233
                                    Direction side) {
234
        IgnoredBlockStatus.Status status = getStatus(partContainer != null
5!
235
                ? (PartTypePanelVariableDriven.State) partContainer.getPartState(side) : null);
5✔
236
        return getBlock().defaultBlockState()
6✔
237
                .setValue(IgnoredBlock.FACING, side)
4✔
238
                .setValue(IgnoredBlockStatus.STATUS, status);
2✔
239
    }
240

241
    protected void onVariableContentsUpdated(IPartNetwork network, PartTarget target, S state) {
242
        state.onVariableContentsUpdated((P) this, target);
4✔
243
    }
1✔
244

245
    @Override
246
    public InteractionResult onPartActivated(final S partState, BlockPos pos, Level world, Player player, InteractionHand hand,
247
                                             ItemStack heldItem, BlockHitResult hit) {
248
        if(WrenchHelpers.isWrench(player, heldItem, world, pos, hit.getDirection())) {
×
249
            WrenchHelpers.wrench(player, heldItem, world, pos, hit.getDirection(),
×
250
                    (player1, pos1, parameter) -> partState.setFacingRotation(partState.getFacingRotation().getClockWise()));
×
251
            return InteractionResult.SUCCESS;
×
252
        }
253
        return super.onPartActivated(partState, pos, world, player, hand, heldItem, hit);
×
254
    }
255

256
    @Override
257
    public void loadTooltip(S state, List<Component> lines) {
258
        if (!state.getInventory().isEmpty()) {
×
259
            if (state.hasVariable() && state.isEnabled()) {
×
260
                IValue value = state.getDisplayValue();
×
261
                if(value != null) {
×
262
                    IValueType valueType = value.getType();
×
263
                    lines.add(Component.translatable(
×
264
                            L10NValues.PART_TOOLTIP_DISPLAY_ACTIVEVALUE,
265
                            valueType.toCompactString(value).withStyle(valueType.getDisplayColorFormat()),
×
266
                            Component.translatable(valueType.getTranslationKey())));
×
267
                }
268
            } else {
×
269
                lines.add(Component.translatable(L10NValues.PART_TOOLTIP_ERRORS).withStyle(ChatFormatting.RED));
×
270
                for (MutableComponent error : state.getGlobalErrors()) {
×
271
                    lines.add(error.withStyle(ChatFormatting.RED));
×
272
                }
×
273
            }
274
        } else {
275
            lines.add(Component.translatable(L10NValues.PART_TOOLTIP_INACTIVE));
×
276
        }
277
        super.loadTooltip(state, lines);
×
278
    }
×
279

280
    @Override
281
    public boolean shouldTriggerBlockRenderUpdate(@Nullable S oldPartState, @Nullable S newPartState) {
282
        return super.shouldTriggerBlockRenderUpdate(oldPartState, newPartState)
×
283
                || getStatus(oldPartState) != getStatus(newPartState);
×
284
    }
285

286
    public static abstract class State<P extends PartTypePanelVariableDriven<P, S>, S extends PartTypePanelVariableDriven.State<P, S>> extends PartStateActiveVariableBase<P> {
287

288
        @Getter
3✔
289
        @Setter
4✔
290
        private IValue displayValue;
291
        @Getter
3✔
292
        @Setter
×
293
        private Direction facingRotation = Direction.NORTH;
294

295
        public State() {
296
            super(1);
3✔
297
        }
1✔
298

299
        @Override
300
        public void writeToNBT(ValueDeseralizationContext valueDeseralizationContext, CompoundTag tag) {
301
            super.writeToNBT(valueDeseralizationContext, tag);
4✔
302
            IValue value = getDisplayValue();
3✔
303
            if(value != null) {
2✔
304
                tag.putString("displayValueType", value.getType().getUniqueName().toString());
7✔
305
                tag.put("displayValue", ValueHelpers.serializeRaw(valueDeseralizationContext, value));
7✔
306
            }
307
            tag.putInt("facingRotation", facingRotation.ordinal());
6✔
308
        }
1✔
309

310
        @Override
311
        public void readFromNBT(ValueDeseralizationContext valueDeseralizationContext, CompoundTag tag) {
312
            super.readFromNBT(valueDeseralizationContext, tag);
×
313
            if(tag.contains("displayValueType", Tag.TAG_STRING)
×
314
                    && tag.contains("displayValue")) {
×
315
                IValueType valueType = ValueTypes.REGISTRY.getValueType(ResourceLocation.parse(tag.getString("displayValueType")));
×
316
                if(valueType != null) {
×
317
                    Tag serializedValue = tag.get("displayValue");
×
318
                    Component deserializationError = valueType.canDeserialize(valueDeseralizationContext, serializedValue);
×
319
                    if(deserializationError == null) {
×
320
                        setDisplayValue(ValueHelpers.deserializeRaw(valueDeseralizationContext, valueType, serializedValue));
×
321
                    } else {
322
                        IntegratedDynamics.clog(org.apache.logging.log4j.Level.ERROR, deserializationError.getString());
×
323
                    }
324
                } else {
×
325
                    IntegratedDynamics.clog(org.apache.logging.log4j.Level.ERROR,
×
326
                            String.format("Tried to deserialize the value \"%s\" for type \"%s\" which could not be found.",
×
327
                                    tag.getString("displayValueType"), tag.getString("value")));
×
328
                }
329
            } else {
×
330
                setDisplayValue(null);
×
331
            }
332
            facingRotation = Direction.values()[Math.max(2, tag.getInt("facingRotation"))];
×
333
        }
×
334
    }
335

336
}
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