main
Raw Download raw file
  1package minecraft
  2
  3import (
  4	"bufio"
  5	"bytes"
  6	"encoding/binary"
  7
  8	"encoding/json"
  9	"fmt"
 10	"net"
 11	//"zappem.net/pub/debug/xxd"
 12)
 13
 14type status struct {
 15	Version struct {
 16		Name     string `json:"name"`
 17		Protocol int    `json:"protocol"`
 18	} `json:"version"`
 19	Players struct {
 20		Max    int `json:"max"`
 21		Online int `json:"online"`
 22	} `json:"players"`
 23}
 24
 25// MinecraftPacket has support for writing minecraft varint packed data
 26// as well as normal bytes
 27type MinecraftPacket struct {
 28	bytes.Buffer
 29}
 30
 31// WriteVarInt writes an integer in Minecraft VarInt to the buffer.
 32func (b *MinecraftPacket) WriteVarInt(value uint64) error {
 33	var buf []byte = make([]byte, binary.MaxVarintLen64)
 34	n := binary.PutUvarint(buf[:], value)
 35	_, err := b.Write(buf[:n])
 36	return err
 37}
 38
 39func (b *MinecraftPacket) Finalize() []byte {
 40	length := b.Len()
 41	var buf []byte = make([]byte, binary.MaxVarintLen64)
 42	n := binary.PutUvarint(buf[:], uint64(length))
 43	return append(buf[:n], b.Bytes()...)
 44}
 45
 46func Connections(host string, port uint16) (int, error) {
 47
 48	address := fmt.Sprintf("%s:%d", host, port)
 49	conn, err := net.Dial("tcp", address)
 50	if err != nil {
 51		return 0, fmt.Errorf("failed to connect to server: %w", err)
 52	}
 53	defer conn.Close()
 54
 55	// Protocol Version - also try 0 if it fails
 56	protocolVersion := uint64(769)
 57	// Server port (BigEndian 2 bytes)
 58	portBytes := make([]byte, 2)
 59	binary.BigEndian.PutUint16(portBytes, uint16(port))
 60
 61	h := MinecraftPacket{bytes.Buffer{}}
 62	h.WriteVarInt(0)                 // Packet ID
 63	h.WriteVarInt(protocolVersion)   // Protocol Version
 64	h.WriteVarInt(uint64(len(host))) // Server Addr Len
 65	h.Write([]byte(host))            // Server Addr
 66	h.Write(portBytes)               // Server Port
 67	h.WriteVarInt(1)                 // Next State = 1 - Status
 68	handshake := h.Finalize()        // Prepend Packet Len
 69
 70	_, err = conn.Write(handshake)
 71	if err != nil {
 72		return 0, fmt.Errorf("failed to connect send handshake: %w", err)
 73	}
 74
 75	sr := MinecraftPacket{bytes.Buffer{}}
 76	sr.WriteVarInt(0)              // Status Packet ID
 77	statusRequest := sr.Finalize() // Prepend Packet Len
 78
 79	_, err = conn.Write(statusRequest)
 80	if err != nil {
 81		return 0, fmt.Errorf("failed to connect send status request: %w", err)
 82	}
 83
 84	byteReader := bufio.NewReader(conn)
 85	_, err = binary.ReadUvarint(byteReader) // respLen
 86	if err != nil {
 87		return 0, fmt.Errorf("failed to read response len: %w", err)
 88	}
 89	_, err = binary.ReadUvarint(byteReader) // packetID
 90	if err != nil {
 91		return 0, fmt.Errorf("failed to read paceket id: %w", err)
 92	}
 93	_, err = binary.ReadUvarint(byteReader) // statusLen
 94	if err != nil {
 95		return 0, fmt.Errorf("failed to read status len: %w", err)
 96	}
 97
 98	decoder := json.NewDecoder(byteReader)
 99	var s status
100	err = decoder.Decode(&s)
101	if err != nil {
102		return 0, fmt.Errorf("failed decoding server status response: %w", err)
103	}
104
105	return s.Players.Online, nil
106}