Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ dependencies {
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"

// Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_api_version}"

}

Expand Down
14 changes: 7 additions & 7 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx1G
org.gradle.jvmargs=-Xmx4G
org.gradle.parallel=true

# IntelliJ IDEA is not yet fully compatible with configuration cache, see: https://github.com/FabricMC/fabric-loom/issues/1349
Expand All @@ -8,13 +8,13 @@ org.gradle.configuration-cache=false
# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.21.11
loader_version=0.18.2
loom_version=1.14-SNAPSHOT
loader_version=0.18.4
loom_version=1.15-SNAPSHOT

# Fabric API
fabric_api_version=0.141.2+1.21.11
Comment on lines +11 to +15
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify Fabric loader version exists
echo "=== Checking Fabric Loader 0.18.4 ==="
curl -s "https://maven.fabricmc.net/net/fabricmc/fabric-loader/maven-metadata.xml" | grep -o '<version>[^<]*</version>' | grep "0.18.4" || echo "Version 0.18.4 not found in metadata"

# Verify Fabric API version exists for MC 1.21.11
echo "=== Checking Fabric API 0.141.2+1.21.11 ==="
curl -s "https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api/maven-metadata.xml" | grep -o '<version>[^<]*</version>' | grep "0.141.2+1.21.11" || echo "Version 0.141.2+1.21.11 not found in metadata"

# Check for fabric-loom releases
echo "=== Checking Fabric Loom versions ==="
curl -s "https://maven.fabricmc.net/net/fabricmc/fabric-loom/maven-metadata.xml" | grep -o '<version>[^<]*</version>' | tail -20

Repository: CodeMonkeysMods/MineTale

Length of output: 919


Consider replacing loom_version=1.15-SNAPSHOT with a stable release.

All versions are available in Maven repositories:

  • loader_version=0.18.4
  • fabric_api_version=0.141.2+1.21.11
  • loom_version=1.15-SNAPSHOT exists, but stable versions 1.15.1, 1.15.2, and 1.15.3 are also available

Using the SNAPSHOT version introduces build instability unnecessarily when stable releases are available. Pin to 1.15.3 (or the latest stable release appropriate for your build).

🤖 Prompt for AI Agents
In `@gradle.properties` around lines 11 - 15, Replace the unstable SNAPSHOT value
for loom_version with a stable release: update the property loom_version from
"1.15-SNAPSHOT" to "1.15.3" (or another chosen stable 1.15.x), keeping
loader_version and fabric_api_version as-is; ensure the change is made where the
gradle property loom_version is defined so builds use the pinned stable loom
release.


# Mod Properties
mod_version=1.0.0
maven_group=com.tcm
archives_base_name=MineTale

# Dependencies
fabric_version=0.139.4+1.21.11
archives_base_name=MineTale
6 changes: 5 additions & 1 deletion src/client/java/com/tcm/MineTale/MineTaleClient.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package com.tcm.MineTale;

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

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

public class MineTaleClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
// This entrypoint is suitable for setting up client-specific logic, such as rendering.
MenuScreens.register(ModMenuTypes.FURNACE_WORKBENCH_MENU, FurnaceWorkbenchScreen::new);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.tcm.MineTale.block.workbenches.screen;

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

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 FurnaceWorkbenchScreen extends AbstractContainerScreen<FurnaceWorkbenchMenu> {
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 +3 to +15
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the FurnaceWorkbenchScreen file
find . -name "FurnaceWorkbenchScreen.java" -type f

Repository: CodeMonkeysMods/MineTale

Length of output: 155


🏁 Script executed:

#!/bin/bash
# Search for furnace_workbench texture asset
find . -name "*furnace_workbench*" -type f 2>/dev/null

Repository: CodeMonkeysMods/MineTale

Length of output: 50


🏁 Script executed:

#!/bin/bash
# Search for MineTale class with MOD_ID constant
find . -name "MineTale.java" -type f

Repository: CodeMonkeysMods/MineTale

Length of output: 114


🏁 Script executed:

#!/bin/bash
# Look at the FurnaceWorkbenchMenu to verify the layout
find . -name "FurnaceWorkbenchMenu.java" -type f

Repository: CodeMonkeysMods/MineTale

Length of output: 149


🏁 Script executed:

#!/bin/bash
cat -n ./src/client/java/com/tcm/MineTale/block/workbenches/screen/FurnaceWorkbenchScreen.java

Repository: CodeMonkeysMods/MineTale

Length of output: 1937


🏁 Script executed:

#!/bin/bash
cat -n ./src/main/java/com/tcm/MineTale/block/workbenches/menu/FurnaceWorkbenchMenu.java

Repository: CodeMonkeysMods/MineTale

Length of output: 6355


🏁 Script executed:

#!/bin/bash
cat -n ./src/main/java/com/tcm/MineTale/MineTale.java | head -50

Repository: CodeMonkeysMods/MineTale

Length of output: 1384


🏁 Script executed:

#!/bin/bash
# Double-check for texture assets in the correct asset directory structure
find . -path "*/assets/*/textures/gui/container/*furnace*" -type f 2>/dev/null

Repository: CodeMonkeysMods/MineTale

Length of output: 50


Custom GUI texture asset must be created to match the 2x2 output slot layout.

The menu defines a 2x2 output grid (slots at coordinates 116/134 × 21/39), but the vanilla furnace texture only has a single output slot. Either create the custom texture asset at src/main/resources/assets/minetale/textures/gui/container/furnace_workbench.png or use a different existing texture. The commented line should only be uncommented once the texture file is in place. Remove the unused import of RenderPipelines while you're at it.

🤖 Prompt for AI Agents
In
`@src/client/java/com/tcm/MineTale/block/workbenches/screen/FurnaceWorkbenchScreen.java`
around lines 3 - 15, The TEXTURE constant in FurnaceWorkbenchScreen points to
the vanilla single-output furnace texture but your menu implements a 2x2 output
grid; add a matching custom GUI texture named furnace_workbench.png in your
mod's resources, change TEXTURE back to use
Identifier.fromNamespaceAndPath(MineTale.MOD_ID,
"textures/gui/container/furnace_workbench.png") (uncomment that line) only after
the texture exists, and remove the unused import RenderPipelines; also ensure
the new texture layout places the four output slots at the menu's coordinates
(116/134 × 21/39).


public FurnaceWorkbenchScreen(FurnaceWorkbenchMenu menu, Inventory inventory, Component title) {
super(menu, inventory, title);
}

@Override
protected void init() {
super.init();
this.titleLabelX = (this.imageWidth - this.font.width(this.title)) / 2;
}

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);
}

@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);
}
Comment on lines +1 to +64
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

fd 'FurnaceWorkbenchScreen.java'

Repository: CodeMonkeysMods/MineTale

Length of output: 151


🏁 Script executed:

rg -n --type=java 'FurnaceWorkbenchScreen' -C2

Repository: CodeMonkeysMods/MineTale

Length of output: 2288


🏁 Script executed:

# Also check for source set configuration files
fd -e 'gradle' -e 'pom.xml' | head -20

Repository: CodeMonkeysMods/MineTale

Length of output: 96


🏁 Script executed:

cat build.gradle

Repository: CodeMonkeysMods/MineTale

Length of output: 2416


🏁 Script executed:

# Check if there are any other references to FurnaceWorkbenchScreen outside client code
rg 'FurnaceWorkbenchScreen' --type=java -l

Repository: CodeMonkeysMods/MineTale

Length of output: 204


Move client-only screen to src/client/java (architectural violation with split source sets).

FurnaceWorkbenchScreen uses client-only APIs (AbstractContainerScreen, GuiGraphics, RenderPipelines) but is placed in src/main/java. The build.gradle declares separate sourceSets.main and sourceSets.client, so client code must live in src/client/java. The class is already referenced only from the client entrypoint (MineTaleClient.java), making it safe to move.

🧰 Tools
🪛 GitHub Actions: build

[error] 1-39: Compilation failed due to missing Minecraft GUI classes and unresolved symbols. Errors include: cannot find symbol for net.minecraft.client.gui.GuiGraphics, net.minecraft.client.gui.screens.inventory.AbstractContainerScreen, net.minecraft.client.renderer.RenderPipelines, and many dependent members (e.g., GuiGraphics, AbstractContainerScreen, RenderPipelines, title/width/font fields). This indicates missing or incompatible Minecraft/LibGraft/Mixin APIs in the project setup.

🤖 Prompt for AI Agents
In
`@src/main/java/com/tcm/MineTale/block/workbenches/screen/FurnaceWorkbenchScreen.java`
around lines 1 - 44, FurnaceWorkbenchScreen uses client-only APIs
(AbstractContainerScreen, GuiGraphics, RenderPipelines) but lives in main; move
the class file for FurnaceWorkbenchScreen into the client source set
(src/client/java) keeping the same package declaration and imports, so the
compiler will exclude it from server/runtime builds; ensure the existing
reference in MineTaleClient.java still points to the same package/class and
remove the file from src/main/java to avoid duplicate symbol errors.

}
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 @@ -10,6 +10,7 @@
import com.tcm.MineTale.registry.ModEntities;
import com.tcm.MineTale.registry.ModEntityDataSerializers;
import com.tcm.MineTale.registry.ModItems;
import com.tcm.MineTale.registry.ModMenuTypes;

public class MineTale implements ModInitializer {
public static final String MOD_ID = "minetale";
Expand All @@ -23,6 +24,7 @@ public class MineTale implements ModInitializer {
public void onInitialize() {
ModBlocks.initialize();
ModBlockEntities.initialize();
ModMenuTypes.initialize();
ModEntities.initialize();
ModItems.initialize();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
Expand All @@ -18,11 +21,15 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.*;
import net.minecraft.world.phys.BlockHitResult;

import org.jetbrains.annotations.Nullable;

import com.tcm.MineTale.block.workbenches.entity.AbstractWorkbenchEntity;

import java.util.function.Supplier;

public abstract class AbstractWorkbench<E extends BlockEntity> extends BaseEntityBlock {
public abstract class AbstractWorkbench<E extends AbstractWorkbenchEntity> extends BaseEntityBlock {
public static final EnumProperty<Direction> FACING = HorizontalDirectionalBlock.FACING;
public static final EnumProperty<DoubleBlockHalf> HALF = BlockStateProperties.DOUBLE_BLOCK_HALF;
public static final EnumProperty<ChestType> TYPE = BlockStateProperties.CHEST_TYPE;
Expand Down Expand Up @@ -131,4 +138,60 @@ private boolean isCompatiblePart(BlockState current, BlockState neighbor) {
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING, HALF, TYPE);
}

@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
// We only want a Block Entity at the 'primary' anchor point of the structure.
// For 1x1: HALF=LOWER, TYPE=SINGLE
// For 2x1: HALF=LOWER, TYPE=LEFT
// For 2x2: HALF=LOWER, TYPE=LEFT

boolean isLower = state.getValue(HALF) == DoubleBlockHalf.LOWER;
ChestType type = state.getValue(TYPE);

// If it's the RIGHT side of a wide block, or the UPPER half of a tall block, return null.
if (isLower && (type == ChestType.LEFT || type == ChestType.SINGLE)) {
return this.blockEntityType.get().create(pos, state);
}

return null;
}

@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
if (level.isClientSide()) {
return InteractionResult.SUCCESS;
}

// 1. Find the Master Position (Bottom-Left)
BlockPos masterPos = getMasterPos(state, pos);
BlockEntity blockEntity = level.getBlockEntity(masterPos);

// 2. Check if the Master block has the MenuProvider trait
if (blockEntity instanceof MenuProvider menuProvider) {
// 3. Open the Screen (this triggers the ScreenHandler/Menu)
player.openMenu(menuProvider);
return InteractionResult.CONSUME;
}

return InteractionResult.PASS;
}

public BlockPos getMasterPos(BlockState state, BlockPos pos) {
BlockPos master = pos;
Direction facing = state.getValue(FACING);

// Move down if we are the upper half
if (state.getValue(HALF) == DoubleBlockHalf.UPPER) {
master = master.below();
}

// Move left if we are the right side (relative to facing)
if (state.getValue(TYPE) == ChestType.RIGHT) {
master = master.relative(facing.getCounterClockWise());
}

return master;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,29 @@
import org.jetbrains.annotations.Nullable;

import com.mojang.serialization.MapCodec;
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.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;

// ChestBlock

public class CampfireWorkbench extends AbstractWorkbench<BlockEntity> {
public class CampfireWorkbench extends AbstractWorkbench<CampfireWorkbenchEntity> {
public static final boolean IS_WIDE = false;
public static final boolean IS_TALL = false;

Expand All @@ -31,7 +39,7 @@ public CampfireWorkbench(Properties properties) {
super(properties, () -> ModBlockEntities.CAMPFIRE_WORKBENCH_BE, IS_WIDE, IS_TALL);
}

public CampfireWorkbench(Properties properties, Supplier<BlockEntityType<? extends BlockEntity>> supplier) {
public CampfireWorkbench(Properties properties, Supplier<BlockEntityType<? extends CampfireWorkbenchEntity>> supplier) {
// isWide = false, isTall = false (1x1 footprint)
super(properties, supplier, IS_WIDE, IS_TALL);
}
Expand All @@ -48,18 +56,45 @@ public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}

private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 7, 16);

@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}

@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
// For a 1x1, we always create the Block Entity at this position.
return this.blockEntityType.get().create(pos, 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;
}

private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 7, 16);

@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
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;
Comment on lines 116 to +129
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

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the complete file to understand the context
cat src/main/java/com/tcm/MineTale/block/workbenches/CampfireWorkbench.java

Repository: CodeMonkeysMods/MineTale

Length of output: 6334


🏁 Script executed:

# Search for other uses of InteractionResult in the codebase to see patterns
rg "InteractionResult\.(SUCCESS|PASS|CONSUME)" --context 2 -A 1

Repository: CodeMonkeysMods/MineTale

Length of output: 1931


🏁 Script executed:

# Check if there are other workbench implementations to compare
fd -e java "Workbench" | head -20

Repository: CodeMonkeysMods/MineTale

Length of output: 702


🏁 Script executed:

cat src/main/java/com/tcm/MineTale/block/workbenches/AbstractWorkbench.java | head -200

Repository: CodeMonkeysMods/MineTale

Length of output: 9181


🏁 Script executed:

# Find the useWithoutItem or similar interaction methods in AbstractWorkbench
rg -A 15 "useWithoutItem|use(" src/main/java/com/tcm/MineTale/block/workbenches/AbstractWorkbench.java

Repository: CodeMonkeysMods/MineTale

Length of output: 156


🏁 Script executed:

# Check if there are other similar incomplete implementations or patterns
rg "useWithoutItem" -B 2 -A 8 src/main/java/com/tcm/MineTale/block/workbenches/

Repository: CodeMonkeysMods/MineTale

Length of output: 2607


🏁 Script executed:

# Look at FurnaceWorkbench to see if it has similar pattern
cat src/main/java/com/tcm/MineTale/block/workbenches/FurnaceWorkbench.java

Repository: CodeMonkeysMods/MineTale

Length of output: 4458


Return PASS on client until workbench logic is implemented.

The current code returns SUCCESS on client but PASS on server, creating a mismatch where the client thinks the interaction is handled while the server ignores it. Since the workbench implementation is commented out, the interaction isn't actually being handled. Once the implementation is complete, the server will return CONSUME (as in the parent AbstractWorkbench), so return PASS on both sides now to signal the interaction remains unhandled.

Suggested fix
-        if (level.isClientSide()) return InteractionResult.SUCCESS;
+        if (level.isClientSide()) return InteractionResult.PASS;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
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;
`@Override`
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
if (level.isClientSide()) return InteractionResult.PASS;
// 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;
🤖 Prompt for AI Agents
In `@src/main/java/com/tcm/MineTale/block/workbenches/CampfireWorkbench.java`
around lines 116 - 129, In CampfireWorkbench.useWithoutItem, the client
currently returns InteractionResult.SUCCESS while the server returns PASS;
change the client-side early return to return InteractionResult.PASS so both
sides match while the workbench logic (commented block interacting with
AbstractWorkbenchEntity) is not implemented; update the early return in the
useWithoutItem method to return PASS on client side to signal the interaction is
unhandled.

}

public BlockPos getMasterPos(BlockState state, BlockPos pos) {
BlockPos master = pos;
Direction facing = state.getValue(FACING);
if (state.getValue(HALF) == DoubleBlockHalf.UPPER) master = master.below();
if (state.getValue(TYPE) == ChestType.RIGHT) master = master.relative(facing.getCounterClockWise());
return master;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.tcm.MineTale.block.workbenches;

import java.util.function.Supplier;

import org.jetbrains.annotations.Nullable;

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

import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
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;

public class FurnaceWorkbench extends AbstractWorkbench<FurnaceWorkbenchEntity> {
// Setting these to true creates the 2x2 multi-block footprint
private static final boolean IS_WIDE = true;
private static final boolean IS_TALL = true;

public static final MapCodec<FurnaceWorkbench> CODEC = simpleCodec((properties) ->
new FurnaceWorkbench(properties, () -> null));
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

/**
* Standard constructor for registration.
*/
public FurnaceWorkbench(Properties properties) {
super(properties, () -> ModBlockEntities.FURNACE_WORKBENCH_BE, IS_WIDE, IS_TALL);
}

/**
* Flexible constructor allowing for specialized Block Entity Types.
*/
public FurnaceWorkbench(Properties properties, Supplier<BlockEntityType<? extends FurnaceWorkbenchEntity>> supplier) {
super(properties, supplier, IS_WIDE, IS_TALL);
}

@Override
public RenderShape getRenderShape(BlockState state) {
// Essential so that the 2x2 model is visible
return RenderShape.MODEL;
}

@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
// Only the Master block (Lower-Left) should tick to process smelting
// This helper ensures the logic only runs on the Server side for our specific BE
return createTickerHelper(type, ModBlockEntities.FURNACE_WORKBENCH_BE, (lvl, pos, st, be) -> {
if (be instanceof FurnaceWorkbenchEntity furnace) {
furnace.tick(lvl, pos, st);
}
});
}

@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
// 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);
}

@Override
protected MapCodec<? extends FurnaceWorkbench> codec() {
return CODEC;
}

}
Loading