Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
1 change: 0 additions & 1 deletion src/client/java/com/tcm/MineTale/MineTaleClient.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.tcm.MineTale;

import com.tcm.MineTale.block.workbenches.menu.BlacksmithsWorkbenchMenu;
import com.tcm.MineTale.block.workbenches.screen.*;
import com.tcm.MineTale.network.ClientboundNearbyInventorySyncPacket;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.tcm.MineTale.MineTale;
import com.tcm.MineTale.block.workbenches.menu.AbstractWorkbenchContainerMenu;
import com.tcm.MineTale.block.workbenches.menu.BlacksmithsWorkbenchMenu;
import com.tcm.MineTale.block.workbenches.menu.FurnitureWorkbenchMenu;
import com.tcm.MineTale.mixin.client.ClientRecipeBookAccessor;
import com.tcm.MineTale.network.CraftRequestPayload;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package com.tcm.MineTale.datagen;

import com.tcm.MineTale.registry.ModBlocks;
import com.tcm.MineTale.util.ModTags;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.minecraft.core.HolderLookup;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;

import java.util.concurrent.CompletableFuture;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import net.minecraft.core.HolderLookup;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Blocks;

import java.util.concurrent.CompletableFuture;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import net.minecraft.client.renderer.block.model.VariantMutator;
import net.minecraft.core.Direction;
import net.minecraft.resources.Identifier;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.tcm.MineTale.registry.ModItems;
import com.tcm.MineTale.registry.ModRecipeDisplay;
import com.tcm.MineTale.registry.ModRecipes;

import net.minecraft.core.HolderLookup;
import net.minecraft.data.recipes.RecipeOutput;
import net.minecraft.data.recipes.RecipeProvider;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.tcm.MineTale.datagen.recipes;

import com.tcm.MineTale.datagen.ModItemTagProvider;
import com.tcm.MineTale.datagen.builders.WorkbenchRecipeBuilder;
import com.tcm.MineTale.registry.ModBlocks;
import com.tcm.MineTale.registry.ModItems;
Expand Down
143 changes: 139 additions & 4 deletions src/main/java/com/tcm/MineTale/block/ChickenCoopBlock.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,50 @@
package com.tcm.MineTale.block;

import com.mojang.serialization.MapCodec;
import com.tcm.MineTale.block.entity.ChickenCoopEntity;
import com.tcm.MineTale.registry.ModBlockEntities;
import com.tcm.MineTale.util.CoopPart;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.util.RandomSource;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.ScheduledTickAccess;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
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.StateDefinition;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.BlockHitResult;

import org.jetbrains.annotations.Nullable;

public class ChickenCoopBlock extends HorizontalDirectionalBlock {
public class ChickenCoopBlock extends HorizontalDirectionalBlock implements EntityBlock {
public static final EnumProperty<CoopPart> PART = EnumProperty.create("part", CoopPart.class);

public static final MapCodec<ChickenCoopBlock> CODEC = simpleCodec(ChickenCoopBlock::new);

/**
* Create a ChickenCoopBlock configured with the provided block properties and a default state.
*
* The default state sets FACING to NORTH and PART to CoopPart.BOTTOM_FRONT_LEFT.
*
* @param properties block properties used to configure this block's behaviour and characteristics
*/
public ChickenCoopBlock(Properties properties) {
super(properties);
// Default to the origin part (Bottom Front Left) facing North
Expand All @@ -35,6 +53,57 @@ public ChickenCoopBlock(Properties properties) {
.setValue(PART, CoopPart.BOTTOM_FRONT_LEFT));
}

/**
* Provides a BlockEntityTicker for the coop's centre-front part on the server.
*
* Returns a ticker that delegates to ChickenCoopEntity.tick when the call is on the logical server,
* the block state's PART is BOTTOM_FRONT_CENTER and the requested BlockEntityType equals ModBlockEntities.CHICKEN_COOP_BE.
*
* @param <T> the block entity type
* @param level the level containing the block
* @param state the block state for which a ticker is requested
* @param type the requested block entity type
* @return a ticker delegating to ChickenCoopEntity.tick when applicable, `null` otherwise
*/
@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
// 1. Only tick on server side
if (level.isClientSide()) return null;

// 2. Only tick if this is the correct part of the coop
if (state.getValue(PART) != CoopPart.BOTTOM_FRONT_CENTER) return null;

// 3. Link to the static tick method in your Entity class
return type == ModBlockEntities.CHICKEN_COOP_BE
? (lvl, pos, st, be) -> ChickenCoopEntity.tick(lvl, pos, st, (ChickenCoopEntity) be)
: null;
}

/**
* Creates the block entity for the coop when this block represents the centre-front (brain) part.
*
* @param pos the block position
* @param state the current block state
* @return {@code ChickenCoopEntity} for the centre-front part, {@code null} otherwise
*/
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
// Only the center-front part gets the "brain"
if (state.getValue(PART) == CoopPart.BOTTOM_FRONT_CENTER) {
return new ChickenCoopEntity(pos, state);
}
return null;
}

/**
* Registers this block's state properties.
*
* Adds the horizontal facing and coop part properties so block states can represent orientation and segment.
*
* @param builder the state definition builder to register properties with
*/
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING, PART);
Expand Down Expand Up @@ -185,7 +254,14 @@ public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state,
}

/**
* Rotates the 3x3x2 grid logic based on which way the player is facing.
* Compute the world block position for a local coordinate inside the coop's 3×2×3 grid, taking block facing into account.
*
* @param origin the reference origin position (the block considered as the grid origin)
* @param facing the horizontal direction the coop is facing; used to convert local depth into world direction
* @param x local x index in the 3-wide grid (0 = left, 1 = centre, 2 = right)
* @param z local depth index along the facing direction (0..2); larger values are further away from the player
* @param y local vertical index (0..2) measured as blocks above the origin
* @return the computed BlockPos in world coordinates for the given local grid coordinate
*/
private BlockPos calculateOffset(BlockPos origin, Direction facing, int x, int z, int y) {
// x-1 centers the 3-wide structure (0=left, 1=center, 2=right)
Expand All @@ -198,8 +274,67 @@ private BlockPos calculateOffset(BlockPos origin, Direction facing, int x, int z
.above(y);
}

@Override
/**
* Provide the block's MapCodec used by the game's codec system for (de)serialisation.
*
* @return the MapCodec instance for this block's state
*/
@Override
protected MapCodec<? extends HorizontalDirectionalBlock> codec() {
return CODEC;
}
}

/**
* Handle interaction with the coop when used without an item, dispensing any collected eggs to the player.
*
* On the client this returns `InteractionResult.SUCCESS`. On the server this locates the coop's brain
* block entity (the bottom-front-center part); if that entity has eggs they are transferred to the player
* (or dropped at the player's feet if their inventory is full) and a chicken-egg sound is played.
*
* @param state the current block state
* @param level the level where the block is located
* @param pos the position of the interacted block
* @param player the player performing the interaction
* @param hitResult hit information for the interaction
* @return `InteractionResult.SUCCESS` if eggs were given or on the client, `InteractionResult.PASS` otherwise.
*/
@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
if (level.isClientSide()) return InteractionResult.SUCCESS;

// 1. Find the "brain" position (the Bottom Front Center)
Direction facing = state.getValue(FACING);
CoopPart currentPart = state.getValue(PART);

// Calculate the origin (Bottom Front Center is our origin in calculateOffset logic)
// Based on your calculateOffset, the BFC is at x=1, z=0, y=0.
BlockPos brainPos = pos.subtract(calculateOffset(BlockPos.ZERO, facing,
currentPart.getXOffset(), currentPart.getZOffset(), currentPart.getYOffset()))
.relative(facing, 0) // already at z=0
.relative(facing.getClockWise(), 0); // x=1 is center, so we shift back to it

// Easier way: Since you know the brain is always at BOTTOM_FRONT_CENTER:
// We just need to find where that specific part is relative to the current block.
// However, your 'calculateOffset' is already the source of truth.

if (level.getBlockEntity(brainPos) instanceof ChickenCoopEntity coopBe) {
int eggsToGive = coopBe.takeAllEggs();

if (eggsToGive > 0) {
// Give the player an egg
ItemStack eggStack = new ItemStack(Items.EGG, eggsToGive);
if (!player.getInventory().add(eggStack)) {
// If inventory full, drop at player's feet
player.drop(eggStack, false);
}

// Play a sound to give feedback
level.playSound(null, pos, SoundEvents.CHICKEN_EGG, SoundSource.PLAYERS, 1.0f, 1.0f);
return InteractionResult.SUCCESS;
}
}

return InteractionResult.PASS;
}

}
Loading
Loading