mirror of
https://github.com/kolbytn/mindcraft.git
synced 2025-08-04 14:25:43 +02:00
commit
845a9334b4
6 changed files with 202 additions and 11 deletions
|
@ -178,6 +178,42 @@ export const queryList = [
|
||||||
return "Saved place names: " + agent.memory_bank.getKeys();
|
return "Saved place names: " + agent.memory_bank.getKeys();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: '!getCraftingPlan',
|
||||||
|
description: "Provides a comprehensive crafting plan for a specified item. This includes a breakdown of required ingredients, the exact quantities needed, and an analysis of missing ingredients or extra items needed based on the bot's current inventory.",
|
||||||
|
params: {
|
||||||
|
targetItem: {
|
||||||
|
type: 'string',
|
||||||
|
description: 'The item that we are trying to craft'
|
||||||
|
},
|
||||||
|
quantity: {
|
||||||
|
type: 'int',
|
||||||
|
description: 'The quantity of the item that we are trying to craft',
|
||||||
|
optional: true,
|
||||||
|
domain: [1, Infinity, '[)'], // Quantity must be at least 1,
|
||||||
|
default: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
perform: function (agent, targetItem, quantity = 1) {
|
||||||
|
let bot = agent.bot;
|
||||||
|
|
||||||
|
// Fetch the bot's inventory
|
||||||
|
const curr_inventory = world.getInventoryCounts(bot);
|
||||||
|
const target_item = targetItem;
|
||||||
|
let existingCount = curr_inventory[target_item] || 0;
|
||||||
|
let prefixMessage = '';
|
||||||
|
if (existingCount > 0) {
|
||||||
|
curr_inventory[target_item] -= existingCount;
|
||||||
|
prefixMessage = `You already have ${existingCount} ${target_item} in your inventory. If you need to craft more,\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate crafting plan
|
||||||
|
let craftingPlan = mc.getDetailedCraftingPlan(target_item, quantity, curr_inventory);
|
||||||
|
craftingPlan = prefixMessage + craftingPlan;
|
||||||
|
console.log(craftingPlan);
|
||||||
|
return pad(craftingPlan);
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: '!help',
|
name: '!help',
|
||||||
description: 'Lists all available commands and their descriptions.',
|
description: 'Lists all available commands and their descriptions.',
|
||||||
|
|
|
@ -79,7 +79,7 @@ export async function craftRecipe(bot, itemName, num=1) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!recipes || recipes.length === 0) {
|
if (!recipes || recipes.length === 0) {
|
||||||
log(bot, `You do not have the resources to craft a ${itemName}. It requires: ${Object.entries(mc.getItemCraftingRecipes(itemName)[0]).map(([key, value]) => `${key}: ${value}`).join(', ')}.`);
|
log(bot, `You do not have the resources to craft a ${itemName}. It requires: ${Object.entries(mc.getItemCraftingRecipes(itemName)[0][0]).map(([key, value]) => `${key}: ${value}`).join(', ')}.`);
|
||||||
if (placedTable) {
|
if (placedTable) {
|
||||||
await collectBlock(bot, 'crafting_table', 1);
|
await collectBlock(bot, 'crafting_table', 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,7 +204,7 @@ class ItemWrapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
createChildren() {
|
createChildren() {
|
||||||
let recipes = mc.getItemCraftingRecipes(this.name);
|
let recipes = mc.getItemCraftingRecipes(this.name).map(([recipe, craftedCount]) => recipe);
|
||||||
if (recipes) {
|
if (recipes) {
|
||||||
for (let recipe of recipes) {
|
for (let recipe of recipes) {
|
||||||
let includes_blacklisted = false;
|
let includes_blacklisted = false;
|
||||||
|
|
|
@ -109,11 +109,11 @@ export class Task {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||||
|
|
||||||
if (this.data.agent_count > 1) {
|
if (this.data.agent_count > 1) {
|
||||||
var initial_inventory = this.data.initial_inventory[this.agent.count_id.toString()];
|
let initial_inventory = this.data.initial_inventory[this.agent.count_id.toString()];
|
||||||
console.log("Initial inventory:", initial_inventory);
|
console.log("Initial inventory:", initial_inventory);
|
||||||
} else if (this.data) {
|
} else if (this.data) {
|
||||||
console.log("Initial inventory:", this.data.initial_inventory);
|
console.log("Initial inventory:", this.data.initial_inventory);
|
||||||
var initial_inventory = this.data.initial_inventory;
|
let initial_inventory = this.data.initial_inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("initial_inventory" in this.data) {
|
if ("initial_inventory" in this.data) {
|
||||||
|
|
|
@ -190,7 +190,10 @@ export function getItemCraftingRecipes(itemName) {
|
||||||
recipe[ingredientName] = 0;
|
recipe[ingredientName] = 0;
|
||||||
recipe[ingredientName]++;
|
recipe[ingredientName]++;
|
||||||
}
|
}
|
||||||
recipes.push(recipe);
|
recipes.push([
|
||||||
|
recipe,
|
||||||
|
{craftedCount : r.result.count}
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return recipes;
|
return recipes;
|
||||||
|
@ -327,4 +330,156 @@ export function calculateLimitingResource(availableItems, requiredItems, discret
|
||||||
}
|
}
|
||||||
if(discrete) num = Math.floor(num);
|
if(discrete) num = Math.floor(num);
|
||||||
return {num, limitingResource}
|
return {num, limitingResource}
|
||||||
|
}
|
||||||
|
|
||||||
|
let loopingItems = new Set();
|
||||||
|
|
||||||
|
export function initializeLoopingItems() {
|
||||||
|
|
||||||
|
loopingItems = new Set(['coal',
|
||||||
|
'wheat',
|
||||||
|
'diamond',
|
||||||
|
'emerald',
|
||||||
|
'raw_iron',
|
||||||
|
'raw_gold',
|
||||||
|
'redstone',
|
||||||
|
'blue_wool',
|
||||||
|
'packed_mud',
|
||||||
|
'raw_copper',
|
||||||
|
'iron_ingot',
|
||||||
|
'dried_kelp',
|
||||||
|
'gold_ingot',
|
||||||
|
'slime_ball',
|
||||||
|
'black_wool',
|
||||||
|
'quartz_slab',
|
||||||
|
'copper_ingot',
|
||||||
|
'lapis_lazuli',
|
||||||
|
'honey_bottle',
|
||||||
|
'rib_armor_trim_smithing_template',
|
||||||
|
'eye_armor_trim_smithing_template',
|
||||||
|
'vex_armor_trim_smithing_template',
|
||||||
|
'dune_armor_trim_smithing_template',
|
||||||
|
'host_armor_trim_smithing_template',
|
||||||
|
'tide_armor_trim_smithing_template',
|
||||||
|
'wild_armor_trim_smithing_template',
|
||||||
|
'ward_armor_trim_smithing_template',
|
||||||
|
'coast_armor_trim_smithing_template',
|
||||||
|
'spire_armor_trim_smithing_template',
|
||||||
|
'snout_armor_trim_smithing_template',
|
||||||
|
'shaper_armor_trim_smithing_template',
|
||||||
|
'netherite_upgrade_smithing_template',
|
||||||
|
'raiser_armor_trim_smithing_template',
|
||||||
|
'sentry_armor_trim_smithing_template',
|
||||||
|
'silence_armor_trim_smithing_template',
|
||||||
|
'wayfinder_armor_trim_smithing_template']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a detailed plan for crafting an item considering current inventory
|
||||||
|
*/
|
||||||
|
export function getDetailedCraftingPlan(targetItem, count = 1, current_inventory = {}) {
|
||||||
|
initializeLoopingItems();
|
||||||
|
if (!targetItem || count <= 0 || !getItemId(targetItem)) {
|
||||||
|
return "Invalid input. Please provide a valid item name and positive count.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBaseItem(targetItem)) {
|
||||||
|
const available = current_inventory[targetItem] || 0;
|
||||||
|
if (available >= count) return "You have all required items already in your inventory!";
|
||||||
|
return `${targetItem} is a base item, you need to find ${count - available} more in the world`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inventory = { ...current_inventory };
|
||||||
|
const leftovers = {};
|
||||||
|
const plan = craftItem(targetItem, count, inventory, leftovers);
|
||||||
|
return formatPlan(plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBaseItem(item) {
|
||||||
|
return loopingItems.has(item) || getItemCraftingRecipes(item) === null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function craftItem(item, count, inventory, leftovers, crafted = { required: {}, steps: [], leftovers: {} }) {
|
||||||
|
// Check available inventory and leftovers first
|
||||||
|
const availableInv = inventory[item] || 0;
|
||||||
|
const availableLeft = leftovers[item] || 0;
|
||||||
|
const totalAvailable = availableInv + availableLeft;
|
||||||
|
|
||||||
|
if (totalAvailable >= count) {
|
||||||
|
// Use leftovers first, then inventory
|
||||||
|
const useFromLeft = Math.min(availableLeft, count);
|
||||||
|
leftovers[item] = availableLeft - useFromLeft;
|
||||||
|
|
||||||
|
const remainingNeeded = count - useFromLeft;
|
||||||
|
if (remainingNeeded > 0) {
|
||||||
|
inventory[item] = availableInv - remainingNeeded;
|
||||||
|
}
|
||||||
|
return crafted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use whatever is available
|
||||||
|
const stillNeeded = count - totalAvailable;
|
||||||
|
if (availableLeft > 0) leftovers[item] = 0;
|
||||||
|
if (availableInv > 0) inventory[item] = 0;
|
||||||
|
|
||||||
|
if (isBaseItem(item)) {
|
||||||
|
crafted.required[item] = (crafted.required[item] || 0) + stillNeeded;
|
||||||
|
return crafted;
|
||||||
|
}
|
||||||
|
|
||||||
|
const recipe = getItemCraftingRecipes(item)?.[0];
|
||||||
|
if (!recipe) {
|
||||||
|
crafted.required[item] = stillNeeded;
|
||||||
|
return crafted;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ingredients, result] = recipe;
|
||||||
|
const craftedPerRecipe = result.craftedCount;
|
||||||
|
const batchCount = Math.ceil(stillNeeded / craftedPerRecipe);
|
||||||
|
const totalProduced = batchCount * craftedPerRecipe;
|
||||||
|
|
||||||
|
// Add excess to leftovers
|
||||||
|
if (totalProduced > stillNeeded) {
|
||||||
|
leftovers[item] = (leftovers[item] || 0) + (totalProduced - stillNeeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process each ingredient
|
||||||
|
for (const [ingredientName, ingredientCount] of Object.entries(ingredients)) {
|
||||||
|
const totalIngredientNeeded = ingredientCount * batchCount;
|
||||||
|
craftItem(ingredientName, totalIngredientNeeded, inventory, leftovers, crafted);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add crafting step
|
||||||
|
const stepIngredients = Object.entries(ingredients)
|
||||||
|
.map(([name, amount]) => `${amount * batchCount} ${name}`)
|
||||||
|
.join(' + ');
|
||||||
|
crafted.steps.push(`Craft ${stepIngredients} -> ${totalProduced} ${item}`);
|
||||||
|
|
||||||
|
return crafted;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPlan({ required, steps, leftovers }) {
|
||||||
|
const lines = [];
|
||||||
|
|
||||||
|
if (Object.keys(required).length > 0) {
|
||||||
|
lines.push('You are missing the following items:');
|
||||||
|
Object.entries(required).forEach(([item, count]) =>
|
||||||
|
lines.push(`- ${count} ${item}`));
|
||||||
|
lines.push('\nOnce you have these items, here\'s your crafting plan:');
|
||||||
|
} else {
|
||||||
|
lines.push('You have all items required to craft this item!');
|
||||||
|
lines.push('Here\'s your crafting plan:');
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.push('');
|
||||||
|
lines.push(...steps);
|
||||||
|
|
||||||
|
if (Object.keys(leftovers).length > 0) {
|
||||||
|
lines.push('\nYou will have leftover:');
|
||||||
|
Object.entries(leftovers).forEach(([item, count]) =>
|
||||||
|
lines.push(`- ${count} ${item}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.join('\n');
|
||||||
}
|
}
|
12
viewer.html
12
viewer.html
|
@ -26,9 +26,9 @@
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
function updateLayout() {
|
function updateLayout() {
|
||||||
var width = window.innerWidth;
|
let width = window.innerWidth;
|
||||||
var height = window.innerHeight;
|
let height = window.innerHeight;
|
||||||
var iframes = document.querySelectorAll('.iframe-wrapper');
|
let iframes = document.querySelectorAll('.iframe-wrapper');
|
||||||
if (width > height) {
|
if (width > height) {
|
||||||
iframes.forEach(function(iframe) {
|
iframes.forEach(function(iframe) {
|
||||||
iframe.style.width = '50%';
|
iframe.style.width = '50%';
|
||||||
|
@ -43,10 +43,10 @@
|
||||||
}
|
}
|
||||||
window.addEventListener('resize', updateLayout);
|
window.addEventListener('resize', updateLayout);
|
||||||
window.addEventListener('load', updateLayout);
|
window.addEventListener('load', updateLayout);
|
||||||
var iframes = document.querySelectorAll('.iframe-wrapper');
|
let iframes = document.querySelectorAll('.iframe-wrapper');
|
||||||
iframes.forEach(function(iframe) {
|
iframes.forEach(function(iframe) {
|
||||||
var port = iframe.getAttribute('data-port');
|
let port = iframe.getAttribute('data-port');
|
||||||
var loaded = false;
|
let loaded = false;
|
||||||
function checkServer() {
|
function checkServer() {
|
||||||
fetch('http://localhost:' + port, { method: 'HEAD' })
|
fetch('http://localhost:' + port, { method: 'HEAD' })
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue