2025-02-20 22:02:44 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2025-02-20 22:13:51 +01:00
|
|
|
"encoding/json"
|
2025-02-20 23:18:43 +01:00
|
|
|
"errors"
|
2025-02-20 22:02:44 +01:00
|
|
|
"fmt"
|
2025-02-20 22:13:51 +01:00
|
|
|
"net"
|
2025-02-20 22:02:44 +01:00
|
|
|
)
|
|
|
|
|
|
2025-02-20 22:13:51 +01:00
|
|
|
const (
|
|
|
|
|
HandshakePacketID = 0x00
|
|
|
|
|
StatusRequestID = 0x00
|
|
|
|
|
StatusResponseID = 0x00
|
|
|
|
|
)
|
|
|
|
|
|
2025-02-20 23:18:43 +01:00
|
|
|
const (
|
|
|
|
|
SEGMENT_BITS = 0x7F
|
|
|
|
|
CONTINUE_BIT = 0x80
|
|
|
|
|
)
|
|
|
|
|
|
2025-02-20 22:13:51 +01:00
|
|
|
type HandshakePacket struct {
|
|
|
|
|
ProtocolVersion int
|
|
|
|
|
ServerAddress string
|
|
|
|
|
ServerPort uint16
|
|
|
|
|
NextState int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type StatusResponse struct {
|
|
|
|
|
Version VersionInfo `json:"version"`
|
|
|
|
|
Players PlayerInfo `json:"players"`
|
|
|
|
|
Description Chat `json:"description"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type VersionInfo struct {
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
Protocol int `json:"protocol"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type PlayerInfo struct {
|
|
|
|
|
Max int `json:"max"`
|
|
|
|
|
Online int `json:"online"`
|
|
|
|
|
Sample []Player `json:"sample"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Player struct {
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
ID string `json:"id"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Chat struct {
|
|
|
|
|
Text string `json:"text"`
|
|
|
|
|
}
|
2025-02-20 22:02:44 +01:00
|
|
|
|
2025-02-20 23:18:43 +01:00
|
|
|
type Reader struct {
|
|
|
|
|
data []byte
|
|
|
|
|
cursor int
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
type ClientState struct {
|
|
|
|
|
conn net.Conn
|
|
|
|
|
nextState int
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 22:02:44 +01:00
|
|
|
func main() {
|
2025-02-20 23:18:43 +01:00
|
|
|
listener, err := net.Listen("tcp", "localhost:25565")
|
2025-02-20 22:13:51 +01:00
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Error starting server:", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer listener.Close()
|
|
|
|
|
|
|
|
|
|
fmt.Println("Server started on port 25565")
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
conn, err := listener.Accept()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Error accepting connection:", err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
client := &ClientState{conn: conn, nextState: 0}
|
|
|
|
|
|
|
|
|
|
go handleConnection(client)
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
func handleConnection(client *ClientState) {
|
|
|
|
|
defer client.conn.Close()
|
|
|
|
|
fmt.Println("New connection from:", client.conn.RemoteAddr())
|
2025-02-20 23:18:43 +01:00
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
r := &Reader{data: make([]byte, 0)}
|
2025-02-20 23:18:43 +01:00
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
buf := make([]byte, 1024)
|
2025-02-20 22:13:51 +01:00
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
for {
|
|
|
|
|
n, err := client.conn.Read(buf)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Error reading from connection or connection closed:", err)
|
|
|
|
|
break
|
|
|
|
|
}
|
2025-02-20 23:18:43 +01:00
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
// Append new data to the reader buffer
|
|
|
|
|
r.data = append(r.data, buf[:n]...)
|
|
|
|
|
|
|
|
|
|
// Process packets as long as there is data
|
|
|
|
|
for len(r.data) > 0 {
|
|
|
|
|
startCursor := r.cursor
|
|
|
|
|
|
|
|
|
|
packetLength, err := r.readVarInt()
|
|
|
|
|
if err != nil {
|
|
|
|
|
r.cursor = startCursor // Reset if incomplete packet
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(r.data[r.cursor:]) < packetLength {
|
|
|
|
|
r.cursor = startCursor // Reset if incomplete packet
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
packetID, err := r.readVarInt()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Error reading packet ID:", err)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Println("Packet ID:", packetID)
|
|
|
|
|
|
|
|
|
|
if packetID == StatusRequestID && client.nextState == 1 {
|
|
|
|
|
handleStatusRequest(client.conn)
|
|
|
|
|
} else {
|
|
|
|
|
if packetID == HandshakePacketID {
|
|
|
|
|
handshake, err := handleHandshake(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Error processing handshake:", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
client.nextState = handshake.NextState
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove processed data
|
|
|
|
|
r.data = r.data[r.cursor:]
|
|
|
|
|
r.cursor = 0
|
|
|
|
|
}
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
func handleHandshake(r *Reader) (HandshakePacket, error) {
|
2025-02-20 22:13:51 +01:00
|
|
|
var handshake HandshakePacket
|
2025-02-20 23:18:43 +01:00
|
|
|
if err := readHandshakePacket(r, &handshake); err != nil {
|
2025-02-20 22:13:51 +01:00
|
|
|
fmt.Println("Error reading handshake packet:", err)
|
2025-02-20 23:59:19 +01:00
|
|
|
return handshake, err
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
return handshake, nil
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
func handleStatusRequest(conn net.Conn) {
|
|
|
|
|
status := StatusResponse{
|
|
|
|
|
Version: VersionInfo{
|
|
|
|
|
Name: "1.17.1",
|
|
|
|
|
Protocol: 756,
|
|
|
|
|
},
|
|
|
|
|
Players: PlayerInfo{
|
|
|
|
|
Max: 100,
|
|
|
|
|
Online: 5,
|
|
|
|
|
Sample: []Player{},
|
|
|
|
|
},
|
|
|
|
|
Description: Chat{
|
|
|
|
|
Text: "A Minecraft Server",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
response, err := json.Marshal(status)
|
2025-02-20 23:18:43 +01:00
|
|
|
if err != nil {
|
2025-02-20 23:59:19 +01:00
|
|
|
fmt.Println("Error marshaling status response:", err)
|
2025-02-20 22:13:51 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
w := &Writer{data: make([]byte, 1024)}
|
2025-02-20 22:13:51 +01:00
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
if err := w.writeVarInt(StatusResponseID); err != nil {
|
|
|
|
|
fmt.Println("Error writing response ID:", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-02-20 23:18:43 +01:00
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
if err := w.writeVarInt(len(response)); err != nil {
|
|
|
|
|
fmt.Println("Error writing response length:", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-02-20 22:13:51 +01:00
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
if err := w.writeString(string(response)); err != nil {
|
|
|
|
|
fmt.Println("Error writing response:", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-02-20 22:13:51 +01:00
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
// Send response to client
|
|
|
|
|
_, err = conn.Write(w.data[:w.cursor])
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Error sending response:", err)
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:18:43 +01:00
|
|
|
func (r *Reader) readByte() (byte, error) {
|
|
|
|
|
if r.cursor >= len(r.data) {
|
|
|
|
|
return 0, errors.New("EOF")
|
|
|
|
|
}
|
|
|
|
|
b := r.data[r.cursor]
|
|
|
|
|
r.cursor++
|
|
|
|
|
return b, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Reader) readVarInt() (int, error) {
|
|
|
|
|
value := 0
|
|
|
|
|
position := 0
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
currentByte, err := r.readByte()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value |= int(currentByte&SEGMENT_BITS) << position
|
|
|
|
|
|
|
|
|
|
if (currentByte & CONTINUE_BIT) == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
position += 7
|
|
|
|
|
if position >= 32 {
|
|
|
|
|
return 0, errors.New("VarInt is too big")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Reader) readString() (string, error) {
|
|
|
|
|
length, err := r.readVarInt()
|
2025-02-20 22:13:51 +01:00
|
|
|
if err != nil {
|
2025-02-20 23:18:43 +01:00
|
|
|
return "", err
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
2025-02-20 23:18:43 +01:00
|
|
|
|
|
|
|
|
if r.cursor+length > len(r.data) {
|
|
|
|
|
return "", errors.New("EOF: Reached String unexpectedly")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str := string(r.data[r.cursor : r.cursor+length])
|
|
|
|
|
r.cursor += length
|
|
|
|
|
return str, nil
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
func (r *Reader) readUnsignedShort() (uint16, error) {
|
|
|
|
|
b1, err := r.readByte()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b2, err := r.readByte()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return uint16(b1)<<8 | uint16(b2), nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:18:43 +01:00
|
|
|
type Writer struct {
|
|
|
|
|
data []byte
|
|
|
|
|
cursor int
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:18:43 +01:00
|
|
|
func (w *Writer) writeByte(b byte) error {
|
|
|
|
|
if w.cursor >= len(w.data) {
|
|
|
|
|
return errors.New("EOF")
|
|
|
|
|
}
|
|
|
|
|
w.data[w.cursor] = b
|
|
|
|
|
w.cursor++
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *Writer) writeVarInt(value int) error {
|
2025-02-20 22:13:51 +01:00
|
|
|
for {
|
2025-02-20 23:18:43 +01:00
|
|
|
temp := byte(value & SEGMENT_BITS)
|
2025-02-20 22:13:51 +01:00
|
|
|
value >>= 7
|
|
|
|
|
if value != 0 {
|
2025-02-20 23:18:43 +01:00
|
|
|
temp |= CONTINUE_BIT
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
2025-02-20 23:18:43 +01:00
|
|
|
if err := w.writeByte(temp); err != nil {
|
2025-02-20 22:13:51 +01:00
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if value == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:18:43 +01:00
|
|
|
func (w *Writer) writeString(s string) error {
|
|
|
|
|
length := len(s)
|
|
|
|
|
if err := w.writeVarInt(length); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if w.cursor+length > len(w.data) {
|
|
|
|
|
return errors.New("EOF")
|
|
|
|
|
}
|
|
|
|
|
copy(w.data[w.cursor:], s)
|
|
|
|
|
w.cursor += length
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func writeByte(conn net.Conn, b byte) error {
|
|
|
|
|
_, err := conn.Write([]byte{b})
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func writeVarInt(conn net.Conn, value int) error {
|
|
|
|
|
var buf [5]byte
|
|
|
|
|
n := 0
|
2025-02-20 22:13:51 +01:00
|
|
|
for {
|
2025-02-20 23:18:43 +01:00
|
|
|
temp := byte(value & SEGMENT_BITS)
|
|
|
|
|
value >>= 7
|
|
|
|
|
if value != 0 {
|
|
|
|
|
temp |= CONTINUE_BIT
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
2025-02-20 23:18:43 +01:00
|
|
|
buf[n] = temp
|
|
|
|
|
n++
|
|
|
|
|
if value == 0 {
|
2025-02-20 22:13:51 +01:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-02-20 23:18:43 +01:00
|
|
|
_, err := conn.Write(buf[:n])
|
|
|
|
|
return err
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 23:18:43 +01:00
|
|
|
func readHandshakePacket(r *Reader, packet *HandshakePacket) error {
|
|
|
|
|
// Print the whole packet
|
|
|
|
|
fmt.Println("Packet: ", r.data)
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
packet.ProtocolVersion, err = r.readVarInt()
|
|
|
|
|
fmt.Println("version: ", packet.ProtocolVersion)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2025-02-20 22:02:44 +01:00
|
|
|
|
2025-02-20 23:18:43 +01:00
|
|
|
packet.ServerAddress, err = r.readString()
|
|
|
|
|
fmt.Println(packet.ServerAddress)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
2025-02-20 22:02:44 +01:00
|
|
|
}
|
2025-02-20 23:18:43 +01:00
|
|
|
|
2025-02-20 23:59:19 +01:00
|
|
|
port, err := r.readUnsignedShort()
|
2025-02-20 23:18:43 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2025-02-20 23:59:19 +01:00
|
|
|
packet.ServerPort = port
|
|
|
|
|
fmt.Println("Port: ", packet.ServerPort)
|
2025-02-20 23:18:43 +01:00
|
|
|
|
|
|
|
|
packet.NextState, err = r.readVarInt()
|
|
|
|
|
fmt.Println("Next state: ", packet.NextState)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 22:13:51 +01:00
|
|
|
return nil
|
2025-02-20 22:02:44 +01:00
|
|
|
}
|