diff --git a/src/main/java/anya/pizza/houseki/block/entity/custom/CrusherBlockEntity.java b/src/main/java/anya/pizza/houseki/block/entity/custom/CrusherBlockEntity.java index 6315e87..7a86e41 100644 --- a/src/main/java/anya/pizza/houseki/block/entity/custom/CrusherBlockEntity.java +++ b/src/main/java/anya/pizza/houseki/block/entity/custom/CrusherBlockEntity.java @@ -110,6 +110,13 @@ public AbstractContainerMenu createMenu(int syncId, @NonNull Inventory playerInv return new CrusherScreenHandler(syncId, playerInventory, this, propertyDelegate); } + /** + * Drops this block entity's inventory at the given position when the block is removed, then + * invokes superclass removal side-effects. + * + * @param pos the position of the block being removed + * @param oldState the previous block state at that position + */ @Override public void preRemoveSideEffects(@NonNull BlockPos pos, @NonNull BlockState oldState) { assert level != null; @@ -191,6 +198,14 @@ private void updateMaxProgress(Level world) { .orElse(CrusherRecipe.DEFAULT_CRUSHING_TIME); } + /** + * Determines whether the current crusher recipe can be executed given available output space. + * + * Checks that a matching recipe exists and that the recipe's primary output and optional auxiliary + * output can both fit into their respective output slots. + * + * @return true if both the main output and the auxiliary output (if present) can be inserted into their slots, false otherwise. + */ private boolean canCraft() { Optional> recipe = getCurrentRecipe(); if (recipe.isEmpty()) return false; @@ -227,13 +242,11 @@ private boolean canInsertIntoSlot(int slot, ItemStack stack) { } /** - * Apply the currently matched crusher recipe: produce the recipe's main output, optionally produce - * the auxiliary output based on its chance, and consume one input item. + * Apply the currently matched crusher recipe, producing the recipe's outputs and consuming one input item. * - * If no matching recipe is available, the method makes no changes. The main output is always - * inserted (or stacked) into the main output slot; the auxiliary output is inserted only if the - * recipe provides one and its configured chance succeeds. One item is removed from the input slot - * when a recipe is applied. + * If no matching recipe is available, no changes are made. The recipe's main output is inserted into (or stacked + * onto) the main output slot; the auxiliary output is inserted into the auxiliary output slot only if the recipe + * provides one and its configured chance succeeds. One item is removed from the input slot when the recipe is applied. */ private void craftItem() { Optional> recipe = getCurrentRecipe(); @@ -276,6 +289,11 @@ private void insertOrIncrement(int slot, ItemStack result, double chance) { } } + /** + * Look up the crusher recipe that matches the current input stack on the server. + * + * @return An Optional containing the matching RecipeHolder when running on a server and a recipe exists; {@code Optional.empty()} otherwise. + */ private Optional> getCurrentRecipe() { Level level = this.getLevel(); if (!(level instanceof ServerLevel serverLevel)) { @@ -285,6 +303,13 @@ private Optional> getCurrentRecipe() { .getRecipeFor(ModTypes.CRUSHER_TYPE, new CrusherRecipeInput(inventory.getFirst()), level); } + /** + * Get the inventory slot indices that are accessible from the given block face. + * + * @param side the block face from which access is attempted + * @return an array of slot indices accessible from the specified face; if {@link Direction#DOWN} returns + * OUTPUT_SLOT and AUXILIARY_OUTPUT_SLOT, otherwise returns INPUT_SLOT and FUEL_SLOT + */ @Override public int @NonNull [] getSlotsForFace(@NonNull Direction side) { return side == Direction.DOWN ? new int[]{OUTPUT_SLOT, AUXILIARY_OUTPUT_SLOT} : new int[]{INPUT_SLOT, FUEL_SLOT}; diff --git a/src/main/java/anya/pizza/houseki/datagen/ModRecipeProvider.java b/src/main/java/anya/pizza/houseki/datagen/ModRecipeProvider.java index d74c4fb..a5ca2dd 100644 --- a/src/main/java/anya/pizza/houseki/datagen/ModRecipeProvider.java +++ b/src/main/java/anya/pizza/houseki/datagen/ModRecipeProvider.java @@ -29,6 +29,17 @@ public ModRecipeProvider(FabricPackOutput output, CompletableFutureThe provider's buildRecipes implementation defines crushing, smelting, blasting, + * stonecutting, crafting, tool/armor, upgrade, and related recipes and emits them to + * the given recipe output with mod-specific resource keys.

+ * + * @param wrapperLookup a registry lookup provider used when constructing recipes + * @param recipeExporter the recipe output to which generated recipes will be saved + * @return a RecipeProvider configured to generate the Houseki mod's recipes + */ @Override protected RecipeProvider createRecipeProvider(HolderLookup.Provider wrapperLookup, RecipeOutput recipeExporter) { return new RecipeProvider(wrapperLookup, recipeExporter) { @@ -469,4 +480,4 @@ public void buildRecipes() { public @NonNull String getName() { return "Houseki Recipes"; } -} +} \ No newline at end of file diff --git a/src/main/java/anya/pizza/houseki/datagen/recipebuilder/CrusherRecipeBuilder.java b/src/main/java/anya/pizza/houseki/datagen/recipebuilder/CrusherRecipeBuilder.java index 3104c3e..0b77269 100644 --- a/src/main/java/anya/pizza/houseki/datagen/recipebuilder/CrusherRecipeBuilder.java +++ b/src/main/java/anya/pizza/houseki/datagen/recipebuilder/CrusherRecipeBuilder.java @@ -29,26 +29,65 @@ public class CrusherRecipeBuilder implements RecipeBuilder { @Nullable public String group; + /** + * Creates a new CrusherRecipeBuilder for building a crusher recipe. + * + * @param input the ingredient(s) consumed by the recipe + * @param output the resulting item produced by the recipe + * @param crushingTime the crushing duration in ticks + */ public CrusherRecipeBuilder(Ingredient input, ItemLike output, int crushingTime) { this.input = input; this.output = output; this.crushingTime = crushingTime; } + /** + * Create a builder for a crusher recipe. + * + * @param input the ingredient consumed by the recipe + * @param output the item produced by the recipe + * @param crushingTime the crushing duration for the recipe + * @return a CrusherRecipeBuilder configured with the provided input, output, and crushing time + */ public static CrusherRecipeBuilder create(Ingredient input, ItemLike output, int crushingTime) { return new CrusherRecipeBuilder(input, output, crushingTime); } + /** + * Sets an optional auxiliary output item for the crusher recipe. + * + * @param stack the auxiliary output item to produce in addition to the primary output + * @return this builder instance + */ public CrusherRecipeBuilder auxiliary(ItemLike stack) { this.auxiliaryOutput = Optional.of(stack); return this; } + /** + * Set the probability that the auxiliary output is produced. + * + * @param chance the probability (0.0 to 1.0) that the auxiliary output is produced + * @return the current CrusherRecipeBuilder instance + */ public CrusherRecipeBuilder chance(double chance) { this.auxiliaryChance = chance; return this; } + /** + * Builds an advancement that unlocks the given recipe and exports the constructed + * CrusherRecipe together with that advancement. + * + * The advancement will include a `"has_the_recipe"` criterion for the provided + * recipe key, any additional criteria configured on this builder, and will reward + * the recipe. The built advancement is placed under the `"recipes/"` advancement + * path when exported. + * + * @param exporter target consumer that accepts the recipe and its advancement + * @param recipeKey resource key identifying the recipe to export + */ public void save(RecipeOutput exporter, ResourceKey> recipeKey) { // 1. Build the advancement // We use recipeKey.getValue() to get the Identifier (e.g., "modid:item_crushing") @@ -76,6 +115,16 @@ public void save(RecipeOutput exporter, ResourceKey> recipeKey) { ); } + /** + * Builds a CrusherRecipe and its unlocking advancement, then registers them with the provided exporter under the "recipes/..." advancement path. + * + * The method parses the given recipeId into an Identifier and ResourceKey, adds a "has_the_recipe" criterion and any configured criteria to the advancement, + * sets the recipe as the advancement reward, constructs a CrusherRecipe using this builder's input, output, crushing time, optional auxiliary output, and auxiliary chance, + * and finally passes the recipe, its resource key, and the built advancement (placed under "recipes/") to the exporter. + * + * @param exporter the RecipeOutput consumer that receives the recipe ResourceKey, the built CrusherRecipe, and its corresponding Advancement + * @param recipeId the string identifier for the recipe (parsed into an Identifier and used to derive the advancement path) + */ public void save(RecipeOutput exporter, String recipeId) { // 1. Convert the String ID into an Identifier and a ResourceKey Identifier id = Identifier.parse(recipeId); @@ -103,6 +152,13 @@ public void save(RecipeOutput exporter, String recipeId) { exporter.accept(recipeKey, recipe, advancement.build(id.withPrefix("recipes/"))); } + /** + * Adds an advancement criterion that will be required to unlock the resulting recipe. + * + * @param name a unique identifier for the criterion within the recipe's advancement + * @param criterion the criterion describing the unlocking condition + * @return this builder instance for method chaining + */ @Override public @NonNull RecipeBuilder unlockedBy(@NonNull String name, @NonNull Criterion criterion) { this.criteria.put(name, criterion); @@ -115,11 +171,21 @@ public void save(RecipeOutput exporter, String recipeId) { return this; } + /** + * Indicates this builder does not supply a default recipe identifier. + * + * @return {@code null} to indicate no default {@code ResourceKey>} is provided. + */ @Override public @Nullable ResourceKey> defaultId() { return null; } + /** + * Gets the Item representation of the configured recipe output. + * + * @return the Item corresponding to the builder's output + */ public Item getResult() { return output.asItem(); } diff --git a/src/main/java/anya/pizza/houseki/recipe/CrusherRecipe.java b/src/main/java/anya/pizza/houseki/recipe/CrusherRecipe.java index 98e44b3..9411b69 100644 --- a/src/main/java/anya/pizza/houseki/recipe/CrusherRecipe.java +++ b/src/main/java/anya/pizza/houseki/recipe/CrusherRecipe.java @@ -35,20 +35,43 @@ public String toString() { } } + /** + * Create an ItemStack containing the recipe's primary output. + * + * @param registries the registry provider (not used by this implementation) + * @return an ItemStack containing one unit of the recipe's output + */ public ItemStack getResult(HolderLookup.Provider registries) { return new ItemStack(this.output); } + /** + * Determines whether this recipe matches the provided crusher input. + * + * @param input the crusher input whose first slot will be tested against the recipe's ingredient + * @param level the current level/world context + * @return true if the recipe's input ingredient matches the item in the first slot of {@code input}, false otherwise + */ @Override public boolean matches(CrusherRecipeInput input, Level level) { return this.inputItem.test(input.getItem(0)); } + /** + * Create an ItemStack representing this recipe's primary output. + * + * @return an ItemStack containing the recipe's output item with a count of 1 + */ @Override public ItemStack assemble(CrusherRecipeInput input) { return new ItemStack(this.output); } + /** + * Indicates whether using this recipe triggers a player notification. + * + * @return true if a notification should be shown when the recipe is used, false otherwise. + */ @Override public boolean showNotification() { return true; @@ -65,6 +88,11 @@ public PlacementInfo placementInfo() { return PlacementInfo.create(this.inputItem); } + /** + * Specifies the recipe book category for this recipe. + * + * @return the RecipeBookCategory under which this recipe appears (RecipeBookCategories.CRAFTING_MISC) + */ @Override public RecipeBookCategory recipeBookCategory() { // Use a standard category or your own @@ -98,6 +126,11 @@ public RecipeSerializer> getSerializer() { return SERIALIZER; } + /** + * Identifies the recipe type for crusher recipes. + * + * @return the RecipeType instance that identifies crusher recipes + */ @Override public RecipeType> getType() { return ModTypes.CRUSHER_TYPE;