Skip to content

Commit 72d35aa

Browse files
committed
mining functionality
1 parent 3f2e1f9 commit 72d35aa

File tree

1 file changed

+387
-0
lines changed

1 file changed

+387
-0
lines changed
Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
1+
package com.steve.ai.action.actions;
2+
3+
import com.steve.ai.SteveMod;
4+
import com.steve.ai.action.ActionResult;
5+
import com.steve.ai.action.Task;
6+
import com.steve.ai.entity.SteveEntity;
7+
import net.minecraft.core.BlockPos;
8+
import net.minecraft.world.InteractionHand;
9+
import net.minecraft.world.level.block.Block;
10+
import net.minecraft.world.level.block.Blocks;
11+
import net.minecraft.core.registries.BuiltInRegistries;
12+
import net.minecraft.resources.ResourceLocation;
13+
import net.minecraft.world.level.block.state.BlockState;
14+
15+
import java.util.ArrayList;
16+
import java.util.HashMap;
17+
import java.util.List;
18+
import java.util.Map;
19+
20+
public class MineBlockAction extends BaseAction {
21+
private Block targetBlock;
22+
private int targetQuantity;
23+
private int minedCount;
24+
private BlockPos currentTarget;
25+
private int searchRadius = 8; // Small search radius - stay near player
26+
private int ticksRunning;
27+
private int ticksSinceLastTorch = 0;
28+
private BlockPos miningStartPos; // Fixed mining spot in front of player
29+
private BlockPos currentTunnelPos; // Current position in the tunnel
30+
private int miningDirectionX = 0; // Direction to mine (-1, 0, or 1)
31+
private int miningDirectionZ = 0; // Direction to mine (-1, 0, or 1)
32+
private int ticksSinceLastMine = 0; // Delay between mining blocks
33+
private static final int MAX_TICKS = 24000; // 20 minutes for deep mining
34+
private static final int TORCH_INTERVAL = 100; // Place torch every 5 seconds (100 ticks)
35+
private static final int MIN_LIGHT_LEVEL = 8;
36+
private static final int MINING_DELAY = 10;
37+
private static final int MAX_MINING_RADIUS = 5;
38+
39+
// Ore depth mappings for intelligent mining
40+
private static final Map<String, Integer> ORE_DEPTHS = new HashMap<>() {{
41+
put("iron_ore", 64); // Iron spawns well at Y=64 and below
42+
put("deepslate_iron_ore", -16); // Deep iron
43+
put("coal_ore", 96);
44+
put("copper_ore", 48);
45+
put("gold_ore", 32);
46+
put("deepslate_gold_ore", -16);
47+
put("diamond_ore", -59);
48+
put("deepslate_diamond_ore", -59);
49+
put("redstone_ore", 16);
50+
put("deepslate_redstone_ore", -32);
51+
put("lapis_ore", 0);
52+
put("deepslate_lapis_ore", -16);
53+
put("emerald_ore", 256); // Mountain biomes
54+
}};
55+
56+
public MineBlockAction(SteveEntity steve, Task task) {
57+
super(steve, task);
58+
}
59+
60+
@Override
61+
protected void onStart() {
62+
String blockName = task.getStringParameter("block");
63+
targetQuantity = task.getIntParameter("quantity", 8); // Mine reasonable amount by default
64+
minedCount = 0;
65+
ticksRunning = 0;
66+
ticksSinceLastTorch = 0;
67+
ticksSinceLastMine = 0;
68+
69+
targetBlock = parseBlock(blockName);
70+
71+
if (targetBlock == null || targetBlock == Blocks.AIR) {
72+
result = ActionResult.failure("Invalid block type: " + blockName);
73+
return;
74+
}
75+
76+
net.minecraft.world.entity.player.Player nearestPlayer = findNearestPlayer();
77+
if (nearestPlayer != null) {
78+
net.minecraft.world.phys.Vec3 eyePos = nearestPlayer.getEyePosition(1.0F);
79+
net.minecraft.world.phys.Vec3 lookVec = nearestPlayer.getLookAngle();
80+
81+
double angle = Math.atan2(lookVec.z, lookVec.x) * 180.0 / Math.PI;
82+
angle = (angle + 360) % 360;
83+
84+
if (angle >= 315 || angle < 45) {
85+
miningDirectionX = 1; miningDirectionZ = 0; // East (+X)
86+
} else if (angle >= 45 && angle < 135) {
87+
miningDirectionX = 0; miningDirectionZ = 1; // South (+Z)
88+
} else if (angle >= 135 && angle < 225) {
89+
miningDirectionX = -1; miningDirectionZ = 0; // West (-X)
90+
} else {
91+
miningDirectionX = 0; miningDirectionZ = -1; // North (-Z)
92+
}
93+
94+
net.minecraft.world.phys.Vec3 targetPos = eyePos.add(lookVec.scale(3));
95+
96+
BlockPos lookTarget = new BlockPos(
97+
(int)Math.floor(targetPos.x),
98+
(int)Math.floor(targetPos.y),
99+
(int)Math.floor(targetPos.z)
100+
);
101+
102+
miningStartPos = lookTarget;
103+
for (int y = lookTarget.getY(); y > lookTarget.getY() - 20 && y > -64; y--) {
104+
BlockPos groundCheck = new BlockPos(lookTarget.getX(), y, lookTarget.getZ());
105+
if (steve.level().getBlockState(groundCheck).isSolid()) {
106+
miningStartPos = groundCheck.above(); // Stand on top of solid block
107+
break;
108+
}
109+
}
110+
111+
currentTunnelPos = miningStartPos;
112+
steve.teleportTo(miningStartPos.getX() + 0.5, miningStartPos.getY(), miningStartPos.getZ() + 0.5);
113+
114+
String[] dirNames = {"North", "East", "South", "West"};
115+
int dirIndex = miningDirectionZ == -1 ? 0 : (miningDirectionX == 1 ? 1 : (miningDirectionZ == 1 ? 2 : 3));
116+
SteveMod.LOGGER.info("Steve '{}' mining {} in ONE direction: {}",
117+
steve.getSteveName(), targetBlock.getName().getString(), dirNames[dirIndex]);
118+
} else {
119+
miningStartPos = steve.blockPosition();
120+
currentTunnelPos = miningStartPos;
121+
miningDirectionX = 1; // Default to East
122+
miningDirectionZ = 0;
123+
}
124+
125+
steve.setFlying(true);
126+
127+
equipIronPickaxe();
128+
129+
SteveMod.LOGGER.info("Steve '{}' mining {} - staying at {} [SLOW & VISIBLE]",
130+
steve.getSteveName(), targetBlock.getName().getString(), miningStartPos);
131+
132+
// Look for ore nearby
133+
findNextBlock();
134+
}
135+
136+
@Override
137+
protected void onTick() {
138+
ticksRunning++;
139+
ticksSinceLastTorch++;
140+
ticksSinceLastMine++;
141+
142+
if (ticksRunning > MAX_TICKS) {
143+
steve.setFlying(false);
144+
steve.setItemInHand(InteractionHand.MAIN_HAND, net.minecraft.world.item.ItemStack.EMPTY);
145+
result = ActionResult.failure("Mining timeout - only found " + minedCount + " blocks");
146+
return;
147+
}
148+
149+
if (ticksSinceLastTorch >= TORCH_INTERVAL) {
150+
placeTorchIfDark();
151+
ticksSinceLastTorch = 0;
152+
}
153+
154+
if (ticksSinceLastMine < MINING_DELAY) {
155+
return; // Still waiting
156+
}
157+
158+
if (currentTarget == null) {
159+
findNextBlock();
160+
161+
if (currentTarget == null) {
162+
if (minedCount >= targetQuantity) {
163+
// Found enough ore, mission accomplished
164+
steve.setFlying(false);
165+
steve.setItemInHand(InteractionHand.MAIN_HAND, net.minecraft.world.item.ItemStack.EMPTY);
166+
result = ActionResult.success("Mined " + minedCount + " " + targetBlock.getName().getString());
167+
return;
168+
} else {
169+
mineNearbyBlock();
170+
return;
171+
}
172+
}
173+
}
174+
175+
if (steve.level().getBlockState(currentTarget).getBlock() == targetBlock) {
176+
steve.teleportTo(currentTarget.getX() + 0.5, currentTarget.getY(), currentTarget.getZ() + 0.5);
177+
178+
steve.swing(InteractionHand.MAIN_HAND, true);
179+
180+
steve.level().destroyBlock(currentTarget, true);
181+
minedCount++;
182+
ticksSinceLastMine = 0; // Reset delay timer
183+
184+
SteveMod.LOGGER.info("Steve '{}' moved to ore and mined {} at {} - Total: {}/{}",
185+
steve.getSteveName(), targetBlock.getName().getString(), currentTarget,
186+
minedCount, targetQuantity);
187+
188+
if (minedCount >= targetQuantity) {
189+
steve.setFlying(false);
190+
steve.setItemInHand(InteractionHand.MAIN_HAND, net.minecraft.world.item.ItemStack.EMPTY);
191+
result = ActionResult.success("Mined " + minedCount + " " + targetBlock.getName().getString());
192+
return;
193+
}
194+
195+
currentTarget = null;
196+
} else {
197+
currentTarget = null;
198+
}
199+
}
200+
201+
@Override
202+
protected void onCancel() {
203+
steve.setFlying(false);
204+
steve.getNavigation().stop();
205+
steve.setItemInHand(InteractionHand.MAIN_HAND, net.minecraft.world.item.ItemStack.EMPTY);
206+
}
207+
208+
@Override
209+
public String getDescription() {
210+
return "Mine " + targetQuantity + " " + targetBlock.getName().getString() + " (" + minedCount + " found)";
211+
}
212+
213+
/**
214+
* Check light level and place torch if too dark
215+
*/
216+
private void placeTorchIfDark() {
217+
BlockPos stevePos = steve.blockPosition();
218+
int lightLevel = steve.level().getBrightness(net.minecraft.world.level.LightLayer.BLOCK, stevePos);
219+
220+
if (lightLevel < MIN_LIGHT_LEVEL) {
221+
BlockPos torchPos = findTorchPosition(stevePos);
222+
223+
if (torchPos != null && steve.level().getBlockState(torchPos).isAir()) {
224+
steve.level().setBlock(torchPos, Blocks.TORCH.defaultBlockState(), 3);
225+
SteveMod.LOGGER.info("Steve '{}' placed torch at {} (light level was {})",
226+
steve.getSteveName(), torchPos, lightLevel);
227+
228+
steve.swing(InteractionHand.MAIN_HAND, true);
229+
}
230+
}
231+
}
232+
233+
/**
234+
* Find a good position to place a torch (on floor or wall)
235+
*/
236+
private BlockPos findTorchPosition(BlockPos center) {
237+
BlockPos floorPos = center.below();
238+
if (steve.level().getBlockState(floorPos).isSolid() &&
239+
steve.level().getBlockState(center).isAir()) {
240+
return center;
241+
}
242+
243+
BlockPos[] wallPositions = {
244+
center.north(), center.south(), center.east(), center.west()
245+
};
246+
247+
for (BlockPos wallPos : wallPositions) {
248+
if (steve.level().getBlockState(wallPos).isSolid() &&
249+
steve.level().getBlockState(center).isAir()) {
250+
return center;
251+
}
252+
}
253+
254+
return null;
255+
}
256+
257+
/**
258+
* Mine forward in ONE DIRECTION - creates a straight tunnel!
259+
* Steve progresses forward block by block
260+
*/
261+
private void mineNearbyBlock() {
262+
BlockPos centerPos = currentTunnelPos;
263+
BlockPos abovePos = centerPos.above();
264+
BlockPos belowPos = centerPos.below();
265+
266+
BlockState centerState = steve.level().getBlockState(centerPos);
267+
if (!centerState.isAir() && centerState.getBlock() != Blocks.BEDROCK) {
268+
steve.teleportTo(centerPos.getX() + 0.5, centerPos.getY(), centerPos.getZ() + 0.5);
269+
steve.swing(InteractionHand.MAIN_HAND, true);
270+
steve.level().destroyBlock(centerPos, true);
271+
SteveMod.LOGGER.info("Steve '{}' mining tunnel at {}", steve.getSteveName(), centerPos);
272+
}
273+
274+
BlockState aboveState = steve.level().getBlockState(abovePos);
275+
if (!aboveState.isAir() && aboveState.getBlock() != Blocks.BEDROCK) {
276+
steve.swing(InteractionHand.MAIN_HAND, true);
277+
steve.level().destroyBlock(abovePos, true);
278+
}
279+
280+
BlockState belowState = steve.level().getBlockState(belowPos);
281+
if (!belowState.isAir() && belowState.getBlock() != Blocks.BEDROCK) {
282+
steve.swing(InteractionHand.MAIN_HAND, true);
283+
steve.level().destroyBlock(belowPos, true);
284+
}
285+
286+
currentTunnelPos = currentTunnelPos.offset(miningDirectionX, 0, miningDirectionZ);
287+
288+
ticksSinceLastMine = 0; // Reset delay
289+
}
290+
291+
/**
292+
* Find ore blocks in the tunnel ahead
293+
* Searches forward in the mining direction
294+
*/
295+
private void findNextBlock() {
296+
List<BlockPos> foundBlocks = new ArrayList<>();
297+
298+
for (int distance = 0; distance < 20; distance++) {
299+
BlockPos checkPos = currentTunnelPos.offset(miningDirectionX * distance, 0, miningDirectionZ * distance);
300+
301+
for (int y = -1; y <= 1; y++) {
302+
BlockPos orePos = checkPos.offset(0, y, 0);
303+
if (steve.level().getBlockState(orePos).getBlock() == targetBlock) {
304+
foundBlocks.add(orePos);
305+
}
306+
}
307+
}
308+
309+
if (!foundBlocks.isEmpty()) {
310+
currentTarget = foundBlocks.stream()
311+
.min((a, b) -> Double.compare(a.distSqr(currentTunnelPos), b.distSqr(currentTunnelPos)))
312+
.orElse(null);
313+
314+
if (currentTarget != null) {
315+
SteveMod.LOGGER.info("Steve '{}' found {} ahead in tunnel at {}",
316+
steve.getSteveName(), targetBlock.getName().getString(), currentTarget);
317+
}
318+
}
319+
}
320+
321+
/**
322+
* Equip an iron pickaxe for mining
323+
*/
324+
private void equipIronPickaxe() {
325+
// Give Steve an iron pickaxe if he doesn't have one
326+
net.minecraft.world.item.ItemStack pickaxe = new net.minecraft.world.item.ItemStack(
327+
net.minecraft.world.item.Items.IRON_PICKAXE
328+
);
329+
steve.setItemInHand(net.minecraft.world.InteractionHand.MAIN_HAND, pickaxe);
330+
SteveMod.LOGGER.info("Steve '{}' equipped iron pickaxe for mining", steve.getSteveName());
331+
}
332+
333+
/**
334+
* Find the nearest player to determine mining direction
335+
*/
336+
private net.minecraft.world.entity.player.Player findNearestPlayer() {
337+
java.util.List<? extends net.minecraft.world.entity.player.Player> players = steve.level().players();
338+
339+
if (players.isEmpty()) {
340+
return null;
341+
}
342+
343+
net.minecraft.world.entity.player.Player nearest = null;
344+
double nearestDistance = Double.MAX_VALUE;
345+
346+
for (net.minecraft.world.entity.player.Player player : players) {
347+
if (!player.isAlive() || player.isRemoved() || player.isSpectator()) {
348+
continue;
349+
}
350+
351+
double distance = steve.distanceTo(player);
352+
if (distance < nearestDistance) {
353+
nearestDistance = distance;
354+
nearest = player;
355+
}
356+
}
357+
358+
return nearest;
359+
}
360+
361+
private Block parseBlock(String blockName) {
362+
blockName = blockName.toLowerCase().replace(" ", "_");
363+
364+
Map<String, String> resourceToOre = new HashMap<>() {{
365+
put("iron", "iron_ore");
366+
put("diamond", "diamond_ore");
367+
put("coal", "coal_ore");
368+
put("gold", "gold_ore");
369+
put("copper", "copper_ore");
370+
put("redstone", "redstone_ore");
371+
put("lapis", "lapis_ore");
372+
put("emerald", "emerald_ore");
373+
}};
374+
375+
if (resourceToOre.containsKey(blockName)) {
376+
blockName = resourceToOre.get(blockName);
377+
}
378+
379+
if (!blockName.contains(":")) {
380+
blockName = "minecraft:" + blockName;
381+
}
382+
383+
ResourceLocation resourceLocation = new ResourceLocation(blockName);
384+
return BuiltInRegistries.BLOCK.get(resourceLocation);
385+
}
386+
}
387+

0 commit comments

Comments
 (0)