Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/client/java/com/tcm/MineTale/MineTaleClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@

public class MineTaleClient implements ClientModInitializer {
/**
* Registers client-side screen factories for custom workbench menu types.
* Register client-side screen factories for custom workbench menu types.
*
* Binds the furnace and campfire workbench menu types to their corresponding screen constructors
* so the client can create the appropriate GUI when those menus are opened.
* Binds ModMenuTypes.FURNACE_WORKBENCH_MENU to FurnaceWorkbenchScreen,
* ModMenuTypes.CAMPFIRE_WORKBENCH_MENU to CampfireWorkbenchScreen, and
* ModMenuTypes.WORKBENCH_WORKBENCH_MENU to WorkbenchWorkbenchScreen so the client
* can create the appropriate GUI when those menus open.
*/
@Override
public void onInitializeClient() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ public WorkbenchWorkbenchScreen(WorkbenchWorkbenchMenu menu, Inventory inventory
this(menu, inventory, title, createRecipeBookComponent(menu));
}

/**
* Creates a WorkbenchWorkbenchScreen bound to the given menu, player inventory, title, and recipe book component.
*
* @param menu the menu backing this screen
* @param inventory the player's inventory shown in the screen
* @param title the screen title component
* @param recipeBook the MineTaleRecipeBookComponent used to display and manage recipes in this screen
*/
private WorkbenchWorkbenchScreen(WorkbenchWorkbenchMenu menu, Inventory inventory, Component title, MineTaleRecipeBookComponent recipeBook) {
super(menu, recipeBook, inventory, title);
this.mineTaleRecipeBook = recipeBook;
Expand All @@ -71,11 +79,12 @@ private static MineTaleRecipeBookComponent createRecipeBookComponent(WorkbenchWo
}

/**
* Sets the screen's GUI size and initializes layout so the title is centered.
*
* Sets imageWidth to 176 and imageHeight to 166 before delegating to the superclass
* init method to complete widget and layout initialization (including horizontal title centering).
*/
* Configure the screen's GUI dimensions and initialize widgets.
*
* Sets the layout size (imageWidth = 176, imageHeight = 166), delegates remaining
* layout initialization to the superclass, and creates the three craft buttons
* ("1", "30", "All") wired to their respective handlers.
*/
@Override
protected void init() {
// Important: Set your GUI size before super.init()
Expand Down Expand Up @@ -156,7 +165,15 @@ protected void init() {
// }
// }

// RecipeBookComponent
/**
* Sends a crafting request for the currently selected recipe in the integrated recipe book.
*
* Locates the last recipe collection and last selected recipe ID from the recipe book component,
* resolves the recipe's result item, and sends a CraftRequestPayload to the server containing that
* item and the requested amount.
*
* @param amount the quantity to craft; use -1 to request crafting of the full available stack ("All")
*/

private void handleCraftRequest(int amount) {
// 1. Cast the book component to the Accessor to get the selected data
Expand Down Expand Up @@ -189,12 +206,12 @@ private void handleCraftRequest(int amount) {
}

/**
* Renders the workbench GUI background texture at the screen's top-left position.
* Draws the workbench GUI background texture at the screen's top-left corner.
*
* @param guiGraphics the graphics context for drawing
* @param f partial tick time used for interpolation
* @param i current mouse x coordinate
* @param j current mouse y coordinate
* @param guiGraphics the graphics context used to draw GUI elements
* @param f partial tick time for interpolation
* @param i current mouse x coordinate relative to the window
* @param j current mouse y coordinate relative to the window
*/
protected void renderBg(GuiGraphics guiGraphics, float f, int i, int j) {
int k = this.leftPos;
Expand Down Expand Up @@ -227,9 +244,9 @@ public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
}

/**
* Compute the on-screen position for the recipe book toggle button for this GUI.
* Computes the on-screen position for the recipe book toggle button for this GUI.
*
* @return the ScreenPosition located 5 pixels from the GUI's left edge and 49 pixels above the GUI's vertical center
* @return the screen position placed 5 pixels from the GUI's left edge and 49 pixels above the GUI's vertical center
*/
@Override
protected ScreenPosition getRecipeBookButtonPosition() {
Expand Down
21 changes: 14 additions & 7 deletions src/client/java/com/tcm/MineTale/datagen/ModRecipeProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,26 @@ public ModRecipeProvider(FabricDataOutput output, CompletableFuture<HolderLookup
}

/**
* Creates a RecipeProvider that registers a campfire cooking recipe for porkchop.
* Creates a RecipeProvider that registers the mod's recipe set: a campfire cooking recipe
* that cooks a porkchop into a cooked porkchop, a furnace cooking recipe that converts a
* porkchop into an acacia boat, and a workbench crafting recipe that assembles a chest from
* logs and sticks.
*
* The produced provider builds a single recipe that cooks a porkchop into a cooked porkchop,
* requires 10 time units, is unlocked when the player has a porkchop, and is saved under
* the mod namespace with path "campfire_pork_cooking".
* Each recipe includes its unlock condition, crafting category, book category, processing time,
* and is saved to the provided exporter under the mod-specific paths:
* "campfire_pork_cooking", "furnace_pork_cooking", and "workbench_wood_chest".
*
* @param registryLookup provider for looking up game registries used when building recipes
* @param exporter destination used to write the generated recipe JSON
* @return a RecipeProvider that produces the described campfire cooking recipe
* @param registryLookup provider for looking up game registries and tags used when building recipes
* @param exporter destination used to write the generated recipe JSON files
* @return a RecipeProvider that produces and saves the described recipes to the exporter
*/
@Override
protected RecipeProvider createRecipeProvider(HolderLookup.Provider registryLookup, RecipeOutput exporter) {
return new RecipeProvider(registryLookup, exporter) {
/**
* Registers three mod-specific recipes with the recipe exporter:
* a campfire pork cooking recipe producing cooked porkchop (unlocked by having a porkchop, saved as "campfire_pork_cooking"), a furnace pork cooking recipe producing an acacia boat (unlocked by having a porkchop, saved as "furnace_pork_cooking"), and a workbench recipe that crafts a chest from 5 logs and 10 sticks (unlocked by having logs, saved as "workbench_wood_chest").
*/
@Override
public void buildRecipes() {
new WorkbenchRecipeBuilder(ModRecipes.CAMPFIRE_TYPE, ModRecipes.CAMPFIRE_SERIALIZER)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,11 @@ public WorkbenchRecipeBuilder input(Ingredient ingredient) {
}

/**
* Adds an item input with a specific count.
* Adds the given item as an ingredient multiple times to this builder.
*
* @param item the item to use as an ingredient
* @param count the number of times to add the ingredient (if less than or equal to zero, no ingredients are added)
* @return this builder instance
*/
public WorkbenchRecipeBuilder input(ItemLike item, int count) {
Ingredient ingredient = Ingredient.of(item);
Expand All @@ -106,8 +110,12 @@ public WorkbenchRecipeBuilder input(ItemLike item, int count) {
}

/**
* Adds a tag input with a specific count.
* Requires a RegistryLookup (usually available in your RecipeProvider).
* Adds the ingredient represented by the given item tag to the recipe inputs the specified number of times.
*
* @param tag the item tag whose matching items will be used as the ingredient
* @param registries a registry lookup provider used to resolve the tag (typically the provider from a RecipeProvider)
* @param count the number of times to add the resolved ingredient; if zero nothing is added
* @return this builder instance
*/
public WorkbenchRecipeBuilder input(TagKey<Item> tag, HolderLookup.Provider registries, int count) {
// 1. Get the lookup for the Item registry from the provider
Expand All @@ -124,6 +132,12 @@ public WorkbenchRecipeBuilder input(TagKey<Item> tag, HolderLookup.Provider regi



/**
* Set the crafting book category used to classify the recipe in the crafting book.
*
* @param category the crafting book category to assign to the recipe
* @return the same WorkbenchRecipeBuilder instance
*/
public WorkbenchRecipeBuilder category(CraftingBookCategory category) {
this.category = category;
return this;
Expand Down Expand Up @@ -196,10 +210,12 @@ public Item getResult() {
}

/**
* Saves this builder's recipe to the given exporter under the specified identifier.
* Registers this builder's recipe with the provided RecipeOutput using the given recipe name.
*
* The provided name is used as the path component to construct a recipe ResourceKey scoped to the MineTale mod.
*
* @param exporter the RecipeOutput that will receive the recipe
* @param id the identifier to use for the saved recipe
* @param name the recipe name (path component) to use when creating the recipe's Identifier
*/
public void save(RecipeOutput exporter, String name) {
this.save(exporter, ResourceKey.create(Registries.RECIPE, Identifier.fromNamespaceAndPath(MineTale.MOD_ID, name)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@

@Mixin(ClientRecipeBook.class)
public abstract class ClientRecipeBookMixin {
/**
* Maps supported custom recipe types to their corresponding recipe-book category and overrides the original method's result when a match is found.
*
* @param recipe the recipe holder to inspect for its recipe type
* @param cir callback that will be used to set and return the mapped {@code RecipeBookCategory} for the original method
*/
@Inject(method = "getCategory", at = @At("HEAD"), cancellable = true)
private static void minetale$addCustomCategory(RecipeHolder<?> recipe, CallbackInfoReturnable<RecipeBookCategory> cir) {
RecipeType<?> type = recipe.value().getType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,59 @@

@Mixin(RecipeBookComponent.class)
public interface RecipeBookComponentAccessor {
// GETTERS for the Screen to read what is selected
/**
* Gets the currently selected recipe display identifier from the recipe book component.
*
* @return the currently selected RecipeDisplayId
*/
@Accessor("lastRecipe")
RecipeDisplayId getLastRecipe();

/**
* Access the last-selected recipe collection from the recipe book component.
*
* @return the last-selected {@link RecipeCollection}
*/
@Accessor("lastRecipeCollection")
RecipeCollection getLastRecipeCollection();

// SETTERS for the Component to update the selection
/**
* Set the currently selected recipe display identifier on the component.
*
* @param id the RecipeDisplayId to set as the current selection
*/
@Accessor("lastRecipe")
void setLastRecipe(RecipeDisplayId id);

/**
* Sets the currently selected recipe collection in the recipe book component.
*
* @param collection the recipe collection to set as the selected collection
*/
@Accessor("lastRecipeCollection")
void setLastRecipeCollection(RecipeCollection collection);

// OTHER NECESSITIES
/**
* Accesses the component's current recipe book page.
*
* @return the current RecipeBookPage instance
*/
@Accessor("recipeBookPage")
RecipeBookPage getRecipeBookPage();

/**
* Obtain the X origin coordinate of the recipe book component.
*
* @return the X origin coordinate of the component
*/
@Invoker("getXOrigin")
int invokeGetXOrigin();

/**
* Obtain the Y origin (vertical coordinate) of the recipe book component.
*
* @return the Y origin (vertical coordinate) of the component
*/
@Invoker("getYOrigin")
int invokeGetYOrigin();
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,23 @@ public class MineTaleRecipeBookComponent extends RecipeBookComponent<RecipeBookM
Identifier.withDefaultNamespace("recipe_book/filter_disabled_focused")
);

/**
* Creates a MineTaleRecipeBookComponent bound to a specific machine recipe type.
*
* @param recipeBookMenu the recipe book menu instance this component is attached to
* @param list the list of tab information to display in the recipe book
* @param filterType the RecipeType used to filter which recipes are shown in this component
*/
public MineTaleRecipeBookComponent(RecipeBookMenu recipeBookMenu, List<TabInfo> list, RecipeType<?> filterType) {
super(recipeBookMenu, list);
this.filterType = filterType;
}

/**
* Get the ID of the last recipe clicked in the current recipe book page.
*
* @return the `RecipeDisplayId` of the last clicked recipe, or `null` if there is no open page or no recipe has been clicked
*/
public @Nullable RecipeDisplayId getSelectedRecipeId() {
// Cast 'this' to the Accessor interface to call the generated getter
RecipeBookPage page = ((RecipeBookComponentAccessor)this).getRecipeBookPage();
Expand All @@ -51,6 +63,15 @@ public MineTaleRecipeBookComponent(RecipeBookMenu recipeBookMenu, List<TabInfo>
return null;
}

/**
* Filters the provided recipe collection to include only workbench displays that match this component's filterType.
*
* Uses the provided StackedItemContents to perform matching and retains only recipe displays whose type is
* ModRecipeDisplay.WORKBENCH_TYPE and whose WorkbenchRecipeDisplay.getRecipeType() equals this.filterType.
*
* @param recipeCollection the collection whose selectable recipes will be updated
* @param stackedItemContents the available stacked item contents used for recipe matching
*/
@Override
protected void selectMatchingRecipes(RecipeCollection recipeCollection, StackedItemContents stackedItemContents) {
// Force everything to be "selected"
Expand All @@ -74,6 +95,13 @@ protected void selectMatchingRecipes(RecipeCollection recipeCollection, StackedI
});
}

/**
* Handle mouse clicks inside the recipe book and select MineTale workbench recipes when clicked.
*
* @param mouseButtonEvent the mouse event to process
* @param bl a pass-through boolean flag forwarded to the underlying recipe page click handler
* @return `true` if the click was handled by selecting a MineTale workbench recipe, `false` otherwise
*/
@Override
public boolean mouseClicked(MouseButtonEvent mouseButtonEvent, boolean bl) {
if (!this.isVisible() || this.minecraft.player.isSpectator()) {
Expand Down Expand Up @@ -110,6 +138,11 @@ public boolean mouseClicked(MouseButtonEvent mouseButtonEvent, boolean bl) {
return super.mouseClicked(mouseButtonEvent, bl);
}

/**
* Provide the sprite set used by the recipe book's filter toggle button.
*
* @return the WidgetSprites used for the filter toggle (enabled/disabled and focused states)
*/
@Override
protected WidgetSprites getFilterButtonTextures() {
// Returns the textures for the "Toggle craftable" button
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/com/tcm/MineTale/MineTale.java
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,14 @@ public void onInitialize() {
LOGGER.info("Hello Fabric world!");
}

private boolean hasIngredients(ServerPlayer player, WorkbenchRecipe recipe) {
/**
* Checks whether the player's inventory contains the necessary ingredients to craft the given recipe without modifying the real inventory.
*
* @param player the server player whose inventory will be simulated
* @param recipe the workbench recipe to validate against the player's inventory
* @return `true` if all required ingredients can be satisfied from the player's current inventory, `false` otherwise
*/
private boolean hasIngredients(ServerPlayer player, WorkbenchRecipe recipe) {
// We simulate the craft using a copy of the inventory
List<ItemStack> tempInv = new java.util.ArrayList<>();
for (int i = 0; i < player.getInventory().getContainerSize(); i++) {
Expand All @@ -189,6 +196,12 @@ private boolean hasIngredients(ServerPlayer player, WorkbenchRecipe recipe) {
return true;
}

/**
* Consumes one matching item from the player's inventory for each ingredient in the given workbench recipe.
*
* @param player the player whose inventory will be modified
* @param recipe the workbench recipe whose ingredients should be consumed
*/
private void consumeIngredients(ServerPlayer player, WorkbenchRecipe recipe) {
for (Ingredient ingredient : recipe.ingredients()) {
for (int i = 0; i < player.getInventory().getContainerSize(); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ public WorkbenchWorkbench(Properties properties, Supplier<BlockEntityType<? exte
}

/**
* Supplies a ticker that updates WorkbenchWorkbench block entities each tick.
* Provides a ticker for workbench block entities when the supplied block entity type matches this block's entity type.
*
* @return a BlockEntityTicker that invokes AbstractWorkbenchEntity.tick for matching WorkbenchWorkbenchEntity instances, `null` if the supplied block entity type does not match
* @param type the block entity type to match against this block's workbench entity type
* @return a BlockEntityTicker that updates matching workbench block entities, or {@code null} if the types do not match
*/
@Nullable
@Override
Expand Down Expand Up @@ -87,9 +88,7 @@ public RenderShape getRenderShape(BlockState state) {
private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 7, 16);

/**
* Provides the block's collision and interaction shape.
*
* <p>Uses a fixed voxel shape covering a 1×1 footprint with a height of 7 units (coordinates: x 0–16, y 0–7, z 0–16).</p>
* The block's collision and interaction shape as a 1×1 footprint with height 7 (x 0–16, y 0–7, z 0–16).
*
* @return the voxel shape used for collision and interaction
*/
Expand Down
Loading