2025-02-20 22:02:44 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2025-02-21 00:26:09 +01:00
|
|
|
"bytes"
|
|
|
|
|
"encoding/binary"
|
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-21 17:30:49 +01:00
|
|
|
"io"
|
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-21 00:26:09 +01:00
|
|
|
PingRequestID = 0x01
|
|
|
|
|
PongResponseID = 0x01
|
2025-02-20 23:18:43 +01:00
|
|
|
)
|
|
|
|
|
|
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"`
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
type Pong struct {
|
|
|
|
|
Timestamp int64 `json:"timestamp"`
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 22:13:51 +01:00
|
|
|
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: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
|
|
|
buf := make([]byte, 1024)
|
|
|
|
|
for {
|
|
|
|
|
n, err := client.conn.Read(buf)
|
|
|
|
|
if err != nil {
|
2025-02-21 17:30:49 +01:00
|
|
|
if err.Error() == "EOF" {
|
|
|
|
|
fmt.Println("Client disconnected:", client.conn.RemoteAddr())
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Println("Error reading from client:", err)
|
|
|
|
|
}
|
2025-02-20 23:59:19 +01:00
|
|
|
break
|
|
|
|
|
}
|
2025-02-20 23:18:43 +01:00
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
reader := bytes.NewReader(buf[:n])
|
2025-02-20 23:59:19 +01:00
|
|
|
|
2025-02-21 17:30:49 +01:00
|
|
|
// Read packet length
|
2025-02-21 00:26:09 +01:00
|
|
|
packetLength, err := readVarInt(reader)
|
2025-02-21 17:30:49 +01:00
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Error reading packet length:", err)
|
2025-02-21 00:26:09 +01:00
|
|
|
break
|
|
|
|
|
}
|
2025-02-20 23:59:19 +01:00
|
|
|
|
2025-02-21 17:30:49 +01:00
|
|
|
// Ensure full packet is read
|
|
|
|
|
packetData := make([]byte, packetLength)
|
|
|
|
|
if _, err := io.ReadFull(reader, packetData); err != nil {
|
|
|
|
|
fmt.Println("Error reading full packet data:", err)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
packetReader := bytes.NewReader(packetData)
|
|
|
|
|
|
|
|
|
|
packetID, err := readVarInt(packetReader)
|
2025-02-21 00:26:09 +01:00
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Error reading packet ID:", err)
|
|
|
|
|
break
|
|
|
|
|
}
|
2025-02-20 23:59:19 +01:00
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
fmt.Println("Packet ID:", packetID)
|
2025-02-20 23:59:19 +01:00
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
switch packetID {
|
2025-02-21 17:30:49 +01:00
|
|
|
case HandshakePacketID: // The same packet ID is used for the Status Request
|
2025-02-21 00:26:09 +01:00
|
|
|
if client.nextState == 1 {
|
|
|
|
|
handleStatusRequest(client)
|
2025-02-21 17:30:49 +01:00
|
|
|
} else if client.nextState == 2 {
|
|
|
|
|
fmt.Println("Received status request in the wrong state")
|
|
|
|
|
} else if client.nextState == 3 {
|
|
|
|
|
fmt.Println("Received status request in the wrong state")
|
2025-02-21 00:26:09 +01:00
|
|
|
} else {
|
2025-02-21 17:30:49 +01:00
|
|
|
handshake, err := handleHandshake(packetReader)
|
2025-02-21 00:26:09 +01:00
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println("Error processing handshake:", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
client.nextState = handshake.NextState
|
|
|
|
|
}
|
|
|
|
|
case PingRequestID:
|
|
|
|
|
var timestamp int64
|
2025-02-21 17:30:49 +01:00
|
|
|
if err := binary.Read(packetReader, binary.BigEndian, ×tamp); err != nil {
|
2025-02-21 00:26:09 +01:00
|
|
|
fmt.Println("Error reading timestamp:", err)
|
2025-02-20 23:59:19 +01:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
var responsePacket bytes.Buffer
|
|
|
|
|
writeVarInt(&responsePacket, 9) // Packet length: 1 byte for ID + 8 bytes for timestamp
|
|
|
|
|
responsePacket.WriteByte(PongResponseID)
|
|
|
|
|
binary.Write(&responsePacket, binary.BigEndian, timestamp)
|
2025-02-20 23:59:19 +01:00
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
if _, err := client.conn.Write(responsePacket.Bytes()); err != nil {
|
|
|
|
|
fmt.Println("Error sending pong response:", err)
|
2025-02-20 23:59:19 +01:00
|
|
|
} else {
|
2025-02-21 00:26:09 +01:00
|
|
|
fmt.Println("Pong response sent successfully:", timestamp)
|
2025-02-20 23:59:19 +01:00
|
|
|
}
|
|
|
|
|
}
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
func handleHandshake(reader *bytes.Reader) (HandshakePacket, error) {
|
2025-02-20 22:13:51 +01:00
|
|
|
var handshake HandshakePacket
|
2025-02-21 00:26:09 +01:00
|
|
|
var err error
|
2025-02-20 23:59:19 +01:00
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
handshake.ProtocolVersion, err = readVarInt(reader)
|
2025-02-20 23:18:43 +01:00
|
|
|
if err != nil {
|
2025-02-21 00:26:09 +01:00
|
|
|
return handshake, err
|
2025-02-20 23:59:19 +01:00
|
|
|
}
|
2025-02-20 22:13:51 +01:00
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
handshake.ServerAddress, err = readString(reader)
|
2025-02-20 23:59:19 +01:00
|
|
|
if err != nil {
|
2025-02-21 00:26:09 +01:00
|
|
|
return handshake, err
|
2025-02-20 23:18:43 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
if err := binary.Read(reader, binary.BigEndian, &handshake.ServerPort); err != nil {
|
|
|
|
|
return handshake, err
|
2025-02-20 23:18:43 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
handshake.NextState, err = readVarInt(reader)
|
2025-02-20 22:13:51 +01:00
|
|
|
if err != nil {
|
2025-02-21 00:26:09 +01:00
|
|
|
return handshake, err
|
2025-02-20 23:18:43 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
fmt.Printf("Handshake received: %+v\n", handshake)
|
|
|
|
|
return handshake, nil
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
func handleStatusRequest(client *ClientState) {
|
|
|
|
|
status := StatusResponse{
|
|
|
|
|
Version: VersionInfo{"1.21.4", 769},
|
|
|
|
|
Players: PlayerInfo{Max: 100, Online: 5, Sample: []Player{}},
|
|
|
|
|
Description: Chat{Text: "A Minecraft Server"},
|
2025-02-20 23:59:19 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
response, err := json.Marshal(status)
|
2025-02-20 23:59:19 +01:00
|
|
|
if err != nil {
|
2025-02-21 00:26:09 +01:00
|
|
|
fmt.Println("Error marshaling status response:", err)
|
|
|
|
|
return
|
2025-02-20 23:59:19 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
var packetData bytes.Buffer
|
2025-02-21 17:30:49 +01:00
|
|
|
writeVarInt(&packetData, StatusResponseID)
|
2025-02-21 00:26:09 +01:00
|
|
|
writeVarInt(&packetData, len(response))
|
|
|
|
|
packetData.Write(response)
|
2025-02-20 23:59:19 +01:00
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
var responsePacket bytes.Buffer
|
|
|
|
|
writeVarInt(&responsePacket, packetData.Len())
|
|
|
|
|
responsePacket.Write(packetData.Bytes())
|
|
|
|
|
|
|
|
|
|
fmt.Println("Final Response Packet:", responsePacket.Bytes())
|
2025-02-20 22:13:51 +01:00
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
if _, err = client.conn.Write(responsePacket.Bytes()); err != nil {
|
|
|
|
|
fmt.Println("Error sending response:", err)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Println("Status response sent successfully")
|
2025-02-20 23:18:43 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
func writeVarInt(buf *bytes.Buffer, value int) {
|
2025-02-20 22:13:51 +01:00
|
|
|
for {
|
2025-02-21 00:26:09 +01:00
|
|
|
temp := byte(value & 0x7F)
|
2025-02-20 22:13:51 +01:00
|
|
|
value >>= 7
|
2025-02-21 00:26:09 +01:00
|
|
|
if value > 0 {
|
|
|
|
|
temp |= 0x80
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
2025-02-21 00:26:09 +01:00
|
|
|
buf.WriteByte(temp)
|
2025-02-20 22:13:51 +01:00
|
|
|
if value == 0 {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-02-20 23:18:43 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
func readVarInt(reader *bytes.Reader) (int, error) {
|
|
|
|
|
value, position := 0, 0
|
2025-02-20 22:13:51 +01:00
|
|
|
for {
|
2025-02-21 00:26:09 +01:00
|
|
|
b, err := reader.ReadByte()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
2025-02-21 00:26:09 +01:00
|
|
|
value |= int(b&0x7F) << position
|
|
|
|
|
if (b & 0x80) == 0 {
|
2025-02-20 22:13:51 +01:00
|
|
|
break
|
|
|
|
|
}
|
2025-02-21 00:26:09 +01:00
|
|
|
position += 7
|
|
|
|
|
if position >= 32 {
|
|
|
|
|
return 0, errors.New("VarInt too big")
|
|
|
|
|
}
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
2025-02-21 00:26:09 +01:00
|
|
|
return value, nil
|
2025-02-20 22:13:51 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
func readString(reader *bytes.Reader) (string, error) {
|
|
|
|
|
length, err := readVarInt(reader)
|
2025-02-20 23:18:43 +01:00
|
|
|
if err != nil {
|
2025-02-21 00:26:09 +01:00
|
|
|
return "", err
|
2025-02-20 23:18:43 +01:00
|
|
|
}
|
|
|
|
|
|
2025-02-21 00:26:09 +01:00
|
|
|
strBuf := make([]byte, length)
|
|
|
|
|
if _, err := reader.Read(strBuf); err != nil {
|
|
|
|
|
return "", err
|
2025-02-20 23:18:43 +01:00
|
|
|
}
|
2025-02-21 00:26:09 +01:00
|
|
|
return string(strBuf), nil
|
2025-02-20 22:02:44 +01:00
|
|
|
}
|