initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
export/
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
||||||
|
"runtime.version": "Lua 5.4",
|
||||||
|
"runtime.nonstandardSymbol": ["+=", "-=", "*=", "/=", "%="],
|
||||||
|
"workspace.library": ["${3rd}/love2d/library"],
|
||||||
|
"format.defaultConfig": {
|
||||||
|
"indent_style": "space",
|
||||||
|
"indent_size": "2"
|
||||||
|
},
|
||||||
|
"diagnostics": {
|
||||||
|
"disable": ["lowercase-global"]
|
||||||
|
}
|
||||||
|
}
|
||||||
+142
@@ -0,0 +1,142 @@
|
|||||||
|
local socket = require("socket")
|
||||||
|
|
||||||
|
local network = {}
|
||||||
|
|
||||||
|
local client
|
||||||
|
|
||||||
|
-- Packet IDs
|
||||||
|
network.MSG_KEY_PRESS = 1
|
||||||
|
network.MSG_GAMESTATE = 2
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
-- Packing
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
local function packU16(n)
|
||||||
|
return string.char(math.floor(n / 256) % 256, n % 256)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function packU32(n)
|
||||||
|
return string.char(math.floor(n / 16777216) % 256, math.floor(n / 65536) % 256, math.floor(n / 256) % 256, n % 256)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpackU16(s)
|
||||||
|
local b1, b2 = s:byte(1, 2)
|
||||||
|
return b1 * 256 + b2
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unpackU32(s)
|
||||||
|
local b1, b2, b3, b4 = s:byte(1, 4)
|
||||||
|
|
||||||
|
return b1 * 16777216 + b2 * 65536 + b3 * 256 + b4
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
-- Connection
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
function network.connect(ip, port)
|
||||||
|
client = assert(socket.tcp())
|
||||||
|
|
||||||
|
client:settimeout(0)
|
||||||
|
|
||||||
|
local ok, err = client:connect(ip, port)
|
||||||
|
|
||||||
|
-- Non-blocking connect is expected
|
||||||
|
if not ok and err ~= "timeout" then
|
||||||
|
error(err)
|
||||||
|
end
|
||||||
|
|
||||||
|
print("Connecting...")
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
-- Sending
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
function network.sendPacket(id, payload)
|
||||||
|
if not client then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
payload = payload or ""
|
||||||
|
|
||||||
|
local length = 2 + #payload
|
||||||
|
|
||||||
|
local packet = packU32(length) .. packU16(id) .. payload
|
||||||
|
|
||||||
|
client:send(packet)
|
||||||
|
end
|
||||||
|
|
||||||
|
function network.sendKey(key)
|
||||||
|
network.sendPacket(network.MSG_KEY_PRESS, key)
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
-- Packet handlers
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
network.handlers = {}
|
||||||
|
|
||||||
|
function network.on(id, callback)
|
||||||
|
network.handlers[id] = callback
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
-- Receiving
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
local function receivePacket()
|
||||||
|
local lenData, err = client:receive(4)
|
||||||
|
|
||||||
|
if not lenData then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local length = unpackU32(lenData)
|
||||||
|
|
||||||
|
local idData = client:receive(2)
|
||||||
|
if not idData then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local msgID = unpackU16(idData)
|
||||||
|
|
||||||
|
local payload = ""
|
||||||
|
|
||||||
|
if length > 2 then
|
||||||
|
payload = client:receive(length - 2)
|
||||||
|
|
||||||
|
if not payload then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return msgID, payload
|
||||||
|
end
|
||||||
|
|
||||||
|
--------------------------------------------------
|
||||||
|
-- Poll every frame
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
function network.update()
|
||||||
|
if not client then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local id, payload = receivePacket()
|
||||||
|
|
||||||
|
if not id then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
local handler = network.handlers[id]
|
||||||
|
|
||||||
|
if handler then
|
||||||
|
handler(payload)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return network
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
tile = {}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
world = {}
|
||||||
|
world.tiles = {}
|
||||||
|
world.utils = {}
|
||||||
|
|
||||||
|
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)
|
||||||
|
end
|
||||||
|
|
||||||
|
function world.utils.set_tile(x, y, tbl)
|
||||||
|
local key = x .. "," .. y
|
||||||
|
world.tiles[key] = tbl
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"grid-mmo-server/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
type world struct {
|
||||||
|
tiles [][]tile
|
||||||
|
}
|
||||||
|
|
||||||
|
type tile struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
server.Start()
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
local network = require("client")
|
||||||
|
|
||||||
|
local player = {
|
||||||
|
x = 100,
|
||||||
|
y = 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
function love.load()
|
||||||
|
network.connect("127.0.0.1", 9000)
|
||||||
|
|
||||||
|
network.on(network.MSG_GAMESTATE, function(payload)
|
||||||
|
print("Server:", payload)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.keypressed(key)
|
||||||
|
network.sendKey(key)
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.update()
|
||||||
|
network.update()
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.draw()
|
||||||
|
love.graphics.print("Connected", 20, 20)
|
||||||
|
|
||||||
|
love.graphics.circle("fill", player.x, player.y, 10)
|
||||||
|
end
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MsgKeyPress uint16 = 1
|
||||||
|
MsgGameState uint16 = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Client connected")
|
||||||
|
|
||||||
|
go handle(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user