From 2ed2daeb25dd4f85130d7b6f71a92770c13eb7a6 Mon Sep 17 00:00:00 2001 From: harper Date: Sat, 29 Aug 2026 15:24:43 -0500 Subject: [PATCH] semi synced multiplayer --- ] | 126 ----------------------------------------------- client/init.lua | 3 ++ client/utils.lua | 9 ++++ client/world.lua | 14 +++--- doc.md | 2 + main.lua | 111 +++++++++++++++++++++++++++++++++++++---- server/server.go | 35 +++++++++---- 7 files changed, 148 insertions(+), 152 deletions(-) delete mode 100644 ] create mode 100644 client/utils.lua create mode 100644 doc.md diff --git a/] b/] deleted file mode 100644 index cfdf130..0000000 --- a/] +++ /dev/null @@ -1,126 +0,0 @@ -package server - -import ( - "encoding/binary" - "fmt" - "io" - "log" - "net" - "strconv" -) - -const ( - MsgKeyPress uint16 = 1 - MsgGameState uint16 = 2 - MSGServerStatus uint16 = 3 - MSGOnConnect uint16 = 4 -) - -var num_clients int = 0 - -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 - } - - num_clients += 1 - fmt.Println(toString(num_clients)) - go SendPacket(conn, MSGOnConnect, []byte(string(num_clients))) - - go handle(conn) - } -} - -func toString(num int) { - return strconv.FormatInt(int64(num), 10) -} - -func SendPacket(conn net.Conn, 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) - - n, err := 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") - 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 - err := SendPacket(conn, MsgGameState, []byte("received key press: "+msg)) - if err != nil { - fmt.Println("Send error:", err) - return - } - - default: - fmt.Println("Unknown message:", msgID) - } - } -} diff --git a/client/init.lua b/client/init.lua index ca237f2..1712d1c 100644 --- a/client/init.lua +++ b/client/init.lua @@ -4,11 +4,14 @@ local network = {} local client +client_id = 0 + -- Packet IDs network.MSG_KEY_PRESS = 1 network.MSG_GAMESTATE = 2 network.MSG_SERVER_STATUS = 3 network.MSG_ON_CONNECT = 4 +network.MSG_ON_PLAYER_CONNECT = 5 -------------------------------------------------- -- Packing diff --git a/client/utils.lua b/client/utils.lua new file mode 100644 index 0000000..b5f8a8d --- /dev/null +++ b/client/utils.lua @@ -0,0 +1,9 @@ +utils = {} + +function vec(x, y) + return {x = x, y = y} +end + +function utils.round(num) + return num >= 0 and math.floor(num + 0.5) or math.ceil(num - 0.5) +end diff --git a/client/world.lua b/client/world.lua index 58cad25..75dedc4 100644 --- a/client/world.lua +++ b/client/world.lua @@ -1,9 +1,15 @@ +require("client.utils") world = {} world.tiles = {} +world.entities = {} +world.entities.com = {} +world.entities.players = {} world.utils = {} +world.cell_size = 10 -- default + function world.utils.to_tile(x, y) - return vec(util.round(x / world.cell_size) * world.cell_size, util.round(y / world.cell_size) * world.cell_size) + return vec(utils.round(x / world.cell_size) * world.cell_size, utils.round(y / world.cell_size) * world.cell_size) end function world.utils.set_tile(x, y, tbl) @@ -15,9 +21,3 @@ function world.utils.get_tile(x, y) local key = x .. "," .. y return world.tiles[key] end - -function world:draw() - for i, v in pairs(world.tiles) do - gfx.rect_fill(v.aabb.x, v.aabb.y, v.aabb.w, v.aabb.h, gfx.COLOR_DARK_GRAY) - end -end diff --git a/doc.md b/doc.md new file mode 100644 index 0000000..8c8289f --- /dev/null +++ b/doc.md @@ -0,0 +1,2 @@ +## tile manager +- diff --git a/main.lua b/main.lua index 721f875..6a83478 100644 --- a/main.lua +++ b/main.lua @@ -1,29 +1,83 @@ local network = require("client") +require("client.world") -local player = { - x = 100, - y = 100, -} +function move(player, x, y) + local dir = strvec_to_intvec(x,y) + player.x = dir.x + player.y = dir.y +end + +function dir_to_vec(dir) + if dir == "up" then + return vec(0,-1) + elseif dir == "down" then + return vec(0,1) + elseif dir == "left" then + return vec(-1,0) + elseif dir == "right" then + return vec(1,0) + else + return vec(0,0) + end +end + +function strvec_to_intvec(x,y) + return vec(tonumber(x), tonumber(y)) +end -local client_id = 0 function love.load() network.connect("127.0.0.1", 9000) network.on(network.MSG_ON_CONNECT, function(payload) print("connected to server with id " .. payload) + add_player(payload) if client_id == 0 then client_id = payload end end) network.on(network.MSG_GAMESTATE, function(payload) - print(payload) + local cmds = read_command(payload) + act_on_command(cmds) + end) + + network.on(network.MSG_ON_PLAYER_CONNECT, function(payload) + if payload == client_id then return end + add_player(payload) + for i, v in pairs(world.entities.players) do + network.sendPacket(network.MSG_KEY_PRESS, "player/" .. v.client_id .. "/moved/" .. v.x .. "/".. v.y) + end end) end +function add_player(id) + local new_player = { + x = 0, + y = 0, + sprite = 0, + client_id = id + } + + world.entities.players[new_player.client_id] = new_player + + return new_player +end + function love.keypressed(key) - network.sendPacket(network.MSG_KEY_PRESS, client_id .. "/pressed/" .. key) + local dir + if key == "w" then + dir = vec(0,-world.cell_size) + elseif key == "a" then + dir = vec(-world.cell_size,0) + elseif key == "s" then + dir = vec(0,world.cell_size) + elseif key == "d" then + dir = vec(world.cell_size,0) + else + dir = "right" + end + network.sendPacket(network.MSG_KEY_PRESS, "player/" .. client_id .. "/moved/" .. world.entities.players[client_id].x + dir.x .. "/".. world.entities.players[client_id].y + dir.y) end function love.update() @@ -31,7 +85,46 @@ function love.update() end function love.draw() - love.graphics.print("Connected as id " .. client_id, 20, 20) + for i, v in pairs(world.entities.players) do + love.graphics.rectangle("fill", v.x, v.y, world.cell_size, world.cell_size) + love.graphics.print(v.client_id, v.x, v.y - world.cell_size - 5) + end - love.graphics.circle("fill", player.x, player.y, 10) +end + +function read_command(payload) + local cmds = {} + local num_cmds = 1 + + local s = "" + for i in string.gmatch(payload, ".") do + if i ~= "/" then + s = s .. i + else + cmds[num_cmds] = s + s = "" + num_cmds = num_cmds + 1 + end + end + cmds[num_cmds] = s + return cmds +end + +function act_on_command(cmds) + if cmds[1] == "player" then + -- do player sync + for i, v in pairs(world.entities.players) do + if v.client_id == cmds[2] then + if cmds[3] == "moved" then + local player = world.entities.players[cmds[2]] + move(player, tonumber(cmds[4]),tonumber(cmds[5])) + end + end + + if world.entities.players[cmds[2]] == nil then + print("adding player") + add_player(cmds[2]) + end + end + end end diff --git a/server/server.go b/server/server.go index 2114a24..9d3487b 100644 --- a/server/server.go +++ b/server/server.go @@ -10,14 +10,22 @@ import ( ) const ( - MsgKeyPress uint16 = 1 - MsgGameState uint16 = 2 - MSGServerStatus uint16 = 3 - MSGOnConnect uint16 = 4 + MsgKeyPress uint16 = 1 + MsgGameState uint16 = 2 + MSGServerStatus uint16 = 3 + MSGOnConnect uint16 = 4 + MSGOnPlayerConnect uint16 = 5 ) var num_clients int = 0 -var clients = map[int]net.Conn{} +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") @@ -34,18 +42,25 @@ func Start() { continue } + // client connects num_clients += 1 client_id := strconv.Itoa(num_clients) fmt.Println(client_id) go SendPacket(MSGOnConnect, []byte(client_id)) - addClient(conn, num_clients) + go SendPacket(MSGOnPlayerConnect, []byte(client_id)) + + addClient(conn, client_id) go handle(conn) } } -func addClient(conn net.Conn, id int) { - clients[id] = 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 { @@ -57,8 +72,8 @@ func SendPacket(msgID uint16, payload []byte) error { binary.BigEndian.PutUint16(buf[4:6], msgID) copy(buf[6:], payload) - for _, conn := range clients { - n, err := conn.Write(buf) + for _, client := range clients { + n, err := client.conn.Write(buf) if err != nil { return err }