///
import { PacketC, PacketS } from "./protocol.ts";
import { normalize } from "./util.ts";
let ctx: CanvasRenderingContext2D;
let canvas: HTMLCanvasElement;
let ws: WebSocket;
document.addEventListener("DOMContentLoaded", () => {
ws = new WebSocket(`${window.location.protocol.endsWith("s:") ? "wss" : "ws"}://${window.location.hostname}:27032/`)
ws.onerror = console.error
ws.onmessage = m => {
packet(JSON.parse(m.data) as PacketC);
}
ws.onclose = () => console.log("close")
ws.onopen = () => {
console.log("open")
send({ join: { name: "test" } })
}
canvas = document.createElement("canvas");
document.body.append(canvas)
ctx = canvas.getContext("2d")!
resize()
globalThis.addEventListener("resize", resize)
draw()
document.addEventListener("keydown", ev => keyboard(ev, true))
document.addEventListener("keyup", ev => keyboard(ev, false))
setInterval(tick_update, 1000 / 25);
})
interface Player { x: number; y: number, name: string, rot: number }
const players = new Map()
interface Item { x: number; y: number }
const items = new Map()
interface Tile { x: number; y: number }
const tiles = new Map()
let my_id: number = -1
function send(p: PacketS) { ws.send(JSON.stringify(p)) }
function packet(p: PacketC) {
console.log(p);
if ("joined" in p) {
my_id = p.joined.id
} else if ("add_player" in p) {
players.set(p.add_player.id, { x: 0, y: 0, name: p.add_player.name, rot: 0 })
} else if ("remove_player" in p) {
players.delete(p.remove_player.id)
} else if ("position" in p) {
const pl = players.get(p.position.player)!
pl.x = p.position.pos[0]
pl.y = p.position.pos[1]
pl.rot = p.position.rot
} else if ("take_item" in p) {
} else if ("put_item" in p) {
} else if ("produce_item" in p) {
} else if ("consume_item" in p) {
} else if ("set_active" in p) {
} else if ("update_map" in p) {
} else console.warn("unknown packet", p);
}
const keys_down = new Set();
const HANDLED_KEYS = ["KeyW", "KeyA", "KeyS", "KeyD", "Space"]
function keyboard(ev: KeyboardEvent, down: boolean) {
if (HANDLED_KEYS.includes(ev.code)) ev.preventDefault()
if (ev.code == "Space") interact()
if (down) keys_down.add(ev.code)
else keys_down.delete(ev.code)
}
function interact() {
}
function tick_update() {
const p = players.get(my_id)
if (!p) return
}
function frame_update(dt: number) {
const p = players.get(my_id)
if (!p) return
const input = normalize({
x: (+keys_down.has("KeyD") - +keys_down.has("KeyA")),
y: (+keys_down.has("KeyS") - +keys_down.has("KeyW"))
})
p.x += input.x * dt * 10
p.y += input.y * dt * 10
}
function resize() {
canvas.width = globalThis.innerWidth
canvas.height = globalThis.innerHeight
}
let last_frame = Date.now()
function draw() {
const now = Date.now()
frame_update((now - last_frame) / 1000)
last_frame = now;
if (ws.readyState == ws.CONNECTING) draw_wait("Connecting...")
else if (ws.readyState == ws.CLOSING) draw_wait("Closing...")
else if (ws.readyState == ws.CLOSED) draw_wait("Disconnected")
else if (ws.readyState == ws.OPEN) draw_ingame()
else throw new Error(`ws state invalid`);
requestAnimationFrame(draw)
}
function draw_wait(text: string) {
ctx.fillStyle = "gray"
ctx.fillRect(0, 0, canvas.width, canvas.height)
ctx.fillStyle = "#555"
ctx.font = "50px sans-serif"
ctx.strokeStyle = "black"
ctx.fillStyle = "white"
ctx.lineWidth = 10
ctx.textAlign = "center"
ctx.textBaseline = "middle"
ctx.lineJoin = "round"
ctx.lineCap = "round"
ctx.strokeText(text, canvas.width / 2, canvas.height / 2)
ctx.fillText(text, canvas.width / 2, canvas.height / 2)
}
function draw_ingame() {
ctx.fillStyle = "#111"
ctx.fillRect(0, 0, canvas.width, canvas.height)
const scale = Math.min(canvas.width, canvas.height) / 10;
ctx.save()
ctx.translate(canvas.width / 2, canvas.height / 2)
ctx.scale(scale, scale)
for (const [_, player] of players) {
ctx.save()
ctx.translate(player.x, player.y)
ctx.rotate(player.rot)
ctx.fillStyle = "rgb(226, 176, 26)"
ctx.fillRect(-0.5, -0.5, 1, 1)
ctx.restore()
}
ctx.restore()
}