Files
2026-08-29 15:24:43 -05:00

144 lines
2.5 KiB
Go

package server
import (
"encoding/binary"
"fmt"
"io"
"log"
"net"
"strconv"
)
const (
MsgKeyPress uint16 = 1
MsgGameState uint16 = 2
MSGServerStatus uint16 = 3
MSGOnConnect uint16 = 4
MSGOnPlayerConnect uint16 = 5
)
var num_clients int = 0
var clients = make(map[string]client)
type client struct {
x uint
y uint
client_id string
conn net.Conn
}
func Start() {
listener, err := net.Listen("tcp", ":9000")
if err != nil {
log.Fatal(err)
}
fmt.Println("Server listening on port 9000")
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Accept error:", err)
continue
}
// client connects
num_clients += 1
client_id := strconv.Itoa(num_clients)
fmt.Println(client_id)
go SendPacket(MSGOnConnect, []byte(client_id))
go SendPacket(MSGOnPlayerConnect, []byte(client_id))
addClient(conn, client_id)
go handle(conn)
}
}
func addClient(conn net.Conn, id string) {
var new_client client = client{
client_id: id,
conn: conn,
}
clients[id] = new_client
}
func SendPacket(msgID uint16, payload []byte) error {
// Length matches Lua: 2 (msgID) + payload size
length := uint32(2 + len(payload))
buf := make([]byte, 4+2+len(payload))
binary.BigEndian.PutUint32(buf[0:4], length)
binary.BigEndian.PutUint16(buf[4:6], msgID)
copy(buf[6:], payload)
for _, client := range clients {
n, err := client.conn.Write(buf)
if err != nil {
return err
}
if n != len(buf) {
return fmt.Errorf("short write: expected %d bytes, got %d", len(buf), n)
}
}
return nil
}
func handle(conn net.Conn) {
defer conn.Close()
for {
// Read packet length
var length uint32
err := binary.Read(conn, binary.BigEndian, &length)
if err != nil {
if err != io.EOF {
fmt.Println("Read length error:", err)
}
fmt.Println("Client disconnected")
num_clients -= 1
return
}
// Prevent invalid packets
if length < 2 {
fmt.Println("Invalid packet length:", length)
return
}
// Read message ID
var msgID uint16
err = binary.Read(conn, binary.BigEndian, &msgID)
if err != nil {
fmt.Println("Read message ID error:", err)
return
}
// Read payload
payload := make([]byte, length-2)
_, err = io.ReadFull(conn, payload)
if err != nil {
fmt.Println("Read payload error:", err)
return
}
switch msgID {
case MsgKeyPress:
msg := string(payload)
fmt.Println(msg)
// Send something back to the client
go SendPacket(MsgGameState, []byte(msg))
default:
fmt.Println("Unknown message:", msgID)
}
}
}