-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
bot.js
139 lines (118 loc) · 3.73 KB
/
bot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import debug from "debug";
import minecraftData from "minecraft-data";
import mineflayer from "mineflayer";
import { mineflayer as mineflayerViewer } from "prismarine-viewer";
import { callOpenAI } from "./api.js";
import {
context,
updateContext,
loadContext,
clearContext,
} from "./context/index.js";
import collectBlock from "mineflayer-collectblock";
//@ts-ignore
import mineflayerPathfinder from "mineflayer-pathfinder";
const { pathfinder } = mineflayerPathfinder;
// load available skills
//@ts-ignore
import { watchPlayer, goToPlayer, mineBlock, giveToPlayer } from "./skills/sample.js";
const log = debug("minecraft-openai.bot:log");
const error = debug("minecraft-openai.bot:error");
// define global variable that will be used to craft items and interact with the world
var mcData;
var goToPlayerInterval;
var watchInterval;
var target;
// a workaround to avoid Code from removing these variables
goToPlayerInterval = null;
watchInterval = null;
mcData = null;
target = null;
export default async function bot(host, port, username) {
const bot = mineflayer.createBot({
username: username || "OpenAI",
host: host || "localhost",
port,
verbose: true,
});
// on error
bot.on("error", (err) => {
error(err);
});
bot.on("login", () => {
log("bot joined the game");
});
bot.on("chat", async (username, input) => {
if (username === bot.username) return;
if (input.startsWith("load context")) {
const contextName = input.replace("load context", "").trim();
if (contextName) {
await loadContext(contextName);
bot.chat(`Loaded context ${contextName}`);
return;
}
} else if (input.startsWith("reset context")) {
clearContext();
bot.chat("Cleared context");
return;
}
const previousContext = context();
log("input: %s", input);
log("context: %s", previousContext);
// call the OpenAI API
const response = await callOpenAI(input, previousContext);
target = bot.players[username].entity;
if (response) {
log("request: %s", response.id);
log("codex: %s", response.model);
log("choices: %o", response.choices);
// extract code instructions from response
const code = await response.choices
.map((choice) => choice.text)
.join("\n");
log("code: ", code);
if (code === "") {
bot.chat(`I am sorry, I don't understand.`);
return;
}
try {
// WARNING: this is a very dangerous way to execute code! Do you trust AI?
// Note: the code is executed in the context of the bot entity
await eval(`(async function inject() {
try {
${code}
}
catch(err){
error("error: %s", err.message);
bot.chat(\`error: \${err.message}\`);
}
})()`);
// update the context for the next time
// Note: we only update context if the code is valid
updateContext(input, code);
} catch (err) {
error("error: %s", err.message);
bot.chat(`error: ${err.message}`);
}
} else {
log("OpenAI response was empty. Ignore.");
}
});
// Log errors and kick reasons:
bot.on("kicked", log);
bot.on("error", log);
bot.once("spawn", () => {
mcData = minecraftData(bot.version);
log("Minecraft version: %s", bot.version);
log("Minecraft protocol version: %s", bot.protocolVersion);
// load all plugins
bot.loadPlugin(collectBlock.plugin);
bot.loadPlugin(pathfinder);
// port is the minecraft server port, if first person is false, you get a bird's-eye view
try {
mineflayerViewer(bot, { port: 31337, firstPerson: true });
} catch (err) {
error("error: %s", err.message);
}
});
}