mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Fix codecs jank
This commit is contained in:
parent
c3229a3126
commit
69b6e3c92c
8 changed files with 94 additions and 56 deletions
|
@ -7,15 +7,11 @@ import java.util.function.Predicate;
|
|||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||
import com.minelittlepony.unicopia.item.EnchantableItem;
|
||||
import com.minelittlepony.unicopia.util.CodecUtils;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.Decoder;
|
||||
import com.mojang.serialization.DynamicOps;
|
||||
import com.mojang.serialization.Encoder;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
|
@ -25,23 +21,11 @@ public class IngredientWithSpell implements Predicate<ItemStack> {
|
|||
private static final IngredientWithSpell EMPTY = new IngredientWithSpell(Optional.empty(), Optional.empty());
|
||||
private static final Predicate<Ingredient> INGREDIENT_IS_PRESENT = ((Predicate<Ingredient>)(Ingredient::isEmpty)).negate();
|
||||
|
||||
public static final Codec<IngredientWithSpell> CODEC = Codec.of(new Encoder<IngredientWithSpell>() {
|
||||
@Override
|
||||
public <T> DataResult<T> encode(IngredientWithSpell input, DynamicOps<T> ops, T prefix) {
|
||||
throw new JsonParseException("cannot serialize this type");
|
||||
}
|
||||
}, new Decoder<IngredientWithSpell>() {
|
||||
@Override
|
||||
public <T> DataResult<Pair<IngredientWithSpell, T>> decode(DynamicOps<T> ops, T input) {
|
||||
// TODO: Doing codecs properly is an exercise left to the readers
|
||||
return DataResult.success(new Pair<>(
|
||||
new IngredientWithSpell(
|
||||
Ingredient.ALLOW_EMPTY_CODEC.decode(ops, input).map(Pair::getFirst).result(),
|
||||
ops.getMap(input).flatMap(maplike -> SpellType.REGISTRY.getCodec().parse(ops, maplike.get("spell"))).result()
|
||||
), input)
|
||||
);
|
||||
}
|
||||
});
|
||||
public static final Codec<IngredientWithSpell> CODEC = CodecUtils.extend(Ingredient.ALLOW_EMPTY_CODEC, SpellType.REGISTRY.getCodec().fieldOf("spell")).xmap(
|
||||
pair -> new IngredientWithSpell(pair.getFirst(), pair.getSecond()),
|
||||
ingredient -> new Pair<>(ingredient.stack, ingredient.spell)
|
||||
);
|
||||
|
||||
public static final Codec<DefaultedList<IngredientWithSpell>> LIST_CODEC = CODEC.listOf().xmap(
|
||||
list -> DefaultedList.<IngredientWithSpell>copyOf(EMPTY, list.toArray(IngredientWithSpell[]::new)),
|
||||
Function.identity()
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
|
|||
import com.minelittlepony.unicopia.container.inventory.SpellbookInventory;
|
||||
import com.minelittlepony.unicopia.item.EnchantableItem;
|
||||
import com.minelittlepony.unicopia.item.URecipes;
|
||||
import com.minelittlepony.unicopia.util.CodecUtils;
|
||||
import com.minelittlepony.unicopia.util.InventoryUtil;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
|
@ -45,9 +46,9 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
|||
/**
|
||||
* The resulting item
|
||||
*/
|
||||
final ItemStackWithSpell output;
|
||||
final ItemStack output;
|
||||
|
||||
private SpellCraftingRecipe(IngredientWithSpell material, TraitIngredient requiredTraits, List<IngredientWithSpell> requiredItems, ItemStackWithSpell output) {
|
||||
private SpellCraftingRecipe(IngredientWithSpell material, TraitIngredient requiredTraits, List<IngredientWithSpell> requiredItems, ItemStack output) {
|
||||
this.material = material;
|
||||
this.requiredTraits = requiredTraits;
|
||||
this.requiredItems = requiredItems;
|
||||
|
@ -63,7 +64,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
|||
requiredTraits.min().ifPresent(min -> {
|
||||
min.forEach(e -> builder.input(e.getKey(), e.getValue()));
|
||||
});
|
||||
builder.result(output.toItemStack());
|
||||
builder.result(output);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -115,7 +116,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
|||
|
||||
@Override
|
||||
public ItemStack getResult(DynamicRegistryManager registries) {
|
||||
return output.toItemStack();
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,29 +124,17 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
|||
return URecipes.TRAIT_REQUIREMENT;
|
||||
}
|
||||
|
||||
record ItemStackWithSpell(ItemStack stack, Optional<SpellType<?>> spell) {
|
||||
public static final Codec<ItemStackWithSpell> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
RecipeCodecs.CRAFTING_RESULT.fieldOf("stack").forGetter(ItemStackWithSpell::stack),
|
||||
SpellType.REGISTRY.getCodec().optionalFieldOf("spell").forGetter(ItemStackWithSpell::spell)
|
||||
).apply(instance, ItemStackWithSpell::new));
|
||||
|
||||
public ItemStack toItemStack() {
|
||||
return spell.filter(s -> s != SpellType.EMPTY_KEY).map(s -> {
|
||||
return EnchantableItem.enchant(stack.copy(), s);
|
||||
}).orElse(stack);
|
||||
}
|
||||
|
||||
public ItemStackWithSpell(ItemStack stack) {
|
||||
this(EnchantableItem.unenchant(stack), Optional.of(EnchantableItem.getSpellKey(stack)));
|
||||
}
|
||||
}
|
||||
|
||||
public static class Serializer implements RecipeSerializer<SpellCraftingRecipe> {
|
||||
private static final Codec<ItemStack> RESULT_CODEC = CodecUtils.extend(RecipeCodecs.CRAFTING_RESULT, SpellType.REGISTRY.getCodec().fieldOf("spell")).xmap(
|
||||
pair -> pair.getSecond().map(spell -> EnchantableItem.enchant(pair.getFirst().orElse(ItemStack.EMPTY), spell)).orElse(pair.getFirst().orElse(ItemStack.EMPTY)),
|
||||
stack -> Pair.of(Optional.of(stack), EnchantableItem.getSpellKeyOrEmpty(stack))
|
||||
);
|
||||
|
||||
private static final Codec<SpellCraftingRecipe> CODEC = RecordCodecBuilder.<SpellCraftingRecipe>create(instance -> instance.group(
|
||||
IngredientWithSpell.CODEC.fieldOf("material").forGetter(recipe -> recipe.material),
|
||||
TraitIngredient.CODEC.fieldOf("traits").forGetter(recipe -> recipe.requiredTraits),
|
||||
IngredientWithSpell.CODEC.listOf().fieldOf("ingredients").forGetter(recipe -> recipe.requiredItems),
|
||||
ItemStackWithSpell.CODEC.fieldOf("result").forGetter(recipe -> recipe.output)
|
||||
RESULT_CODEC.fieldOf("result").forGetter(recipe -> recipe.output)
|
||||
).apply(instance, SpellCraftingRecipe::new));
|
||||
|
||||
@Override
|
||||
|
@ -159,7 +148,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
|||
IngredientWithSpell.fromPacket(buf),
|
||||
TraitIngredient.fromPacket(buf),
|
||||
buf.readCollection(DefaultedList::ofSize, IngredientWithSpell::fromPacket),
|
||||
new ItemStackWithSpell(buf.readItemStack())
|
||||
buf.readItemStack()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -168,7 +157,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
|||
recipe.material.write(buf);
|
||||
recipe.requiredTraits.write(buf);
|
||||
buf.writeCollection(recipe.requiredItems, (b, i) -> i.write(b));
|
||||
buf.writeItemStack(recipe.output.toItemStack());
|
||||
buf.writeItemStack(recipe.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ public enum Trait implements CommandArgumentEnum<Trait> {
|
|||
|
||||
@Deprecated
|
||||
public static Optional<Trait> fromId(Identifier id) {
|
||||
return Optional.ofNullable(ID_CODEC.byId(id.toString()));
|
||||
return Optional.ofNullable(IDS.get(id));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
|
|
@ -3,9 +3,9 @@ package com.minelittlepony.unicopia.advancement;
|
|||
import net.minecraft.advancement.criterion.Criteria;
|
||||
|
||||
public interface UCriteria {
|
||||
CustomEventCriterion CUSTOM_EVENT = Criteria.register("unicopia:send_dragon_breath", new CustomEventCriterion());
|
||||
CustomEventCriterion CUSTOM_EVENT = Criteria.register("unicopia:custom", new CustomEventCriterion());
|
||||
RaceChangeCriterion PLAYER_CHANGE_RACE = Criteria.register("unicopia:player_change_race", new RaceChangeCriterion());
|
||||
SendViaDragonBreathScrollCriterion SEND_DRAGON_BREATH = Criteria.register("unicopia:custom", new SendViaDragonBreathScrollCriterion());
|
||||
SendViaDragonBreathScrollCriterion SEND_DRAGON_BREATH = Criteria.register("unicopia:send_dragon_breath", new SendViaDragonBreathScrollCriterion());
|
||||
|
||||
CustomEventCriterion.Trigger LOOK_INTO_SUN = CUSTOM_EVENT.createTrigger("look_into_sun");
|
||||
CustomEventCriterion.Trigger WEAR_SHADES = CUSTOM_EVENT.createTrigger("wear_shades");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.minelittlepony.unicopia.item;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -83,6 +84,10 @@ public interface EnchantableItem extends ItemConvertible {
|
|||
return stack;
|
||||
}
|
||||
|
||||
static Optional<SpellType<?>> getSpellKeyOrEmpty(ItemStack stack) {
|
||||
return isEnchanted(stack) ? SpellType.REGISTRY.getOrEmpty(new Identifier(stack.getNbt().getString("spell"))) : Optional.empty();
|
||||
}
|
||||
|
||||
static <T extends Spell> SpellType<T> getSpellKey(ItemStack stack) {
|
||||
return SpellType.getKey(isEnchanted(stack) ? new Identifier(stack.getNbt().getString("spell")) : SpellType.EMPTY_ID);
|
||||
}
|
||||
|
|
|
@ -20,12 +20,11 @@ public class ZapAppleRecipe extends ShapelessRecipe {
|
|||
public static class Serializer implements RecipeSerializer<ZapAppleRecipe> {
|
||||
private static final Codec<ZapAppleRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Codec.STRING.optionalFieldOf("group", "").forGetter(ZapAppleRecipe::getGroup),
|
||||
CraftingRecipeCategory.CODEC.fieldOf("category").forGetter(ZapAppleRecipe::getCategory),
|
||||
Registries.ITEM.getCodec().xmap(item -> {
|
||||
return UItems.ZAP_APPLE.setAppearance(UItems.ZAP_APPLE.getDefaultStack(), item.getDefaultStack());
|
||||
}, stack -> {
|
||||
return UItems.ZAP_APPLE.getAppearance(stack);
|
||||
}).fieldOf("appearance").forGetter(recipe -> recipe.getResult(null)),
|
||||
CraftingRecipeCategory.CODEC.optionalFieldOf("category", CraftingRecipeCategory.MISC).forGetter(ZapAppleRecipe::getCategory),
|
||||
Registries.ITEM.getCodec().xmap(
|
||||
item -> UItems.ZAP_APPLE.setAppearance(UItems.ZAP_APPLE.getDefaultStack(), item.getDefaultStack()),
|
||||
stack -> UItems.ZAP_APPLE.getAppearance(stack)
|
||||
).fieldOf("appearance").forGetter(recipe -> recipe.getResult(null)),
|
||||
URecipes.SHAPELESS_RECIPE_INGREDIENTS_CODEC.fieldOf("ingredients").forGetter(ZapAppleRecipe::getIngredients)
|
||||
).apply(instance, ZapAppleRecipe::new));
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package com.minelittlepony.unicopia.util;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
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;
|
||||
|
||||
public interface CodecUtils {
|
||||
/**
|
||||
* Combines the result of two unrelated codecs into a single object.
|
||||
* <p>
|
||||
* The first codec serves as the "base" whilst the second codec serves as an additional field to merge into
|
||||
* that object when serializing. Deserializing produces a pair with the parent value and the extra value.
|
||||
* <p>
|
||||
* Recommended usage:
|
||||
* <code>
|
||||
* Codec<MyObject> CODEC = CodecUtils.extend(SOME_CODEC, MY_FIELD_CODEC.fieldOf("my_extra_field")).xmap(
|
||||
* pair -> new MyObject(pair.getLeft(), pair.getRight()),
|
||||
* myObject -> Pair.of(myObject.parent(), myObject.myExtraField());
|
||||
* </code>
|
||||
* <p>
|
||||
* Json:
|
||||
* <code>
|
||||
* {
|
||||
* "something": "something",
|
||||
* "something_else": 1,
|
||||
*
|
||||
* "my_extra_field": "HAH EAT THAT CODECS"
|
||||
* }
|
||||
* </code>
|
||||
* @param <A> The base type
|
||||
* @param <B> Type of the field to append
|
||||
* @param baseCodec Codec for the base type
|
||||
* @param fieldCodec Codec for the appended field
|
||||
* @return A codec for serializing objects of the base with the extra field inserted
|
||||
*/
|
||||
static <A, B> Codec<Pair<Optional<A>, Optional<B>>> extend(Codec<A> baseCodec, MapCodec<B> fieldCodec) {
|
||||
return Codec.of(new Encoder<Pair<Optional<A>, Optional<B>>>() {
|
||||
@Override
|
||||
public <T> DataResult<T> encode(Pair<Optional<A>, Optional<B>> input, DynamicOps<T> ops, T prefix) {
|
||||
return baseCodec.encode(input.getFirst().get(), ops, prefix)
|
||||
.flatMap(leftResult -> input.getSecond()
|
||||
.map(r -> fieldCodec.encode(r, ops, ops.mapBuilder()).build(prefix))
|
||||
.orElse(DataResult.success(leftResult)));
|
||||
}
|
||||
}, new Decoder<Pair<Optional<A>, Optional<B>>>() {
|
||||
@Override
|
||||
public <T> DataResult<Pair<Pair<Optional<A>, Optional<B>>, T>> decode(DynamicOps<T> ops, T input) {
|
||||
return DataResult.success(new Pair<>(new Pair<>(
|
||||
baseCodec.decode(ops, input).map(Pair::getFirst).result(),
|
||||
fieldCodec.decode(ops, ops.getMap(input).result().get()).result()
|
||||
), input));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
"block": "unicopia:apple_pie",
|
||||
"condition": "minecraft:block_state_property",
|
||||
"properties": {
|
||||
"stomped": true
|
||||
"stomped": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue