Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
6 changes: 6 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ loom {

}

fabricApi {
configureDataGeneration() {
client = true
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

dependencies {
// To change the versions see the gradle.properties file
minecraft "com.mojang:minecraft:${project.minecraft_version}"
Expand Down
7 changes: 6 additions & 1 deletion src/client/java/com/tcm/MineTale/MineTaleClient.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package com.tcm.MineTale;

import com.tcm.MineTale.block.workbenches.screen.FurnaceWorkbenchScreen;
import com.tcm.MineTale.block.workbenches.screen.CampfireWorkbenchScreen;
import com.tcm.MineTale.registry.ModMenuTypes;

import net.fabricmc.api.ClientModInitializer;
import net.minecraft.client.gui.screens.MenuScreens;

public class MineTaleClient implements ClientModInitializer {
/**
* Registers the screen factory for the furnace workbench menu so the client can create FurnaceWorkbenchScreen instances for that menu type.
* Registers 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.
*/
@Override
public void onInitializeClient() {
MenuScreens.register(ModMenuTypes.FURNACE_WORKBENCH_MENU, FurnaceWorkbenchScreen::new);
MenuScreens.register(ModMenuTypes.CAMPFIRE_WORKBENCH_MENU, CampfireWorkbenchScreen::new);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.tcm.MineTale.block.workbenches.screen;

import com.tcm.MineTale.block.workbenches.menu.CampfireWorkbenchMenu;

import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.resources.Identifier;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.network.chat.Component;

public class CampfireWorkbenchScreen extends AbstractContainerScreen<CampfireWorkbenchMenu> {
private static final Identifier TEXTURE =
// Identifier.fromNamespaceAndPath(MineTale.MOD_ID, "textures/gui/container/furnace_workbench.png");
Identifier.withDefaultNamespace("textures/gui/container/furnace.png");
Comment on lines +13 to +15

@coderabbitai coderabbitai Bot Jan 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Background texture likely doesn’t match the 2‑input/4‑output layout.

Using the vanilla furnace texture will leave the extra slots floating on a blank background. Consider switching to a custom workbench texture that matches the slot grid.

🤖 Prompt for AI Agents
In
`@src/client/java/com/tcm/MineTale/block/workbenches/screen/CampfireWorkbenchScreen.java`
around lines 13 - 15, The background texture constant TEXTURE in
CampfireWorkbenchScreen currently points to the vanilla furnace PNG which
doesn't match the 2-input/4-output slot layout; update TEXTURE (the static
Identifier) to reference a new custom texture name that matches your workbench
layout (e.g. "textures/gui/container/campfire_workbench.png" using
Identifier.fromNamespaceAndPath(MineTale.MOD_ID, ...)), add the corresponding
PNG asset and any required GUI JSON/atlas entries to assets, and verify the
screen size/layout code in CampfireWorkbenchScreen still aligns with the new
texture.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont have a texture yet but this will be changed later.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@The-Code-Monkey, understood! Using the vanilla furnace texture as a placeholder makes sense until you have the custom asset ready. 👍


/**
* Creates a campfire workbench screen for the provided menu, player inventory, and title.
*
* @param menu the container menu that provides slots and synchronizes state for this screen
* @param inventory the player's inventory to display and interact with
* @param title the title component shown at the top of the screen
*/
public CampfireWorkbenchScreen(CampfireWorkbenchMenu menu, Inventory inventory, Component title) {
super(menu, inventory, title);
}

/**
* Initializes the screen and centers the title horizontally by setting {@code titleLabelX}.
*/
@Override
protected void init() {
super.init();
this.titleLabelX = (this.imageWidth - this.font.width(this.title)) / 2;
}

/**
* Renders the campfire workbench background texture at the screen's top-left position.
*
* @param guiGraphics the graphics context used for drawing
* @param f partial ticks for interpolation
* @param i current mouse x position
* @param j current mouse y position
*/
protected void renderBg(GuiGraphics guiGraphics, float f, int i, int j) {
int k = this.leftPos;
int l = this.topPos;
guiGraphics.blit(RenderPipelines.GUI_TEXTURED, TEXTURE, k, l, 0.0F, 0.0F, this.imageWidth, this.imageHeight, 256, 256);
}

/**
* Renders the campfire workbench screen, drawing its background, contents, and tooltips.
*
* @param graphics the graphics context used for rendering
* @param mouseX the current mouse X coordinate
* @param mouseY the current mouse Y coordinate
* @param delta the frame time delta (partial tick) used for animated rendering
*/
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
renderBackground(graphics, mouseX, mouseY, delta);
super.render(graphics, mouseX, mouseY, delta);
renderTooltip(graphics, mouseX, mouseY);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// 1.21.11 -999999999-01-01T00:00:00 Example mod/minetaleModRecipeProvider
dcc5dac31dc51d16b53e14666f87d47297089c0d data/minetale/advancement/recipes/campfire_pork_cooking.json
96af174cae154bddc108902a40e90c9bd971c7cf data/minetale/recipe/campfire_pork_cooking.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_the_recipe": {
"conditions": {
"recipe": "minetale:campfire_pork_cooking"
},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [
[
"has_the_recipe"
]
],
"rewards": {
"recipes": [
"minetale:campfire_pork_cooking"
]
}
}
13 changes: 13 additions & 0 deletions src/main/generated/data/minetale/recipe/campfire_pork_cooking.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"type": "minetale:campfire_alloying",
"cookTime": 600,
"ingredients": [
"minecraft:porkchop"
],
"results": [
{
"count": 1,
"id": "minecraft:cooked_porkchop"
}
]
}
2 changes: 2 additions & 0 deletions src/main/java/com/tcm/MineTale/MineTale.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.tcm.MineTale.registry.ModEntityDataSerializers;
import com.tcm.MineTale.registry.ModItems;
import com.tcm.MineTale.registry.ModMenuTypes;
import com.tcm.MineTale.registry.ModRecipes;

import static com.tcm.MineTale.item.ModCreativeTab.MINETALE_CREATIVE_TAB;
import static com.tcm.MineTale.item.ModCreativeTab.MINETALE_CREATIVE_TAB_KEY;
Expand All @@ -34,6 +35,7 @@ public class MineTale implements ModInitializer {
@Override
public void onInitialize() {
ModBlocks.initialize();
ModRecipes.initialize();
ModBlockEntities.initialize();
ModMenuTypes.initialize();
ModEntities.initialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,22 @@
import org.jetbrains.annotations.Nullable;

import com.mojang.serialization.MapCodec;
import com.tcm.MineTale.block.workbenches.entity.AbstractWorkbenchEntity;
import com.tcm.MineTale.block.workbenches.entity.CampfireWorkbenchEntity;
import com.tcm.MineTale.registry.ModBlockEntities;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.ChestType;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;

Expand All @@ -44,16 +43,33 @@ public CampfireWorkbench(Properties properties) {
}

/**
* Creates a CampfireWorkbench with the given block properties and block-entity type supplier.
* Constructs a CampfireWorkbench using the provided block properties and block-entity type supplier.
*
* @param properties the block's properties
* @param supplier supplier that provides the BlockEntityType for this workbench
* @param properties block properties to apply to this workbench
* @param supplier supplier that provides the BlockEntityType for the CampfireWorkbenchEntity
*/
public CampfireWorkbench(Properties properties, Supplier<BlockEntityType<? extends CampfireWorkbenchEntity>> supplier) {
// isWide = false, isTall = false (1x1 footprint)
super(properties, supplier, IS_WIDE, IS_TALL);
}

/**
* Provides a ticker that updates campfire workbench block entities each tick.
*
* @return a BlockEntityTicker that invokes AbstractWorkbenchEntity.tick for CampfireWorkbenchEntity instances, or `null` if the supplied block entity type does not match the campfire workbench type.
*/
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
// This connects the Level's ticking system to your static tick method
return createTickerHelper(type, ModBlockEntities.CAMPFIRE_WORKBENCH_BE, AbstractWorkbenchEntity::tick);
}

/**
* The codec used to serialize and deserialize this CampfireWorkbench type.
*
* @return the MapCodec for this CampfireWorkbench
*/
@Override
protected MapCodec<? extends CampfireWorkbench> codec() {
return CODEC;
Expand Down Expand Up @@ -84,49 +100,18 @@ public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, Co
}

/**
* Creates and returns the block entity for this block only when the block represents the master
* position (the lower half and not of type RIGHT).
* Create a block entity for the master block of this workbench.
*
* Only the master block of the multi-block workbench receives an entity; other positions return {@code null}.
*
* @return the created BlockEntity when this block is the master (HALF == LOWER and TYPE != RIGHT), or `null` otherwise
* @return the block entity for the master block ({@link CampfireWorkbenchEntity}), or {@code null} if this position does not host an entity
*/
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
// Only spawn the entity at the "Master" position (LOWER + LEFT or LOWER + SINGLE)
if (state.getValue(HALF) == DoubleBlockHalf.LOWER && state.getValue(TYPE) != ChestType.RIGHT) {
return blockEntityType.get().create(pos, state);
}
return null;
}

/**
* Handles a player's interaction with the workbench when no item is used.
*
* <p>On the client this acknowledges the interaction. On the server this method
* is a hook for workbench-specific handling; if the workbench processes the
* interaction it will consume it, otherwise the interaction is passed to other handlers.</p>
*
* @param state the block state of the workbench
* @param level the world in which the interaction occurs
* @param pos the position of the interacted block
* @param player the player performing the interaction
* @param hit the hit result describing the interaction point
* @return {@code InteractionResult.SUCCESS} on client, {@code InteractionResult.CONSUME} if handled by the workbench, or {@code InteractionResult.PASS} otherwise
*/
@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
if (level.isClientSide()) return InteractionResult.SUCCESS;

// BlockPos masterPos = getMasterPos(state, pos);
// BlockEntity be = level.getBlockEntity(masterPos);

// if (be instanceof AbstractWorkbenchEntity) {
// // Open UI or handle Recycling logic here
// // Example: if player is holding a tool, try to recycle it
// return InteractionResult.CONSUME;
// }

return InteractionResult.PASS;
// AbstractWorkbench logic ensures only the Master block gets the entity.
// We override it here to point specifically to our Furnace entity.
return super.newBlockEntity(pos, state);
}

/**
Expand Down
Loading
Loading