Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
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
24 changes: 0 additions & 24 deletions src/main/java/com/example/ExampleMod.java

This file was deleted.

20 changes: 20 additions & 0 deletions src/main/java/com/example/GolemsExtra.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.example;

import com.example.block.ModBlocks;
import com.example.entity.ModEntities;
import net.fabricmc.api.ModInitializer;

public class GolemsExtra implements ModInitializer {
public static final String MOD_ID = "golemsextra";

@Override
public void onInitialize() {
System.out.println("GolemsExtra: Initializing Mod Components...");

// ** CALL REGISTRATION METHODS **
ModBlocks.registerModBlocks();
ModEntities.registerModEntities();

System.out.println("GolemsExtra: Initialization Complete.");
}
}
40 changes: 40 additions & 0 deletions src/main/java/com/example/block/ModBlocks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.example.block;

import com.example.GolemsExtra;
import com.example.block.entity.StrawChestBlockEntity;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;

public class ModBlocks {

// 1. Declare Block & BlockEntityType (updated to use final)
public static final Block STRAW_CHEST = registerBlock("straw_chest",
// Copy settings from Hay Block (e.g., strength, sound)
new StrawChestBlock(FabricBlockSettings.copy(Blocks.HAY_BLOCK))
);

// We can use a wildcard type here for simplicity
public static BlockEntityType<StrawChestBlockEntity> STRAW_CHEST_ENTITY;

public static void registerModBlocks() {
// 2. Register the Block Entity Type
STRAW_CHEST_ENTITY = Registry.register(
Registry.BLOCK_ENTITY_TYPE,
new Identifier(GolemsExtra.MOD_ID, "straw_chest_entity"),
// Create the Block Entity Type and associate it with the STRAW_CHEST block
BlockEntityType.Builder.create(StrawChestBlockEntity::new, STRAW_CHEST).build(null)
);

// This log confirms the registration methods were called.
System.out.println("Registered Mod Blocks and Entities for " + GolemsExtra.MOD_ID);
}

// Helper method to simplify block registration
private static Block registerBlock(String name, Block block) {
return Registry.register(Registry.BLOCK, new Identifier(GolemsExtra.MOD_ID, name), block);
}
}
32 changes: 32 additions & 0 deletions src/main/java/com/example/block/StrawChestBlock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.example.block;

import com.example.block.entity.StrawChestBlockEntity;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.block.BlockWithEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.util.math.BlockPos;

public class StrawChestBlock extends BlockWithEntity {

// Constructor: Uses settings copied from HAY_BLOCK (or your preferred base)
public StrawChestBlock(FabricBlockSettings settings) {
super(settings);
}

// Required method: Creates the specific Block Entity when placed
@Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new StrawChestBlockEntity(pos, state);
}

// Tells Minecraft that this block uses a Block Entity for rendering
@Override
public BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.MODEL; // Use a standard block model
}

// NOTE: You would add player interaction (onUse) logic here later
// to allow players to open the inventory.
}
13 changes: 13 additions & 0 deletions src/main/java/com/example/block/entity/StrawChestBlockEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.block.entity;

import com.example.block.ModBlocks; // Used for the BlockEntityType reference
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;

public class StrawChestBlockEntity extends UtilityStorageBlockEntity {

public StrawChestBlockEntity(BlockPos pos, BlockState state) {
// We pass the specific BlockEntityType defined in ModBlocks to the generic constructor
super(ModBlocks.STRAW_CHEST_ENTITY, pos, state);
}
}
114 changes: 114 additions & 0 deletions src/main/java/com/example/block/entity/UtilityStorageBlockEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.example.block.entity;

import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventories;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;

public abstract class UtilityStorageBlockEntity extends BlockEntity implements SidedInventory {

// All specific chests will have 9 slots for Golem-deposited items
private static final int INVENTORY_SIZE = 9;
protected DefaultedList<ItemStack> inventory;

// Constructor (requires the specific BlockEntityType from ModBlocks)
public UtilityStorageBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
this.inventory = DefaultedList.ofSize(INVENTORY_SIZE, ItemStack.EMPTY);
}

// --- Inventory Read/Write (NBT) ---

@Override
public void readNbt(NbtCompound nbt) {
super.readNbt(nbt);
Inventories.readNbt(nbt, this.inventory);
}

@Override
public void writeNbt(NbtCompound nbt) {
super.writeNbt(nbt);
Inventories.writeNbt(nbt, this.inventory);
}

// --- Standard Inventory Interface Implementation ---

@Override
public int size() {
return INVENTORY_SIZE;
}

@Override
public boolean isEmpty() {
return this.inventory.stream().allMatch(ItemStack::isEmpty);
}

@Override
public ItemStack getStack(int slot) {
return this.inventory.get(slot);
}

@Override
public ItemStack removeStack(int slot, int amount) {
return Inventories.splitStack(this.inventory, slot, amount);
}

@Override
public ItemStack removeStack(int slot) {
return Inventories.removeStack(this.inventory, slot);
}

@Override
public void setStack(int slot, ItemStack stack) {
this.inventory.set(slot, stack);
if (stack.getCount() > this.getMaxItemCount()) {
stack.setCount(this.getMaxItemCount());
}
this.markDirty();
}

@Override
public boolean canPlayerUse(PlayerEntity player) {
if (this.world.getBlockEntity(this.pos) != this) {
return false;
}
return player.squaredDistanceTo((double)this.pos.getX() + 0.5, (double)this.pos.getY() + 0.5, (double)this.pos.getZ() + 0.5) <= 64.0;
}

@Override
public void clear() {
this.inventory.clear();
}

// --- SidedInventory (For Golem/Hopper Transfer) ---

@Override
public int[] getAvailableSlots(Direction side) {
// All 9 slots are available for I/O
int[] slots = new int[INVENTORY_SIZE];
for (int i = 0; i < INVENTORY_SIZE; i++) {
slots[i] = i;
}
return slots;
}

// Items can be inserted by Golems or Hoppers from any side
@Override
public boolean canInsert(int slot, ItemStack stack, @org.jetbrains.annotations.Nullable Direction dir) {
return true;
}

// By default, prevent auto-extraction (e.g., by Hoppers below) to keep it simple.
// You can override this in specific subclasses if needed.
@Override
public boolean canExtract(int slot, ItemStack stack, Direction dir) {
return false;
}
}
42 changes: 42 additions & 0 deletions src/main/java/com/example/entity/ModEntities.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.example.entity;

import com.example.GolemsExtra;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;

public class ModEntities {

// 1. Declare the Straw Golem Entity Type
public static final EntityType<StrawGolemEntity> STRAW_GOLEM_ENTITY_TYPE = registerEntityType(
"straw_golem",
FabricEntityTypeBuilder.create(SpawnGroup.MISC, StrawGolemEntity::new)
// Define the Golem's size (Adjust as needed for Copper Golem size)
.dimensions(EntityDimensions.fixed(0.6f, 1.2f))
.build()
);

public static void registerModEntities() {
// 2. Register the Golem's Attributes (Health, Speed, etc.)
FabricDefaultAttributeRegistry.register(
STRAW_GOLEM_ENTITY_TYPE,
StrawGolemEntity.createStrawGolemAttributes()
);

System.out.println("Registered Mod Entities for " + GolemsExtra.MOD_ID);
}

// Helper method to simplify entity type registration
private static EntityType<StrawGolemEntity> registerEntityType(String name, EntityType<StrawGolemEntity> entityType) {
// NOTE: We cast the return type here to match the specific Golem class for easier use.
return (EntityType<StrawGolemEntity>)Registry.register(
Registry.ENTITY_TYPE,
new Identifier(GolemsExtra.MOD_ID, name),
entityType
);
}
}
93 changes: 93 additions & 0 deletions src/main/java/com/example/entity/StrawGolemEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.example.entity;

import com.example.block.ModBlocks;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.ai.goal.LookAroundGoal;
import net.minecraft.entity.ai.goal.LookAtEntityGoal;
import net.minecraft.entity.ai.goal.WanderAroundFarGoal;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.World;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.util.math.random.Random;

public class StrawGolemEntity extends UtilityGolemEntity {

public StrawGolemEntity(EntityType<? extends UtilityGolemEntity> entityType, World world) {
super(entityType, world);
}

// --- Placeholder Entity Attributes ---
// Defines health, speed, etc.
public static DefaultAttributeContainer.Builder createStrawGolemAttributes() {
// Placeholder stats (Low Health, Moderate Speed)
return MobEntity.createMobAttributes()
.add(EntityAttributes.GENERIC_MAX_HEALTH, 10.0)
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.28);
}

// --- Placeholder AI Goals (Basic Movement) ---
// We will replace goals 1 and 2 later with farming/item transfer logic
@Override
protected void initGoals() {
// Placeholder Goals: Golem simply wanders and looks around
this.goalSelector.add(5, new WanderAroundFarGoal(this, 0.6));
this.goalSelector.add(6, new LookAtEntityGoal(this, PlayerEntity.class, 6.0f));
this.goalSelector.add(7, new LookAroundGoal(this));
}

/**
* Checks for the two-block pattern (Hay Bale + Pumpkin) and spawns the Golem and Chest.
* @param world The world.
* @param pos The position where the Carved Pumpkin was placed.
*/
public static boolean checkAndSpawn(World world, BlockPos pos) {
if (world.isClient) return false;

BlockPos basePos = pos.down();
BlockState baseState = world.getBlockState(basePos);

// 1. Check if the base is a Hay Bale
if (baseState.isOf(Blocks.HAY_BLOCK)) {

// --- PATTERN MATCHED ---

// 2. Clear the Pumpkin
// Use flag 3: notify neighbors, re-render, don't update lighting
world.setBlockState(pos, Blocks.AIR.getDefaultState(), 3);
world.syncWorldEvent(2001, pos, Block.getRawIdFromState(world.getBlockState(pos)));

// 3. Replace the Hay Bale with the custom Straw Chest Block
world.setBlockState(basePos, ModBlocks.STRAW_CHEST.getDefaultState(), 3);

// 4. Spawn the Straw Golem Entity
StrawGolemEntity golem = ModEntities.STRAW_GOLEM_ENTITY_TYPE.create(world);

if (golem != null) {
BlockPos spawnPos = basePos.up();
Random random = world.random;

// Position and angle setup
golem.refreshPositionAndAngles(
(double)spawnPos.getX() + 0.5,
(double)spawnPos.getY() + 0.05,
(double)spawnPos.getZ() + 0.5,
random.nextFloat() * 360.0F, 0.0F
);

// ** CRUCIAL STEP: Set the Golem's storage location to the new chest **
golem.setStoragePos(basePos);

world.spawnEntity(golem);
return true;
}
}
return false;
}
}
Loading
Loading