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,
velocity: number
}
export interface Keys {
up: boolean,
left: boolean,
down: boolean,
right: boolean
}
export const global: GlobalData = {
client: null,
players: [],
planets: [],
me: null,
canvas: <HTMLCanvasElement>document.getElementById("canvas"),
spritesheet_img: null,
spritesheet: null,
context: <CanvasRenderingContext2D>(<HTMLCanvasElement>document.getElementById("canvas")).getContext("2d"),
keys: {
up: false,
down: false,
left: false,
right: false
},
velocity: 0
}
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<void>(async (resolve) => {
const image_promise: Promise<HTMLImageElement> = 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<Object> = 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!}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);
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"
}