Skip to content
Open
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
109 changes: 109 additions & 0 deletions src/agent/modes.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,72 @@ const modes_list = [
}
}
},
{
name: 'fall_protection',
description: 'Use water bucket to break a long fall (MLG water). Requires a water bucket in inventory.',
interrupts: ['all'],
on: true,
active: false,
fallStartY: null,
update: async function (agent) {
const bot = agent.bot;
const pos = bot.entity.position;
const vel = bot.entity.velocity;

// Detect if falling (negative Y velocity)
if (vel.y < -0.5) {
if (this.fallStartY === null) {
this.fallStartY = pos.y;
}

const fallDistance = this.fallStartY - pos.y;

// If falling more than 10 blocks and still accelerating, try MLG water
if (fallDistance > 10 && vel.y < -0.5) {
const waterBucket = bot.inventory.items().find(item => item.name === 'water_bucket');
if (waterBucket && !this.active) {
// Check if ground is near (within 4 blocks below)
const groundBlock = bot.blockAt(pos.offset(0, -4, 0));
if (groundBlock && groundBlock.name !== 'air' && groundBlock.name !== 'water') {
execute(this, agent, async () => {
const currentPos = bot.entity.position.clone();
say(agent, 'MLG water!');
try {
await bot.equip(waterBucket, 'hand');
await bot.lookAt(currentPos.offset(0, -3, 0));
bot.activateItem();
// Wait until the bot has actually landed
await new Promise(resolve => {
const start = Date.now();
const checkLanding = () => {
if (bot.entity.onGround || bot.entity.velocity.y >= 0) {
return resolve();
}
if (Date.now() - start > 2000) {
return resolve();
}
setTimeout(checkLanding, 50);
};
checkLanding();
});
// Pick up water after landing
const waterBlock = world.getNearestBlock(bot, 'water', 3);
if (waterBlock) {
await bot.lookAt(waterBlock.position);
bot.activateItem();
}
} catch (e) {
console.log('[FALL_PROTECTION] Error:', e.message);
}
});
}
}
}
} else {
this.fallStartY = null;
}
}
},
{
name: 'unstuck',
description: 'Attempt to get unstuck when in the same place for a while. Interrupts some actions.',
Expand Down Expand Up @@ -169,6 +235,49 @@ const modes_list = [
}
}
},
{
name: 'auto_sleep',
description: 'Automatically sleep in a nearby bed when night falls to skip the night and avoid monsters.',
interrupts: ['action:followPlayer'],
on: true,
active: false,
lastSleepCheck: 0,
update: async function (agent) {
const bot = agent.bot;

// Only check every 30 seconds to avoid spamming
if (Date.now() - this.lastSleepCheck < 30000) return;
this.lastSleepCheck = Date.now();

// Check if it's nighttime (time >= 13000 ticks) and we're not already sleeping
const time = bot.time.timeOfDay;
const isNight = time >= 13000;
if (!isNight || bot.isSleeping) return;

// Look for a bed within 32 blocks using block name matching (beds are named like 'white_bed', 'red_bed', etc.)
const beds = bot.findBlocks({
matching: (block) => block.name.includes('bed'),
maxDistance: 32,
count: 1
});
if (beds.length > 0) {
execute(this, agent, async () => {
say(agent, 'It\'s getting dark, I should sleep.');
try {
await skills.goToBed(bot);
} catch (e) {
if (e && e.message && e.message.includes('occupied')) {
say(agent, 'The bed is occupied.');
} else {
const errorMessage = e && e.message ? e.message : 'unknown reason';
console.log('[AUTO_SLEEP] Error:', errorMessage);
say(agent, `I couldn't sleep (${errorMessage}).`);
}
}
});
}
Comment on lines 257 to 278
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bed finding logic here duplicates the same search that skills.goToBed() performs (see skills.js lines 1551-1557). This means the bed search happens twice: once here to check if a bed exists, and again inside skills.goToBed(). Consider removing the bed search here and letting skills.goToBed() handle it, or check the return value from skills.goToBed() to determine if a bed was found.

Suggested change
// Look for a bed within 32 blocks using block name matching (beds are named like 'white_bed', 'red_bed', etc.)
const beds = bot.findBlocks({
matching: (block) => block.name.includes('bed'),
maxDistance: 32,
count: 1
});
if (beds.length > 0) {
execute(this, agent, async () => {
say(agent, 'It\'s getting dark, I should sleep.');
try {
await skills.goToBed(bot);
} catch (e) {
if (e.message && e.message.includes('occupied')) {
say(agent, 'The bed is occupied.');
}
}
});
}
// Let skills.goToBed handle finding a suitable bed
execute(this, agent, async () => {
try {
await skills.goToBed(bot);
say(agent, 'It\'s getting dark, I should sleep.');
} catch (e) {
if (e && e.message && e.message.includes('occupied')) {
say(agent, 'The bed is occupied.');
}
}
});

Copilot uses AI. Check for mistakes.
}
},
{
name: 'hunting',
description: 'Hunt nearby animals when idle.',
Expand Down