mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-08-25 16:43:45 +02:00
commit
d0b3fbd3f5
12 changed files with 420 additions and 36 deletions
|
@ -1,8 +1,35 @@
|
|||
diff --git a/node_modules/mineflayer-pathfinder/index.js b/node_modules/mineflayer-pathfinder/index.js
|
||||
index b38bd30..bf16a63 100644
|
||||
index b38bd30..fb39b45 100644
|
||||
--- a/node_modules/mineflayer-pathfinder/index.js
|
||||
+++ b/node_modules/mineflayer-pathfinder/index.js
|
||||
@@ -550,6 +550,7 @@ function inject (bot) {
|
||||
@@ -170,6 +170,16 @@ function inject (bot) {
|
||||
const curPoint = path[i]
|
||||
if (curPoint.toBreak.length > 0 || curPoint.toPlace.length > 0) break
|
||||
const b = bot.blockAt(new Vec3(curPoint.x, curPoint.y, curPoint.z))
|
||||
+
|
||||
+ // openned doors have small Collision box
|
||||
+ // that may stop the bot from moving forward
|
||||
+ if(i === 0 && b.name.includes('door')) {
|
||||
+ curPoint.x = Math.floor(curPoint.x) + 0.5
|
||||
+ curPoint.y = Math.floor(curPoint.y)
|
||||
+ curPoint.z = Math.floor(curPoint.z) + 0.5
|
||||
+ continue
|
||||
+ }
|
||||
+
|
||||
if (b && (b.type === waterType || ((b.type === ladderId || b.type === vineId) && i + 1 < path.length && path[i + 1].y < curPoint.y))) {
|
||||
curPoint.x = Math.floor(curPoint.x) + 0.5
|
||||
curPoint.y = Math.floor(curPoint.y)
|
||||
@@ -524,6 +534,9 @@ function inject (bot) {
|
||||
bot.activateBlock(bot.blockAt(new Vec3(placingBlock.x, placingBlock.y, placingBlock.z))).then(() => {
|
||||
lockUseBlock.release()
|
||||
placingBlock = nextPoint.toPlace.shift()
|
||||
+ if (!placingBlock) {
|
||||
+ placing = false
|
||||
+ }
|
||||
}, err => {
|
||||
console.error(err)
|
||||
lockUseBlock.release()
|
||||
@@ -550,6 +563,7 @@ function inject (bot) {
|
||||
lockEquipItem.release()
|
||||
const refBlock = bot.blockAt(new Vec3(placingBlock.x, placingBlock.y, placingBlock.z), false)
|
||||
if (!lockPlaceBlock.tryAcquire()) return
|
||||
|
@ -10,7 +37,7 @@ index b38bd30..bf16a63 100644
|
|||
if (interactableBlocks.includes(refBlock.name)) {
|
||||
bot.setControlState('sneak', true)
|
||||
}
|
||||
@@ -557,6 +558,7 @@ function inject (bot) {
|
||||
@@ -557,6 +571,7 @@ function inject (bot) {
|
||||
.then(function () {
|
||||
// Dont release Sneak if the block placement was not successful
|
||||
bot.setControlState('sneak', false)
|
||||
|
@ -18,3 +45,152 @@ index b38bd30..bf16a63 100644
|
|||
if (bot.pathfinder.LOSWhenPlacingBlocks && placingBlock.returnPos) returningPos = placingBlock.returnPos.clone()
|
||||
})
|
||||
.catch(_ignoreError => {
|
||||
diff --git a/node_modules/mineflayer-pathfinder/lib/movements.js b/node_modules/mineflayer-pathfinder/lib/movements.js
|
||||
index a7e3505..3c4a8f2 100644
|
||||
--- a/node_modules/mineflayer-pathfinder/lib/movements.js
|
||||
+++ b/node_modules/mineflayer-pathfinder/lib/movements.js
|
||||
@@ -62,7 +62,13 @@
|
||||
|
||||
this.climbables = new Set()
|
||||
this.climbables.add(registry.blocksByName.ladder.id)
|
||||
- // this.climbables.add(registry.blocksByName.vine.id)
|
||||
+ if (registry.blocksByName.vine) this.climbables.add(registry.blocksByName.vine.id)
|
||||
+ if (registry.blocksByName.weeping_vines) this.climbables.add(registry.blocksByName.weeping_vines.id)
|
||||
+ if (registry.blocksByName.weeping_vines_plant) this.climbables.add(registry.blocksByName.weeping_vines_plant.id)
|
||||
+ if (registry.blocksByName.twisting_vines) this.climbables.add(registry.blocksByName.twisting_vines.id)
|
||||
+ if (registry.blocksByName.twisting_vines_plant) this.climbables.add(registry.blocksByName.twisting_vines_plant.id)
|
||||
+ if (registry.blocksByName.cave_vines) this.climbables.add(registry.blocksByName.cave_vines.id)
|
||||
+ if (registry.blocksByName.cave_vines_plant) this.climbables.add(registry.blocksByName.cave_vines_plant.id)
|
||||
this.emptyBlocks = new Set()
|
||||
|
||||
this.replaceables = new Set()
|
||||
@@ -92,13 +98,15 @@
|
||||
}
|
||||
})
|
||||
registry.blocksArray.forEach(block => {
|
||||
- if (this.interactableBlocks.has(block.name) && block.name.toLowerCase().includes('gate') && !block.name.toLowerCase().includes('iron')) {
|
||||
+ if (this.interactableBlocks.has(block.name)
|
||||
+ && (block.name.toLowerCase().includes('gate') || block.name.toLowerCase().includes('door') || block.name.toLowerCase().includes('trapdoor'))
|
||||
+ && !block.name.toLowerCase().includes('iron')) {
|
||||
// console.info(block)
|
||||
this.openable.add(block.id)
|
||||
}
|
||||
})
|
||||
|
||||
- this.canOpenDoors = false // Causes issues. Probably due to none paper servers.
|
||||
+ this.canOpenDoors = true
|
||||
|
||||
this.exclusionAreasStep = []
|
||||
this.exclusionAreasBreak = []
|
||||
@@ -230,8 +238,13 @@
|
||||
}
|
||||
}
|
||||
b.climbable = this.climbables.has(b.type)
|
||||
- b.safe = (b.boundingBox === 'empty' || b.climbable || this.carpets.has(b.type)) && !this.blocksToAvoid.has(b.type)
|
||||
- b.physical = b.boundingBox === 'block' && !this.fences.has(b.type)
|
||||
+
|
||||
+ // Enhanced trapdoor logic - open trapdoors are safe to pass through
|
||||
+ const isOpenTrapdoor = this.openable.has(b.type) && b.name.includes('trapdoor') && b._properties?.open === true
|
||||
+ const isClosedTrapdoor = this.openable.has(b.type) && b.name.includes('trapdoor') && b._properties?.open !== true
|
||||
+
|
||||
+ b.safe = (b.boundingBox === 'empty' || b.climbable || this.carpets.has(b.type) || isOpenTrapdoor) && !this.blocksToAvoid.has(b.type)
|
||||
+ b.physical = (b.boundingBox === 'block' && !this.fences.has(b.type)) || isClosedTrapdoor
|
||||
b.replaceable = this.replaceables.has(b.type) && !b.physical
|
||||
b.liquid = this.liquids.has(b.type)
|
||||
b.height = pos.y + dy
|
||||
@@ -284,6 +297,18 @@
|
||||
cost += this.exclusionStep(block) // Is excluded so can't move or break
|
||||
cost += this.getNumEntitiesAt(block.position, 0, 0, 0) * this.entityCost
|
||||
if (block.safe) return cost
|
||||
+
|
||||
+ // process door cost
|
||||
+ if ((this.canOpenDoors && block.openable)
|
||||
+ || (block.openable && block._properties?.open === true)) {
|
||||
+ return cost
|
||||
+ }
|
||||
+
|
||||
+ // Handle trapdoors specifically - they can be opened instead of broken
|
||||
+ if (this.canOpenDoors && block.openable && block.name.includes('trapdoor') && !block.name.includes('iron')) {
|
||||
+ return cost + 1 // Small cost for opening trapdoor
|
||||
+ }
|
||||
+
|
||||
if (!this.safeToBreak(block)) return 100 // Can't break, so can't move
|
||||
toBreak.push(block.position)
|
||||
|
||||
@@ -387,8 +412,8 @@
|
||||
cost += this.safeOrBreak(blockB, toBreak)
|
||||
if (cost > 100) return
|
||||
|
||||
- // Open fence gates
|
||||
- if (this.canOpenDoors && blockC.openable && blockC.shapes && blockC.shapes.length !== 0) {
|
||||
+ // Open fence gates and doors
|
||||
+ if (this.canOpenDoors && blockC.openable && !blockC._properties.open) {
|
||||
toPlace.push({ x: node.x + dir.x, y: node.y, z: node.z + dir.z, dx: 0, dy: 0, dz: 0, useOne: true }) // Indicate that a block should be used on this block not placed
|
||||
} else {
|
||||
cost += this.safeOrBreak(blockC, toBreak)
|
||||
@@ -552,6 +577,54 @@
|
||||
if (cost > 100) return
|
||||
|
||||
neighbors.push(new Move(node.x, node.y + 1, node.z, node.remainingBlocks - toPlace.length, cost, toBreak, toPlace))
|
||||
+ }
|
||||
+
|
||||
+ getMoveClimbUpThroughTrapdoor (node, neighbors) {
|
||||
+ const blockCurrent = this.getBlock(node, 0, 0, 0) // Current position (should be climbable)
|
||||
+ const blockAbove = this.getBlock(node, 0, 1, 0) // Block directly above
|
||||
+ const blockCeiling = this.getBlock(node, 0, 2, 0) // Trapdoor or ceiling block
|
||||
+
|
||||
+ // Only attempt this move if we're on a climbable block (ladder/vine)
|
||||
+ if (!blockCurrent.climbable) return
|
||||
+
|
||||
+ // Check if there's a closed trapdoor above us
|
||||
+ if (!blockCeiling.openable || blockCeiling._properties?.open === true) return
|
||||
+
|
||||
+ let cost = 2 // Base cost for climbing up and opening trapdoor
|
||||
+ const toBreak = []
|
||||
+ const toPlace = []
|
||||
+
|
||||
+ // Make sure we can break/pass through the block above if needed
|
||||
+ cost += this.safeOrBreak(blockAbove, toBreak)
|
||||
+ if (cost > 100) return
|
||||
+
|
||||
+ // Add cost for opening the trapdoor
|
||||
+ toPlace.push({ x: node.x, y: node.y + 2, z: node.z, dx: 0, dy: 0, dz: 0, useOne: true })
|
||||
+
|
||||
+ neighbors.push(new Move(node.x, node.y + 2, node.z, node.remainingBlocks - toPlace.length, cost, toBreak, toPlace))
|
||||
+ }
|
||||
+
|
||||
+ // Enhanced ladder/vine climbing that can handle stepping on top and jumping
|
||||
+ getMoveClimbTop (node, neighbors) {
|
||||
+ const blockCurrent = this.getBlock(node, 0, 0, 0) // Current position (should be climbable)
|
||||
+ const blockAbove = this.getBlock(node, 0, 1, 0) // Block directly above
|
||||
+
|
||||
+ // Only attempt this move if we're on a climbable block (ladder/vine)
|
||||
+ if (!blockCurrent.climbable) return
|
||||
+
|
||||
+ // Check if we can step on top of the ladder/vine and then jump up
|
||||
+ if (!blockAbove.safe) return
|
||||
+
|
||||
+ let cost = 2 // Cost for climbing to top of ladder and jumping
|
||||
+ const toBreak = []
|
||||
+ const toPlace = []
|
||||
+
|
||||
+ // Check if there's space to jump up from the top of the ladder
|
||||
+ const blockJumpTarget = this.getBlock(node, 0, 2, 0)
|
||||
+ cost += this.safeOrBreak(blockJumpTarget, toBreak)
|
||||
+ if (cost > 100) return
|
||||
+
|
||||
+ neighbors.push(new Move(node.x, node.y + 2, node.z, node.remainingBlocks - toPlace.length, cost, toBreak, toPlace))
|
||||
}
|
||||
|
||||
// Jump up, down or forward over a 1 block gap
|
||||
@@ -655,6 +728,10 @@
|
||||
|
||||
this.getMoveDown(node, neighbors)
|
||||
this.getMoveUp(node, neighbors)
|
||||
+
|
||||
+ // Enhanced climbing moves for ladders, vines, and trapdoors
|
||||
+ this.getMoveClimbUpThroughTrapdoor(node, neighbors)
|
||||
+ this.getMoveClimbTop(node, neighbors)
|
||||
|
||||
return neighbors
|
||||
}
|
13
patches/prismarine-item+1.17.0.patch
Normal file
13
patches/prismarine-item+1.17.0.patch
Normal file
|
@ -0,0 +1,13 @@
|
|||
diff --git a/node_modules/prismarine-item/index.js b/node_modules/prismarine-item/index.js
|
||||
index a1397a2..1d75cad 100644
|
||||
--- a/node_modules/prismarine-item/index.js
|
||||
+++ b/node_modules/prismarine-item/index.js
|
||||
@@ -231,7 +231,7 @@ function loader (registryOrVersion) {
|
||||
const typeOfEnchantLevelValue = registry.supportFeature('typeOfValueForEnchantLevel')
|
||||
const useStoredEnchantments = registry.supportFeature('booksUseStoredEnchantments') && this.name === 'enchanted_book'
|
||||
|
||||
- if (typeOfEnchantLevelValue === 'short' && enchantNbtKey === 'ench') {
|
||||
+ if (typeOfEnchantLevelValue === 'short' && (enchantNbtKey === 'ench' || enchantNbtKey === 'componentEnchantments')) {
|
||||
let itemEnch = []
|
||||
|
||||
if (useStoredEnchantments && this?.nbt?.value?.StoredEnchantments) {
|
14
profiles/defaults/assistant.json
Normal file
14
profiles/defaults/assistant.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"modes": {
|
||||
"self_preservation": true,
|
||||
"unstuck": true,
|
||||
"cowardice": false,
|
||||
"self_defense": true,
|
||||
"hunting": false,
|
||||
"item_collecting": true,
|
||||
"torch_placing": true,
|
||||
"elbow_room": true,
|
||||
"idle_staring": true,
|
||||
"cheat": false
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ const settings = {
|
|||
// the mindserver manages all agents and hosts the UI
|
||||
"mindserver_port": 8080,
|
||||
|
||||
"base_profile": "survival", // survival, creative, or god_mode
|
||||
"base_profile": "survival", // survival, creative, assistant, or god_mode
|
||||
"profiles": [
|
||||
"./andy.json",
|
||||
// "./profiles/gpt.json",
|
||||
|
@ -42,6 +42,9 @@ const settings = {
|
|||
"verbose_commands": true, // show full command syntax
|
||||
"narrate_behavior": true, // chat simple automatic actions ('Picking up item!')
|
||||
"chat_bot_messages": true, // publicly chat messages to other bots
|
||||
|
||||
"block_place_delay": 0, // delay between placing blocks (ms) if using newAction. helps avoid bot being kicked by anti-cheat mechanisms on servers.
|
||||
|
||||
"log_all_prompts": false, // log ALL prompts to file
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ export class ActionManager {
|
|||
this.timedout = false;
|
||||
this.resume_func = null;
|
||||
this.resume_name = '';
|
||||
this.last_action_time = 0;
|
||||
this.recent_action_counter = 0;
|
||||
}
|
||||
|
||||
async resumeAction(actionFn, timeout) {
|
||||
|
@ -59,6 +61,25 @@ export class ActionManager {
|
|||
async _executeAction(actionLabel, actionFn, timeout = 10) {
|
||||
let TIMEOUT;
|
||||
try {
|
||||
if (this.last_action_time > 0) {
|
||||
let time_diff = Date.now() - this.last_action_time;
|
||||
if (time_diff < 20) {
|
||||
this.recent_action_counter++;
|
||||
}
|
||||
else {
|
||||
this.recent_action_counter = 0;
|
||||
}
|
||||
if (this.recent_action_counter > 2) {
|
||||
console.warn('Fast action loop detected, cancelling resume.');
|
||||
this.cancelResume(); // likely cause of repetition
|
||||
}
|
||||
if (this.recent_action_counter > 5) {
|
||||
console.error('Infinite action loop detected, shutting down.');
|
||||
this.agent.cleanKill('Infinite action loop detected, shutting down.');
|
||||
return { success: false, message: 'Infinite action loop detected, shutting down.', interrupted: false, timedout: false };
|
||||
}
|
||||
}
|
||||
this.last_action_time = Date.now();
|
||||
console.log('executing code...\n');
|
||||
|
||||
// await current action to finish (executing=false), with 10 seconds timeout
|
||||
|
|
|
@ -118,6 +118,7 @@ export class Agent {
|
|||
];
|
||||
|
||||
const respondFunc = async (username, message) => {
|
||||
if (message === "") return;
|
||||
if (username === this.name) return;
|
||||
if (settings.only_chat_with.length > 0 && !settings.only_chat_with.includes(username)) return;
|
||||
try {
|
||||
|
@ -438,7 +439,11 @@ export class Agent {
|
|||
this.bot.clearControlStates();
|
||||
this.bot.pathfinder.stop(); // clear any lingering pathfinder
|
||||
this.bot.modes.unPauseAll();
|
||||
this.actions.resumeAction();
|
||||
setTimeout(() => {
|
||||
if (this.isIdle()) {
|
||||
this.actions.resumeAction();
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// Init NPC controller
|
||||
|
|
|
@ -2,7 +2,10 @@ import * as mc from "../../utils/mcdata.js";
|
|||
import * as world from "./world.js";
|
||||
import pf from 'mineflayer-pathfinder';
|
||||
import Vec3 from 'vec3';
|
||||
import settings from "../../../settings.js";
|
||||
|
||||
const blockPlaceDelay = settings.block_place_delay == null ? 0 : settings.block_place_delay;
|
||||
const useDelay = blockPlaceDelay > 0;
|
||||
|
||||
export function log(bot, message) {
|
||||
bot.output += message + '\n';
|
||||
|
@ -503,7 +506,7 @@ export async function pickupNearbyItems(bot) {
|
|||
let pickedUp = 0;
|
||||
while (nearestItem) {
|
||||
bot.pathfinder.setMovements(new pf.Movements(bot));
|
||||
await bot.pathfinder.goto(new pf.goals.GoalFollow(nearestItem, 0.8), true);
|
||||
await goToGoal(bot, new pf.goals.GoalFollow(nearestItem, 0.8));
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
let prev = nearestItem;
|
||||
nearestItem = getNearestItem(bot);
|
||||
|
@ -533,6 +536,7 @@ export async function breakBlockAt(bot, x, y, z) {
|
|||
let block = bot.blockAt(Vec3(x, y, z));
|
||||
if (block.name !== 'air' && block.name !== 'water' && block.name !== 'lava') {
|
||||
if (bot.modes.isOn('cheat')) {
|
||||
if (useDelay) { await new Promise(resolve => setTimeout(resolve, blockPlaceDelay)); }
|
||||
let msg = '/setblock ' + Math.floor(x) + ' ' + Math.floor(y) + ' ' + Math.floor(z) + ' air';
|
||||
bot.chat(msg);
|
||||
log(bot, `Used /setblock to break block at ${x}, ${y}, ${z}.`);
|
||||
|
@ -545,7 +549,7 @@ export async function breakBlockAt(bot, x, y, z) {
|
|||
movements.canPlaceOn = false;
|
||||
movements.allow1by1towers = false;
|
||||
bot.pathfinder.setMovements(movements);
|
||||
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
|
||||
await goToGoal(bot, new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
|
||||
}
|
||||
if (bot.game.gameMode !== 'creative') {
|
||||
await bot.tool.equipForBlock(block);
|
||||
|
@ -629,11 +633,14 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont
|
|||
if (blockType.includes('stairs')) {
|
||||
blockType += `[facing=${face}]`;
|
||||
}
|
||||
if (useDelay) { await new Promise(resolve => setTimeout(resolve, blockPlaceDelay)); }
|
||||
let msg = '/setblock ' + Math.floor(x) + ' ' + Math.floor(y) + ' ' + Math.floor(z) + ' ' + blockType;
|
||||
bot.chat(msg);
|
||||
if (blockType.includes('door'))
|
||||
if (useDelay) { await new Promise(resolve => setTimeout(resolve, blockPlaceDelay)); }
|
||||
bot.chat('/setblock ' + Math.floor(x) + ' ' + Math.floor(y+1) + ' ' + Math.floor(z) + ' ' + blockType + '[half=upper]');
|
||||
if (blockType.includes('bed'))
|
||||
if (useDelay) { await new Promise(resolve => setTimeout(resolve, blockPlaceDelay)); }
|
||||
bot.chat('/setblock ' + Math.floor(x) + ' ' + Math.floor(y) + ' ' + Math.floor(z-1) + ' ' + blockType + '[part=head]');
|
||||
log(bot, `Used /setblock to place ${blockType} at ${target_dest}.`);
|
||||
return true;
|
||||
|
@ -720,7 +727,7 @@ export async function placeBlock(bot, blockType, x, y, z, placeOn='bottom', dont
|
|||
let pos = targetBlock.position;
|
||||
let movements = new pf.Movements(bot);
|
||||
bot.pathfinder.setMovements(movements);
|
||||
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
|
||||
await goToGoal(bot, new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
|
||||
}
|
||||
|
||||
await bot.equip(block, 'hand');
|
||||
|
@ -945,6 +952,10 @@ export async function giveToPlayer(bot, itemType, username, num=1) {
|
|||
* @example
|
||||
* await skills.giveToPlayer(bot, "oak_log", "player1");
|
||||
**/
|
||||
if (bot.username === username) {
|
||||
log(bot, `You cannot give items to yourself.`);
|
||||
return false;
|
||||
}
|
||||
let player = bot.players[username].entity
|
||||
if (!player) {
|
||||
log(bot, `Could not find ${username}.`);
|
||||
|
@ -1002,6 +1013,115 @@ export async function giveToPlayer(bot, itemType, username, num=1) {
|
|||
return false;
|
||||
}
|
||||
|
||||
export async function goToGoal(bot, goal) {
|
||||
/**
|
||||
* Navigate to the given goal. Use doors and attempt minimally destructive movements.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @param {pf.goals.Goal} goal, the goal to navigate to.
|
||||
**/
|
||||
|
||||
const nonDestructiveMovements = new pf.Movements(bot);
|
||||
const dontBreakBlocks = ['glass', 'glass_pane'];
|
||||
for (let block of dontBreakBlocks) {
|
||||
nonDestructiveMovements.blocksCantBreak.add(mc.getBlockId(block));
|
||||
}
|
||||
nonDestructiveMovements.digCost = 10;
|
||||
|
||||
const destructiveMovements = new pf.Movements(bot);
|
||||
|
||||
let final_movements = destructiveMovements;
|
||||
|
||||
const pathfind_timeout = 1000;
|
||||
if (await bot.pathfinder.getPathTo(nonDestructiveMovements, goal, pathfind_timeout).status === 'success') {
|
||||
final_movements = nonDestructiveMovements;
|
||||
log(bot, `Found non-destructive path.`);
|
||||
}
|
||||
else if (await bot.pathfinder.getPathTo(destructiveMovements, goal, pathfind_timeout).status === 'success') {
|
||||
log(bot, `Found destructive path.`);
|
||||
}
|
||||
else {
|
||||
log(bot, `Could not find a path to goal, attempting to navigate anyway using destructive movements.`);
|
||||
}
|
||||
|
||||
const doorCheckInterval = startDoorInterval(bot);
|
||||
|
||||
bot.pathfinder.setMovements(final_movements);
|
||||
try {
|
||||
await bot.pathfinder.goto(goal);
|
||||
clearInterval(doorCheckInterval);
|
||||
return true;
|
||||
} catch (err) {
|
||||
clearInterval(doorCheckInterval);
|
||||
// we need to catch so we can clean up the door check interval, then rethrow the error
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
let _doorInterval = null;
|
||||
function startDoorInterval(bot) {
|
||||
/**
|
||||
* Start helper interval that opens nearby doors if the bot is stuck.
|
||||
* @param {MinecraftBot} bot, reference to the minecraft bot.
|
||||
* @returns {number} the interval id.
|
||||
**/
|
||||
if (_doorInterval) {
|
||||
clearInterval(_doorInterval);
|
||||
}
|
||||
let prev_pos = bot.entity.position.clone();
|
||||
let prev_check = Date.now();
|
||||
let stuck_time = 0;
|
||||
|
||||
|
||||
const doorCheckInterval = setInterval(() => {
|
||||
const now = Date.now();
|
||||
if (bot.entity.position.distanceTo(prev_pos) >= 0.1) {
|
||||
stuck_time = 0;
|
||||
} else {
|
||||
stuck_time += now - prev_check;
|
||||
}
|
||||
|
||||
if (stuck_time > 1200) {
|
||||
// shuffle positions so we're not always opening the same door
|
||||
const positions = [
|
||||
bot.entity.position.clone(),
|
||||
bot.entity.position.offset(0, 0, 1),
|
||||
bot.entity.position.offset(0, 0, -1),
|
||||
bot.entity.position.offset(1, 0, 0),
|
||||
bot.entity.position.offset(-1, 0, 0),
|
||||
]
|
||||
let elevated_positions = positions.map(position => position.offset(0, 1, 0));
|
||||
positions.push(...elevated_positions);
|
||||
positions.push(bot.entity.position.offset(0, 2, 0)); // above head
|
||||
positions.push(bot.entity.position.offset(0, -1, 0)); // below feet
|
||||
|
||||
let currentIndex = positions.length;
|
||||
while (currentIndex != 0) {
|
||||
let randomIndex = Math.floor(Math.random() * currentIndex);
|
||||
currentIndex--;
|
||||
[positions[currentIndex], positions[randomIndex]] = [
|
||||
positions[randomIndex], positions[currentIndex]];
|
||||
}
|
||||
|
||||
for (let position of positions) {
|
||||
let block = bot.blockAt(position);
|
||||
if (block && block.name &&
|
||||
!block.name.includes('iron') &&
|
||||
(block.name.includes('door') ||
|
||||
block.name.includes('fence_gate') ||
|
||||
block.name.includes('trapdoor')))
|
||||
{
|
||||
bot.activateBlock(block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
stuck_time = 0;
|
||||
}
|
||||
prev_pos = bot.entity.position.clone();
|
||||
prev_check = now;
|
||||
}, 200);
|
||||
_doorInterval = doorCheckInterval;
|
||||
return doorCheckInterval;
|
||||
}
|
||||
|
||||
export async function goToPosition(bot, x, y, z, min_distance=2) {
|
||||
/**
|
||||
|
@ -1026,10 +1146,7 @@ export async function goToPosition(bot, x, y, z, min_distance=2) {
|
|||
return true;
|
||||
}
|
||||
|
||||
const movements = new pf.Movements(bot);
|
||||
bot.pathfinder.setMovements(movements);
|
||||
|
||||
const checkProgress = () => {
|
||||
const checkDigProgress = () => {
|
||||
if (bot.targetDigBlock) {
|
||||
const targetBlock = bot.targetDigBlock;
|
||||
const itemId = bot.heldItem ? bot.heldItem.type : null;
|
||||
|
@ -1041,17 +1158,24 @@ export async function goToPosition(bot, x, y, z, min_distance=2) {
|
|||
}
|
||||
};
|
||||
|
||||
const progressInterval = setInterval(checkProgress, 1000);
|
||||
const progressInterval = setInterval(checkDigProgress, 1000);
|
||||
|
||||
try {
|
||||
await bot.pathfinder.goto(new pf.goals.GoalNear(x, y, z, min_distance));
|
||||
log(bot, `You have reached at ${x}, ${y}, ${z}.`);
|
||||
return true;
|
||||
await goToGoal(bot, new pf.goals.GoalNear(x, y, z, min_distance));
|
||||
clearInterval(progressInterval);
|
||||
const distance = bot.entity.position.distanceTo(new Vec3(x, y, z));
|
||||
if (distance <= min_distance+1) {
|
||||
log(bot, `You have reached at ${x}, ${y}, ${z}.`);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
log(bot, `Unable to reach ${x}, ${y}, ${z}, you are ${Math.round(distance)} blocks away.`);
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
log(bot, `Pathfinding stopped: ${err.message}.`);
|
||||
return false;
|
||||
} finally {
|
||||
clearInterval(progressInterval);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1112,7 +1236,10 @@ export async function goToPlayer(bot, username, distance=3) {
|
|||
* @example
|
||||
* await skills.goToPlayer(bot, "player");
|
||||
**/
|
||||
|
||||
if (bot.username === username) {
|
||||
log(bot, `You are already at ${username}.`);
|
||||
return true;
|
||||
}
|
||||
if (bot.modes.isOn('cheat')) {
|
||||
bot.chat('/tp @s ' + username);
|
||||
log(bot, `Teleported to ${username}.`);
|
||||
|
@ -1127,9 +1254,10 @@ export async function goToPlayer(bot, username, distance=3) {
|
|||
return false;
|
||||
}
|
||||
|
||||
const move = new pf.Movements(bot);
|
||||
bot.pathfinder.setMovements(move);
|
||||
await bot.pathfinder.goto(new pf.goals.GoalFollow(player, distance), true);
|
||||
distance = Math.max(distance, 0.5);
|
||||
const goal = new pf.goals.GoalFollow(player, distance);
|
||||
|
||||
await goToGoal(bot, goal, true);
|
||||
|
||||
log(bot, `You have reached ${username}.`);
|
||||
}
|
||||
|
@ -1149,24 +1277,36 @@ export async function followPlayer(bot, username, distance=4) {
|
|||
return false;
|
||||
|
||||
const move = new pf.Movements(bot);
|
||||
move.digCost = 10;
|
||||
bot.pathfinder.setMovements(move);
|
||||
let doorCheckInterval = startDoorInterval(bot);
|
||||
|
||||
bot.pathfinder.setGoal(new pf.goals.GoalFollow(player, distance), true);
|
||||
log(bot, `You are now actively following player ${username}.`);
|
||||
|
||||
|
||||
while (!bot.interrupt_code) {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
// in cheat mode, if the distance is too far, teleport to the player
|
||||
if (bot.modes.isOn('cheat') && bot.entity.position.distanceTo(player.position) > 100 && player.isOnGround) {
|
||||
await goToPlayer(bot, username);
|
||||
}
|
||||
if (bot.modes.isOn('unstuck')) {
|
||||
const is_nearby = bot.entity.position.distanceTo(player.position) <= distance + 1;
|
||||
if (is_nearby)
|
||||
bot.modes.pause('unstuck');
|
||||
else
|
||||
bot.modes.unpause('unstuck');
|
||||
const is_nearby = bot.entity.position.distanceTo(player.position) <= distance + 2;
|
||||
if (is_nearby) {
|
||||
clearInterval(doorCheckInterval);
|
||||
doorCheckInterval = null;
|
||||
bot.modes.pause('unstuck');
|
||||
bot.modes.pause('elbow_room');
|
||||
}
|
||||
else {
|
||||
if (!doorCheckInterval) {
|
||||
doorCheckInterval = startDoorInterval(bot);
|
||||
}
|
||||
bot.modes.unpause('unstuck');
|
||||
bot.modes.unpause('elbow_room');
|
||||
}
|
||||
}
|
||||
clearInterval(doorCheckInterval);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1189,7 +1329,6 @@ export async function moveAway(bot, distance) {
|
|||
const move = new pf.Movements(bot);
|
||||
const path = await bot.pathfinder.getPathTo(move, inverted_goal, 10000);
|
||||
let last_move = path.path[path.path.length-1];
|
||||
console.log(last_move);
|
||||
if (last_move) {
|
||||
let x = Math.floor(last_move.x);
|
||||
let y = Math.floor(last_move.y);
|
||||
|
@ -1199,7 +1338,7 @@ export async function moveAway(bot, distance) {
|
|||
}
|
||||
}
|
||||
|
||||
await bot.pathfinder.goto(inverted_goal);
|
||||
await goToGoal(bot, inverted_goal);
|
||||
let new_pos = bot.entity.position;
|
||||
log(bot, `Moved away from nearest entity to ${new_pos}.`);
|
||||
return true;
|
||||
|
@ -1393,7 +1532,7 @@ export async function tillAndSow(bot, x, y, z, seedType=null) {
|
|||
if (bot.entity.position.distanceTo(block.position) > 4.5) {
|
||||
let pos = block.position;
|
||||
bot.pathfinder.setMovements(new pf.Movements(bot));
|
||||
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
|
||||
await goToGoal(bot, new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
|
||||
}
|
||||
if (block.name !== 'farmland') {
|
||||
let hoe = bot.inventory.items().find(item => item.name.includes('hoe'));
|
||||
|
@ -1439,7 +1578,7 @@ export async function activateNearestBlock(bot, type) {
|
|||
if (bot.entity.position.distanceTo(block.position) > 4.5) {
|
||||
let pos = block.position;
|
||||
bot.pathfinder.setMovements(new pf.Movements(bot));
|
||||
await bot.pathfinder.goto(new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
|
||||
await goToGoal(bot, new pf.goals.GoalNear(pos.x, pos.y, pos.z, 4));
|
||||
}
|
||||
await bot.activateBlock(block);
|
||||
log(bot, `Activated ${type} at x:${block.position.x.toFixed(1)}, y:${block.position.y.toFixed(1)}, z:${block.position.z.toFixed(1)}.`);
|
||||
|
|
|
@ -354,6 +354,7 @@ export async function isClearPath(bot, target) {
|
|||
let movements = new pf.Movements(bot)
|
||||
movements.canDig = false;
|
||||
movements.canPlaceOn = false;
|
||||
movements.canOpenDoors = false;
|
||||
let goal = new pf.goals.GoalNear(target.position.x, target.position.y, target.position.z, 1);
|
||||
let path = await bot.pathfinder.getPathTo(movements, goal, 100);
|
||||
return path.status === 'success';
|
||||
|
|
|
@ -114,6 +114,11 @@ const modes_list = [
|
|||
});
|
||||
}
|
||||
this.last_time = Date.now();
|
||||
},
|
||||
unpause: function () {
|
||||
this.prev_location = null;
|
||||
this.stuck_time = 0;
|
||||
this.prev_dig_block = null;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -342,13 +347,18 @@ class ModeController {
|
|||
}
|
||||
|
||||
unpause(mode_name) {
|
||||
modes_map[mode_name].paused = false;
|
||||
const mode = modes_map[mode_name];
|
||||
//if unpause func is defined and mode is currently paused
|
||||
if (mode.unpause && mode.paused) {
|
||||
mode.unpause();
|
||||
}
|
||||
mode.paused = false;
|
||||
}
|
||||
|
||||
unPauseAll() {
|
||||
for (let mode of modes_list) {
|
||||
if (mode.paused) console.log(`Unpausing mode ${mode.name}`);
|
||||
mode.paused = false;
|
||||
this.unpause(mode.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
},
|
||||
"base_profile": {
|
||||
"type": "string",
|
||||
"description": "Allowed values: survival, creative, god_mode. Each has fine tuned settings for different game modes.",
|
||||
"description": "Allowed values: survival, assistant, creative, god_mode. Each has fine tuned settings for different game modes.",
|
||||
"default": "survival"
|
||||
},
|
||||
"load_memory": {
|
||||
|
|
|
@ -28,7 +28,7 @@ export class GPT {
|
|||
stop: stop_seq,
|
||||
...(this.params || {})
|
||||
};
|
||||
if (this.model_name.includes('o1')) {
|
||||
if (this.model_name.includes('o1') || this.model_name.includes('o3') || this.model_name.includes('5')) {
|
||||
delete pack.stop;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ export class Prompter {
|
|||
let base_fp = '';
|
||||
if (settings.base_profile.includes('survival')) {
|
||||
base_fp = './profiles/defaults/survival.json';
|
||||
} else if (settings.base_profile.includes('assistant')) {
|
||||
base_fp = './profiles/defaults/assistant.json';
|
||||
} else if (settings.base_profile.includes('creative')) {
|
||||
base_fp = './profiles/defaults/creative.json';
|
||||
} else if (settings.base_profile.includes('god_mode')) {
|
||||
|
|
Loading…
Add table
Reference in a new issue