Skip to content

シンプル常駐ボット

指定した Bedrock サーバーにプレイヤーとしてログインし、ワールド内に常駐しながら、チャットで話しかけられたら自動で挨拶を返す自動応答ボットの実装例です。


完全なコード例

go
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/google/uuid"
	"github.com/sandertv/gophertunnel/minecraft"
	"github.com/sandertv/gophertunnel/minecraft/auth"
	"github.com/sandertv/gophertunnel/minecraft/protocol/login"
	"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)

func main() {
	var (
		serverAddr = flag.String("addr", "127.0.0.1:19132", "接続先サーバー")
		botName    = flag.String("name", "GopherEchoBot", "ボットの表示名")
		onlineAuth = flag.Bool("online", false, "Microsoft認証を使用するか")
	)
	flag.Parse()

	dialer := minecraft.Dialer{
		IdentityData: login.IdentityData{
			DisplayName: *botName,
			Identity:    uuid.New().String(),
		},
	}

	if *onlineAuth {
		dialer.TokenSource = auth.TokenSource
	}

	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
	defer cancel()

	log.Printf("サーバー %s へ接続中...\n", *serverAddr)
	conn, err := dialer.DialContext(ctx, "raknet", *serverAddr)
	if err != nil {
		log.Fatalf("接続失敗: %v", err)
	}
	defer conn.Close()

	log.Printf("ボット %s がサーバーに参加しました! (RuntimeID: %d)\n",
		*botName, conn.GameData().EntityRuntimeID)

	// 入室メッセージを送信
	sendChat(conn, fmt.Sprintf("こんにちは!%s がオンラインになりました。", *botName))

	// パケット受信ループ
	for {
		pk, err := conn.ReadPacket()
		if err != nil {
			log.Printf("サーバーから切断されました: %v", err)
			break
		}

		switch p := pk.(type) {
		case *packet.Text:
			// 自分の発言は無視
			if p.SourceName == *botName {
				continue
			}

			// チャットを受信した時の処理
			if p.TextType == packet.TextTypeChat {
				msg := strings.TrimSpace(p.Message)
				log.Printf("[%s] %s", p.SourceName, msg)

				if strings.Contains(msg, "ping") {
					sendChat(conn, fmt.Sprintf("@%s pong!", p.SourceName))
				} else if strings.Contains(msg, "hello") || strings.Contains(msg, "こんにちは") {
					sendChat(conn, fmt.Sprintf("@%s よろしくお願いします!", p.SourceName))
				}
			}

		case *packet.Disconnect:
			log.Printf("サーバーからキックされました: %s", p.Message)
			return
		}
	}
}

func sendChat(conn *minecraft.Conn, msg string) {
	_ = conn.WritePacket(&packet.Text{
		TextType:         packet.TextTypeChat,
		NeedsTranslation: false,
		SourceName:       conn.IdentityData().DisplayName,
		Message:          msg,
	})
	_ = conn.Flush()
}

Released under the MIT License.