mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-30 16:28:00 +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 java.util.function.Supplier;
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType;
|
||||||
import com.minelittlepony.unicopia.item.EnchantableItem;
|
import com.minelittlepony.unicopia.item.EnchantableItem;
|
||||||
|
import com.minelittlepony.unicopia.util.CodecUtils;
|
||||||
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.DataResult;
|
|
||||||
import com.mojang.serialization.Decoder;
|
|
||||||
import com.mojang.serialization.DynamicOps;
|
|
||||||
import com.mojang.serialization.Encoder;
|
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.network.PacketByteBuf;
|
import net.minecraft.network.PacketByteBuf;
|
||||||
import net.minecraft.recipe.Ingredient;
|
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 IngredientWithSpell EMPTY = new IngredientWithSpell(Optional.empty(), Optional.empty());
|
||||||
private static final Predicate<Ingredient> INGREDIENT_IS_PRESENT = ((Predicate<Ingredient>)(Ingredient::isEmpty)).negate();
|
private static final Predicate<Ingredient> INGREDIENT_IS_PRESENT = ((Predicate<Ingredient>)(Ingredient::isEmpty)).negate();
|
||||||
|
|
||||||
public static final Codec<IngredientWithSpell> CODEC = Codec.of(new Encoder<IngredientWithSpell>() {
|
public static final Codec<IngredientWithSpell> CODEC = CodecUtils.extend(Ingredient.ALLOW_EMPTY_CODEC, SpellType.REGISTRY.getCodec().fieldOf("spell")).xmap(
|
||||||
@Override
|
pair -> new IngredientWithSpell(pair.getFirst(), pair.getSecond()),
|
||||||
public <T> DataResult<T> encode(IngredientWithSpell input, DynamicOps<T> ops, T prefix) {
|
ingredient -> new Pair<>(ingredient.stack, ingredient.spell)
|
||||||
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<DefaultedList<IngredientWithSpell>> LIST_CODEC = CODEC.listOf().xmap(
|
public static final Codec<DefaultedList<IngredientWithSpell>> LIST_CODEC = CODEC.listOf().xmap(
|
||||||
list -> DefaultedList.<IngredientWithSpell>copyOf(EMPTY, list.toArray(IngredientWithSpell[]::new)),
|
list -> DefaultedList.<IngredientWithSpell>copyOf(EMPTY, list.toArray(IngredientWithSpell[]::new)),
|
||||||
Function.identity()
|
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.container.inventory.SpellbookInventory;
|
||||||
import com.minelittlepony.unicopia.item.EnchantableItem;
|
import com.minelittlepony.unicopia.item.EnchantableItem;
|
||||||
import com.minelittlepony.unicopia.item.URecipes;
|
import com.minelittlepony.unicopia.item.URecipes;
|
||||||
|
import com.minelittlepony.unicopia.util.CodecUtils;
|
||||||
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;
|
||||||
|
@ -45,9 +46,9 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
||||||
/**
|
/**
|
||||||
* The resulting item
|
* 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.material = material;
|
||||||
this.requiredTraits = requiredTraits;
|
this.requiredTraits = requiredTraits;
|
||||||
this.requiredItems = requiredItems;
|
this.requiredItems = requiredItems;
|
||||||
|
@ -63,7 +64,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
||||||
requiredTraits.min().ifPresent(min -> {
|
requiredTraits.min().ifPresent(min -> {
|
||||||
min.forEach(e -> builder.input(e.getKey(), e.getValue()));
|
min.forEach(e -> builder.input(e.getKey(), e.getValue()));
|
||||||
});
|
});
|
||||||
builder.result(output.toItemStack());
|
builder.result(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -115,7 +116,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getResult(DynamicRegistryManager registries) {
|
public ItemStack getResult(DynamicRegistryManager registries) {
|
||||||
return output.toItemStack();
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -123,29 +124,17 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
||||||
return URecipes.TRAIT_REQUIREMENT;
|
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> {
|
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(
|
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),
|
||||||
TraitIngredient.CODEC.fieldOf("traits").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)
|
RESULT_CODEC.fieldOf("result").forGetter(recipe -> recipe.output)
|
||||||
).apply(instance, SpellCraftingRecipe::new));
|
).apply(instance, SpellCraftingRecipe::new));
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -159,7 +148,7 @@ public class SpellCraftingRecipe implements SpellbookRecipe {
|
||||||
IngredientWithSpell.fromPacket(buf),
|
IngredientWithSpell.fromPacket(buf),
|
||||||
TraitIngredient.fromPacket(buf),
|
TraitIngredient.fromPacket(buf),
|
||||||
buf.readCollection(DefaultedList::ofSize, IngredientWithSpell::fromPacket),
|
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.material.write(buf);
|
||||||
recipe.requiredTraits.write(buf);
|
recipe.requiredTraits.write(buf);
|
||||||
buf.writeCollection(recipe.requiredItems, (b, i) -> i.write(b));
|
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
|
@Deprecated
|
||||||
public static Optional<Trait> fromId(Identifier id) {
|
public static Optional<Trait> fromId(Identifier id) {
|
||||||
return Optional.ofNullable(ID_CODEC.byId(id.toString()));
|
return Optional.ofNullable(IDS.get(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
|
|
@ -3,9 +3,9 @@ package com.minelittlepony.unicopia.advancement;
|
||||||
import net.minecraft.advancement.criterion.Criteria;
|
import net.minecraft.advancement.criterion.Criteria;
|
||||||
|
|
||||||
public interface UCriteria {
|
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());
|
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 LOOK_INTO_SUN = CUSTOM_EVENT.createTrigger("look_into_sun");
|
||||||
CustomEventCriterion.Trigger WEAR_SHADES = CUSTOM_EVENT.createTrigger("wear_shades");
|
CustomEventCriterion.Trigger WEAR_SHADES = CUSTOM_EVENT.createTrigger("wear_shades");
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.minelittlepony.unicopia.item;
|
package com.minelittlepony.unicopia.item;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
@ -83,6 +84,10 @@ public interface EnchantableItem extends ItemConvertible {
|
||||||
return stack;
|
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) {
|
static <T extends Spell> SpellType<T> getSpellKey(ItemStack stack) {
|
||||||
return SpellType.getKey(isEnchanted(stack) ? new Identifier(stack.getNbt().getString("spell")) : SpellType.EMPTY_ID);
|
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> {
|
public static class Serializer implements RecipeSerializer<ZapAppleRecipe> {
|
||||||
private static final Codec<ZapAppleRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
private static final Codec<ZapAppleRecipe> CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||||
Codec.STRING.optionalFieldOf("group", "").forGetter(ZapAppleRecipe::getGroup),
|
Codec.STRING.optionalFieldOf("group", "").forGetter(ZapAppleRecipe::getGroup),
|
||||||
CraftingRecipeCategory.CODEC.fieldOf("category").forGetter(ZapAppleRecipe::getCategory),
|
CraftingRecipeCategory.CODEC.optionalFieldOf("category", CraftingRecipeCategory.MISC).forGetter(ZapAppleRecipe::getCategory),
|
||||||
Registries.ITEM.getCodec().xmap(item -> {
|
Registries.ITEM.getCodec().xmap(
|
||||||
return UItems.ZAP_APPLE.setAppearance(UItems.ZAP_APPLE.getDefaultStack(), item.getDefaultStack());
|
item -> UItems.ZAP_APPLE.setAppearance(UItems.ZAP_APPLE.getDefaultStack(), item.getDefaultStack()),
|
||||||
}, stack -> {
|
stack -> UItems.ZAP_APPLE.getAppearance(stack)
|
||||||
return UItems.ZAP_APPLE.getAppearance(stack);
|
).fieldOf("appearance").forGetter(recipe -> recipe.getResult(null)),
|
||||||
}).fieldOf("appearance").forGetter(recipe -> recipe.getResult(null)),
|
|
||||||
URecipes.SHAPELESS_RECIPE_INGREDIENTS_CODEC.fieldOf("ingredients").forGetter(ZapAppleRecipe::getIngredients)
|
URecipes.SHAPELESS_RECIPE_INGREDIENTS_CODEC.fieldOf("ingredients").forGetter(ZapAppleRecipe::getIngredients)
|
||||||
).apply(instance, ZapAppleRecipe::new));
|
).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",
|
"block": "unicopia:apple_pie",
|
||||||
"condition": "minecraft:block_state_property",
|
"condition": "minecraft:block_state_property",
|
||||||
"properties": {
|
"properties": {
|
||||||
"stomped": true
|
"stomped": "true"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue