import * as PIXI from "pixi.js"; import {Sprite} from "pixi.js"; import {Logger, logSetup} from "./logger"; import {gateway_connect, GatewayClient} from "./gateway"; import {Player} from "./protocol/player"; import {Planet, PlanetType} from "./protocol/planet"; import {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 } 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 } } async function client_main(server: string, username: string, texture_quality: string) { logger.info("StarKingdoms client - starting"); 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") { // arrow-left global.keys.left = true; } else if (e.code == "ArrowRight") { // arrow-right global.keys.right = true; } else if (e.code == "ArrowUp") { // arrow-up global.keys.up = true; } else if (e.code == "ArrowDown") { // 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") { // arrow-left global.keys.left = false; } else if (e.code == "ArrowRight") { // arrow-right global.keys.right = false; } else if (e.code == "ArrowUp") { // arrow-up global.keys.up = false; } else if (e.code == "ArrowDown") { // 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!}px ${-global.me?.y!}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); 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 } 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(() => {}); /* let app = new PIXI.Application({width: window.innerWidth, height: window.innerHeight, resizeTo: window }); // @ts-ignore document.body.appendChild(app.view); let sprite = PIXI.Sprite.from("./hearty.png"); app.stage.addChild(sprite); let elapsed = 0.0; app.ticker.add((delta) => { elapsed += delta; sprite.x = 100.0 + Math.cos(elapsed/50.0) * 100.0; }); */ function planet_type_to_tex_id(ty: PlanetType): string { if (ty == PlanetType.Earth) { return "earth.png" } return "unknown.png" }