クライアント活用例
ここでは createClient() を使って書ける実用的なボットの例をまとめます。各例はコピーしてそのまま動くことを意識していますが、接続先のサーバーの仕様に合わせて調整してください。
基本形: 接続 + チャットのオウム返し
リポジトリの examples/client/client.js と同じ構成です。受信したチャットに返信します。
const bedrock = require('bedrock-protocol')
const client = bedrock.createClient({
host: 'localhost',
port: 19132,
username: 'Notch',
offline: true // オフライン(認証なし)で接続
})
client.on('join', () => console.log('参加しました'))
client.on('spawn', () => console.log('ワールドに出現しました'))
// 他人のチャットに反応してオウム返し
client.on('text', packet => {
if (packet.source_name !== client.username) {
client.queue('text', {
type: 'chat',
needs_translation: false,
source_name: client.username,
xuid: '',
platform_chat_id: '',
filtered_message: '',
message: `${packet.source_name} said: ${packet.message}`
})
}
})参加者への自動挨拶
add_player パケットでプレイヤーの参加を検知して挨拶します。
client.on('add_player', packet => {
client.queue('text', {
type: 'chat',
needs_translation: false,
source_name: client.username,
xuid: '',
platform_chat_id: '',
filtered_message: '',
message: `ようこそ、${packet.username}!`
})
})コマンドの実行と応答の受け取り
command_request を送り、自分で生成した UUID で command_output を突き合わせます。
const { randomUUID } = require('crypto')
const uuid = randomUUID()
client.on('command_output', packet => {
if (packet.origin.uuid === uuid) {
console.log('コマンド結果:', packet.output)
}
})
client.queue('command_request', {
command: '/list',
origin: {
type: 'player',
uuid,
request_id: '',
player_entity_id: 0n // 1.21.130 以降は必須
},
internal: false,
version: 'latest' // 1.26.x では文字列 'latest'(1.21.x 以下は varint の数値)
})バージョン依存の注意
version と origin.player_entity_id はバージョンで扱いが変わります。詳細はクライアントガイドの注意点を参照してください。
オンライン認証(デバイスコード)
オンラインモード(offline: false が既定)では Microsoft アカウントのサインインが必要です。onMsaCode で認証 URL / コードを受け取り、ユーザーに提示できます。
const client = bedrock.createClient({
username: 'Notch',
onMsaCode: data => {
console.log(`ブラウザで ${data.verification_uri} を開き、コード ${data.user_code} を入力してください`)
}
})2 回目以降は profilesFolder(既定 .minecraft)にキャッシュされたトークンで自動認証されるため、認証 URL は出ません。
全パケットのダンプ
'packet' イベントで受信パケットをすべて観察できます。プロトコルの解析や、サーバーの実装確認に便利です。
client.on('packet', ({ name, params }) => {
console.log(`[受信] ${name}`)
// 特定パケットだけ詳細表示
if (name === 'add_player') console.log(JSON.stringify(params, null, 2))
})
// 送信パケットも見たい場合は inLog / outLog を差し替え
// client.inLog = (...args) => console.log('[受信]', ...args)
// client.outLog = (...args) => console.log('[送信]', ...args)
// または process.env.DEBUG = 'minecraft-protocol' で全ログ出力サーバー監視ボット(ping 定期実行)
ボットを接続させずに、サーバーの人数・バージョンを定期取得できます。
const { ping } = require('bedrock-protocol')
const TARGET = { host: 'play.cubecraft.net', port: 19132 }
async function monitor() {
try {
const s = await ping(TARGET)
console.log(`[${new Date().toLocaleTimeString()}] ${s.motd} — ${s.playersOnline}/${s.playersMax} 人 (${s.version})`)
} catch (err) {
console.log('応答なし:', err.message)
}
}
monitor()
setInterval(monitor, 30_000)自動再接続(ダウン時リトライ)
kick / close / error を拾って再参加する、常駐ボットの基本形です。
const batching = { host: 'localhost', port: 19132, username: 'AutoBot', offline: true }
function login() {
const client = bedrock.createClient(batching)
client.on('spawn', () => console.log('復帰しました'))
client.on('kick', packet => {
console.log('キックされたので再接続:', packet.message)
setTimeout(login, 5000)
})
client.on('close', () => {
console.log('切断。5 秒後に再接続します')
setTimeout(login, 5000)
})
client.on('error', err => console.log('エラー:', err.message))
}
login()多重接続に注意
再接続ループで error と close の両方が発火するケースがあるため、タイマーは何重にも積まないよう、フラグでガードするのが安全です。
接続を手動制御(delayedInit)
接続前に ping や事前チェックを挟みたい場合は、Client クラスを直接使います。
const { Client } = require('bedrock-protocol')
const client = new Client({
host: '127.0.0.1',
port: 19132,
username: 'Notch',
offline: true,
delayedInit: true // コンストラクタ時点での自動初期化を止める
})
client.init() // シリアライザ等を準備して connect_allowed を発火
client.once('connect_allowed', async () => {
// 接続先を動的に変えたり、事前チェックしたりできる
await client.ping() // 疎通確認(失敗時は例外)
client.connect()
})詳細は低レベル API のガイドを参照してください。
Realm への接続
host / port を書かずに realms オプションで接続します。
const client = bedrock.createClient({
username: 'Notch',
// realmId / realmInvite / pickRealm のどれかで指定
realms: {
pickRealm: async realms => realms.find(r => r.name === 'My Realm')
}
})詳細はRealms ガイドを参照してください。
切断
client.close() // 即座に切断
client.disconnect() // disconnect パケットを送ってから切断組み合わせ例: 留守番ボット
チャットを受信してコマンドに応答する、1 ファイルのミニボットです。
const bedrock = require('bedrock-protocol')
const client = bedrock.createClient({ host: 'localhost', port: 19132, username: 'Butler', offline: true })
const say = message => client.queue('text', {
type: 'chat', needs_translation: false, source_name: client.username,
xuid: '', platform_chat_id: '', filtered_message: '', message
})
client.on('text', ({ source_name, message }) => {
if (source_name === client.username) return
const m = message.toLowerCase()
if (m.includes('おはよう')) say('おはようございます!')
else if (m.includes('時間')) say(`今は ${new Date().toLocaleTimeString()} です`)
else if (m === '!ping') say('応答します:pong')
else say(`${source_name} さんの発言「${message}」を受け取りました`)
})注意: メッセージ送信の type
text パケットは双方向で、type の意味が方向ごとに異なります。
- 下り(サーバー → クライアント):
typeで表示様式を選ぶ(詳細はRelay ガイドの表)。 - 上り(クライアント → サーバー): バニラクライアントが送るのは実質
'chat'のみ。サーバーは上りのtypeを見て、'chat'なら「プレイヤー発言」として通常のチャット(ブロードキャスト・ログ・コマンド処理)に入れます。
したがって、bot でチャット欄に発言として送りたい場合は必ず type: 'chat' を使い、source_name に自分のユーザー名を入れます。'system' や 'raw' は表示専用の type なので、上りで送るとサーバーに無視されたり想定外の扱いをされたりします。