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
3 changes: 3 additions & 0 deletions src/client/java/com/tcm/MineTale/MineTaleClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
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.
*/
@Override
public void onInitializeClient() {
MenuScreens.register(ModMenuTypes.FURNACE_WORKBENCH_MENU, FurnaceWorkbenchScreen::new);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,48 @@ public class FurnaceWorkbenchScreen extends AbstractContainerScreen<FurnaceWorkb
// Identifier.fromNamespaceAndPath(MineTale.MOD_ID, "textures/gui/container/furnace_workbench.png");
Identifier.withDefaultNamespace("textures/gui/container/furnace.png");

/**
* Creates a new furnace workbench screen for the given menu, player inventory, and title.
*
* @param menu the container menu that provides slots and syncs 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 FurnaceWorkbenchScreen(FurnaceWorkbenchMenu 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;
}

protected void renderBg(GuiGraphics guiGraphics, float f, int i, int j) {
/**
* Draws the furnace workbench background texture onto the screen.
*
* @param guiGraphics the graphics context used for drawing
* @param f partial tick time used 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 furnace 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);
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/tcm/MineTale/MineTale.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ public class MineTale implements ModInitializer {
// That way, it's clear which mod wrote info, warnings, and errors.
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);

/**
* Initializes and registers the mod's game content and subsystems during Fabric startup.
*
* <p>Triggers initialization for blocks, block entities, menu types, entities, items, and entity
* data serializers so they are registered with the game before gameplay begins.</p>
*/
@Override
public void onInitialize() {
ModBlocks.initialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,23 @@ private boolean isCompatiblePart(BlockState current, BlockState neighbor) {
return true;
}

/**
* Registers the block state properties used by this block.
*
* @param builder the state builder to populate with this block's properties (`FACING`, `HALF`, `TYPE`)
*/
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING, HALF, TYPE);
}

/**
* Create the block entity for the primary anchor of a multipart workbench.
*
* @param pos the position where the block entity would be created
* @param state the block state at the position
* @return the new block entity when this block is the primary anchor (lower half with TYPE `LEFT` or `SINGLE`), or `null` if this block is a secondary part
*/
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
Expand All @@ -158,6 +170,16 @@ public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return null;
}

/**
* Open the workbench menu for the block's master part when a player interacts without an item.
*
* @param state the block state at the clicked position
* @param level the level in which the interaction occurs
* @param pos the position of the block that was interacted with
* @param player the player performing the interaction
* @param hitResult details about the hit (hit position and face)
* @return {@code InteractionResult.CONSUME} if a menu was opened on the server, {@code InteractionResult.SUCCESS} on the client, {@code InteractionResult.PASS} otherwise
*/
@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
if (level.isClientSide()) {
Expand All @@ -178,6 +200,18 @@ protected InteractionResult useWithoutItem(BlockState state, Level level, BlockP
return InteractionResult.PASS;
}

/**
* Compute the master (bottom-left) anchor position for this workbench block.
*
* The master is the block that serves as the primary anchor for multi-block
* behavior and block-entity placement: if this block is the upper half the
* master is one block below; if this block is the right-side part the master
* is one block to the left relative to the block's facing.
*
* @param state the block state used to determine HALF, TYPE, and FACING
* @param pos the current block position
* @return the position of the master (bottom-left) block for this workbench
*/
public BlockPos getMasterPos(BlockState state, BlockPos pos) {
BlockPos master = pos;
Direction facing = state.getValue(FACING);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,22 @@ public class CampfireWorkbench extends AbstractWorkbench<CampfireWorkbenchEntity
public static final MapCodec<CampfireWorkbench> CODEC = simpleCodec((properties) ->
new CampfireWorkbench(properties, () -> null));

/**
* Creates a CampfireWorkbench configured to use the mod's CAMPFIRE_WORKBENCH_BE block entity type.
*
* @param properties block properties used to construct this workbench
*/
public CampfireWorkbench(Properties properties) {
// Hardcode the supplier and sounds here if they never change
super(properties, () -> ModBlockEntities.CAMPFIRE_WORKBENCH_BE, IS_WIDE, IS_TALL);
}

/**
* Creates a CampfireWorkbench with the given block properties and block-entity type supplier.
*
* @param properties the block's properties
* @param supplier supplier that provides the BlockEntityType for this workbench
*/
public CampfireWorkbench(Properties properties, Supplier<BlockEntityType<? extends CampfireWorkbenchEntity>> supplier) {
// isWide = false, isTall = false (1x1 footprint)
super(properties, supplier, IS_WIDE, IS_TALL);
Expand All @@ -49,6 +60,11 @@ protected MapCodec<? extends CampfireWorkbench> codec() {
return CODEC;
}

/**
* Specifies that this block is rendered using its block model.
*
* @return RenderShape.MODEL to render the block using its JSON/model representation.
*/
@Override
public RenderShape getRenderShape(BlockState state) {
// BaseEntityBlock defaults to INVISIBLE.
Expand All @@ -58,11 +74,22 @@ public RenderShape getRenderShape(BlockState state) {

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

/**
* Gets the block's collision and interaction shape.
*
* @return the voxel shape representing the block's collision and interaction bounds
*/
@Override
public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return SHAPE;
}

/**
* 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).
*
* @return the created BlockEntity when this block is the master (HALF == LOWER and TYPE != RIGHT), or `null` otherwise
*/
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
Expand All @@ -73,6 +100,20 @@ public BlockEntity newBlockEntity(BlockPos pos, BlockState 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;
Expand All @@ -89,6 +130,13 @@ protected InteractionResult useWithoutItem(BlockState state, Level level, BlockP
return InteractionResult.PASS;
}

/**
* Compute the master (base) block position for this block based on its state.
*
* @param state the block state of the current block
* @param pos the position of the current block
* @return the position of the master (base) block: if the block is the upper half, the block below is used; if the block's type is `RIGHT`, the position is offset one block counterclockwise from its facing direction; otherwise the original position
*/
public BlockPos getMasterPos(BlockState state, BlockPos pos) {
BlockPos master = pos;
Direction facing = state.getValue(FACING);
Expand All @@ -97,4 +145,4 @@ public BlockPos getMasterPos(BlockState state, BlockPos pos) {
return master;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,49 @@ public class FurnaceWorkbench extends AbstractWorkbench<FurnaceWorkbenchEntity>
public static final MapCodec<FurnaceWorkbench> CODEC = simpleCodec(FurnaceWorkbench::new);

/**
* Standard constructor for registration.
* Creates a FurnaceWorkbench using the default furnace workbench block entity type and a 2×2 footprint.
*
* @param properties block properties for this workbench
*/
public FurnaceWorkbench(Properties properties) {
super(properties, () -> ModBlockEntities.FURNACE_WORKBENCH_BE, IS_WIDE, IS_TALL);
}

/**
* Flexible constructor allowing for specialized Block Entity Types.
* Creates a FurnaceWorkbench that uses a custom BlockEntityType supplier and a 2x2 footprint.
*
* @param properties block properties for this workbench
* @param supplier supplies the BlockEntityType to use for the workbench's master block entity
*/
public FurnaceWorkbench(Properties properties, Supplier<BlockEntityType<? extends FurnaceWorkbenchEntity>> supplier) {
super(properties, supplier, IS_WIDE, IS_TALL);
}

/**
* Ensures the block is rendered using its model so the 2x2 workbench model is visible.
*
* @return {@code RenderShape.MODEL} to render the block with its model
*/
@Override
public RenderShape getRenderShape(BlockState state) {
// Essential so that the 2x2 model is visible
return RenderShape.MODEL;
}

/**
* Provides a ticker that drives furnace workbench logic for the master block.
*
* The returned ticker invokes {@link FurnaceWorkbenchEntity#tick(Level, BlockPos, BlockState)} on the master
* workbench block's entity when the supplied `type` matches the furnace workbench block entity type;
* otherwise no ticker is provided.
*
* @param <T> block entity type
* @param level the level in which the ticker will run
* @param state the block state for which the ticker is requested
* @param type the block entity type being ticked
* @return a ticker that calls `FurnaceWorkbenchEntity.tick(...)` for the master furnace workbench entity, or
* `null` if the provided `type` does not match the furnace workbench block entity type
*/
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
Expand All @@ -55,6 +79,11 @@ public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, Block
});
}

/**
* Create the block entity for this block; only the master block of the multi-block workbench receives an entity.
*
* @return the created {@link BlockEntity} for the master block, or `null` if this position does not host an entity
*/
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
Expand All @@ -63,9 +92,14 @@ public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return super.newBlockEntity(pos, state);
}

@Override
/**
* Supply the codec used to serialize and deserialize this FurnaceWorkbench.
*
* @return the MapCodec for this FurnaceWorkbench
*/
@Override
protected MapCodec<? extends FurnaceWorkbench> codec() {
return CODEC;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,38 @@ public abstract class AbstractWorkbenchEntity extends BlockEntity implements Men
protected int tier = 1;
protected double scanRadius = 5.0;

/**
* Creates a new workbench block entity instance.
*
* @param type the BlockEntityType for this entity
* @param pos the world position of the block entity
* @param state the block state at the position
*/
public AbstractWorkbenchEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}

// --- TIER SYSTEM ---
/**
* Gets the workstation's current tier.
*
* @return the current tier value
*/
public int getTier() { return tier; }
public void setTier(int tier) { this.tier = tier; setChanged(); }
/**
* Sets the workstation's tier and marks the block entity as changed.
*
* @param tier the new tier value for this workstation
*/
public void setTier(int tier) { this.tier = tier; setChanged(); }

// --- CHEST SCANNING ---
/**
* Collects nearby inventory-containing block entities within the configured scan radius and vertical range.
*
* Scans a square area centered on this entity from -scanRadius..+scanRadius on X/Z and -2..+2 on Y, gathers any
* block entities implementing `Container`, and returns them sorted by increasing distance to this entity.
*
* @return a list of nearby `Container` instances sorted by proximity; an empty list if none are found or if the world (`level`) is null
*/
public List<Container> getNearbyInventories() {
List<Container> inventories = new ArrayList<>();
if (level == null) {
Expand All @@ -55,20 +78,39 @@ public List<Container> getNearbyInventories() {
return inventories;
}

// --- RECYCLER LOGIC ---
/**
* Attempt to recycle an ItemStack into component items and distribute those components to nearby inventories or drop them at the workbench location.
*
* <p>The base implementation is a no-op; subclasses should override to perform actual recycling. Implementations are expected to insert resulting items into nearby Container block entities when possible and otherwise spawn the items at this entity's world position.</p>
*
* @param stack the ItemStack to recycle
*/
public void attemptRecycle(ItemStack stack) {
// Logic to break down stack.getItem() and return components
// to nearby chests or drop them at worldPosition.
}

/**
* Create the container menu presented to the player when they open this workbench.
*
* @param syncId the window synchronization id provided by the client
* @param playerInventory the player's inventory
* @param player the player opening the menu
* @return the created AbstractContainerMenu, or `null` if no menu should be opened
*/
@Nullable
@Override
public abstract AbstractContainerMenu createMenu(int syncId, Inventory playerInventory, Player player);

/**
* Provides the display name for this workbench block.
*
* @return a translatable Component created from the block's description ID
*/
@Override
public Component getDisplayName() {
return Component.translatable(this.getBlockState().getBlock().getDescriptionId());
}


}
}
Loading