-
Notifications
You must be signed in to change notification settings - Fork 0
Add normal Workbench #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
a91f5c4
4d00701
6c39d4c
b8c1841
5f162d4
13c40cb
a9e2d85
dfa2baa
bf2c444
6971c34
8819d40
030ccd2
91f60c7
d47ff42
5105790
ce734fd
185249b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,25 +1,26 @@ | ||
| package com.tcm.MineTale; | ||
|
|
||
| import com.tcm.MineTale.block.workbenches.screen.FurnaceWorkbenchScreen; | ||
| import com.tcm.MineTale.block.workbenches.screen.WorkbenchWorkbenchScreen; | ||
| 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 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() { | ||
| MenuScreens.register(ModMenuTypes.FURNACE_WORKBENCH_MENU, FurnaceWorkbenchScreen::new); | ||
| MenuScreens.register(ModMenuTypes.CAMPFIRE_WORKBENCH_MENU, CampfireWorkbenchScreen::new); | ||
| MenuScreens.register(ModMenuTypes.WORKBENCH_WORKBENCH_MENU, WorkbenchWorkbenchScreen::new); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,262 @@ | ||
| package com.tcm.MineTale.block.workbenches.screen; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| import com.tcm.MineTale.MineTale; | ||
| import com.tcm.MineTale.block.workbenches.menu.WorkbenchWorkbenchMenu; | ||
| import com.tcm.MineTale.mixin.client.RecipeBookComponentAccessor; | ||
| import com.tcm.MineTale.network.CraftRequestPayload; | ||
| import com.tcm.MineTale.recipe.MineTaleRecipeBookComponent; | ||
| import com.tcm.MineTale.registry.ModBlocks; | ||
| import com.tcm.MineTale.registry.ModRecipeDisplay; | ||
| import com.tcm.MineTale.registry.ModRecipes; | ||
|
|
||
| import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; | ||
| import net.minecraft.client.gui.GuiGraphics; | ||
| import net.minecraft.client.gui.components.Button; | ||
| import net.minecraft.client.gui.navigation.ScreenPosition; | ||
| import net.minecraft.client.gui.screens.inventory.AbstractRecipeBookScreen; | ||
| import net.minecraft.client.gui.screens.recipebook.RecipeBookComponent; | ||
| import net.minecraft.client.gui.screens.recipebook.RecipeCollection; | ||
| import net.minecraft.client.renderer.RenderPipelines; | ||
| import net.minecraft.resources.Identifier; | ||
| import net.minecraft.world.entity.player.Inventory; | ||
| import net.minecraft.world.item.ItemStack; | ||
| import net.minecraft.world.item.crafting.display.RecipeDisplayEntry; | ||
| import net.minecraft.world.item.crafting.display.RecipeDisplayId; | ||
| import net.minecraft.world.item.crafting.display.SlotDisplayContext; | ||
| import net.minecraft.network.chat.Component; | ||
|
|
||
| public class WorkbenchWorkbenchScreen extends AbstractRecipeBookScreen<WorkbenchWorkbenchMenu> { | ||
| private static final Identifier TEXTURE = | ||
| Identifier.fromNamespaceAndPath(MineTale.MOD_ID, "textures/gui/container/furnace_workbench.png"); | ||
|
|
||
| private final MineTaleRecipeBookComponent mineTaleRecipeBook; | ||
|
|
||
| private Button craftOneBtn; | ||
| private Button craftThirtyBtn; | ||
| private Button craftAllBtn; | ||
|
|
||
| /** | ||
| * Initialize a workbench GUI screen using the provided container menu, player inventory, and title. | ||
| * | ||
| * @param menu the menu supplying slots and synchronized 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 WorkbenchWorkbenchScreen(WorkbenchWorkbenchMenu menu, Inventory inventory, Component title) { | ||
| 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; | ||
| } | ||
|
|
||
| /** | ||
| * Create a MineTaleRecipeBookComponent configured for the workbench screen. | ||
| * | ||
| * @param menu the workbench menu used to initialize the recipe book component | ||
| * @return a MineTaleRecipeBookComponent containing the workbench tab and associated recipe category | ||
| */ | ||
| private static MineTaleRecipeBookComponent createRecipeBookComponent(WorkbenchWorkbenchMenu menu) { | ||
| ItemStack tabIcon = new ItemStack(ModBlocks.WORKBENCH_WORKBENCH_BLOCK.asItem()); | ||
|
|
||
| List<RecipeBookComponent.TabInfo> tabs = List.of( | ||
| new RecipeBookComponent.TabInfo(tabIcon.getItem(), ModRecipeDisplay.WORKBENCH_SEARCH) | ||
| ); | ||
|
|
||
| return new MineTaleRecipeBookComponent(menu, tabs, ModRecipes.WORKBENCH_TYPE); | ||
| } | ||
|
|
||
| /** | ||
| * 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() | ||
| this.imageWidth = 176; | ||
| this.imageHeight = 166; | ||
|
|
||
| super.init(); | ||
|
|
||
| this.craftOneBtn = addRenderableWidget(Button.builder(Component.literal("1"), (button) -> { | ||
| handleCraftRequest(1); | ||
| }).bounds(this.leftPos + 80, this.topPos + 20, 30, 20).build()); | ||
|
|
||
| this.craftThirtyBtn = addRenderableWidget(Button.builder(Component.literal("30"), (button) -> { | ||
| handleCraftRequest(30); | ||
| }).bounds(this.leftPos + 112, this.topPos + 20, 30, 20).build()); | ||
|
|
||
| this.craftAllBtn = addRenderableWidget(Button.builder(Component.literal("All"), (button) -> { | ||
| handleCraftRequest(-1); // -1 represents "All" logic | ||
| }).bounds(this.leftPos + 144, this.topPos + 20, 30, 20).build()); | ||
| } | ||
|
|
||
| // private void handleCraftRequest(int amount) { | ||
| // RecipeBookPage page = ((RecipeBookComponentAccessor)this.mineTaleRecipeBook).getRecipeBookPage(); | ||
| // RecipeCollection collection = page.getLastClickedRecipeCollection(); | ||
| // RecipeDisplayId displayId = page.getLastClickedRecipe(); | ||
|
|
||
| // if (collection != null && displayId != null) { | ||
| // // 1. Find the specific entry that was clicked | ||
| // for (RecipeDisplayEntry entry : collection.getSelectedRecipes(RecipeCollection.CraftableStatus.ANY)) { | ||
| // if (entry.id().equals(displayId)) { | ||
| // // 2. Resolve the visual result into an actual ItemStack | ||
| // List<ItemStack> results = entry.resultItems(SlotDisplayContext.fromLevel(this.minecraft.level)); | ||
|
|
||
| // if (!results.isEmpty()) { | ||
| // ItemStack resultStack = results.get(0); | ||
| // // 3. Send the item and amount to the server | ||
| // // Note: Update your CraftRequestPayload to accept ItemStack instead of Identifier | ||
| // ClientPlayNetworking.send(new CraftRequestPayload(resultStack, amount)); | ||
| // } | ||
| // break; | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
|
|
||
| // private void handleCraftRequest(int amount) { | ||
| // // 1. Get the current page from the recipe book | ||
| // // We use your mixin/accessor to get the internal page object | ||
| // RecipeBookPage page = ((RecipeBookComponentAccessor)this.mineTaleRecipeBook).getRecipeBookPage(); | ||
|
|
||
| // // 2. Identify WHAT was clicked | ||
| // RecipeCollection collection = page.getLastClickedRecipeCollection(); | ||
| // RecipeDisplayId displayId = page.getLastClickedRecipe(); | ||
|
|
||
| // if (collection != null && displayId != null) { | ||
| // // 3. Find the display entry | ||
| // for (RecipeDisplayEntry entry : collection.getSelectedRecipes(RecipeCollection.CraftableStatus.ANY)) { | ||
| // if (entry.id().equals(displayId)) { | ||
| // // 4. Get the result item (the Chest) | ||
| // // 1.21.1 uses SlotDisplayContext to handle dynamic results | ||
| // List<ItemStack> results = entry.resultItems(SlotDisplayContext.fromLevel(this.minecraft.level)); | ||
|
|
||
| // if (!results.isEmpty()) { | ||
| // ItemStack resultStack = results.get(0); | ||
|
|
||
| // // 5. Send the packet to the Server | ||
| // // IMPORTANT: Ensure your CraftRequestPayload is registered to handle | ||
| // // an ItemStack and an Int. | ||
| // ClientPlayNetworking.send(new CraftRequestPayload(resultStack, amount)); | ||
|
|
||
| // // Optional: Play a click sound so the player knows it worked | ||
| // this.minecraft.getSoundManager().play(net.minecraft.client.resources.sounds.SimpleSoundInstance.forUI( | ||
| // net.minecraft.sounds.SoundEvents.UI_BUTTON_CLICK, 1.0F)); | ||
| // } | ||
| // break; | ||
| // } | ||
| // } | ||
| // } | ||
| // } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| /** | ||
| * 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 | ||
| RecipeBookComponentAccessor accessor = (RecipeBookComponentAccessor) this.mineTaleRecipeBook; | ||
|
|
||
| RecipeCollection collection = accessor.getLastRecipeCollection(); | ||
| RecipeDisplayId displayId = accessor.getLastRecipe(); | ||
|
|
||
| if (collection != null && displayId != null) { | ||
| // 2. Find the visual entry | ||
| for (RecipeDisplayEntry entry : collection.getSelectedRecipes(RecipeCollection.CraftableStatus.ANY)) { | ||
| if (entry.id().equals(displayId)) { | ||
| // 3. Resolve result for the packet | ||
| List<ItemStack> results = entry.resultItems(SlotDisplayContext.fromLevel(this.minecraft.level)); | ||
|
|
||
| if (!results.isEmpty()) { | ||
| ItemStack resultStack = results.get(0); | ||
|
|
||
| // 4. LOG FOR DEBUGGING: Does this print in your console? | ||
| System.out.println("Sending craft request for: " + resultStack + " amount: " + amount); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Replace Debug prints via Proposed fix- // 4. LOG FOR DEBUGGING: Does this print in your console?
- System.out.println("Sending craft request for: " + resultStack + " amount: " + amount);
+ MineTale.LOGGER.debug("Sending craft request for: {} amount: {}", resultStack, amount);- System.out.println("Request failed: Collection or DisplayID is null!");
+ MineTale.LOGGER.debug("Craft request skipped: collection or displayId is null");Also applies to: 186-188 🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I want to keep this for now.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🧠 Learnings used |
||
|
|
||
| ClientPlayNetworking.send(new CraftRequestPayload(resultStack, amount)); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
| } else { | ||
| System.out.println("Request failed: Collection or DisplayID is null!"); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Draws the workbench GUI background texture at the screen's top-left corner. | ||
| * | ||
| * @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; | ||
| int l = this.topPos; | ||
| guiGraphics.blit(RenderPipelines.GUI_TEXTURED, TEXTURE, k, l, 0.0F, 0.0F, this.imageWidth, this.imageHeight, 256, 256); | ||
| } | ||
|
|
||
| /** | ||
| * Renders the workbench screen including the background tint, GUI elements, and tooltips. | ||
| * | ||
| * @param graphics the graphics context | ||
| * @param mouseX the current mouse x-coordinate | ||
| * @param mouseY the current mouse y-coordinate | ||
| * @param delta the partial tick delta for frame interpolation | ||
| */ | ||
| @Override | ||
| public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) { | ||
| // 1. Always render the dark background tint first | ||
| renderBackground(graphics, mouseX, mouseY, delta); | ||
|
|
||
| // 3. Call super (this draws your slots and items) | ||
| super.render(graphics, mouseX, mouseY, delta); | ||
|
|
||
| boolean hasSelection = this.mineTaleRecipeBook.getSelectedRecipeId() != null; | ||
| this.craftOneBtn.active = hasSelection; | ||
| this.craftThirtyBtn.active = hasSelection; | ||
| this.craftAllBtn.active = hasSelection; | ||
|
|
||
| renderTooltip(graphics, mouseX, mouseY); | ||
| } | ||
|
|
||
| /** | ||
| * Computes the on-screen position for the recipe book toggle button for this GUI. | ||
| * | ||
| * @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() { | ||
| // 1. Calculate the start (left) of your workbench GUI | ||
| int guiLeft = (this.width - this.imageWidth) / 2; | ||
|
|
||
| // 2. Calculate the top of your workbench GUI | ||
| int guiTop = (this.height - this.imageHeight) / 2; | ||
|
|
||
| // 3. Standard Vanilla positioning: | ||
| // Usually 5 pixels in from the left and 49 pixels up from the center | ||
| return new ScreenPosition(guiLeft + 5, guiTop + this.imageHeight / 2 - 49); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,39 @@ | ||
| package com.tcm.MineTale.datagen; | ||
|
|
||
| import com.tcm.MineTale.MineTale; | ||
| import com.tcm.MineTale.registry.ModBlocks; | ||
| import net.fabricmc.fabric.api.client.datagen.v1.provider.FabricModelProvider; | ||
| import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; | ||
| import net.minecraft.client.data.models.BlockModelGenerators; | ||
| import net.minecraft.client.data.models.ItemModelGenerators; | ||
| import net.minecraft.client.data.models.blockstates.MultiVariantGenerator; | ||
| import net.minecraft.client.data.models.blockstates.PropertyDispatch; | ||
| import net.minecraft.client.data.models.model.ModelLocationUtils; | ||
| import net.minecraft.client.data.models.model.ModelTemplates; | ||
| import net.minecraft.client.data.models.model.TextureMapping; | ||
| import net.minecraft.client.data.models.model.TextureSlot; | ||
| import net.minecraft.client.renderer.block.model.VariantMutator; | ||
| import net.minecraft.core.Direction; | ||
| import net.minecraft.resources.Identifier; | ||
| import net.minecraft.world.level.block.Block; | ||
| import net.minecraft.world.level.block.state.properties.BlockStateProperties; | ||
| import net.minecraft.world.level.block.state.properties.ChestType; | ||
| import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; | ||
|
|
||
| public class ModModelProvider extends FabricModelProvider { | ||
| /** | ||
| * Creates a ModModelProvider using the given Fabric data output. | ||
| * | ||
| * @param output the FabricDataOutput used to write generated model and blockstate data | ||
| */ | ||
| public ModModelProvider(FabricDataOutput output) { super(output); } | ||
| * Creates a ModModelProvider using the given Fabric data output. | ||
| * | ||
| * @param output the FabricDataOutput used to write generated model and blockstate data | ||
| */ | ||
| public ModModelProvider(FabricDataOutput output) { super(output); } | ||
|
|
||
| // Recreate the rotation logic locally since the base one is private | ||
| private static final PropertyDispatch<VariantMutator> WORKBENCH_ROTATION = PropertyDispatch.modify(BlockStateProperties.HORIZONTAL_FACING) | ||
| .select(Direction.NORTH, BlockModelGenerators.NOP) | ||
| .select(Direction.EAST, BlockModelGenerators.Y_ROT_90) | ||
| .select(Direction.SOUTH, BlockModelGenerators.Y_ROT_180) | ||
| .select(Direction.WEST, BlockModelGenerators.Y_ROT_270); | ||
|
|
||
| /** | ||
| * Registers block state and model definitions for the mod's log blocks. | ||
|
|
@@ -54,6 +75,38 @@ public void generateBlockStateModels(BlockModelGenerators blockStateModelGenerat | |
| blockStateModelGenerator.woodProvider(ModBlocks.STRIPPED_LOG).logWithHorizontal(ModBlocks.STRIPPED_LOG); | ||
| blockStateModelGenerator.woodProvider(ModBlocks.WINDWILLOW_LOG).logWithHorizontal(ModBlocks.WINDWILLOW_LOG); | ||
| blockStateModelGenerator.woodProvider(ModBlocks.WILD_WISTERIA_LOG).logWithHorizontal(ModBlocks.WILD_WISTERIA_LOG).wood(ModBlocks.WILD_WISTERIA_WOOD); | ||
|
|
||
| registerLargeWorkbench(blockStateModelGenerator, ModBlocks.FURNACE_WORKBENCH_BLOCK_T1); | ||
| } | ||
|
Comment on lines
+74
to
+77
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if WORKBENCH_WORKBENCH_BLOCK exists and whether it has any model JSON or other datagen registration
echo "=== Searching for WORKBENCH_WORKBENCH_BLOCK definition ==="
rg -n "WORKBENCH_WORKBENCH_BLOCK" --type=java -C 3
echo ""
echo "=== Searching for hand-written workbench model JSONs ==="
find . -path "*/models/block/*workbench*" -type f | sort
echo ""
echo "=== Searching for hand-written blockstate JSONs ==="
find . -path "*/blockstates/*workbench*" -type f | sortRepository: CodeMonkeysMods/MineTale Length of output: 5360 🏁 Script executed: #!/bin/bash
echo "=== Checking WorkbenchWorkbench class structure ==="
rg -n "class WorkbenchWorkbench" --type=java -A 20
echo ""
echo "=== Searching for all methods in ModModelProvider.java ==="
rg -n "def |void |public " src/client/java/com/tcm/MineTale/datagen/ModModelProvider.java | head -30
echo ""
echo "=== Check if WORKBENCH_WORKBENCH_BLOCK is registered anywhere in ModModelProvider ==="
rg -n "WORKBENCH_WORKBENCH_BLOCK" src/client/java/com/tcm/MineTale/datagen/ModModelProvider.javaRepository: CodeMonkeysMods/MineTale Length of output: 11567 🏁 Script executed: #!/bin/bash
echo "=== Full generateBlockStateModels method ==="
sed -n '43,77p' src/client/java/com/tcm/MineTale/datagen/ModModelProvider.javaRepository: CodeMonkeysMods/MineTale Length of output: 3657 Add model registration for The new 🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. workbenchworkbench is a 1x2 model so needs to be two wide one tall.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: Length of output: 11513 🏁 Script executed: Length of output: 17720
Looking at public static final boolean IS_WIDE = false;
public static final boolean IS_TALL = false;This configures it as a 1×1 block (single block). For a 1×2 block (two wide, one tall), you need: public static final boolean IS_WIDE = true; // ← Change to true
public static final boolean IS_TALL = false;When
Two fixes are needed:
Would you like me to help generate the model registration code for the 1×2 workbench? 🧬 Code Graph Analysis Resultssrc/client/java/com/tcm/MineTale/datagen/ModModelProvider.java
✏️ Learnings added
Comment on lines
+74
to
+77
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Proposed fix registerLargeWorkbench(blockStateModelGenerator, ModBlocks.FURNACE_WORKBENCH_BLOCK_T1);
+ registerLargeWorkbench(blockStateModelGenerator, ModBlocks.FURNACE_WORKBENCH_BLOCK_T2);
}This will also require the corresponding T2 model JSON files ( 🤖 Prompt for AI Agents |
||
|
|
||
| private void registerLargeWorkbench(BlockModelGenerators generator, Block block) { | ||
| // 1. Get the base identifier (e.g., minetale:block/furnace_workbench_block_t1) | ||
| Identifier blockId = ModelLocationUtils.getModelLocation(block); | ||
|
|
||
| // 2. Build the references to your manual JSON files | ||
| // .withSuffix() creates: minetale:block/furnace_workbench_block_t1_bottom_left, etc. | ||
| Identifier bottomLeft = blockId.withSuffix("_bottom_left"); | ||
| Identifier bottomRight = blockId.withSuffix("_bottom_right"); | ||
| Identifier topLeft = blockId.withSuffix("_top_left"); | ||
| Identifier topRight = blockId.withSuffix("_top_right"); | ||
| Identifier inventory = blockId.withSuffix("_inventory"); | ||
|
|
||
| // 3. Dispatch to Blockstate (Tells the game which model to show for each state) | ||
| generator.blockStateOutput.accept(MultiVariantGenerator.dispatch(block) | ||
| .with(PropertyDispatch.initial(BlockStateProperties.DOUBLE_BLOCK_HALF, BlockStateProperties.CHEST_TYPE) | ||
| .select(DoubleBlockHalf.LOWER, ChestType.LEFT, BlockModelGenerators.plainVariant(bottomLeft)) | ||
| .select(DoubleBlockHalf.LOWER, ChestType.RIGHT, BlockModelGenerators.plainVariant(bottomRight)) | ||
| .select(DoubleBlockHalf.UPPER, ChestType.LEFT, BlockModelGenerators.plainVariant(topLeft)) | ||
| .select(DoubleBlockHalf.UPPER, ChestType.RIGHT, BlockModelGenerators.plainVariant(topRight)) | ||
| // Support the 'SINGLE' state as a fallback | ||
| .select(DoubleBlockHalf.LOWER, ChestType.SINGLE, BlockModelGenerators.plainVariant(bottomLeft)) | ||
| .select(DoubleBlockHalf.UPPER, ChestType.SINGLE, BlockModelGenerators.plainVariant(topLeft)) | ||
| ) | ||
| .with(WORKBENCH_ROTATION) | ||
| ); | ||
|
|
||
| // 4. Map the Item in your hand to the inventory JSON | ||
| generator.registerSimpleItemModel(block, inventory); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| /** | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.