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

CyclopsMC / IntegratedDynamics / 16552051255

27 Jul 2025 01:58PM UTC coverage: 53.206% (+8.0%) from 45.161%
16552051255

push

github

rubensworks
Resolve minor TODOs

2888 of 8740 branches covered (33.04%)

Branch coverage included in aggregate %.

17341 of 29280 relevant lines covered (59.22%)

3.08 hits per line

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

80.11
/src/main/java/org/cyclops/integrateddynamics/core/evaluate/operator/CombinedOperator.java
1
package org.cyclops.integrateddynamics.core.evaluate.operator;
2

3
import com.google.common.collect.Lists;
4
import net.minecraft.network.chat.Component;
5
import net.minecraft.resources.ResourceLocation;
6
import net.minecraft.world.level.storage.ValueInput;
7
import net.minecraft.world.level.storage.ValueOutput;
8
import org.apache.commons.lang3.ArrayUtils;
9
import org.apache.commons.lang3.tuple.Pair;
10
import org.cyclops.integrateddynamics.Reference;
11
import org.cyclops.integrateddynamics.api.evaluate.EvaluationException;
12
import org.cyclops.integrateddynamics.api.evaluate.operator.IOperator;
13
import org.cyclops.integrateddynamics.api.evaluate.operator.IOperatorSerializer;
14
import org.cyclops.integrateddynamics.api.evaluate.variable.IValue;
15
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueType;
16
import org.cyclops.integrateddynamics.api.evaluate.variable.IVariable;
17
import org.cyclops.integrateddynamics.api.logicprogrammer.IConfigRenderPattern;
18
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueHelpers;
19
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeBoolean;
20
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypes;
21
import org.cyclops.integrateddynamics.core.evaluate.variable.Variable;
22
import org.cyclops.integrateddynamics.core.helper.L10NValues;
23

24
import javax.annotation.Nullable;
25
import java.util.List;
26
import java.util.Objects;
27

28
/**
29
 * An operator that somehow combines one or more operators.
30
 * @author rubensworks
31
 */
32
public class CombinedOperator extends OperatorBase {
33

34
    private final String unlocalizedType;
35

36
    public CombinedOperator(String symbol, String operatorName, String interactName, OperatorsFunction function, IValueType outputType) {
37
        this(symbol, operatorName, interactName, function, new IValueType[]{ValueTypes.CATEGORY_ANY}, outputType, null);
14✔
38
    }
1✔
39

40
    public CombinedOperator(String symbol, String operatorName, String interactName, OperatorsFunction function, IValueType[] inputTypes,
41
                            IValueType outputType, @Nullable IConfigRenderPattern configRenderPattern) {
42
        super(symbol, operatorName, interactName, null, false,
11✔
43
                inputTypes, outputType, function, configRenderPattern);
44
        this.unlocalizedType = "virtual";
3✔
45
    }
1✔
46

47
    @Override
48
    protected String getUnlocalizedType() {
49
        return unlocalizedType;
3✔
50
    }
51

52
    @Override
53
    public IOperator materialize() {
54
        return this;
×
55
    }
56

57
    public static abstract class OperatorsFunction implements IFunction {
58

59
        private final IOperator[] operators;
60

61
        public OperatorsFunction(IOperator... operators) {
2✔
62
            this.operators = operators;
3✔
63
        }
1✔
64

65
        public IOperator[] getOperators() {
66
            return operators;
3✔
67
        }
68

69
        public int getInputOperatorCount() {
70
            return getOperators().length;
×
71
        }
72
    }
73

74
    public static class Conjunction extends OperatorsFunction {
75

76
        public Conjunction(IOperator... operators) {
77
            super(operators);
3✔
78
        }
1✔
79

80
        @Override
81
        public IValue evaluate(SafeVariablesGetter variables) throws EvaluationException {
82
            IValue value = variables.getValue(0);
4✔
83
            for (IOperator operator : getOperators()) {
17✔
84
                IValue result = ValueHelpers.evaluateOperator(operator, value);
9✔
85
                ValueHelpers.validatePredicateOutput(operator, result);
3✔
86
                if (!((ValueTypeBoolean.ValueBoolean) result).getRawValue()) {
4✔
87
                    return ValueTypeBoolean.ValueBoolean.of(false);
3✔
88
                }
89
            }
90
            return ValueTypeBoolean.ValueBoolean.of(true);
3✔
91
        }
92

93
        public static CombinedOperator asOperator(IOperator... operators) {
94
            CombinedOperator.Conjunction conjunction = new CombinedOperator.Conjunction(operators);
5✔
95
            return new CombinedOperator(":&&:", "p_conjunction", "p_conjunction", conjunction, ValueTypes.BOOLEAN);
9✔
96
        }
97

98
        public static class Serializer extends ListOperatorSerializer<Conjunction> {
99

100
            public Serializer() {
101
                super("conjunction", Conjunction.class);
4✔
102
            }
1✔
103

104
            @Override
105
            public CombinedOperator newFunction(IOperator... operators) {
106
                return Conjunction.asOperator(operators);
×
107
            }
108

109
        }
110
    }
111

112
    public static class Disjunction extends OperatorsFunction {
113

114
        public Disjunction(IOperator... operators) {
115
            super(operators);
3✔
116
        }
1✔
117

118
        @Override
119
        public IValue evaluate(SafeVariablesGetter variables) throws EvaluationException {
120
            IValue value = variables.getValue(0);
4✔
121
            for (IOperator operator : getOperators()) {
17✔
122
                IValue result = ValueHelpers.evaluateOperator(operator, value);
9✔
123
                ValueHelpers.validatePredicateOutput(operator, result);
3✔
124
                if (((ValueTypeBoolean.ValueBoolean) result).getRawValue()) {
4✔
125
                    return ValueTypeBoolean.ValueBoolean.of(true);
3✔
126
                }
127
            }
128
            return ValueTypeBoolean.ValueBoolean.of(false);
3✔
129
        }
130

131
        public static CombinedOperator asOperator(IOperator... operators) {
132
            CombinedOperator.Disjunction disjunction = new CombinedOperator.Disjunction(operators);
5✔
133
            return new CombinedOperator(":||:", "p_disjunction", "p_disjunction", disjunction, ValueTypes.BOOLEAN);
9✔
134
        }
135

136
        public static class Serializer extends ListOperatorSerializer<Disjunction> {
137

138
            public Serializer() {
139
                super("disjunction", Disjunction.class);
4✔
140
            }
1✔
141

142
            @Override
143
            public CombinedOperator newFunction(IOperator... operators) {
144
                return Disjunction.asOperator(operators);
×
145
            }
146

147
        }
148
    }
149

150
    public static class Negation extends OperatorsFunction {
151

152
        public Negation(IOperator operator) {
153
            super(new IOperator[]{operator});
8✔
154
        }
1✔
155

156
        @Override
157
        public IValue evaluate(SafeVariablesGetter variables) throws EvaluationException {
158
            IValue value = variables.getValue(0);
4✔
159
            IOperator operator = getOperators()[0];
5✔
160
            IValue result = ValueHelpers.evaluateOperator(operator, value);
9✔
161
            ValueHelpers.validatePredicateOutput(operator, result);
3✔
162
            return ValueTypeBoolean.ValueBoolean.of(!((ValueTypeBoolean.ValueBoolean) result).getRawValue());
9✔
163
        }
164

165
        public static CombinedOperator asOperator(IOperator operator) {
166
            CombinedOperator.Negation negation = new CombinedOperator.Negation(operator);
5✔
167
            return new CombinedOperator("!:", "p_negation", "p_negation", negation, ValueTypes.BOOLEAN);
9✔
168
        }
169

170
        public static class Serializer extends ListOperatorSerializer<Negation> {
171

172
            public Serializer() {
173
                super("negation", Negation.class);
4✔
174
            }
1✔
175

176
            @Override
177
            public CombinedOperator newFunction(IOperator... operators) {
178
                return Negation.asOperator(operators[0]);
×
179
            }
180

181
        }
182
    }
183

184
    public static class Pipe extends OperatorsFunction {
185

186
        public Pipe(IOperator... operators) {
187
            super(operators);
3✔
188
        }
1✔
189

190
        @Override
191
        public IValue evaluate(SafeVariablesGetter variables) throws EvaluationException {
192
            return pipeVariablesToOperators(variables.getVariables(), getOperators());
6✔
193
        }
194

195
        /**
196
         * Pass the first variable to all n-1 first operators.
197
         * Prepend the results of these operators to the variables array.
198
         * Pass the final variables array to the last operator, and return the result.
199
         * @param allVariables The input variables.
200
         * @param operators The operators to apply to. The n-1 first ones are the inputs, and the last one is the target to pipe to.
201
         * @return The final result.
202
         * @throws EvaluationException If evaluation failed.
203
         */
204
        public static IValue pipeVariablesToOperators(IVariable[] allVariables, IOperator[] operators) throws EvaluationException {
205
            int firstInputRange = operators.length - 1;
5✔
206
            IVariable input = allVariables[0];
4✔
207
            IVariable[] intermediates = new IVariable[firstInputRange];
3✔
208
            for (int i = 0; i < firstInputRange; ++i) {
7✔
209
                intermediates[i] = new Variable<>(ValueHelpers.evaluateOperator(operators[i], input));
16✔
210
            }
211
            IVariable[] remaining = ArrayUtils.subarray(allVariables, 1, allVariables.length);
7✔
212
            IVariable[] newVariables = ArrayUtils.addAll(intermediates, remaining);
5✔
213
            return ValueHelpers.evaluateOperator(operators[operators.length - 1], newVariables);
9✔
214
        }
215

216
        /**
217
         * Determine the input types and output type for the given operators.
218
         * @param operators The operators to apply to. The n-1 first ones are the inputs, and the last one is the target to pipe to.
219
         * @return The input types and output type.
220
         */
221
        public static Pair<IValueType[], IValueType> getPipedInputOutputTypes(IOperator[] operators) {
222
            int firstInputRange = operators.length - 1;
5✔
223
            IValueType[] inputTypes = new IValueType[1];
3✔
224
            for (int i = 0; i < operators.length; ++i) {
8✔
225
                IValueType[] operatorInputTypes = operators[i].getInputTypes();
5✔
226
                if (i < firstInputRange) {
3✔
227
                    if (inputTypes[0] == null) {
4✔
228
                        inputTypes[0] = operatorInputTypes[0];
7✔
229
                    } else {
230
                        if (inputTypes[0] != operatorInputTypes[0]) {
7✔
231
                            if (ValueHelpers.correspondsTo(inputTypes[0], operatorInputTypes[0])) {
8!
232
                                if (inputTypes[0].isCategory()) {
5!
233
                                    inputTypes[0] = operatorInputTypes[0];
7✔
234
                                }
235
                            }
236
                        }
237
                    }
238
                } else {
239
                    inputTypes = ArrayUtils.addAll(inputTypes,
8✔
240
                            ArrayUtils.subarray(operatorInputTypes, firstInputRange, operatorInputTypes.length));
2✔
241
                }
242
            }
243
            IValueType lastOutputType = operators[operators.length - 1].getOutputType();
8✔
244
            if (lastOutputType == ValueTypes.OPERATOR) {
3✔
245
                // If output type is an operator, make it ANY, as we don't know yet what we will pipe with.
246
                lastOutputType = ValueTypes.CATEGORY_ANY;
2✔
247
            }
248
            return Pair.of(inputTypes, lastOutputType);
4✔
249

250
        }
251

252
        public static CombinedOperator asOperator(final IOperator... operators) {
253
            return asOperator(new CombinedOperator.Pipe(operators), ":.:", "piped", "piped", operators);
10✔
254
        }
255

256
        public static CombinedOperator asOperator(OperatorsFunction function, String symbol, String operatorName, String interactName, final IOperator... operators) {
257
            Pair<IValueType[], IValueType> ioTypes = getPipedInputOutputTypes(operators);
3✔
258
            return new CombinedOperator(symbol, operatorName, interactName, function, ioTypes.getRight()) {
27✔
259
                @Override
260
                public IValueType getConditionalOutputType(IVariable[] allVariables) {
261
                    try {
262
                        return pipeVariablesToOperators(allVariables, operators).getType();
6✔
263
                    } catch (EvaluationException e) {
×
264
                        return ValueTypes.CATEGORY_ANY;
×
265
                    }
266
                }
267

268
                @Override
269
                public IValueType[] getInputTypes() {
270
                    return ioTypes.getLeft();
5✔
271
                }
272
            };
273
        }
274

275
        public static class Serializer extends ListOperatorSerializer<Pipe> {
276

277
            public Serializer() {
278
                super("pipe", Pipe.class);
4✔
279
            }
1✔
280

281
            @Override
282
            public CombinedOperator newFunction(IOperator... operators) {
283
                return Pipe.asOperator(operators);
×
284
            }
285

286
        }
287
    }
288

289
    public static class Pipe2 extends OperatorsFunction {
290

291
        public Pipe2(IOperator... operators) {
292
            super(operators);
3✔
293
        }
1✔
294

295
        @Override
296
        public IValue evaluate(SafeVariablesGetter variables) throws EvaluationException {
297
            return Pipe.pipeVariablesToOperators(variables.getVariables(), getOperators());
6✔
298
        }
299

300
        public static CombinedOperator asOperator(IOperator... operators) {
301
            return Pipe.asOperator(new CombinedOperator.Pipe2(operators), ":.2:", "piped2", "piped2", operators);
10✔
302
        }
303

304
        public static class Serializer extends ListOperatorSerializer<Pipe2> {
305

306
            public Serializer() {
307
                super("pipe2", Pipe2.class);
4✔
308
            }
1✔
309

310
            @Override
311
            public CombinedOperator newFunction(IOperator... operators) {
312
                return Pipe2.asOperator(operators);
×
313
            }
314

315
        }
316
    }
317

318
    public static class Flip extends OperatorsFunction {
319

320
        public Flip(IOperator operator) {
321
            super(new IOperator[]{operator});
8✔
322
        }
1✔
323

324
        @Override
325
        public IValue evaluate(SafeVariablesGetter variables) throws EvaluationException {
326
            int size = variables.getVariables().length;
4✔
327
            IValue[] values = new IValue[size];
3✔
328
            for (int i = 0; i < size; i++) {
7✔
329
                int targetI = i < 2 ? 1 - i : i;
9✔
330
                values[i] = variables.getValue(targetI);
6✔
331
            }
332
            return ValueHelpers.evaluateOperator(getOperators()[0], values);
7✔
333
        }
334

335
        public static CombinedOperator asOperator(IOperator operator) throws EvaluationException {
336
            CombinedOperator.Flip flip = new CombinedOperator.Flip(operator);
5✔
337
            IValueType[] originalInputTypes = operator.getInputTypes();
3✔
338
            IValueType[] flippedInputTypes = new IValueType[originalInputTypes.length];
4✔
339
            if (originalInputTypes.length < 2) {
4!
340
                throw new EvaluationException(Component.translatable(L10NValues.OPERATOR_ERROR_WRONGINPUTLENGTHVIRTIUAL,
×
341
                        Component.translatable(Operators.OPERATOR_FLIP.getTranslationKey()),
×
342
                        Component.translatable(operator.getTranslationKey()),
×
343
                        originalInputTypes.length, 2));
×
344
            }
345
            for (int i = 0; i < flippedInputTypes.length; i++) {
8✔
346
                int targetI = i < 2 ? 1 - i : i;
9✔
347
                flippedInputTypes[i] = originalInputTypes[targetI];
6✔
348
            }
349
            CombinedOperator combinedOperator;
350
            try {
351
                combinedOperator = new CombinedOperator(":flip:", "flipped", "flipped", flip, flippedInputTypes,
8✔
352
                        operator.getOutputType(), null);
4✔
353
            } catch (IllegalArgumentException e) {
×
354
                throw new EvaluationException(Component.translatable(e.getMessage()));
×
355
            }
1✔
356
            return combinedOperator;
2✔
357
        }
358

359
        public static class Serializer extends ListOperatorSerializer<Flip> {
360

361
            public Serializer() {
362
                super("flip", Flip.class);
4✔
363
            }
1✔
364

365
            @Override
366
            public CombinedOperator newFunction(IOperator... operators) throws EvaluationException {
367
                return Flip.asOperator(operators[0]);
×
368
            }
369

370
        }
371
    }
372

373
    public static abstract class ListOperatorSerializer<F extends IFunction> implements IOperatorSerializer<CombinedOperator> {
374

375
        private final String functionName;
376
        private final Class<F> functionClass;
377

378
        public ListOperatorSerializer(String functionName, Class<F> functionClass) {
2✔
379
            this.functionName = functionName;
3✔
380
            this.functionClass = functionClass;
3✔
381
        }
1✔
382

383
        @Override
384
        public boolean canHandle(IOperator operator) {
385
            return operator instanceof CombinedOperator && functionClass.isInstance(((CombinedOperator) operator).getFunction());
5!
386
        }
387

388
        @Override
389
        public ResourceLocation getUniqueName() {
390
            return ResourceLocation.fromNamespaceAndPath(Reference.MOD_ID, "combined." + functionName);
6✔
391
        }
392

393
        @Override
394
        public void serialize(ValueOutput valueOutput, CombinedOperator operator) {
395
            OperatorsFunction function = (OperatorsFunction) operator.getFunction();
×
396
            IOperator[] operators = function.getOperators();
×
397
            ValueOutput.ValueOutputList list = valueOutput.childrenList("operators");
×
398
            for (IOperator functionOperator : operators) {
×
399
                Operators.REGISTRY.serialize(list.addChild(), functionOperator);
×
400
            }
401
        }
×
402

403
        @Override
404
        public CombinedOperator deserialize(ValueInput valueInput) throws EvaluationException {
405
            List<IOperator> operators = Lists.newArrayList();
×
406
            for (ValueInput input : valueInput.childrenList("operators").orElseThrow()) {
×
407
                operators.add(Objects.requireNonNull(Operators.REGISTRY.deserialize(input)));
×
408
            }
×
409
            return newFunction(operators.toArray(new IOperator[0]));
×
410
        }
411

412
        public abstract CombinedOperator newFunction(IOperator... operators) throws EvaluationException;
413
    }
414
}
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