diff --git a/main.go b/main.go index 19e1dbd..6ad1e1a 100644 --- a/main.go +++ b/main.go @@ -1,21 +1,194 @@ package main import ( + "encoding/json" "fmt" + "net" ) -//TIP

To run your code, right-click the code and select Run.

Alternatively, click -// the icon in the gutter and select the Run menu item from here.

+const ( + HandshakePacketID = 0x00 + StatusRequestID = 0x00 + StatusResponseID = 0x00 +) + +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"` +} func main() { - //TIP

Press when your caret is at the underlined text - // to see how GoLand suggests fixing the warning.

Alternatively, if available, click the lightbulb to view possible fixes.

- s := "gopher" - fmt.Println("Hello and welcome, %s!", s) + listener, err := net.Listen("tcp", ":25565") + if err != nil { + fmt.Println("Error starting server:", err) + return + } + defer listener.Close() - for i := 1; i <= 5; i++ { - //TIP

To start your debugging session, right-click your code in the editor and select the Debug option.

We have set one breakpoint - // for you, but you can always add more by pressing .

- fmt.Println("i =", 100/i) + fmt.Println("Server started on port 25565") + + for { + conn, err := listener.Accept() + if err != nil { + fmt.Println("Error accepting connection:", err) + continue + } + + go handleConnection(conn) } } + +func handleConnection(conn net.Conn) { + var packetID byte + if err := readByte(conn, &packetID); err != nil { + fmt.Println("Error reading packet ID:", err) + return + } + + if packetID == HandshakePacketID { + handleHandshake(conn) + } +} + +func handleHandshake(conn net.Conn) { + var handshake HandshakePacket + if err := readHandshakePacket(conn, &handshake); err != nil { + fmt.Println("Error reading handshake packet:", err) + return + } + + if handshake.NextState == 1 { + handleStatusRequest(conn) + } +} + +func handleStatusRequest(conn net.Conn) { + var packetID byte + if err := readByte(conn, &packetID); err != nil { + fmt.Println("Error reading packet ID:", err) + return + } + + if packetID == StatusRequestID { + 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) + if err != nil { + fmt.Println("Error marshaling status response:", err) + return + } + + if err := writeByte(conn, StatusResponseID); err != nil { + fmt.Println("Error writing response ID:", err) + return + } + + if err := writeVarInt(conn, len(response)); err != nil { + fmt.Println("Error writing response length:", err) + return + } + + if _, err := conn.Write(response); err != nil { + fmt.Println("Error writing response:", err) + return + } + } +} + +func readByte(conn net.Conn, b *byte) error { + buf := make([]byte, 1) + _, err := conn.Read(buf) + if err != nil { + return err + } + *b = buf[0] + 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 { + for { + temp := byte(value & 0x7F) + value >>= 7 + if value != 0 { + temp |= 0x80 + } + if _, err := conn.Write([]byte{temp}); err != nil { + return err + } + if value == 0 { + break + } + } + return nil +} + +func readVarInt(conn net.Conn, value *int) error { + var result int + var shift uint + for { + var b byte + if err := readByte(conn, &b); err != nil { + return err + } + result |= int(b&0x7F) << shift + shift += 7 + if b&0x80 == 0 { + break + } + } + *value = result + return nil +} + +func readHandshakePacket(conn net.Conn, packet *HandshakePacket) error { + if err := readVarInt(conn, &packet.ProtocolVersion); err != nil { + + } + return nil +}