From fa657d46e84bccbc2fdf544a1da5075909f96dbc Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Thu, 27 Jan 2022 20:34:26 +0000 Subject: [PATCH] Fix recipe syncing, improve (add) error handling. --- .../common/crafting/RebornRecipeType.java | 17 +++- .../common/crafting/RecipeManager.java | 2 +- .../common/crafting/RecipeUtils.java | 5 +- .../common/crafting/ShapedRecipeHelper.java | 72 ++++++++++++++++ .../crafting/ingredient/DummyIngredient.java | 2 +- .../crafting/ingredient/FluidIngredient.java | 2 +- .../ingredient/IngredientManager.java | 5 -- .../crafting/ingredient/RebornIngredient.java | 10 ++- .../crafting/ingredient/StackIngredient.java | 2 +- .../crafting/ingredient/TagIngredient.java | 10 ++- .../ingredient/WrappedIngredient.java | 86 ------------------- .../crafting/serde/AbstractRecipeSerde.java | 4 +- .../serde/RebornFluidRecipeSerde.java | 9 +- .../crafting/serde/RebornRecipeSerde.java | 10 +-- .../common/crafting/serde/RecipeSerde.java | 2 +- .../crafting/serde/RecipeSerdeException.java | 39 +++++++++ .../main/resources/reborncore.accesswidener | 6 ++ build.gradle | 12 ++- .../groovy/techreborn/test/TRGameTest.groovy | 19 +++- .../test/recipe/RecipeSyncTests.groovy | 69 +++++++++++++++ src/gametest/resources/fabric.mod.json | 3 +- .../serde/BlastFurnaceRecipeSerde.java | 2 +- .../serde/FusionReactorRecipeSerde.java | 2 +- .../serde/RollingMachineRecipeSerde.java | 9 +- 24 files changed, 273 insertions(+), 126 deletions(-) create mode 100644 RebornCore/src/main/java/reborncore/common/crafting/ShapedRecipeHelper.java delete mode 100644 RebornCore/src/main/java/reborncore/common/crafting/ingredient/WrappedIngredient.java create mode 100644 RebornCore/src/main/java/reborncore/common/crafting/serde/RecipeSerdeException.java create mode 100644 src/gametest/groovy/techreborn/test/recipe/RecipeSyncTests.groovy diff --git a/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipeType.java b/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipeType.java index 4b429ece7..2dca819df 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipeType.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipeType.java @@ -32,6 +32,7 @@ import net.minecraft.util.Identifier; import net.minecraft.util.JsonHelper; import net.minecraft.world.World; import reborncore.common.crafting.serde.RecipeSerde; +import reborncore.common.crafting.serde.RecipeSerdeException; import reborncore.common.util.serialization.SerializationUtil; import java.util.List; @@ -47,14 +48,22 @@ public record RebornRecipeType( throw new RuntimeException("RebornRecipe type not supported!"); } - return recipeSerde.fromJson(json, this, recipeId); + try { + return recipeSerde.fromJson(json, this, recipeId); + } catch (Throwable e) { + throw new RecipeSerdeException(recipeId, e); + } } - private JsonObject toJson(R recipe) { + public JsonObject toJson(R recipe, boolean networkSync) { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("type", name.toString()); - recipeSerde.toJson(recipe, jsonObject); + try { + recipeSerde.toJson(recipe, jsonObject, networkSync); + } catch (Throwable e) { + throw new RecipeSerdeException(recipe.getId(), e); + } return jsonObject; } @@ -67,7 +76,7 @@ public record RebornRecipeType( @Override public void write(PacketByteBuf buffer, R recipe) { - String output = SerializationUtil.GSON_FLAT.toJson(toJson(recipe)); + String output = SerializationUtil.GSON_FLAT.toJson(toJson(recipe, true)); buffer.writeInt(output.length()); buffer.writeString(output); } diff --git a/RebornCore/src/main/java/reborncore/common/crafting/RecipeManager.java b/RebornCore/src/main/java/reborncore/common/crafting/RecipeManager.java index 842034cc5..51018243a 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/RecipeManager.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/RecipeManager.java @@ -62,7 +62,7 @@ public class RecipeManager { return recipeTypes.get(name); } - public static List getRecipeTypes(String namespace) { + public static List> getRecipeTypes(String namespace) { return recipeTypes.values().stream().filter(rebornRecipeType -> rebornRecipeType.name().getNamespace().equals(namespace)).collect(Collectors.toList()); } } diff --git a/RebornCore/src/main/java/reborncore/common/crafting/RecipeUtils.java b/RebornCore/src/main/java/reborncore/common/crafting/RecipeUtils.java index 72e69c6af..78a3bc134 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/RecipeUtils.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/RecipeUtils.java @@ -45,16 +45,15 @@ import reborncore.common.util.serialization.SerializationUtil; import reborncore.mixin.common.AccessorRecipeManager; import java.util.Collection; -import java.util.Collections; import java.util.List; public class RecipeUtils { @SuppressWarnings("unchecked") public static List getRecipes(World world, RebornRecipeType type) { final AccessorRecipeManager accessorRecipeManager = (AccessorRecipeManager) world.getRecipeManager(); - final Collection> recipes = accessorRecipeManager.getAll(type).values(); + final Collection> recipes = accessorRecipeManager.getAll(type).values().stream().toList(); //noinspection unchecked - return Collections.unmodifiableList((List) (Object) recipes); + return (List) (Object) recipes; } public static DefaultedList deserializeItems(JsonElement jsonObject) { diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ShapedRecipeHelper.java b/RebornCore/src/main/java/reborncore/common/crafting/ShapedRecipeHelper.java new file mode 100644 index 000000000..017b6bd39 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ShapedRecipeHelper.java @@ -0,0 +1,72 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import net.minecraft.item.Item; +import net.minecraft.recipe.Ingredient; +import net.minecraft.recipe.ShapedRecipe; +import net.minecraft.tag.Tag; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.registry.Registry; + +import java.util.Map; + +public class ShapedRecipeHelper { + public static JsonObject rewriteForNetworkSync(JsonObject shapedRecipeJson) { + final Map symbols = ShapedRecipe.readSymbols(JsonHelper.getObject(shapedRecipeJson, "key")); + final JsonObject keys = new JsonObject(); + + for (Map.Entry entry : symbols.entrySet()) { + if (entry.getKey().equals(" ")) continue; + + JsonArray entries = new JsonArray(); + + for (Ingredient.Entry ingredientEntry : entry.getValue().entries) { + if (ingredientEntry instanceof Ingredient.StackEntry stackEntry) { + entries.add(stackEntry.toJson()); + } else if (ingredientEntry instanceof Ingredient.TagEntry tagEntry) { + final Tag tag = tagEntry.tag; + final Item[] items = tag.values().toArray(new Item[0]); + + for (Item item : items) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("item", Registry.ITEM.getId(item).toString()); + entries.add(jsonObject); + } + } else { + throw new UnsupportedOperationException("Cannot write " + ingredientEntry.getClass()); + } + } + + keys.add(entry.getKey(), entries); + } + + shapedRecipeJson.remove("key"); + shapedRecipeJson.add("key", keys); + return shapedRecipeJson; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/DummyIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/DummyIngredient.java index c52a28cbd..5de2017f5 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/DummyIngredient.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/DummyIngredient.java @@ -54,7 +54,7 @@ public class DummyIngredient extends RebornIngredient { } @Override - protected JsonObject toJson() { + protected JsonObject toJson(boolean networkSync) { return new JsonObject(); } diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/FluidIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/FluidIngredient.java index 4708c74e3..24306087a 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/FluidIngredient.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/FluidIngredient.java @@ -137,7 +137,7 @@ public class FluidIngredient extends RebornIngredient { } @Override - public JsonObject toJson() { + public JsonObject toJson(boolean networkSync) { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("fluid", Registry.FLUID.getId(fluid).toString()); if (holders.isPresent()) { diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/IngredientManager.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/IngredientManager.java index 24aee0e03..d406dc2a9 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/IngredientManager.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/IngredientManager.java @@ -39,7 +39,6 @@ public class IngredientManager { public static final Identifier STACK_RECIPE_TYPE = new Identifier("reborncore", "stack"); public static final Identifier FLUID_RECIPE_TYPE = new Identifier("reborncore", "fluid"); public static final Identifier TAG_RECIPE_TYPE = new Identifier("reborncore", "tag"); - public static final Identifier WRAPPED_RECIPE_TYPE = new Identifier("reborncore", "wrapped"); private static final HashMap> recipeTypes = new HashMap<>(); @@ -47,7 +46,6 @@ public class IngredientManager { recipeTypes.put(STACK_RECIPE_TYPE, StackIngredient::deserialize); recipeTypes.put(FLUID_RECIPE_TYPE, FluidIngredient::deserialize); recipeTypes.put(TAG_RECIPE_TYPE, TagIngredient::deserialize); - recipeTypes.put(WRAPPED_RECIPE_TYPE, WrappedIngredient::deserialize); } public static RebornIngredient deserialize(@Nullable JsonElement jsonElement) { @@ -63,8 +61,6 @@ public class IngredientManager { recipeTypeIdent = FLUID_RECIPE_TYPE; } else if (json.has("tag")) { recipeTypeIdent = TAG_RECIPE_TYPE; - } else if (json.has("wrapped")) { - recipeTypeIdent = WRAPPED_RECIPE_TYPE; } if (json.has("type")) { @@ -77,5 +73,4 @@ public class IngredientManager { } return recipeTypeFunction.apply(json); } - } diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/RebornIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/RebornIngredient.java index 98c3788b0..b006560bc 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/RebornIngredient.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/RebornIngredient.java @@ -48,17 +48,21 @@ public abstract class RebornIngredient implements Predicate { public abstract List getPreviewStacks(); - protected abstract JsonObject toJson(); + protected abstract JsonObject toJson(boolean networkSync); public abstract int getCount(); //Same as above but adds the type - public final JsonObject witeToJson() { - JsonObject jsonObject = toJson(); + public final JsonObject writeToJson(boolean networkSync) { + JsonObject jsonObject = toJson(networkSync); jsonObject.addProperty("type", ingredientType.toString()); return jsonObject; } + public final JsonObject writeToSyncJson() { + return writeToJson(true); + } + public void ifType(Class clazz, Consumer consumer) { if (this.getClass().isAssignableFrom(clazz)) { //noinspection unchecked diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/StackIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/StackIngredient.java index 13233c3c9..522f56b2a 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/StackIngredient.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/StackIngredient.java @@ -138,7 +138,7 @@ public class StackIngredient extends RebornIngredient { } @Override - public JsonObject toJson() { + public JsonObject toJson(boolean networkSync) { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("item", Registry.ITEM.getId(stacks.get(0).getItem()).toString()); diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/TagIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/TagIngredient.java index 6fe89e7d9..607589440 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/TagIngredient.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/TagIngredient.java @@ -104,7 +104,15 @@ public class TagIngredient extends RebornIngredient { } @Override - public JsonObject toJson() { + public JsonObject toJson(boolean networkSync) { + if (networkSync) { + return toItemJsonObject(); + } + + throw new UnsupportedOperationException("TODO"); + } + + private JsonObject toItemJsonObject() { //Tags are not synced across the server so we sync all the items JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("server_sync", true); diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/WrappedIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/WrappedIngredient.java deleted file mode 100644 index c89db9baf..000000000 --- a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/WrappedIngredient.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is part of RebornCore, licensed under the MIT License (MIT). - * - * Copyright (c) 2021 TeamReborn - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package reborncore.common.crafting.ingredient; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import net.minecraft.item.ItemStack; -import net.minecraft.recipe.Ingredient; - -import java.util.Arrays; -import java.util.List; - -public class WrappedIngredient extends RebornIngredient { - private Ingredient wrapped; - - public WrappedIngredient() { - super(IngredientManager.WRAPPED_RECIPE_TYPE); - } - - public WrappedIngredient(Ingredient wrapped) { - this(); - this.wrapped = wrapped; - } - - @Override - public boolean test(ItemStack itemStack) { - return wrapped.test(itemStack); - } - - @Override - public Ingredient getPreview() { - return wrapped; - } - - @Override - public List getPreviewStacks() { - return Arrays.asList(wrapped.getMatchingStacks()); - } - - @Override - protected JsonObject toJson() { - if (wrapped.toJson() instanceof JsonObject) { - return (JsonObject) wrapped.toJson(); - } - JsonObject jsonObject = new JsonObject(); - jsonObject.add("options", wrapped.toJson()); - return jsonObject; - } - - @Override - public int getCount() { - return wrapped.getMatchingStacks().length; - } - - public static RebornIngredient deserialize(JsonObject jsonObject) { - Ingredient underlying; - if (jsonObject.has("options") && jsonObject.get("options") instanceof JsonArray) { - underlying = Ingredient.fromJson(jsonObject.get("options")); - } else { - underlying = Ingredient.fromJson(jsonObject); - } - return new WrappedIngredient(underlying); - } -} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/serde/AbstractRecipeSerde.java b/RebornCore/src/main/java/reborncore/common/crafting/serde/AbstractRecipeSerde.java index c0b8ea63e..ca524161d 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/serde/AbstractRecipeSerde.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/serde/AbstractRecipeSerde.java @@ -61,9 +61,9 @@ public abstract class AbstractRecipeSerde implements Rec return RecipeUtils.deserializeItems(resultsJson); } - protected void writeIngredients(R recipe, JsonObject jsonObject) { + protected void writeIngredients(R recipe, JsonObject jsonObject, boolean networkSync) { final JsonArray ingredientsArray = new JsonArray(); - recipe.getRebornIngredients().stream().map(RebornIngredient::witeToJson).forEach(ingredientsArray::add); + recipe.getRebornIngredients().stream().map(RebornIngredient::writeToSyncJson).forEach(ingredientsArray::add); jsonObject.add("ingredients", ingredientsArray); } diff --git a/RebornCore/src/main/java/reborncore/common/crafting/serde/RebornFluidRecipeSerde.java b/RebornCore/src/main/java/reborncore/common/crafting/serde/RebornFluidRecipeSerde.java index 94d741357..19b879bdd 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/serde/RebornFluidRecipeSerde.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/serde/RebornFluidRecipeSerde.java @@ -49,7 +49,7 @@ public abstract class RebornFluidRecipeSerde extend final Fluid fluid = Registry.FLUID.get(identifier); FluidValue value = FluidValue.BUCKET; - if(tank.has("amount")){ + if (tank.has("amount")){ value = FluidValue.parseFluidValue(tank.get("amount")); } @@ -59,10 +59,13 @@ public abstract class RebornFluidRecipeSerde extend } @Override - public void collectJsonData(R recipe, JsonObject jsonObject) { + public void collectJsonData(R recipe, JsonObject jsonObject, boolean networkSync) { final JsonObject tankObject = new JsonObject(); tankObject.addProperty("fluid", Registry.FLUID.getId(recipe.getFluidInstance().getFluid()).toString()); - tankObject.addProperty("value", recipe.getFluidInstance().getAmount().getRawValue()); + + var amountObject = new JsonObject(); + amountObject.addProperty("droplets", recipe.getFluidInstance().getAmount().getRawValue()); + tankObject.add("amount", amountObject); jsonObject.add("tank", tankObject); } diff --git a/RebornCore/src/main/java/reborncore/common/crafting/serde/RebornRecipeSerde.java b/RebornCore/src/main/java/reborncore/common/crafting/serde/RebornRecipeSerde.java index 5d16f31f7..fd7843024 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/serde/RebornRecipeSerde.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/serde/RebornRecipeSerde.java @@ -48,16 +48,16 @@ public abstract class RebornRecipeSerde extends Abstract return fromJson(jsonObject, type, name, ingredients, outputs, power, time); } - protected abstract void collectJsonData(R recipe, JsonObject jsonObject); + protected abstract void collectJsonData(R recipe, JsonObject jsonObject, boolean networkSync); @Override - public final void toJson(R recipe, JsonObject jsonObject) { + public final void toJson(R recipe, JsonObject jsonObject, boolean networkSync) { writePower(recipe, jsonObject); writeTime(recipe, jsonObject); - writeIngredients(recipe, jsonObject); + writeIngredients(recipe, jsonObject, true); writeOutputs(recipe, jsonObject); - collectJsonData(recipe, jsonObject); + collectJsonData(recipe, jsonObject, networkSync); } public static RebornRecipeSerde create(SimpleRecipeFactory factory) { @@ -68,7 +68,7 @@ public abstract class RebornRecipeSerde extends Abstract } @Override - protected void collectJsonData(R recipe, JsonObject jsonObject) { + protected void collectJsonData(R recipe, JsonObject jsonObject, boolean networkSync) { } }; } diff --git a/RebornCore/src/main/java/reborncore/common/crafting/serde/RecipeSerde.java b/RebornCore/src/main/java/reborncore/common/crafting/serde/RecipeSerde.java index 6f84ab6b1..d097b0432 100644 --- a/RebornCore/src/main/java/reborncore/common/crafting/serde/RecipeSerde.java +++ b/RebornCore/src/main/java/reborncore/common/crafting/serde/RecipeSerde.java @@ -32,5 +32,5 @@ import reborncore.common.crafting.RebornRecipeType; public interface RecipeSerde { R fromJson(JsonObject jsonObject, RebornRecipeType type, Identifier name); - void toJson(R recipe, JsonObject jsonObject); + void toJson(R recipe, JsonObject jsonObject, boolean networkSync); } diff --git a/RebornCore/src/main/java/reborncore/common/crafting/serde/RecipeSerdeException.java b/RebornCore/src/main/java/reborncore/common/crafting/serde/RecipeSerdeException.java new file mode 100644 index 000000000..ad47a1126 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/serde/RecipeSerdeException.java @@ -0,0 +1,39 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting.serde; + +import net.minecraft.util.Identifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RecipeSerdeException extends RuntimeException { + private static final Logger LOGGER = LoggerFactory.getLogger(RecipeSerdeException.class); + + public RecipeSerdeException(Identifier identifier, Throwable cause) { + super("Failed to ser/de " + identifier, cause); + // Dont trust minecraft to log this. + LOGGER.error(getMessage(), this); + } +} diff --git a/RebornCore/src/main/resources/reborncore.accesswidener b/RebornCore/src/main/resources/reborncore.accesswidener index 947bf14e0..7601023d7 100644 --- a/RebornCore/src/main/resources/reborncore.accesswidener +++ b/RebornCore/src/main/resources/reborncore.accesswidener @@ -4,6 +4,12 @@ accessible method net/minecraft/recipe/ShapedRecipe readSymbols (Lco accessible method net/minecraft/recipe/ShapedRecipe getPattern (Lcom/google/gson/JsonArray;)[Ljava/lang/String; accessible method net/minecraft/recipe/ShapedRecipe createPatternMatrix ([Ljava/lang/String;Ljava/util/Map;II)Lnet/minecraft/util/collection/DefaultedList; +accessible class net/minecraft/recipe/Ingredient$Entry +accessible class net/minecraft/recipe/Ingredient$TagEntry +accessible class net/minecraft/recipe/Ingredient$StackEntry +accessible field net/minecraft/recipe/Ingredient entries [Lnet/minecraft/recipe/Ingredient$Entry; +accessible field net/minecraft/recipe/Ingredient$TagEntry tag Lnet/minecraft/tag/Tag; + accessible method net/minecraft/client/gui/screen/ingame/HandledScreen getSlotAt (DD)Lnet/minecraft/screen/slot/Slot; accessible method net/minecraft/client/render/WorldRenderer drawShapeOutline (Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumer;Lnet/minecraft/util/shape/VoxelShape;DDDFFFF)V \ No newline at end of file diff --git a/build.gradle b/build.gradle index fb7cb8a05..443ef92fd 100644 --- a/build.gradle +++ b/build.gradle @@ -78,6 +78,10 @@ allprojects { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 + loom { + runtimeOnlyLog4j = true + } + // Shared deps between TR and RC dependencies { minecraft "com.mojang:minecraft:${project.minecraft_version}" @@ -173,8 +177,12 @@ dependencies { disabledOptionalDependency "net.oskarstrom:DashLoader:${project.dashloader_version}" // Use groovy for datagen/gametest, if you are copying this you prob dont want it. - gametestImplementation 'org.apache.groovy:groovy:4.0.0-beta-2' - datagenImplementation 'org.apache.groovy:groovy:4.0.0-beta-2' + gametestImplementation 'org.apache.groovy:groovy:4.0.0-rc-2' + datagenImplementation 'org.apache.groovy:groovy:4.0.0-rc-2' + + gametestImplementation ("com.google.truth:truth:1.1.3") { + exclude module: "guava" + } } def optionalDependency(String dep) { diff --git a/src/gametest/groovy/techreborn/test/TRGameTest.groovy b/src/gametest/groovy/techreborn/test/TRGameTest.groovy index 93086b31a..783532342 100644 --- a/src/gametest/groovy/techreborn/test/TRGameTest.groovy +++ b/src/gametest/groovy/techreborn/test/TRGameTest.groovy @@ -24,6 +24,7 @@ package techreborn.test +import groovy.util.logging.Slf4j import net.fabricmc.fabric.api.gametest.v1.FabricGameTest import net.minecraft.test.TestContext @@ -34,9 +35,25 @@ import java.lang.reflect.Method * * All test methods should accept 1 argument of TRTestContext */ +@Slf4j abstract class TRGameTest implements FabricGameTest { @Override void invokeTestMethod(TestContext context, Method method) { - method.invoke(this, new TRTestContext(context)) + try { + method.invoke(this, new TRTestContext(context)) + } catch (TRGameTestException gameTestException) { + log.error("Test ${method.name} failed with message ${gameTestException.message}", gameTestException.cause) + log.error(gameTestException.cause.message) + throw gameTestException + } catch (Throwable throwable) { + log.error("Test ${method.name} failed", throwable) + throw throwable + } } + + static class TRGameTestException extends AssertionError { + TRGameTestException(String message, Throwable cause) { + super(message, cause) + } + } } diff --git a/src/gametest/groovy/techreborn/test/recipe/RecipeSyncTests.groovy b/src/gametest/groovy/techreborn/test/recipe/RecipeSyncTests.groovy new file mode 100644 index 000000000..e0ee9f194 --- /dev/null +++ b/src/gametest/groovy/techreborn/test/recipe/RecipeSyncTests.groovy @@ -0,0 +1,69 @@ +/* + * This file is part of TechReborn, licensed under the MIT License (MIT). + * + * Copyright (c) 2020 TechReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package techreborn.test.recipe + +import com.google.common.truth.Truth +import net.minecraft.test.GameTest +import reborncore.common.crafting.RebornRecipe +import reborncore.common.crafting.RebornRecipeType +import reborncore.common.crafting.RecipeManager +import techreborn.test.TRGameTest +import techreborn.test.TRTestContext + +/** + * A bit of a mess, but checks that we can ser/de all recipes to and from json. + */ +class RecipeSyncTests extends TRGameTest { + @GameTest(structureName = "fabric-gametest-api-v1:empty", tickLimit = 150) + def testRecipes(TRTestContext context) { + + def recipeTypes = RecipeManager.getRecipeTypes("techreborn") + + recipeTypes.each { type -> + def recipes = type.getRecipes(context.world) + recipes.each { recipe -> + try { + testRecipe(type, recipe) + } catch (Throwable t) { + throw new TRGameTestException(recipe.id.toString(), t) + } + } + } + + context.complete() + } + + def void testRecipe(RebornRecipeType type, R recipe) { + def firstJson = type.toJson(recipe, true).deepCopy() + def newRecipe = type.read(recipe.id, firstJson) + def secondJson = type.toJson(newRecipe, true).deepCopy() + + Truth.assertThat(firstJson.toString()) + .isEqualTo(secondJson.toString()) + + // And check we can create a data json + def dataJson = type.toJson(newRecipe, false).deepCopy() + } +} diff --git a/src/gametest/resources/fabric.mod.json b/src/gametest/resources/fabric.mod.json index 36a58fcc4..1b384a5ea 100644 --- a/src/gametest/resources/fabric.mod.json +++ b/src/gametest/resources/fabric.mod.json @@ -6,7 +6,8 @@ "environment": "*", "entrypoints": { "fabric-gametest" : [ - "techreborn.test.machine.GrinderTest" + "techreborn.test.machine.GrinderTest", + "techreborn.test.recipe.RecipeSyncTests" ] } } \ No newline at end of file diff --git a/src/main/java/techreborn/api/recipe/recipes/serde/BlastFurnaceRecipeSerde.java b/src/main/java/techreborn/api/recipe/recipes/serde/BlastFurnaceRecipeSerde.java index af3efc237..fb15ba9e6 100644 --- a/src/main/java/techreborn/api/recipe/recipes/serde/BlastFurnaceRecipeSerde.java +++ b/src/main/java/techreborn/api/recipe/recipes/serde/BlastFurnaceRecipeSerde.java @@ -43,7 +43,7 @@ public class BlastFurnaceRecipeSerde extends RebornRecipeSerde { @Override @@ -23,8 +25,9 @@ public class RollingMachineRecipeSerde extends RebornRecipeSerde