Skip to content

Commit a9dc7d5

Browse files
shinohara-rinnekomeowww
authored andcommitted
feat(minecraft): hook up prismarine-viewer
1 parent b11bb1a commit a9dc7d5

File tree

4 files changed

+76
-0
lines changed

4 files changed

+76
-0
lines changed

services/minecraft/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"es-toolkit": "^1.44.0",
2020
"eventemitter3": "^5.0.4",
2121
"minecraft-data": "^3.102.3",
22+
"canvas": "^3.2.1",
2223
"mineflayer": "^4.33.0",
2324
"mineflayer-armor-manager": "^2.0.1",
2425
"mineflayer-auto-eat": "^5.0.3",
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type { Bot } from 'mineflayer'
2+
3+
import { useLogger } from '../utils/logger'
4+
5+
interface MineflayerViewerOptions {
6+
port: number
7+
firstPerson?: boolean
8+
}
9+
10+
export function setupMineflayerViewer(mineflayer: { bot: Bot }, options: MineflayerViewerOptions): void {
11+
let isViewerStarted = false
12+
13+
mineflayer.bot.once('spawn', async () => {
14+
if (isViewerStarted)
15+
return
16+
17+
isViewerStarted = true
18+
19+
const logger = useLogger()
20+
try {
21+
const { mineflayer: mineflayerViewer } = await import('prismarine-viewer')
22+
23+
mineflayerViewer(mineflayer.bot, {
24+
port: options.port,
25+
firstPerson: options.firstPerson ?? true,
26+
})
27+
28+
logger.log(`Mineflayer viewer running at http://localhost:${options.port}`)
29+
}
30+
catch (err) {
31+
const e = err as NodeJS.ErrnoException
32+
const message = typeof e.message === 'string' ? e.message : ''
33+
const isCanvasMissing = e?.code === 'MODULE_NOT_FOUND' && message.includes('\'canvas\'')
34+
const isCanvasBinaryMissing = e?.code === 'MODULE_NOT_FOUND' && message.includes('canvas.node')
35+
36+
if (isCanvasMissing || isCanvasBinaryMissing) {
37+
logger.log('Mineflayer viewer disabled: node-canvas is not available')
38+
return
39+
}
40+
41+
logger.errorWithError('Failed to start mineflayer viewer', e as Error)
42+
}
43+
})
44+
}

services/minecraft/src/debug/server.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ import { useLogger } from '../utils/logger'
1818
const __filename = fileURLToPath(import.meta.url)
1919
const __dirname = path.dirname(__filename)
2020

21+
function createViewerHtml(targetUrl: string): string {
22+
return `<!doctype html>
23+
<html lang="en">
24+
<head>
25+
<meta charset="utf-8" />
26+
<meta name="viewport" content="width=device-width, initial-scale=1" />
27+
<title>Mineflayer Viewer</title>
28+
<style>
29+
html, body { height: 100%; margin: 0; }
30+
iframe { width: 100%; height: 100%; border: 0; }
31+
</style>
32+
</head>
33+
<body>
34+
<iframe src="${targetUrl}" allow="fullscreen" referrerpolicy="no-referrer"></iframe>
35+
</body>
36+
</html>`
37+
}
38+
2139
interface ClientInfo {
2240
ws: WebSocket
2341
id: string
@@ -165,6 +183,16 @@ export class DebugServer {
165183
return
166184
}
167185

186+
if (req.method === 'GET' && (req.url === '/viewer' || req.url?.startsWith('/viewer?'))) {
187+
const html = createViewerHtml('http://localhost:3007')
188+
res.writeHead(200, {
189+
'Content-Type': 'text/html; charset=utf-8',
190+
'Cache-Control': 'no-cache',
191+
})
192+
res.end(html)
193+
return
194+
}
195+
168196
// Serve static files from web directory
169197
let filePath = req.url === '/' ? '/index.html' : req.url || '/index.html'
170198

services/minecraft/src/main.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { initBot } from './composables/bot'
1414
import { config, initEnv } from './composables/config'
1515
import { createNeuriAgent } from './composables/neuri'
1616
import { DebugService } from './debug'
17+
import { setupMineflayerViewer } from './debug/mineflayer-viewer'
1718
import { wrapPlugin } from './libs/mineflayer'
1819
import { initLogger, useLogger } from './utils/logger'
1920

@@ -38,6 +39,8 @@ async function main() {
3839
],
3940
})
4041

42+
setupMineflayerViewer(bot, { port: 3007, firstPerson: true })
43+
4144
// Connect airi server
4245
const airiClient = new Client({
4346
name: config.airi.clientName,

0 commit comments

Comments
 (0)