Skip to content

Commit a91f5c4

Browse files
feat: clone campfire to workbench
1 parent c43b5df commit a91f5c4

9 files changed

Lines changed: 560 additions & 18 deletions

File tree

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package com.tcm.MineTale.block.workbenches.screen;
2+
3+
import java.util.List;
4+
5+
import com.tcm.MineTale.MineTale;
6+
import com.tcm.MineTale.block.workbenches.menu.WorkbenchWorkbenchMenu;
7+
import com.tcm.MineTale.recipe.MineTaleRecipeBookComponent;
8+
import com.tcm.MineTale.registry.ModBlocks;
9+
import com.tcm.MineTale.registry.ModRecipeDisplay;
10+
import com.tcm.MineTale.registry.ModRecipes;
11+
12+
import net.minecraft.client.gui.GuiGraphics;
13+
import net.minecraft.client.gui.navigation.ScreenPosition;
14+
import net.minecraft.client.gui.screens.inventory.AbstractRecipeBookScreen;
15+
import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent;
16+
import net.minecraft.client.renderer.RenderPipelines;
17+
import net.minecraft.resources.Identifier;
18+
import net.minecraft.world.entity.player.Inventory;
19+
import net.minecraft.world.item.ItemStack;
20+
import net.minecraft.network.chat.Component;
21+
22+
public class WorkbenchWorkbenchScreen extends AbstractRecipeBookScreen<WorkbenchWorkbenchMenu> {
23+
private static final Identifier TEXTURE =
24+
Identifier.fromNamespaceAndPath(MineTale.MOD_ID, "textures/gui/container/furnace_workbench.png");
25+
26+
/**
27+
* Creates a campfire workbench screen for the provided menu, player inventory, and title.
28+
*
29+
* @param menu the container menu that provides slots and synchronizes state for this screen
30+
* @param inventory the player's inventory to display and interact with
31+
* @param title the title component shown at the top of the screen
32+
*/
33+
public WorkbenchWorkbenchScreen(WorkbenchWorkbenchMenu menu, Inventory inventory, Component title) {
34+
super(menu, createRecipeBookComponent(menu), inventory, title);
35+
}
36+
37+
/**
38+
* Static helper to build the component with the custom MineTale tabs
39+
* before the super constructor is called.
40+
*/
41+
private static MineTaleRecipeBookComponent createRecipeBookComponent(WorkbenchWorkbenchMenu menu) {
42+
ItemStack tabIcon = new ItemStack(ModBlocks.WORKBENCH_WORKBENCH_BLOCK.asItem());
43+
44+
List<RecipeBookComponent.TabInfo> tabs = List.of(
45+
new RecipeBookComponent.TabInfo(tabIcon.getItem(), ModRecipeDisplay.WORKBENCH_SEARCH)
46+
);
47+
48+
return new MineTaleRecipeBookComponent(menu, tabs, ModRecipes.WORKBENCH_TYPE);
49+
}
50+
51+
/**
52+
* Initializes the screen and centers the title horizontally by setting {@code titleLabelX}.
53+
*/
54+
@Override
55+
protected void init() {
56+
// Important: Set your GUI size before super.init()
57+
this.imageWidth = 176;
58+
this.imageHeight = 166;
59+
60+
super.init();
61+
}
62+
63+
/**
64+
* Renders the campfire workbench background texture at the screen's top-left position.
65+
*
66+
* @param guiGraphics the graphics context used for drawing
67+
* @param f partial ticks for interpolation
68+
* @param i current mouse x position
69+
* @param j current mouse y position
70+
*/
71+
protected void renderBg(GuiGraphics guiGraphics, float f, int i, int j) {
72+
int k = this.leftPos;
73+
int l = this.topPos;
74+
guiGraphics.blit(RenderPipelines.GUI_TEXTURED, TEXTURE, k, l, 0.0F, 0.0F, this.imageWidth, this.imageHeight, 256, 256);
75+
}
76+
77+
/**
78+
* Renders the campfire workbench screen, drawing its background, contents, and tooltips.
79+
*
80+
* @param graphics the graphics context used for rendering
81+
* @param mouseX the current mouse X coordinate
82+
* @param mouseY the current mouse Y coordinate
83+
* @param delta the frame time delta (partial tick) used for animated rendering
84+
*/
85+
@Override
86+
public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
87+
// 1. Always render the dark background tint first
88+
renderBackground(graphics, mouseX, mouseY, delta);
89+
90+
// 3. Call super (this draws your slots and items)
91+
super.render(graphics, mouseX, mouseY, delta);
92+
93+
renderTooltip(graphics, mouseX, mouseY);
94+
}
95+
96+
@Override
97+
protected ScreenPosition getRecipeBookButtonPosition() {
98+
// 1. Calculate the start (left) of your workbench GUI
99+
int guiLeft = (this.width - this.imageWidth) / 2;
100+
101+
// 2. Calculate the top of your workbench GUI
102+
int guiTop = (this.height - this.imageHeight) / 2;
103+
104+
// 3. Standard Vanilla positioning:
105+
// Usually 5 pixels in from the left and 49 pixels up from the center
106+
return new ScreenPosition(guiLeft + 5, guiTop + this.imageHeight / 2 - 49);
107+
}
108+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package com.tcm.MineTale.block.workbenches;
2+
3+
import java.util.function.Supplier;
4+
5+
import org.jetbrains.annotations.Nullable;
6+
7+
import com.mojang.serialization.MapCodec;
8+
import com.tcm.MineTale.block.workbenches.entity.AbstractWorkbenchEntity;
9+
import com.tcm.MineTale.block.workbenches.entity.WorkbenchWorkbenchEntity;
10+
import com.tcm.MineTale.registry.ModBlockEntities;
11+
12+
import net.minecraft.core.BlockPos;
13+
import net.minecraft.world.level.BlockGetter;
14+
import net.minecraft.world.level.Level;
15+
import net.minecraft.world.level.block.Block;
16+
import net.minecraft.world.level.block.RenderShape;
17+
import net.minecraft.world.level.block.entity.BlockEntity;
18+
import net.minecraft.world.level.block.entity.BlockEntityTicker;
19+
import net.minecraft.world.level.block.entity.BlockEntityType;
20+
import net.minecraft.world.level.block.state.BlockState;
21+
import net.minecraft.world.phys.shapes.CollisionContext;
22+
import net.minecraft.world.phys.shapes.VoxelShape;
23+
24+
// ChestBlock
25+
26+
public class WorkbenchWorkbench extends AbstractWorkbench<WorkbenchWorkbenchEntity> {
27+
public static final boolean IS_WIDE = false;
28+
public static final boolean IS_TALL = false;
29+
30+
public static final MapCodec<WorkbenchWorkbench> CODEC = simpleCodec(WorkbenchWorkbench::new);
31+
32+
/**
33+
* Creates a WorkbenchWorkbench configured to use the mod's WORKBENCH_WORKBENCH_BE block entity type.
34+
*
35+
* @param properties block properties used to construct this workbench
36+
*/
37+
public WorkbenchWorkbench(Properties properties) {
38+
// Hardcode the supplier and sounds here if they never change
39+
super(properties, () -> ModBlockEntities.WORKBENCH_WORKBENCH_BE, IS_WIDE, IS_TALL, 1);
40+
}
41+
42+
/**
43+
* Constructs a WorkbenchWorkbench using the provided block properties and block-entity type supplier.
44+
*
45+
* @param properties block properties to apply to this workbench
46+
* @param supplier supplier that provides the BlockEntityType for the WorkbenchWorkbenchEntity
47+
*/
48+
public WorkbenchWorkbench(Properties properties, Supplier<BlockEntityType<? extends WorkbenchWorkbenchEntity>> supplier) {
49+
// isWide = false, isTall = false (1x1 footprint)
50+
super(properties, supplier, IS_WIDE, IS_TALL, 1);
51+
}
52+
53+
/**
54+
* Provides a ticker that updates workbench workbench block entities each tick.
55+
*
56+
* @return a BlockEntityTicker that invokes AbstractWorkbenchEntity.tick for WorkbenchWorkbenchEntity instances, or `null` if the supplied block entity type does not match the workbench workbench type.
57+
*/
58+
@Nullable
59+
@Override
60+
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
61+
// This connects the Level's ticking system to your static tick method
62+
return createTickerHelper(type, ModBlockEntities.WORKBENCH_WORKBENCH_BE, AbstractWorkbenchEntity::tick);
63+
}
64+
65+
/**
66+
* The codec used to serialize and deserialize this WorkbenchWorkbench type.
67+
*
68+
* @return the MapCodec for this WorkbenchWorkbench
69+
*/
70+
@Override
71+
protected MapCodec<? extends WorkbenchWorkbench> codec() {
72+
return CODEC;
73+
}
74+
75+
/**
76+
* Specifies that this block is rendered using its block model.
77+
*
78+
* @return RenderShape.MODEL to render the block using its JSON/model representation.
79+
*/
80+
@Override
81+
public RenderShape getRenderShape(BlockState state) {
82+
// BaseEntityBlock defaults to INVISIBLE.
83+
// We set it to MODEL so the JSON model is rendered.
84+
return RenderShape.MODEL;
85+
}
86+
87+
private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 7, 16);
88+
89+
/**
90+
* Gets the block's collision and interaction shape.
91+
*
92+
* @return the voxel shape representing the block's collision and interaction bounds
93+
*/
94+
@Override
95+
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
96+
return SHAPE;
97+
}
98+
}

0 commit comments

Comments
 (0)