Skip to content

Commit edc363e

Browse files
Another day, another component wrapper rework
1 parent c6edb92 commit edc363e

File tree

2 files changed

+50
-30
lines changed

2 files changed

+50
-30
lines changed

src/main/java/dev/latvian/mods/kubejs/component/ComponentFunctions.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
import com.mojang.authlib.GameProfile;
44
import com.mojang.authlib.properties.PropertyMap;
55
import dev.latvian.mods.kubejs.color.KubeColor;
6+
import dev.latvian.mods.kubejs.error.KubeRuntimeException;
7+
import dev.latvian.mods.kubejs.script.SourceLine;
68
import dev.latvian.mods.kubejs.util.Cast;
79
import dev.latvian.mods.kubejs.util.RegistryAccessContainer;
810
import dev.latvian.mods.rhino.Context;
9-
import dev.latvian.mods.rhino.Undefined;
1011
import dev.latvian.mods.rhino.util.HideFromJS;
1112
import dev.latvian.mods.rhino.util.RemapPrefixForJS;
1213
import dev.latvian.mods.rhino.util.ReturnsSelf;
@@ -40,6 +41,8 @@
4041
import java.util.Optional;
4142
import java.util.UUID;
4243

44+
import static dev.latvian.mods.kubejs.component.DataComponentWrapper.tryWrapComponent;
45+
4346
@RemapPrefixForJS("kjs$")
4447
@ReturnsSelf
4548
public interface ComponentFunctions {
@@ -56,10 +59,16 @@ public interface ComponentFunctions {
5659
<T> ComponentFunctions kjs$override(DataComponentType<T> type, @Nullable T value);
5760

5861
default ComponentFunctions kjs$set(Context cx, DataComponentType<?> component, Object value) {
59-
if (value == null || Undefined.isUndefined(value)) {
60-
return kjs$remove(component);
62+
var wrapped = tryWrapComponent(cx, component, value)
63+
.getOrThrow(msg ->
64+
new KubeRuntimeException("Failed to wrap data component %s from '%s': %s".formatted(component, value, msg))
65+
.source(SourceLine.of(cx))
66+
);
67+
68+
if (wrapped.isPresent()) {
69+
return kjs$override((DataComponentType) component, wrapped.get());
6170
} else {
62-
return kjs$override((DataComponentType) component, cx.jsToJava(value, DataComponentWrapper.getTypeInfo(component)));
71+
return kjs$remove(component);
6372
}
6473
}
6574

src/main/java/dev/latvian/mods/kubejs/component/DataComponentWrapper.java

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import net.minecraft.network.chat.Component;
4141
import net.minecraft.resources.ResourceLocation;
4242
import net.minecraft.world.item.component.CustomData;
43+
import org.apache.commons.lang3.mutable.MutableObject;
4344
import org.jetbrains.annotations.Nullable;
4445

4546
import java.lang.reflect.Modifier;
@@ -48,6 +49,7 @@
4849
import java.util.HashSet;
4950
import java.util.Map;
5051
import java.util.Objects;
52+
import java.util.Optional;
5153
import java.util.Set;
5254
import java.util.StringJoiner;
5355
import java.util.function.BiConsumer;
@@ -430,56 +432,65 @@ static DataResult<DataComponentPatch> tryPatchOf(Context cx, @Nullable Object o)
430432
};
431433
}
432434

433-
private static void wrapEntry(
434-
Context cx,
435-
Map.Entry<DataComponentType<?>, ?> entry,
436-
@Nullable Consumer<DataComponentType<?>> ifNull,
437-
@SuppressWarnings("rawtypes") BiConsumer<DataComponentType, Object> builder,
438-
BiConsumer<DataComponentType<?>, String> error
439-
) {
435+
static <T> DataResult<Optional<T>> tryWrapComponent(Context cx, DataComponentType<T> type, Object value) {
440436
var reg = RegistryAccessContainer.of(cx);
441437

442-
var type = entry.getKey();
443438
var valueType = getTypeInfo(type);
444439

445-
var value = entry.getValue();
446-
447440
if (value == null || value instanceof Undefined) {
448-
if (ifNull != null) {
449-
ifNull.accept(type);
450-
}
451-
452-
return;
441+
return success(Optional.empty());
453442
}
454443

455-
EvaluatorException evalError = null;
444+
var evalError = new MutableObject<EvaluatorException>();
456445

457446
if (valueType.shouldConvert() && cx.canConvert(value, valueType)) {
458447
try {
459448
Object converted = cx.jsToJava(value, valueType);
460449
if (converted != null) {
461-
builder.accept(type, converted);
462-
return;
450+
return success(Optional.of(Cast.to(converted)));
463451
}
464452
} catch (EvaluatorException e) {
465-
evalError = e;
453+
evalError.setValue(e);
466454
}
467455
}
468456

457+
469458
var codec = type.codec();
470459

471460
if (codec != null) {
472-
switch (codec.parse(reg.json(), JsonUtils.of(cx, value))) {
473-
case DataResult.Success<?> success -> builder.accept(type, success.value());
474-
case DataResult.Error<?> err -> error.accept(type, evalError != null
475-
? "Failed to parse component from type wrappers and codec! Native: %s, Codec: %s".formatted(evalError.details(), err.message())
476-
: "Failed to parse component from codec: %s!".formatted(err.message()));
477-
}
461+
//noinspection unchecked
462+
return (DataResult<Optional<T>>) switch (codec.parse(reg.json(), JsonUtils.of(cx, value))) {
463+
case DataResult.Success<?> success -> success.map(Optional::of);
464+
case DataResult.Error<?> error -> error.mapError(err -> evalError.getValue() != null
465+
? "Failed to parse component from type wrappers and codec! Native: %s, Codec: %s".formatted(evalError.getValue().details(), err)
466+
: "Failed to parse component from codec: %s!".formatted(err));
467+
};
478468
} else {
479-
error.accept(type, "Component has non-serializable type");
469+
return error(() -> "Component has non-serializable type");
480470
}
481471
}
482472

473+
private static void wrapEntry(
474+
Context cx,
475+
Map.Entry<DataComponentType<?>, ?> entry,
476+
@Nullable Consumer<DataComponentType<?>> ifNull,
477+
@SuppressWarnings("rawtypes") BiConsumer<DataComponentType, Object> builder,
478+
BiConsumer<DataComponentType<?>, String> errorBuilder
479+
) {
480+
var type = entry.getKey();
481+
var value = entry.getValue();
482+
483+
tryWrapComponent(cx, type, value)
484+
.ifSuccess(success -> {
485+
if (success.isPresent()) {
486+
builder.accept(type, success.get());
487+
} else if (ifNull != null) {
488+
ifNull.accept(type);
489+
}
490+
})
491+
.ifError(error -> errorBuilder.accept(type, error.message()));
492+
}
493+
483494
private static <B, T> DataResult<T> fnToBuilder(Context cx, Class<B> builderType, BaseFunction fn, Function<B, T> build) {
484495
try {
485496
B builder = Cast.to(cx.createInterfaceAdapter(TypeInfo.of(builderType), fn));

0 commit comments

Comments
 (0)