import {Logger, logSetup} from "./logger"; import {gateway_connect, GatewayClient} from "./gateway"; import {Player} from "./protocol/player"; import {Planet, PlanetType} from "./protocol/planet"; import { MessageC2SAuthenticateAndBeamOut, MessageC2SAuthenticateAndBeamOut_packetInfo, MessageC2SInput, MessageC2SInput_packetInfo } from "./protocol/message_c2s"; import {encode} from "./serde"; logSetup(); const logger = new Logger("client"); export interface GlobalData { client: GatewayClient | null, players: Player[], planets: Planet[], me: Player | null, canvas: HTMLCanvasElement, spritesheet_img: HTMLImageElement | null, spritesheet: object | null, context: CanvasRenderingContext2D, keys: Keys, velocity: number, can_beam_out: boolean } export interface Keys { up: boolean, left: boolean, down: boolean, right: boolean } export const global: GlobalData = { client: null, players: [], planets: [], me: null, canvas: document.getElementById("canvas"), spritesheet_img: null, spritesheet: null, context: (document.getElementById("canvas")).getContext("2d"), keys: { up: false, down: false, left: false, right: false }, velocity: 0, can_beam_out: false } async function client_main(server: string, username: string, texture_quality: string) { logger.info("StarKingdoms client - starting"); if (window.localStorage.getItem("token") !== null && window.localStorage.getItem("user") !== null) { global.can_beam_out = true; document.getElementById("beamout")!.style.setProperty("display", "block"); document.getElementById("beamout")!.addEventListener("click", () => { let msg = MessageC2SAuthenticateAndBeamOut.encode({ userId: window.localStorage.getItem("user")!, token: window.localStorage.getItem("token")! }).finish(); global.client?.socket.send(encode(MessageC2SAuthenticateAndBeamOut_packetInfo.type, msg)); }) } logger.info("Loading textures"); let spritesheet_url = `/assets/dist/spritesheet-${texture_quality}.png`; let spritesheet_data_url = `/assets/dist/spritesheet-${texture_quality}.json`; let load_textures = new Promise(async (resolve) => { const image_promise: Promise = new Promise((resolve, reject) => { const image = document.createElement("img"); image.src = spritesheet_url; image.onload = () => { resolve(image); } image.onerror = err => reject(err); }); const dat_promise: Promise = fetch(spritesheet_data_url).then(res => res.json()); let image = await image_promise; let data = await dat_promise; global.spritesheet_img = image; global.spritesheet = data; resolve(); }); await load_textures; logger.info("Starting the renderer"); //let sprite = PIXI.Sprite.from(global.spritesheet?.textures["hearty.png"]); global.client = await gateway_connect(server, username); global.canvas.width = window.innerWidth; global.canvas.height = window.innerHeight; window.onresize = () => { global.canvas.width = window.innerWidth; global.canvas.height = window.innerHeight; } global.canvas.style.setProperty("background-image", `url("/assets/final/${texture_quality}/starfield.png")`); document.onkeydown = (e) => { if (e.code == "ArrowLeft" || e.code == "KeyA") { // arrow-left global.keys.left = true; } else if (e.code == "ArrowRight" || e.code == "KeyD") { // arrow-right global.keys.right = true; } else if (e.code == "ArrowUp" || e.code == "KeyW") { // arrow-up global.keys.up = true; } else if (e.code == "ArrowDown" || e.code == "KeyS") { // arrow-down global.keys.down = true; } let msg = MessageC2SInput.encode({ upPressed: global.keys.up, downPressed: global.keys.down, leftPressed: global.keys.left, rightPressed: global.keys.right }).finish(); global.client?.socket.send(encode(MessageC2SInput_packetInfo.type, msg)); } document.onkeyup = (e) => { if (e.code == "ArrowLeft" || e.code == "KeyA") { // arrow-left global.keys.left = false; } else if (e.code == "ArrowRight" || e.code == "KeyD") { // arrow-right global.keys.right = false; } else if (e.code == "ArrowUp" || e.code == "KeyW") { // arrow-up global.keys.up = false; } else if (e.code == "ArrowDown" || e.code == "KeyS") { // arrow-down global.keys.down = false; } let msg = MessageC2SInput.encode({ upPressed: global.keys.up, downPressed: global.keys.down, leftPressed: global.keys.left, rightPressed: global.keys.right }).finish(); global.client?.socket.send(encode(MessageC2SInput_packetInfo.type, msg)); } let last_time = performance.now(); let render = (now_time: DOMHighResTimeStamp) => { const delta_ms = now_time - last_time; last_time = now_time; let viewer_size_x = global.canvas.width; let viewer_size_y = global.canvas.height; global.canvas.style.setProperty("background-position", `${-global.me?.x!/5}px ${-global.me?.y!/5}px`); global.context.setTransform(1, 0, 0, 1, 0, 0); global.context.clearRect(0, 0, viewer_size_x, viewer_size_y); // *dont* translate the camera. we're movign everything else around us. cameracentrism. // only translation will be to center our core module. global.context.translate(viewer_size_x / 2, viewer_size_y / 2); if (global.me !== null) { document.getElementById("pos").innerText = `Position: ${Math.trunc(global.me.x)}, ${Math.trunc(global.me.y)}`; } document.getElementById("vel").innerText = `Velocity: ${Math.trunc(global.velocity)}`; for (let i = 0; i < global.planets.length; i++) { let planet = global.planets[i]; // @ts-ignore let tex = global.spritesheet!["frames"][planet_type_to_tex_id(planet.planetType)]; global.context.drawImage(global.spritesheet_img!, tex.frame.x, // sx tex.frame.y, // sy tex.frame.w, // sw tex.frame.h, // sh (planet.x - planet.radius - global.me?.x!), // dx (planet.y - planet.radius - global.me?.y!), // dy planet.radius * 2, // dw planet.radius * 2); // dh if (planet.planetType == PlanetType.Moon) { if (global.me !== null) { global.context.beginPath(); global.context.strokeStyle = "gray"; global.context.lineWidth = 5; global.context.moveTo(global.me!.x - global.me!.x, global.me!.y - global.me!.y); global.context.lineTo(planet.x - global.me!.x, planet.y - global.me!.y); global.context.stroke(); document.getElementById("pos-moon").innerText = `Relative to Moon: ${Math.trunc(global.me!.x - planet.x)}, ${Math.trunc(global.me!.y - planet.y)}` } } else if (planet.planetType == PlanetType.Earth) { if (global.me !== null) { global.context.beginPath(); global.context.strokeStyle = "limegreen"; global.context.lineWidth = 5; global.context.moveTo(global.me!.x - global.me!.x, global.me!.y - global.me!.y); global.context.lineTo(planet.x - global.me!.x, planet.y - global.me!.y); global.context.stroke(); } } } for (let i = 0; i < global.players.length; i++) { let player = global.players[i]; // @ts-ignore let tex = global.spritesheet!["frames"]["hearty.png"]; global.context.save(); global.context.translate(player.x - global.me!.x, player.y - global.me!.y); global.context.textAlign = "center"; global.context.font = "30px Segoe UI"; global.context.fillStyle = "white"; global.context.fillText(player.username, 0, -35); global.context.rotate(player.rotation); global.context.drawImage(global.spritesheet_img!, tex.frame.x, // sx tex.frame.y, // sy tex.frame.w, // sw tex.frame.h, // sh -25, -25, 50, 50); // dh global.context.restore(); } requestAnimationFrame(render); } requestAnimationFrame(render); } let query = new URLSearchParams(window.location.search); if (!(query.has("server") || query.has("username") || query.has("textures"))) { window.location.href = "/index.html"; } client_main(query.get("server")!, query.get("username")!, query.get("textures")!).then(() => {}); function planet_type_to_tex_id(ty: PlanetType): string { if (ty == PlanetType.Earth) { return "earth.png" } else if (ty == PlanetType.Moon) { return "moon.png" } return "unknown.png" }