Skip to content

Commit

Permalink
Remove unsafe dispatch codec (#343)
Browse files Browse the repository at this point in the history
Modders should make sure that their dispatch targets are instances of MapCodecCodec.
  • Loading branch information
Technici4n authored Dec 13, 2023
1 parent 997cdc6 commit c045a7e
Show file tree
Hide file tree
Showing 7 changed files with 14 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,16 @@
p_297904_ -> p_297904_.group(
ExtraCodecs.strictOptionalField(TagKey.codec(Registries.ITEM), "tag").forGetter(ItemPredicate::tag),
ExtraCodecs.strictOptionalField(ITEMS_CODEC, "items").forGetter(ItemPredicate::items),
@@ -51,8 +_,34 @@
@@ -51,8 +_,33 @@
)
.apply(p_297904_, ItemPredicate::new)
);
+ public static Codec<ItemPredicate> CODEC = ExtraCodecs.<net.neoforged.neoforge.common.advancements.critereon.ICustomItemPredicate, ItemPredicate>either(
+ // Use dispatchUnsafe to always inline the dispatched type parameters into the root ingredient object, next to the "type"
+ net.neoforged.neoforge.common.util.NeoForgeExtraCodecs.dispatchUnsafe(
+ net.neoforged.neoforge.registries.NeoForgeRegistries.ITEM_PREDICATE_SERIALIZERS.byNameCodec(),
+ net.neoforged.neoforge.common.advancements.critereon.ICustomItemPredicate::codec,
+ java.util.function.Function.identity()),
+ VANILLA_CODEC
+ net.neoforged.neoforge.registries.NeoForgeRegistries.ITEM_PREDICATE_SERIALIZERS.byNameCodec()
+ .dispatch(
+ net.neoforged.neoforge.common.advancements.critereon.ICustomItemPredicate::codec,
+ java.util.function.Function.identity()),
+ VANILLA_CODEC
+ ).xmap(either -> either.map(ItemPredicate::new, p -> p), predicate -> {
+ // Serialize using dispatch codec if custom logic is present, otherwise use vanilla codec
+ if (predicate.customLogic.isPresent()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ public static <T> Codec<Optional<T>> createConditionalCodec(final Codec<T> owner
* Creates a conditional codec.
*
* <p>The conditional codec is generally not suitable for use as a dispatch target because it is never a {@link MapCodec.MapCodecCodec}.
* If you need to dispatch on a conditional codec, consider using {@link NeoForgeExtraCodecs#dispatchUnsafe}.
*/
public static <T> Codec<Optional<T>> createConditionalCodec(final Codec<T> ownerCodec, String conditionalsKey) {
return createConditionalCodecWithConditions(ownerCodec, conditionalsKey).xmap(r -> r.map(WithConditions::carrier), r -> r.map(i -> new WithConditions<>(List.of(), i)));
Expand Down Expand Up @@ -116,7 +115,6 @@ public static <T> Codec<Optional<WithConditions<T>>> createConditionalCodecWithC
* Creates a conditional codec.
*
* <p>The conditional codec is generally not suitable for use as a dispatch target because it is never a {@link MapCodec.MapCodecCodec}.
* If you need to dispatch on a conditional codec, consider using {@link NeoForgeExtraCodecs#dispatchUnsafe}.
*/
public static <T> Codec<Optional<WithConditions<T>>> createConditionalCodecWithConditions(final Codec<T> ownerCodec, String conditionalsKey) {
return Codec.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
package net.neoforged.neoforge.common.conditions;

import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;

public final class FalseCondition implements ICondition {

public static final FalseCondition INSTANCE = new FalseCondition();

public static final Codec<FalseCondition> CODEC = Codec.unit(INSTANCE).stable();
public static final Codec<FalseCondition> CODEC = MapCodec.unit(INSTANCE).stable().codec();

private FalseCondition() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,11 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.util.Unit;
import net.neoforged.neoforge.common.util.NeoForgeExtraCodecs;
import net.neoforged.neoforge.registries.NeoForgeRegistries;

public interface ICondition {
// Use dispatchUnsafe to always write the condition value inline.
Codec<ICondition> CODEC = NeoForgeExtraCodecs.dispatchUnsafe(
NeoForgeRegistries.CONDITION_SERIALIZERS.byNameCodec(),
ICondition::codec,
Function.identity());
Codec<ICondition> CODEC = NeoForgeRegistries.CONDITION_SERIALIZERS.byNameCodec()
.dispatch(ICondition::codec, Function.identity());
Codec<List<ICondition>> LIST_CODEC = CODEC.listOf();

static <V, T> Optional<T> getConditionally(Codec<T> codec, DynamicOps<V> ops, V element) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
package net.neoforged.neoforge.common.conditions;

import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;

public final class TrueCondition implements ICondition {

public static final TrueCondition INSTANCE = new TrueCondition();

public static Codec<TrueCondition> CODEC = Codec.unit(INSTANCE).stable();
public static Codec<TrueCondition> CODEC = MapCodec.unit(INSTANCE).stable().codec();

private TrueCondition() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,8 @@ public static Codec<Ingredient> makeIngredientCodec(boolean allowEmpty, Codec<In
// Choose between dispatch codec for custom ingredients and vanilla codec
private static Codec<Ingredient> makeIngredientCodec0(boolean allowEmpty, Codec<Ingredient> vanillaCodec) {
// Dispatch codec for custom ingredient types:
Codec<Ingredient> dispatchCodec =
// Use dispatchUnsafe to always inline the dispatched type parameters into the root ingredient object, next to the "type"
NeoForgeExtraCodecs.dispatchUnsafe(
NeoForgeRegistries.INGREDIENT_TYPES.byNameCodec(),
Ingredient::getType,
ingredientType -> ingredientType.codec(allowEmpty));
Codec<Ingredient> dispatchCodec = NeoForgeRegistries.INGREDIENT_TYPES.byNameCodec()
.dispatch(Ingredient::getType, ingredientType -> ingredientType.codec(allowEmpty));
// Either codec to combine with the vanilla ingredient codec:
Codec<Either<Ingredient, Ingredient>> eitherCodec = ExtraCodecs.either(
dispatchCodec,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
import com.mojang.serialization.DataResult;
import com.mojang.serialization.Decoder;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Encoder;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.MapCodec.MapCodecCodec;
import com.mojang.serialization.codecs.KeyDispatchCodec;
import java.util.List;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -82,39 +79,6 @@ public static <T> Codec<Set<T>> setOf(final Codec<T> codec) {
return Codec.list(codec).xmap(ImmutableSet::copyOf, ImmutableList::copyOf);
}

/**
* Version of {@link Codec#dispatch(Function, Function)} that always writes the dispatched codec inline,
* i.e. at the same nesting level as the {@code "type": ...}.
* <p>
* Note: the codec produced by {@code .dispatch()} inlines the dispatched codec ONLY if it is a {@link MapCodecCodec}.
* This function always inlines.
*/
public static <K, V> Codec<V> dispatchUnsafe(final Codec<K> keyCodec, final Function<? super V, ? extends K> type, final Function<? super K, ? extends Codec<? extends V>> codec) {
return dispatchUnsafe(keyCodec, "type", type, codec);
}

/**
* Version of {@link Codec#dispatch(String, Function, Function)} that always writes the dispatched codec inline,
* i.e. at the same nesting level as the {@code "type": ...}.
* <p>
* Note: the codec produced by {@code .dispatch()} inlines the dispatched codec ONLY if it is a {@link MapCodecCodec}.
* This function always inlines.
*/
public static <K, V> Codec<V> dispatchUnsafe(final Codec<K> keyCodec, final String typeKey, final Function<? super V, ? extends K> type, final Function<? super K, ? extends Codec<? extends V>> codec) {
return partialDispatchUnsafe(keyCodec, typeKey, type.andThen(DataResult::success), codec.andThen(DataResult::success));
}

/**
* Version of {@link Codec#partialDispatch(String, Function, Function)} that always writes the dispatched codec inline,
* i.e. at the same nesting level as the {@code "type": ...}.
* <p>
* Note: the codec produced by {@code .dispatch()} inlines the dispatched codec ONLY if it is a {@link MapCodecCodec}.
* This function always inlines.
*/
public static <K, V> Codec<V> partialDispatchUnsafe(final Codec<K> keyCodec, final String typeKey, final Function<? super V, ? extends DataResult<? extends K>> type, final Function<? super K, ? extends DataResult<? extends Codec<? extends V>>> codec) {
return KeyDispatchCodec.unsafe(typeKey, keyCodec, type, codec, v -> type.apply(v).<Encoder<? extends V>>flatMap(k -> codec.apply(k).map(Function.identity())).map(e -> ((Encoder<V>) e))).codec();
}

/**
* Creates a codec from a decoder.
* The returned codec can only decode, and will throw on any attempt to encode.
Expand Down

0 comments on commit c045a7e

Please sign in to comment.