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
73 changes: 73 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
name: Build and Release

on:
pull_request:
types: [closed]
branches: [main]

jobs:
release:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Java 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'

- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: ${{ runner.os }}-gradle-

- name: Increment version
id: version
run: |
CURRENT=$(grep '^mod_version=' gradle.properties | cut -d'=' -f2)
NEW=$(python3 -c "
parts = '$CURRENT'.split('.')
major, minor = int(parts[0]), int(parts[1])
minor += 1
if minor >= 10:
major += 1
minor = 0
print(f'{major}.{minor}')
")
sed -i "s/^mod_version=.*/mod_version=$NEW/" gradle.properties
echo "version=$NEW" >> "$GITHUB_OUTPUT"
echo "Bumped $CURRENT → $NEW"

- name: Build
run: ./gradlew build

- name: Commit version bump
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add gradle.properties
git commit -m "chore: bump version to ${{ steps.version.outputs.version }} [skip ci]"
git push

- name: Create release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
JAR=$(find build/libs -name "hardworkers-*.jar" ! -name "*-sources*" | head -1)
gh release create "v${{ steps.version.outputs.version }}" \
"$JAR#hardworkers-${{ steps.version.outputs.version }}.jar" \
--title "Hard Workers v${{ steps.version.outputs.version }}" \
--generate-notes
27 changes: 27 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Gradle
.gradle/
build/
out/

# Generated sources
src/generated/

# IntelliJ IDEA
.idea/
*.iml
*.ipr
*.iws

# Eclipse
.classpath
.project
.settings/

# VS Code
.vscode/

# macOS
.DS_Store

# Windows
Thumbs.db
13 changes: 13 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ repositories {
mavenLocal()
}

// NeoForge 21.1.x puts ASM 9.7 on the JVM module path. The NeoGradle plugin
// pulls in a transitive ASM 9.5 which then also lands on the classpath,
// causing BootstrapLauncher to refuse to start. Force everything to 9.7.
configurations.all {
resolutionStrategy {
force 'org.ow2.asm:asm:9.7'
force 'org.ow2.asm:asm-analysis:9.7'
force 'org.ow2.asm:asm-commons:9.7'
force 'org.ow2.asm:asm-tree:9.7'
force 'org.ow2.asm:asm-util:9.7'
}
}

dependencies {
implementation "net.neoforged:neoforge:${project.neo_version}"
}
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ loader_version_range=[2,)
mod_id=hardworkers
mod_name=Hard Workers
mod_license=MIT
mod_version=1.0.0
mod_version=0.0
mod_group_id=com.hardworkers.hardworkers
mod_authors=holty07
mod_description=Adds worker blocks that spawn entities to automate tasks. Place a Lumberjack Block and watch him chop trees and replant saplings.
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 2 additions & 0 deletions src/main/java/com/hardworkers/hardworkers/HardWorkers.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.hardworkers.hardworkers;

import com.hardworkers.hardworkers.init.ModBlockEntities;
import com.hardworkers.hardworkers.init.ModBlocks;
import com.hardworkers.hardworkers.init.ModEntities;
import com.hardworkers.hardworkers.init.ModItems;
Expand All @@ -17,6 +18,7 @@ public HardWorkers(IEventBus modEventBus, ModContainer modContainer) {
ModBlocks.BLOCKS.register(modEventBus);
ModItems.ITEMS.register(modEventBus);
ModEntities.ENTITY_TYPES.register(modEventBus);
ModBlockEntities.BLOCK_ENTITY_TYPES.register(modEventBus);

modContainer.registerConfig(ModConfig.Type.COMMON, HardWorkersConfig.SPEC);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ public class HardWorkersConfig {
public static final ModConfigSpec SPEC;

public static final ModConfigSpec.IntValue LUMBERJACK_SEARCH_RADIUS;
public static final ModConfigSpec.IntValue LUMBERJACK_CHOP_INTERVAL;

static {
BUILDER.comment("Lumberjack Settings").push("lumberjack");
Expand All @@ -18,10 +17,6 @@ public class HardWorkersConfig {
.comment("Radius in blocks the lumberjack searches for trees around its home block")
.defineInRange("searchRadius", 16, 4, 64);

LUMBERJACK_CHOP_INTERVAL = BUILDER
.comment("Ticks between each log broken (20 ticks = 1 second)")
.defineInRange("chopInterval", 20, 5, 100);

BUILDER.pop();
SPEC = BUILDER.build();
}
Expand Down
148 changes: 148 additions & 0 deletions src/main/java/com/hardworkers/hardworkers/block/FarmerBlock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package com.hardworkers.hardworkers.block;

import com.hardworkers.hardworkers.blockentity.FarmerBlockEntity;
import com.hardworkers.hardworkers.entity.FarmerEntity;
import com.hardworkers.hardworkers.init.ModBlockEntities;
import com.hardworkers.hardworkers.init.ModEntities;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.Containers;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BaseEntityBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.SoundType;
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.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.material.MapColor;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;

import javax.annotation.Nullable;

public class FarmerBlock extends BaseEntityBlock {

public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;

public static final MapCodec<FarmerBlock> WOOD_CODEC = simpleCodec(p -> new FarmerBlock(FarmerTier.WOOD, p));
public static final MapCodec<FarmerBlock> STONE_CODEC = simpleCodec(p -> new FarmerBlock(FarmerTier.STONE, p));
public static final MapCodec<FarmerBlock> IRON_CODEC = simpleCodec(p -> new FarmerBlock(FarmerTier.IRON, p));
public static final MapCodec<FarmerBlock> DIAMOND_CODEC = simpleCodec(p -> new FarmerBlock(FarmerTier.DIAMOND, p));
public static final MapCodec<FarmerBlock> NETHERITE_CODEC = simpleCodec(p -> new FarmerBlock(FarmerTier.NETHERITE, p));

private final FarmerTier tier;

public FarmerBlock(FarmerTier tier, BlockBehaviour.Properties properties) {
super(properties);
this.tier = tier;
registerDefaultState(defaultBlockState().setValue(FACING, Direction.NORTH));
}

public FarmerTier getTier() { return tier; }

@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING);
}

@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite());
}

@Override
public BlockState rotate(BlockState state, Rotation rotation) {
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
}

@Override
public BlockState mirror(BlockState state, Mirror mirror) {
return state.rotate(mirror.getRotation(state.getValue(FACING)));
}

@Override
public MapCodec<? extends BaseEntityBlock> codec() {
return switch (tier) {
case WOOD -> WOOD_CODEC;
case STONE -> STONE_CODEC;
case IRON -> IRON_CODEC;
case DIAMOND -> DIAMOND_CODEC;
case NETHERITE -> NETHERITE_CODEC;
};
}

@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new FarmerBlockEntity(pos, state);
}

@Nullable
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
return level.isClientSide() ? null
: createTickerHelper(type, ModBlockEntities.FARMER_BLOCK_ENTITY.get(), FarmerBlockEntity::serverTick);
}

@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}

@Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
if (!level.isClientSide()) {
FarmerEntity farmer = ModEntities.FARMER.get().create(level);
if (farmer != null) {
farmer.setHomePosition(pos);
farmer.setTierEquipment(this.tier);
farmer.moveTo(pos.getX() + 0.5, pos.getY() + 1.0, pos.getZ() + 0.5, 0f, 0f);
level.addFreshEntity(farmer);
}
}
}

@Override
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!level.isClientSide() && !state.is(newState.getBlock())) {
if (level.getBlockEntity(pos) instanceof FarmerBlockEntity be) {
Containers.dropContents(level, pos, be);
}
AABB searchArea = new AABB(pos).inflate(3.0);
level.getEntitiesOfClass(FarmerEntity.class, searchArea)
.stream()
.filter(e -> pos.equals(e.getHomePosition()))
.forEach(FarmerEntity::discard);
}
super.onRemove(state, level, pos, newState, movedByPiston);
}

@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos,
Player player, BlockHitResult hitResult) {
if (!level.isClientSide() && level.getBlockEntity(pos) instanceof FarmerBlockEntity be) {
player.displayClientMessage(be.getStorageStatus(), true);
}
return InteractionResult.sidedSuccess(level.isClientSide());
}

public static BlockBehaviour.Properties baseProperties(MapColor color) {
return BlockBehaviour.Properties.of()
.mapColor(color)
.sound(SoundType.WOOD)
.strength(2.0f);
}
}
21 changes: 21 additions & 0 deletions src/main/java/com/hardworkers/hardworkers/block/FarmerTier.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.hardworkers.hardworkers.block;

public enum FarmerTier {
WOOD ("wood", 30, 0),
STONE ("stone", 24, 200),
IRON ("iron", 18, 100),
DIAMOND ("diamond", 12, 50),
NETHERITE("netherite", 6, 25);

public final String id;
/** Ticks between each crop harvest action. */
public final int harvestInterval;
/** Ticks between forced random-tick calls on crops in range (0 = no boost). */
public final int growthBoostInterval;

FarmerTier(String id, int harvestInterval, int growthBoostInterval) {
this.id = id;
this.harvestInterval = harvestInterval;
this.growthBoostInterval = growthBoostInterval;
}
}
Loading
Loading