-
Notifications
You must be signed in to change notification settings - Fork 39
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add test for CooptCodec and adjust how error recover is handled with …
…deserialization
- Loading branch information
1 parent
cfdfc6b
commit 2247a50
Showing
17 changed files
with
628 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
src/main/java/io/wispforest/owo/serialization/endecs/EitherEndec.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package io.wispforest.owo.serialization.endecs; | ||
|
||
import com.mojang.datafixers.util.Either; | ||
import io.wispforest.owo.serialization.Deserializer; | ||
import io.wispforest.owo.serialization.Endec; | ||
import io.wispforest.owo.serialization.Serializer; | ||
import io.wispforest.owo.serialization.impl.SerializationAttribute; | ||
|
||
import java.util.Objects; | ||
import java.util.Optional; | ||
|
||
public record EitherEndec<F, S>(Endec<F> first, Endec<S> second) implements Endec<Either<F, S>> { | ||
|
||
@Override | ||
public <E> void encode(Serializer<E> serializer, Either<F, S> either) { | ||
boolean selfDescribing = serializer.attributes().contains(SerializationAttribute.SELF_DESCRIBING); | ||
|
||
if(!selfDescribing){ | ||
either.ifLeft(left -> { | ||
try(var struct = serializer.struct()) { | ||
struct.field("side", Endec.VAR_INT, 0) | ||
.field("value", first, left); | ||
} | ||
}).ifRight(right -> { | ||
try(var struct = serializer.struct()) { | ||
struct.field("side", Endec.VAR_INT, 1) | ||
.field("value", second, right); | ||
} | ||
}); | ||
|
||
return; | ||
} | ||
|
||
either.ifLeft(left -> first.encode(serializer, left)) | ||
.ifRight(right -> second.encode(serializer, right)); | ||
} | ||
|
||
@Override | ||
public <E> Either<F, S> decode(Deserializer<E> deserializer) { | ||
boolean selfDescribing = deserializer.attributes().contains(SerializationAttribute.SELF_DESCRIBING); | ||
|
||
if(!selfDescribing){ | ||
var struct = deserializer.struct(); | ||
|
||
return switch (struct.field("side", Endec.VAR_INT)){ | ||
case 0 -> Either.left(struct.field("value", first)); | ||
case 1 -> Either.right(struct.field("value", second)); | ||
default -> throw new IllegalStateException("Unknown Int value for given Either Endec"); | ||
}; | ||
} | ||
|
||
Optional<Either<F, S>> result1 = Optional.empty(); | ||
|
||
try { | ||
result1 = Optional.of(Either.left(deserializer.tryRead(first::decode))); | ||
} catch (Exception ignore) {} | ||
|
||
Optional<Either<F, S>> result2 = Optional.empty(); | ||
|
||
try { | ||
result2 = Optional.of(Either.right(deserializer.tryRead(second::decode))); | ||
} catch (Exception ignore) {} | ||
|
||
if (result1.isPresent()) return result1.get(); | ||
if (result2.isPresent()) return result2.get(); | ||
|
||
throw new IllegalStateException("Neither alternatives read successfully!"); | ||
} | ||
|
||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
|
||
if (o != null && this.getClass() == o.getClass()) { | ||
EitherEndec<?, ?> either = (EitherEndec) o; | ||
return Objects.equals(this.first, either.first) && Objects.equals(this.second, either.second); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
public String toString() { | ||
return "EitherCodec[" + this.first + ", " + this.second + "]"; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/main/java/io/wispforest/owo/serialization/endecs/ExtraEndecs.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package io.wispforest.owo.serialization.endecs; | ||
|
||
import io.wispforest.owo.serialization.Endec; | ||
import io.wispforest.owo.serialization.impl.ReflectionEndecBuilder; | ||
import net.minecraft.recipe.book.CraftingRecipeCategory; | ||
|
||
import java.util.function.Function; | ||
|
||
public class ExtraEndecs { | ||
|
||
public static final Endec<Integer> NONNEGATIVE_INT = rangedInt(0, Integer.MAX_VALUE, v -> "Value must be non-negative: " + v); | ||
public static final Endec<Integer> POSITIVE_INT = rangedInt(1, Integer.MAX_VALUE, v -> "Value must be positive: " + v); | ||
|
||
|
||
private static Endec<Integer> rangedInt(int min, int max, Function<Integer, String> messageFactory) { | ||
return Endec.INT.validate(value -> { | ||
if(value.compareTo(min) >= 0 && value.compareTo(max) <= 0) return value; | ||
|
||
throw new IllegalStateException(messageFactory.apply(value)); | ||
}); | ||
} | ||
} |
70 changes: 70 additions & 0 deletions
70
src/main/java/io/wispforest/owo/serialization/endecs/IngredientEndec.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package io.wispforest.owo.serialization.endecs; | ||
|
||
import com.mojang.datafixers.util.Either; | ||
import io.wispforest.owo.serialization.Endec; | ||
import io.wispforest.owo.serialization.impl.StructEndecBuilder; | ||
import net.minecraft.recipe.Ingredient; | ||
import net.minecraft.registry.RegistryKeys; | ||
import net.minecraft.util.collection.DefaultedList; | ||
|
||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class IngredientEndec { | ||
|
||
private static final Endec<Ingredient.StackEntry> STACK_ENTRY_ENDEC = StructEndecBuilder.of( | ||
RecipeEndecs.INGREDIENT.field("item", e -> e.stack), | ||
Ingredient.StackEntry::new | ||
); | ||
|
||
private static final Endec<Ingredient.TagEntry> TAG_ENTRY_ENDEC = StructEndecBuilder.of( | ||
Endec.unprefixedTagKey(RegistryKeys.ITEM).field("tag", e -> e.tag), | ||
Ingredient.TagEntry::new | ||
); | ||
|
||
private static final Endec<Ingredient.Entry> INGREDIENT_ENTRY_ENDEC = new XorEndec<>(STACK_ENTRY_ENDEC, TAG_ENTRY_ENDEC) | ||
.then( | ||
either -> either.map(stackEntry -> stackEntry, tagEntry -> tagEntry), | ||
entry -> { | ||
if (entry instanceof Ingredient.TagEntry tagEntry) return Either.right(tagEntry); | ||
if (entry instanceof Ingredient.StackEntry stackEntry) return Either.left(stackEntry); | ||
|
||
throw new UnsupportedOperationException("This is neither an item value nor a tag value."); | ||
} | ||
); | ||
|
||
public static final Endec<Ingredient> ALLOW_EMPTY_CODEC = createEndec(true); | ||
public static final Endec<Ingredient> DISALLOW_EMPTY_CODEC = createEndec(false); | ||
|
||
// public static final Endec<Ingredient> RAW_DATA = Endec.ITEM_STACK.list() | ||
// .then( | ||
// stackList -> Ingredient.ofEntries(stackList.stream().map(Ingredient.StackEntry::new)), | ||
// ingredient -> Arrays.stream(ingredient.getMatchingStacks()).toList() | ||
// ); | ||
|
||
private static Endec<Ingredient> createEndec(boolean allowEmpty) { | ||
Endec<Ingredient.Entry[]> endec = INGREDIENT_ENTRY_ENDEC.list() | ||
.validate(entries -> { | ||
if(!allowEmpty && entries.size() < 1){ | ||
throw new IllegalStateException("Item array cannot be empty, at least one item must be defined"); | ||
} | ||
|
||
return entries; | ||
}) | ||
.then(entries -> entries.toArray(new Ingredient.Entry[0]), List::of); | ||
|
||
return new EitherEndec<>(endec, INGREDIENT_ENTRY_ENDEC) | ||
.then( | ||
either -> either.map(Ingredient::new, entry -> new Ingredient(new Ingredient.Entry[]{entry})), | ||
ingredient -> { | ||
if(ingredient.entries.length == 0 && !allowEmpty){ | ||
throw new IllegalStateException("Item array cannot be empty, at least one item must be defined"); | ||
} | ||
|
||
return (ingredient.entries.length == 1) | ||
? Either.right(ingredient.entries[0]) | ||
: Either.left(ingredient.entries); | ||
} | ||
); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
src/main/java/io/wispforest/owo/serialization/endecs/RecipeEndecs.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package io.wispforest.owo.serialization.endecs; | ||
|
||
import io.wispforest.owo.serialization.Endec; | ||
import io.wispforest.owo.serialization.impl.ReflectionEndecBuilder; | ||
import io.wispforest.owo.serialization.impl.StructEndecBuilder; | ||
import io.wispforest.owo.serialization.impl.StructField; | ||
import net.minecraft.item.Item; | ||
import net.minecraft.item.ItemStack; | ||
import net.minecraft.item.Items; | ||
import net.minecraft.recipe.book.CraftingRecipeCategory; | ||
import net.minecraft.registry.Registries; | ||
|
||
public class RecipeEndecs { | ||
private static final Endec<Item> CRAFTING_RESULT_ITEM = Endec.ofRegistry(Registries.ITEM) | ||
.validate(item -> { | ||
if(item == Items.AIR) throw new IllegalStateException("Crafting result must not be minecraft:air"); | ||
|
||
return item; | ||
}); | ||
|
||
public static final Endec<ItemStack> CRAFTING_RESULT = StructEndecBuilder.of( | ||
CRAFTING_RESULT_ITEM.field("item", ItemStack::getItem), | ||
StructField.defaulted("count", ExtraEndecs.POSITIVE_INT, ItemStack::getCount, 1), | ||
ItemStack::new | ||
); | ||
|
||
static final Endec<ItemStack> INGREDIENT = Endec.ofRegistry(Registries.ITEM) | ||
.validate(item -> { | ||
if(item == Items.AIR) throw new IllegalStateException("Empty ingredient not allowed here"); | ||
|
||
return item; | ||
}) | ||
.then(ItemStack::new, ItemStack::getItem); | ||
|
||
public static final Endec<CraftingRecipeCategory> CATEGORY_ENDEC = ReflectionEndecBuilder.createEnumSerializer(CraftingRecipeCategory.class); | ||
|
||
} |
Oops, something went wrong.