Fix a bunch of codec-related stuff

This commit is contained in:
Sollace 2023-09-29 22:39:19 +01:00
parent c4e3383c36
commit 9cf6f2818a
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
5 changed files with 57 additions and 66 deletions

View file

@ -13,7 +13,6 @@ import com.minelittlepony.unicopia.item.URecipes;
import com.minelittlepony.unicopia.util.InventoryUtil; import com.minelittlepony.unicopia.util.InventoryUtil;
import com.mojang.datafixers.util.Pair; import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
@ -144,7 +143,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
public static class Serializer implements RecipeSerializer<SpellCraftingRecipe> { public static class Serializer implements RecipeSerializer<SpellCraftingRecipe> {
private static final Codec<SpellCraftingRecipe> CODEC = RecordCodecBuilder.<SpellCraftingRecipe>create(instance -> instance.group( private static final Codec<SpellCraftingRecipe> CODEC = RecordCodecBuilder.<SpellCraftingRecipe>create(instance -> instance.group(
IngredientWithSpell.CODEC.fieldOf("material").forGetter(recipe -> recipe.material), IngredientWithSpell.CODEC.fieldOf("material").forGetter(recipe -> recipe.material),
((MapCodec<TraitIngredient>)null).forGetter(recipe -> recipe.requiredTraits), TraitIngredient.CODEC.fieldOf("traits").forGetter(recipe -> recipe.requiredTraits),
IngredientWithSpell.CODEC.listOf().fieldOf("ingredients").forGetter(recipe -> recipe.requiredItems), IngredientWithSpell.CODEC.listOf().fieldOf("ingredients").forGetter(recipe -> recipe.requiredItems),
ItemStackWithSpell.CODEC.fieldOf("result").forGetter(recipe -> recipe.output) ItemStackWithSpell.CODEC.fieldOf("result").forGetter(recipe -> recipe.output)
).apply(instance, SpellCraftingRecipe::new)); ).apply(instance, SpellCraftingRecipe::new));

View file

@ -3,16 +3,31 @@ package com.minelittlepony.unicopia.ability.magic.spell.crafting;
import java.util.Optional; import java.util.Optional;
import java.util.function.Predicate; import java.util.function.Predicate;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.JsonHelper; import net.minecraft.util.dynamic.Codecs;
public record TraitIngredient ( public record TraitIngredient (
Optional<SpellTraits> min, Optional<SpellTraits> min,
Optional<SpellTraits> max Optional<SpellTraits> max
) implements Predicate<SpellTraits> { ) implements Predicate<SpellTraits> {
public static final Codec<TraitIngredient> CODEC = Codecs.xor(
SpellTraits.CODEC.flatXmap(
traits -> DataResult.success(new TraitIngredient(Optional.ofNullable(traits), Optional.empty())),
ingredient -> ingredient.min().map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Cannot serialize an empty trait ingredient"))),
RecordCodecBuilder.<TraitIngredient>create(instance -> instance.group(
SpellTraits.CODEC.optionalFieldOf("min").forGetter(TraitIngredient::min),
SpellTraits.CODEC.optionalFieldOf("max").forGetter(TraitIngredient::max)
).apply(instance, TraitIngredient::new))
).flatXmap(
either -> either.left().or(either::right).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Invalid traits")),
ingredient -> DataResult.success(ingredient.max.isPresent() ? Either.left(ingredient) : Either.right(ingredient))
);
@Override @Override
public boolean test(SpellTraits t) { public boolean test(SpellTraits t) {
@ -29,22 +44,4 @@ public record TraitIngredient (
public static TraitIngredient fromPacket(PacketByteBuf buf) { public static TraitIngredient fromPacket(PacketByteBuf buf) {
return new TraitIngredient(SpellTraits.fromPacketOrEmpty(buf), SpellTraits.fromPacketOrEmpty(buf)); return new TraitIngredient(SpellTraits.fromPacketOrEmpty(buf), SpellTraits.fromPacketOrEmpty(buf));
} }
public static TraitIngredient fromJson(JsonObject json) {
Optional<SpellTraits> min = Optional.empty();
Optional<SpellTraits> max = Optional.empty();
if (json.has("min") || json.has("max")) {
if (json.has("min")) {
min = SpellTraits.fromJson(JsonHelper.getObject(json, "min"));
}
if (json.has("max")) {
max = SpellTraits.fromJson(JsonHelper.getObject(json, "max"));
}
} else {
min = SpellTraits.fromJson(json);
}
return new TraitIngredient(min, max);
}
} }

View file

@ -17,10 +17,12 @@ import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.gui.ItemTraitsTooltipRenderer; import com.minelittlepony.unicopia.client.gui.ItemTraitsTooltipRenderer;
import com.minelittlepony.unicopia.util.InventoryUtil; import com.minelittlepony.unicopia.util.InventoryUtil;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.fabricmc.api.EnvType; import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment; import net.fabricmc.api.Environment;
@ -30,6 +32,7 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtOps;
import net.minecraft.network.PacketByteBuf; import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -42,6 +45,10 @@ public final class SpellTraits implements Iterable<Map.Entry<Trait, Float>> {
private static Map<Identifier, SpellTraits> REGISTRY = new HashMap<>(); private static Map<Identifier, SpellTraits> REGISTRY = new HashMap<>();
static final Map<Trait, List<Item>> ITEMS = new HashMap<>(); static final Map<Trait, List<Item>> ITEMS = new HashMap<>();
public static final Codec<SpellTraits> CODEC = Codec.unboundedMap(Trait.CODEC, Codec.FLOAT).flatXmap(map -> {
return fromEntries(map.entrySet().stream()).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "No traits were supplied"));
}, traits -> DataResult.success(traits.traits));
public static void load(Map<Identifier, SpellTraits> newRegistry) { public static void load(Map<Identifier, SpellTraits> newRegistry) {
REGISTRY = new HashMap<>(newRegistry); REGISTRY = new HashMap<>(newRegistry);
ITEMS.clear(); ITEMS.clear();
@ -244,11 +251,7 @@ public final class SpellTraits implements Iterable<Map.Entry<Trait, Float>> {
} }
public static Optional<SpellTraits> fromNbt(NbtCompound traits) { public static Optional<SpellTraits> fromNbt(NbtCompound traits) {
return fromEntries(streamFromNbt(traits)); return CODEC.decode(NbtOps.INSTANCE, traits).result().map(Pair::getFirst);
}
public static Optional<SpellTraits> fromJson(JsonObject traits) {
return fromEntries(streamFromJson(traits));
} }
public static Optional<SpellTraits> fromPacketOrEmpty(PacketByteBuf buf) { public static Optional<SpellTraits> fromPacketOrEmpty(PacketByteBuf buf) {
@ -256,7 +259,6 @@ public final class SpellTraits implements Iterable<Map.Entry<Trait, Float>> {
} }
public static SpellTraits fromPacket(PacketByteBuf buf) { public static SpellTraits fromPacket(PacketByteBuf buf) {
Map<Trait, Float> entries = new HashMap<>(); Map<Trait, Float> entries = new HashMap<>();
int count = buf.readInt(); int count = buf.readInt();
if (count <= 0) { if (count <= 0) {
@ -295,26 +297,6 @@ public final class SpellTraits implements Iterable<Map.Entry<Trait, Float>> {
})); }));
} }
public static Stream<Map.Entry<Trait, Float>> streamFromNbt(NbtCompound traits) {
return traits.getKeys().stream().map(key -> {
Trait trait = Trait.fromId(key).orElse(null);
if (trait == null || !traits.contains(key, NbtElement.NUMBER_TYPE)) {
return null;
}
return Map.entry(trait, traits.getFloat(key));
});
}
public static Stream<Map.Entry<Trait, Float>> streamFromJson(JsonObject traits) {
return traits.entrySet().stream().map(entry -> {
Trait trait = Trait.fromName(entry.getKey()).orElse(null);
if (trait == null || !entry.getValue().isJsonPrimitive() && !entry.getValue().getAsJsonPrimitive().isNumber()) {
return null;
}
return Map.entry(trait, entry.getValue().getAsJsonPrimitive().getAsFloat());
});
}
public static Optional<SpellTraits> fromEntries(Stream<Map.Entry<Trait, Float>> entries) { public static Optional<SpellTraits> fromEntries(Stream<Map.Entry<Trait, Float>> entries) {
var result = collect(entries); var result = collect(entries);

View file

@ -7,7 +7,9 @@ import java.util.stream.Stream;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.command.CommandArgumentEnum; import com.minelittlepony.unicopia.command.CommandArgumentEnum;
import com.mojang.datafixers.util.Either;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import net.minecraft.command.argument.EnumArgumentType; import net.minecraft.command.argument.EnumArgumentType;
import net.minecraft.item.Item; import net.minecraft.item.Item;
@ -18,6 +20,7 @@ import net.minecraft.text.*;
import net.minecraft.util.Formatting; import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.StringIdentifiable; import net.minecraft.util.StringIdentifiable;
import net.minecraft.util.dynamic.Codecs;
public enum Trait implements CommandArgumentEnum<Trait> { public enum Trait implements CommandArgumentEnum<Trait> {
/** /**
@ -60,8 +63,17 @@ public enum Trait implements CommandArgumentEnum<Trait> {
POISON(TraitGroup.DARKNESS), POISON(TraitGroup.DARKNESS),
BLOOD(TraitGroup.DARKNESS); BLOOD(TraitGroup.DARKNESS);
private static final Map<String, Trait> REGISTRY = Arrays.stream(values()).collect(Collectors.toMap(Trait::name, Function.identity()));
private static final Map<Identifier, Trait> IDS = Arrays.stream(values()).collect(Collectors.toMap(Trait::getId, Function.identity())); private static final Map<Identifier, Trait> IDS = Arrays.stream(values()).collect(Collectors.toMap(Trait::getId, Function.identity()));
@Deprecated
private static final EnumCodec<Trait> NAME_CODEC = StringIdentifiable.createCodec(Trait::values);
@Deprecated
private static final EnumCodec<Trait> ID_CODEC = StringIdentifiable.createCodec(Trait::values, i -> "unicopia:" + i);
public static final Codec<Trait> CODEC = Codecs.xor(NAME_CODEC, ID_CODEC).flatXmap(
either -> either.left().or(either::right).map(DataResult::success).orElseGet(() -> DataResult.error(() -> "Not a proper trait")),
trait -> DataResult.success(Either.right(trait))
);
private final Identifier id; private final Identifier id;
private final Identifier sprite; private final Identifier sprite;
private final TraitGroup group; private final TraitGroup group;
@ -149,25 +161,26 @@ public enum Trait implements CommandArgumentEnum<Trait> {
.flatMap(Optional::stream); .flatMap(Optional::stream);
} }
@Deprecated
public static Optional<Trait> fromId(Identifier id) { public static Optional<Trait> fromId(Identifier id) {
return Optional.ofNullable(IDS.getOrDefault(id, null)); return Optional.ofNullable(ID_CODEC.byId(id.toString()));
} }
@Deprecated
public static Optional<Trait> fromId(String name) { public static Optional<Trait> fromId(String name) {
return Optional.ofNullable(Identifier.tryParse(name)).flatMap(Trait::fromId); return Optional.ofNullable(Identifier.tryParse(name)).flatMap(Trait::fromId);
} }
@Deprecated
public static Optional<Trait> fromName(String name) { public static Optional<Trait> fromName(String name) {
return Optional.ofNullable(REGISTRY.getOrDefault(name.toUpperCase(), null)); return Optional.ofNullable(NAME_CODEC.byId(name.toUpperCase()));
} }
public static EnumArgumentType<Trait> argument() { public static EnumArgumentType<Trait> argument() {
return new ArgumentType(); return new ArgumentType();
} }
public static final class ArgumentType extends EnumArgumentType<Trait> { public static class ArgumentType extends EnumArgumentType<Trait> {
static final Codec<Trait> CODEC = StringIdentifiable.createCodec(Trait::values);
protected ArgumentType() { protected ArgumentType() {
super(CODEC, Trait::values); super(CODEC, Trait::values);
} }

View file

@ -17,17 +17,6 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.collection.DefaultedList;
public interface URecipes { public interface URecipes {
RecipeType<SpellbookRecipe> SPELLBOOK = RecipeType.register("unicopia:spellbook");
RecipeSerializer<ZapAppleRecipe> ZAP_APPLE_SERIALIZER = RecipeSerializer.register("unicopia:crafting_zap_apple", new ZapAppleRecipe.Serializer());
RecipeSerializer<GlowingRecipe> GLOWING_SERIALIZER = RecipeSerializer.register("unicopia:crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new));
RecipeSerializer<JarInsertRecipe> JAR_INSERT_SERIALIZER = RecipeSerializer.register("unicopia:jar_insert", new SpecialRecipeSerializer<>(JarInsertRecipe::new));
RecipeSerializer<JarExtractRecipe> JAR_EXTRACT_SERIALIZER = RecipeSerializer.register("unicopia:jar_extract", new SpecialRecipeSerializer<>(JarExtractRecipe::new));
RecipeSerializer<ShapedRecipe> CRAFTING_MAGICAL_SERIALIZER = RecipeSerializer.register("unicopia:crafting_magical", new SpellShapedCraftingRecipe.Serializer());
RecipeSerializer<SpellCraftingRecipe> TRAIT_REQUIREMENT = RecipeSerializer.register("unicopia:spellbook/crafting", new SpellCraftingRecipe.Serializer());
RecipeSerializer<SpellEnhancingRecipe> TRAIT_COMBINING = RecipeSerializer.register("unicopia:spellbook/combining", new SpellEnhancingRecipe.Serializer());
RecipeSerializer<SpellDuplicatingRecipe> SPELL_DUPLICATING = RecipeSerializer.register("unicopia:spellbook/duplicating", new SpellDuplicatingRecipe.Serializer());
Codec<DefaultedList<Ingredient>> SHAPELESS_RECIPE_INGREDIENTS_CODEC = Ingredient.DISALLOW_EMPTY_CODEC.listOf().flatXmap(ingredients -> { Codec<DefaultedList<Ingredient>> SHAPELESS_RECIPE_INGREDIENTS_CODEC = Ingredient.DISALLOW_EMPTY_CODEC.listOf().flatXmap(ingredients -> {
Ingredient[] ingredients2 = ingredients.stream().filter(ingredient -> !ingredient.isEmpty()).toArray(Ingredient[]::new); Ingredient[] ingredients2 = ingredients.stream().filter(ingredient -> !ingredient.isEmpty()).toArray(Ingredient[]::new);
if (ingredients2.length == 0) { if (ingredients2.length == 0) {
@ -39,6 +28,17 @@ public interface URecipes {
return DataResult.success(DefaultedList.copyOf(Ingredient.EMPTY, ingredients2)); return DataResult.success(DefaultedList.copyOf(Ingredient.EMPTY, ingredients2));
}, DataResult::success); }, DataResult::success);
RecipeType<SpellbookRecipe> SPELLBOOK = RecipeType.register("unicopia:spellbook");
RecipeSerializer<ZapAppleRecipe> ZAP_APPLE_SERIALIZER = RecipeSerializer.register("unicopia:crafting_zap_apple", new ZapAppleRecipe.Serializer());
RecipeSerializer<GlowingRecipe> GLOWING_SERIALIZER = RecipeSerializer.register("unicopia:crafting_glowing", new SpecialRecipeSerializer<>(GlowingRecipe::new));
RecipeSerializer<JarInsertRecipe> JAR_INSERT_SERIALIZER = RecipeSerializer.register("unicopia:jar_insert", new SpecialRecipeSerializer<>(JarInsertRecipe::new));
RecipeSerializer<JarExtractRecipe> JAR_EXTRACT_SERIALIZER = RecipeSerializer.register("unicopia:jar_extract", new SpecialRecipeSerializer<>(JarExtractRecipe::new));
RecipeSerializer<ShapedRecipe> CRAFTING_MAGICAL_SERIALIZER = RecipeSerializer.register("unicopia:crafting_magical", new SpellShapedCraftingRecipe.Serializer());
RecipeSerializer<SpellCraftingRecipe> TRAIT_REQUIREMENT = RecipeSerializer.register("unicopia:spellbook/crafting", new SpellCraftingRecipe.Serializer());
RecipeSerializer<SpellEnhancingRecipe> TRAIT_COMBINING = RecipeSerializer.register("unicopia:spellbook/combining", new SpellEnhancingRecipe.Serializer());
RecipeSerializer<SpellDuplicatingRecipe> SPELL_DUPLICATING = RecipeSerializer.register("unicopia:spellbook/duplicating", new SpellDuplicatingRecipe.Serializer());
static void bootstrap() { static void bootstrap() {
LootTableEvents.MODIFY.register((res, manager, id, supplier, setter) -> { LootTableEvents.MODIFY.register((res, manager, id, supplier, setter) -> {
if (!"minecraft".contentEquals(id.getNamespace())) { if (!"minecraft".contentEquals(id.getNamespace())) {