Compare commits

...

9 Commits

Author SHA1 Message Date
jay
bf45a53f08 refactor: remove gameplay
temporarily remove gameplay until it is fixed and more stable

miner plugin won't work now
2020-12-24 10:40:46 +05:00
jay
a7ccb08d43 refactor: remove sleeper's prismarine-gameplay dependence 2020-12-24 10:35:01 +05:00
jay
8e4eb7748f style: fix crlf to lf 2020-12-24 09:33:08 +05:00
jay
47a944fe2a fix: 🐛 compat: don't use ?. for compat with older node.js 2020-12-24 09:19:32 +05:00
jay
1a3c345017 chore: 🙈 ignore .env 2020-12-24 09:16:11 +05:00
jay
de0af4d2ac feat: 🚀 add and use dotenv-packed
Use dotenv for more convenient credential management
2020-12-24 08:52:50 +05:00
jay
73d5f43ad3 feat: actually enable mover and eater plugins 2020-12-23 13:28:34 +05:00
jay
b970231519 feat: add mover plugin
General purpose mover / goto plugin.
Replaces the old solver based `comehere` in miner.js.
Instead, directly based on mineflayer bot apis and pathfinder.
This makes it simpler and easier to debug.
While less general, pathfinder is sophisticated enough for most cases.

For anything that needs moving from point A to point B.
Such as:
- following
- go to a location

Not in scope: locations and places. Would be a separate plugin.
2020-12-22 15:38:45 +05:00
jay
787d08dd31 feat: add automatic eater plugin 2020-12-22 15:29:06 +05:00
7 changed files with 267 additions and 76 deletions

1
.gitignore vendored
View File

@@ -13,6 +13,7 @@
# misc
.DS_Store
.env
.env.local
.env.development.local
.env.test.local

56
.vscode/launch.json vendored
View File

@@ -1,29 +1,29 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "protospace",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/lib/index.js",
"args": ["games.protospace.ca"]
},
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/lib/index.js",
// port may need to be changed for each session
"args": ["localhost", "56901"]
}
]
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "protospace",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/lib/index.js",
"args": ["games.protospace.ca"]
},
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/lib/index.js",
// port may need to be changed for each session
"args": ["localhost", "56901"]
}
]
}

View File

@@ -1,4 +1,4 @@
// TODO reload
const env = require("dotenv-packed").parseEnv().parsed
const fs = require('fs');
let cfg = {
admin: "Applezaus",
@@ -12,14 +12,14 @@ const mineflayer = require("mineflayer");
const bot =
!isNaN(parseInt(process.argv[3])) && parseInt(process.argv[3]) > 1e2 ?
mineflayer.createBot({
host: process.argv[2] || process.env.MINECRAFT_HOST || 'localhost', // Change this to the ip you want.
port: parseInt(process.argv[3]) || process.env.MINECRAFT_PORT // || 58471,
host: process.argv[2] || process.env.MINECRAFT_HOST || env.MINECRAFT_HOST || 'localhost', // Change this to the ip you want.
port: parseInt(process.argv[3]) || process.env.MINECRAFT_PORT || env.MINECRAFT_PORT // || 58471,
})
:
mineflayer.createBot({
host: process.argv[2] || process.env.MINECRAFT_HOST || 'localhost', // Change this to the ip you want.
username: process.argv[3] || process.env.MINECRAFT_USER,
password: process.argv[4] || process.env.MINECRAFT_PASS,
host: process.argv[2] || process.env.MINECRAFT_HOST || env.MINECRAFT_HOST || 'localhost', // Change this to the ip you want.
username: process.argv[3] || process.env.MINECRAFT_USER || env.MINECRAFT_USER,
password: process.argv[4] || process.env.MINECRAFT_PASS || env.MINECRAFT_PASS,
// port: process.argv[5] || process.env.MINECRAFT_PORT || 58471,
})
@@ -29,7 +29,7 @@ let plugins = {}
function loadplugin(pluginname, pluginpath) {
try {
plugins[pluginname] = require(pluginpath)
plugins[pluginname]?.load(cfg)
plugins[pluginname].load(cfg)
} catch (error) {
if (error.code == 'MODULE_NOT_FOUND') {
console.warn('plugin not used:', pluginpath)
@@ -44,7 +44,7 @@ function unloadplugin(pluginname, pluginpath) {
const plugin = require.resolve(pluginpath)
try {
if (plugin && require.cache[plugin]) {
require.cache[plugin].exports?.unload()
require.cache[plugin].exports.unload()
delete plugins[pluginname]
delete require.cache[plugin]
}
@@ -94,12 +94,12 @@ bot.once("spawn", () => {
command: require('./plugins/command'),
sleeper: require('./plugins/sleeper'),
armor: require('./plugins/armor'),
// mover: require('./plugins/mover'),
mover: require('./plugins/mover'),
guard: require('./plugins/guard'),
inventory: require('./plugins/inventory'),
// eater: require('./plugins/eater'),
eater: require('./plugins/eater'),
finder: require('./plugins/finder'),
miner: require('./plugins/miner'),
// miner: require('./plugins/miner.js'),
// statemachine: require('./plugins/statemachine'),
}

113
lib/plugins/eater.js Normal file
View File

@@ -0,0 +1,113 @@
let cfg = {}
let bot = {}
let isEating = false
function callbackHandle(err) {
if (err) console.error(err)
}
function eat(callback) {
isEating = true
const foodNames = require('minecraft-data')(bot.version).foodsArray.map((item) => item.name)
let available_food = bot.inventory
.items()
.filter((item) => foodNames.includes(item.name))
if (available_food.length === 0 || !available_food) {
isEating = false
return callback(new Error('No food found.'))
}
if (cfg.eat.bannedFood.length > 0) {
available_food = available_food.filter(
(item) => !cfg.eat.bannedFood.includes(item.name)
)
}
let priority = cfg.eat.priority
let best_food = available_food.reduce((prev, current) => (prev[priority] > current[priority]) ? prev : current)
if (!best_food) {
isEating = false
return callback(new Error('No best food has been found.'))
}
bot.emit('eat_start')
bot.equip(best_food, 'hand', function (error) {
if (error) {
console.error(error)
isEating = false
bot.emit('eat_stop')
} else {
bot.consume(function (err) {
if (err) {
console.error(err)
isEating = false
bot.emit('eat_stop')
return callback(err)
} else {
isEating = false
bot.emit('eat_stop')
callback(null)
if (!bot.food === 20) eat(callbackHandle)
}
})
}
})
}
function checkFood() {
console.info("eater: "
// , " status: ", !isEating
, cfg.eat.auto && "auto"
, bot.food < cfg.eat.startAt && "hungry"
, "hunger:", bot.food
, "at:", cfg.eat.startAt)
if (
!isEating
&& cfg.eat.auto
&& bot.food < cfg.eat.startAt
) {
if (
(bot.pathfinder
&& !(bot.pathfinder.isMining() || bot.pathfinder.isBuilding())
// TODO implement better idle state
) || true // idle most likely
) {
eat(callbackHandle)
}
}
}
function resetEat(value) {
// to prevent the plugin from breaking if the bot gets killed while eating btw
isEating = !!value // false
}
const load = (config) => {
cfg = config
bot = cfg.bot
cfg.eat = {
priority: 'saturation', //'foodPoints', //
// startAt: 19, //anarchy
// startAt: 18,
startAt: 14,
bannedFood: [
"enchanted_golden_apple", "golden_apple", "pufferfish", "chorus_fruit"
],
auto: true
}
bot.on('health', checkFood)
bot.on('spawn', resetEat)
}
const unload = () => {
bot.off('health', checkFood)
bot.off('spawn', resetEat)
}
module.exports = { load, unload, eat, resetEat }

95
lib/plugins/mover.js Normal file
View File

@@ -0,0 +1,95 @@
// import { EntityFilters } from "mineflayer-statemachine"
// import v from "vec3"
// import { Movements } from "mineflayer-pathfinder"
// const mineflayer = require('mineflayer')
const { Movements } = require('mineflayer-pathfinder')
// const { GoalBLah } = require('mineflayer-pathfinder').goals
const v = require('vec3')
let cfg = {}
let bot = {}
// let moving
let pathfinder
let movements = []
function initMoves(bot = bot, mcData = require('minecraft-data')(bot.version)) {
let defaultMove = new Movements(bot, mcData)
defaultMove.canDig = false
defaultMove.scafoldingBlocks.push(mcData.blocksByName.slime_block.id)
// defaultMove.blocksCantBreak.add(mcData.blocksByName.glass.id)
// defaultMove.blocksToAvoid.add(mcData.blocksByName.magma.id)
movements.defaultMove = defaultMove
bot.pathfinder.setMovements(defaultMove)
}
function moveNear(pos, distance = 3) {
const { GoalNear } = require('mineflayer-pathfinder').goals
cfg.quiet || bot.chat(`moving to ${pos}`)
pos = v(pos)
bot.pathfinder.setMovements(movements.defaultMove)
bot.pathfinder.setGoal(new GoalNear(pos.x, pos.y, pos.z, distance))
}
function follow(entity, dynamic = true) {
console.assert(entity)
const { GoalFollow } = require('mineflayer-pathfinder').goals
cfg.quiet && console.log(entity)
|| bot.chat(
`following ${entity.type
}: ${entity.username || entity.displayName
}${dynamic ? "" : " once"}`
)
entity = entity.entity ? entity.entity : entity
// console.log(entity)
bot.pathfinder.setMovements(movements.defaultMove)
bot.pathfinder.setGoal(new GoalFollow(entity, 3), dynamic)
}
function hit(blockOrEntity) {
bot.chat(`hitting ${entity.name || entity.type}`)
}
function stop() {
bot.pathfinder.setGoal(null)
bot.stopDigging()
}
const load = (config) => {
cfg = config
bot = cfg.bot
cfg.move = {
// auto: true,
canDig: false,
// list: ["hello", "wassup"],
quiet: !!cfg.quiet,
movements: []
}
pathfinder = bot.pathfinder || bot.loadPlugin(require('mineflayer-pathfinder').pathfinder)
// initMoves(bot, mcData)
setTimeout(initMoves, 500, bot)
// bot.loadPlugin(pathfinder)
// bot.on('time', hello)
}
const unload = () => {
// TODO stop pathfinding maybe?
}
module.exports = { load, unload, stop, initMoves, moveNear, follow }

View File

@@ -1,13 +1,6 @@
let pathfinder
//TODO replace with simple pathfinder motions
const {
gameplay,
MoveTo,
MoveToInteract,
ObtainItem,
// Craft
} = require('prismarine-gameplay')
let cfg = {}
let bot = {}
@@ -33,42 +26,33 @@ function sleep(quiet) {
}
if (bed && bedstatus == "") {
bot.lookAt(bed.position)
// const nearbed =
bot.gameplay.solveFor(
new MoveTo((bed.position.range = 2) && bed.position), (err) => {
// new MoveTo(bed.position), (err) => {
// new MoveToInteract(bed.position), (err) => {
bot.waitForChunksToLoad(() => {
cfg.plugins.moveNear(bed.position)
bot.sleep(bed, (err) => {
if (err) {
!quiet && bot.chat(`can't reach bed: ${err.message}`)
!quiet && bot.chat(`can't sleep: ${err.message}`)
} else {
bot.waitForChunksToLoad(() => {
bot.sleep(bed, (err) => {
if (err) {
!quiet && bot.chat(`can't sleep: ${err.message}`)
} else {
!quiet && bot.chat("zzz")
console.log("sleeping? ", bot.isSleeping)
// hack until this is fixed
// bot.isSleeping = bot.isSleeping ? bot.isSleeping : true
bot.isSleeping = true
}
})
})
!quiet && bot.chat("zzz")
console.log("sleeping? ", bot.isSleeping)
// hack until this is fixed
// bot.isSleeping = bot.isSleeping ? bot.isSleeping : true
bot.isSleeping = true
}
})
// } else if (bed){
})
} else if (inv && inv.equipItem("red_bed", "hand", true)) {
// doesn't work fortunately
// FIXME: DONT IMPLEMENT until it is detected as NOT NETHER
bot.placeBlock()
// bot.placeBlock()
} else {
bot.gameplay.solveFor(
new ObtainItem("bed"), (err) => {
if (err) {
!quiet && bot.chat(`need a${bedstatus} bed: may not see if just placed`)
}
}
)
// TODO: use mover
// bot.gameplay.solveFor(
// new ObtainItem("bed"), (err) => {
// if (err) {
// !quiet && bot.chat(`need a${bedstatus} bed: may not see if just placed`)
// }
// }
// )
// bot.chat('/afk')
}
bot.pathfinder.movements
@@ -104,7 +88,6 @@ const load = (config) => {
pathfinder = bot.pathfinder || require('mineflayer-pathfinder').pathfinder
// bot.loadPlugin(pathfinder)
bot.loadPlugin(gameplay)
inv = cfg.plugins["inventory"]
bot.on("time", autoSleep)

View File

@@ -42,7 +42,6 @@
"prismarine-block": "^1",
"prismarine-chat": "^1",
"prismarine-entity": "^1.1.0",
"prismarine-gameplay": "github:TheDudeFromCI/prismarine-gameplay#crafting",
"prismarine-item": "^1.5.0",
"prismarine-nbt": "^1.3",
"prismarine-recipe": "^1",