package main import ( "bufio" "errors" "github.com/Tnze/go-mc/bot" "github.com/Tnze/go-mc/bot/basic" "github.com/Tnze/go-mc/chat" "github.com/Tnze/go-mc/data/packetid" "github.com/Tnze/go-mc/net/packet" "github.com/Tnze/go-mc/yggdrasil" "github.com/bwmarrin/discordgo" "github.com/google/uuid" "github.com/rs/zerolog/log" "io" "os" "strings" "time" ) var discordFmt = strings.NewReplacer( "_", `\_`, "*", `\*`, "~", `\~`, ) type Client struct { discord *discordgo.Session channelID string minecraft *bot.Client serverIP string } func NewClient(email, password, serverIP, discordToken string) (*Client, error) { c := &Client{ serverIP: serverIP, } if err := c.setupMinecraft(email, password); err != nil { return nil, err } if discordToken != "" { if err := c.setupDiscord(discordToken); err != nil { return nil, err } } return c, nil } func (c *Client) Run() { go c.onChatSend() c.handleGame() } func (c *Client) handleGame() { for { err := c.minecraft.JoinServer(c.serverIP) if err != nil { log.Err(err).Msg("") <-time.After(time.Minute * 5) return } log.Info().Msg("Login success") for { err := c.minecraft.HandleGame() if err != nil { log.Err(err).Msg("") if errors.Is(err, io.EOF) { <-time.After(time.Minute * 5) break } } } } } func (c *Client) sendChat(msg string) { if err := c.minecraft.Conn.WritePacket(packet.Marshal( packetid.ServerboundChat, packet.String(msg), )); err != nil { log.Err(err).Msg("") } } func (c *Client) onChatMsg(msg chat.Message, _ byte, _ uuid.UUID) error { if c.discord != nil { _, err := c.discord.ChannelMessageSend(c.channelID, discordFmt.Replace(msg.ClearString())) return err } log.Info().Msg(msg.String()) return nil } func (c *Client) setupDiscord(token string) error { var err error c.discord, err = discordgo.New("Bot " + token) if err != nil { return err } info, err := c.discord.Application("@me") if err != nil { return err } ch, err := c.discord.UserChannelCreate(info.Owner.ID) if err != nil { return err } c.channelID = ch.ID c.discord.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) { if m.Author.Bot || m.ChannelID != c.channelID { return } c.sendChat(m.Content) }) return c.discord.Open() } func (c *Client) setupMinecraft(email, password string) error { c.minecraft = bot.NewClient() basic.NewPlayer(c.minecraft, basic.DefaultSettings) auth, err := yggdrasil.Authenticate(email, password) if err != nil { return err } c.minecraft.Auth.UUID, c.minecraft.Auth.Name = auth.SelectedProfile() c.minecraft.Auth.AsTk = auth.AccessToken() basic.EventsListener{ GameStart: func() error { <-time.After(time.Second * 5) c.sendChat("/afk") return nil }, ChatMsg: c.onChatMsg, }.Attach(c.minecraft) return nil } func (c *Client) onChatSend() { scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { msg := scanner.Text() if strings.TrimSpace(msg) == "" { continue } c.sendChat(msg) } }