import { createCanvas, loadImage, GlobalFonts } from "@napi-rs/canvas"; import { GenerateBattlerOptions, GenerateBattleImageOptions, PlayerActionOptions, Opponents, CustomActionOptions } from "./types"; import { generateBattler, drawText, applyText, validOpponents, validPlayerActions } from "./utils"; import { createServer } from "node:http"; import GenerateParty from "./party" GlobalFonts .registerFromPath(import.meta.dirname + "/LilitaOne.ttf", "Lilita One"); const opponents = { [Opponents.BattleBeginner]: { text: "Battle Beginner", colour: ["#007500", "#FFFFFF"] }, [Opponents.BattleBeginner2024]: { text: "Battle Beginner", colour: ["#007500", "#FFFFFF"] }, [Opponents.BattleCasual]: { text: "Battle Casual", colour: ["#757500", "#FFFFFF"] }, [Opponents.BattleMaster]: { text: "Battle Master", colour: ["#750000", "#FFFFFF"] }, [Opponents.BattlePro]: { text: "Battle Pro", colour: ["#753000", "#FFFFFF"] }, [Opponents.Battler]: { text: "Battler", colour: ["#FFFFFF", "#000000"] }, [Opponents.BattlerElite]: { text: "Battler Elite", colour: ["#FFFFFF", "#FF0000"] }, [Opponents.None]: { text: "", colour: ["#FFFFFF", "#FFFFFF"] }, [Opponents.RapStar]: { text: "Rap Star", colour: ["#FF0000", "#FFFFFF"] }, [Opponents.ArtMaster]: { text: "Art Master", colour: ["#000000", "#FFFFFF"] }, [Opponents.TheInterrogator]: { text: "The Interrogator", colour: ["#FFFFFF", "#000000"] }, [Opponents.CommonOverseer]: { text: "Common Overseer", colour: ["#000000", "#32CD32"] }, [Opponents.Moonlite]: { text: "Moonlite", colour: ["#000000", "#FFFFFF"] }, [Opponents.Dicey]: { text: "Dicey", colour: ["#000000", "#FFFFFF"] }, [Opponents.Kacey]: { text: "Kacey", colour: ["#000000", "#FFFFFF"] }, [Opponents.Lexa]: { text: "Lexa", colour: ["#FFFFFF", "#FF00FF"] }, [Opponents.Delta]: { text: "Delta", colour: ["#000000", "#FFFFFF"] }, [Opponents.DoodlePro]: { text: "Doodle Pro", colour: ["#000000", "#FFFFFF"] }, [Opponents.GuitarHero]: { text: "Guitar Hero", colour: ["#FFFFFF", "#FF8000"] }, [Opponents.SmallKeyMaster]: { text: "Small KeyMaster", colour: ["#FFFFFF", "#32CD32"] }, [Opponents.RareOverseer]: { text: "Rare Overseer", colour: ["#000000", "#00FFFF"] }, [Opponents.DEMUL]: { text: "DEMUL", colour: ["#FFFFFF", "#000000"] }, [Opponents.AgentZ]: { text: "Agent Z", colour: ["#FFFFFF", "#000000"] }, [Opponents.MediumKeyMaster]: { text: "Medium KeyMaster", colour: ["#000000", "#00FFFF"] }, [Opponents.IncomingSword]: { text: "Incoming Sword", colour: ["#FF0000", "#FFFFFF"] }, [Opponents.Eda]: { text: "Eda", colour: ["#9000FF", "#FFFFFF"] }, [Opponents.TheFirewall]: { text: "The Firewall", colour: ["#FFFFFF", "#FFAA00"] }, [Opponents.HouseannorSupport]: { text: "Houseannor Support", colour: ["#FF00FF", "#FFFFFF"] }, [Opponents.Dicey2024]: { text: "Dicey", colour: ["#000000", "#FFFFFF"] }, [Opponents.CakeDay]: { text: "Cake Day", colour: ["#FA61FF", "#FFFFFF"] }, [Opponents.MasterOG]: { text: "Master OG", colour: ["#FF0000", "#FFFFFF"] } } // const _server = Bun.serve({ // port: 41399, // async fetch(req: Request) { // if (req.method == "OPTIONS") { // return new Response(null, { // headers: { // "access-control-allow-origin": "*", // }, // }); // } // const url = new URL(req.url); // if (req.method == "GET" && url.pathname == "/") { // return new Response(null, { // status: 204 // }); // } // if (req.method == "GET" && url.pathname == "/party.png") { // return GenerateParty(req, url) // } // if (req.method == "GET" && url.pathname == "/battler.png") { // const opts = Object.fromEntries( // Array.from(url.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions; // const battler = await generateBattler(opts); // return new Response(battler.toBuffer("image/png"), { // headers: { // "content-type": "image/png", // }, // }); // } // if (req.method == "GET" && url.pathname == "/profilebattler.png") { // const opts = Object.fromEntries( // Array.from(url.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions & { username: string }; // const canvas = createCanvas(1280, 1280); // const ctx = canvas.getContext("2d"); // const battler = await generateBattler(opts) // ctx.drawImage(battler, 0, 0); // ctx.textAlign = "center" // ctx.font = applyText(canvas, opts.username, canvas.width - 20) // drawText([640, 1100], opts.username, opts.username == "homeannor" ? "#AA00FF" : "#000000", { colour: "#FFFFFF", width: 20 }, ctx) // return new Response(canvas.toBuffer("image/png"), { // headers: { // "content-type": "image/png", // }, // }); // } // if ( // req.method == "GET" && // (url.pathname == "/battlesquadfight.png" || // url.pathname == "/battlestart.png") // ) { // const opts = Object.fromEntries( // Array.from(url.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions & GenerateBattleImageOptions; // if (!opts.opponent) { // return new Response( // JSON.stringify({ // error: '"opponent" query parameter not specified', // }), // { // status: 400, // headers: { // "content-type": "application/json", // }, // }, // ); // } // // Image dimensions // const canvas = createCanvas(1920, 1080); // const context = canvas.getContext("2d"); // if (!validOpponents.includes(opts.opponent)) opts.opponent = Opponents.None // const SquadBackground = await loadImage( // `./assets/battlebgs/${opts.opponent}.png`, // ); // context.drawImage(SquadBackground, 0, 0, canvas.width, canvas.height); // const battler = await generateBattler(opts); // context.drawImage(battler, -140, -100, battler.width, battler.height); // context.textAlign = "center" // context.font = applyText(canvas, opponents[opts.opponent].text, 875) // drawText([1450, 1000], opponents[opts.opponent].text, opponents[opts.opponent].colour[1], { colour: opponents[opts.opponent].colour[0], width: 20 }, context); // context.font = applyText(canvas, opts.username, 675) // drawText([470, 1000], opts.username, opts.username == "homeannor" ? "#AA00FF" : "#000000", { colour: "#FFFFFF", width: 20 }, context) // return new Response(canvas.toBuffer("image/png"), { // headers: { // "content-type": "image/png", // }, // }); // } // if ( // req.method == "GET" && // url.pathname == "/playeraction.png" // ) { // const opts = Object.fromEntries( // Array.from(url.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as PlayerActionOptions; // if (!opts.action) { // return new Response( // JSON.stringify({ // error: '"action" query parameter not specified', // }), // { // status: 400, // headers: { // "content-type": "application/json", // }, // }, // ); // } // if (!validPlayerActions.includes(opts.action)) { // return new Response( // JSON.stringify({ // error: // '"action" query parameter not formatted correctly. Got "' + // opts.action + // '".', // }), // { // status: 400, // headers: { // "content-type": "application/json", // }, // }, // ); // } // // Image dimensions // const canvas = createCanvas(1920, 1080); // const context = canvas.getContext("2d"); // const actionBackground = await loadImage( // `./assets/actionbgs/${opts.action}.png`, // ); // context.drawImage(actionBackground, 0, 0, canvas.width, canvas.height); // const pUrl = new URL(encodeURI(opts.player)) // const player = Object.fromEntries( // Array.from(pUrl.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions // if (opts.action.endsWith("Left")) { // const battler = await generateBattler(player); // context.drawImage(battler, -50, -100, battler.width, battler.height); // } else if (opts.action.endsWith("Right")) { // const battler = await generateBattler({ ...player, direction: "left" }); // context.drawImage(battler, (canvas.width / 2) - 300, -100, battler.width, battler.height); // } // return new Response(canvas.toBuffer("image/png"), { // headers: { // "content-type": "image/png", // }, // }); // } // if ( // req.method == "GET" && // url.pathname == "/customaction.png" // ) { // const opts = Object.fromEntries( // Array.from(url.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as CustomActionOptions; // if (!opts.background) { // return new Response( // JSON.stringify({ // error: '"background" query parameter not specified', // }), // { // status: 400, // headers: { // "content-type": "application/json", // }, // }, // ); // } // // Image dimensions // const canvas = createCanvas(1920, 1080); // const context = canvas.getContext("2d"); // const actionBackground = await loadImage( // opts.background, // ); // context.drawImage(actionBackground, 0, 0, canvas.width, canvas.height); // const pUrl = new URL(encodeURI(opts.player)) // const player = Object.fromEntries( // Array.from(pUrl.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions // const battler = await generateBattler(player); // if (opts.position == "middle") { // context.drawImage(battler, (1920 / 2) - 640, -100, battler.width, battler.height); // } else { // context.drawImage(battler, -50, -100, battler.width, battler.height); // } // return new Response(canvas.toBuffer("image/png"), { // headers: { // "content-type": "image/png", // }, // }); // } // if ( // req.method == "GET" && // url.pathname == "/playermap.png" // ) { // const opts = Object.fromEntries( // Array.from(url.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as { player1: string, player2: string, map: string }; // if (!opts.player1 || !opts.player2 || !opts.map) { // return new Response( // JSON.stringify({ // error: 'Did not pass all parameters', // }), // { // status: 400, // headers: { // "content-type": "application/json", // }, // }, // ); // } // const p1URL = new URL(encodeURI(opts.player1)) // const p2URL = new URL(encodeURI(opts.player2)) // const p1Opts = Object.fromEntries( // Array.from(p1URL.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions // const p2Opts = Object.fromEntries( // Array.from(p2URL.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions // const p1 = await generateBattler(p1Opts); // const p2 = await generateBattler({ ...p2Opts, direction: "left" }) // // Image dimensions // const canvas = createCanvas(1920, 1080); // const context = canvas.getContext("2d"); // const Background = await loadImage( // `./assets/locations/${opts.map}.png`, // ); // context.drawImage(Background, 0, 0, canvas.width, canvas.height); // context.drawImage(p1, 140, 313, p1.width / 2, p1.height / 2); // context.drawImage(p2, (canvas.width / 2) + 177, 313, p2.width / 2, p2.height / 2); // return new Response(canvas.toBuffer("image/png"), { // headers: { // "content-type": "image/png", // }, // }); // } // if ( // req.method == "GET" && // url.pathname == "/map.png" // ) { // const opts = Object.fromEntries( // Array.from(url.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as { player: string, map: string }; // if (!opts.player || !opts.map) { // return new Response( // JSON.stringify({ // error: 'Did not pass all parameters', // }), // { // status: 400, // headers: { // "content-type": "application/json", // }, // }, // ); // } // const p1URL = new URL(encodeURI(opts.player)) // const p1Opts = Object.fromEntries( // Array.from(p1URL.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions // const p1 = await generateBattler(p1Opts); // // Image dimensions // const canvas = createCanvas(1920, 1080); // const context = canvas.getContext("2d"); // const Background = await loadImage( // `./assets/locations/${opts.map}.png`, // ); // context.drawImage(Background, 0, 0, canvas.width, canvas.height); // context.drawImage(p1, 140, 313, p1.width / 2, p1.height / 2); // return new Response(canvas.toBuffer("image/png"), { // headers: { // "content-type": "image/png", // }, // }); // } // if ( // req.method == "GET" && // url.pathname == "/pvp.png" // ) { // const opts = Object.fromEntries( // Array.from(url.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as { player1: string, player2: string, username1: string, username2: string }; // if (!opts.player1 || !opts.player2 || !opts.username1 || !opts.username2) { // return new Response( // JSON.stringify({ // error: 'Did not pass all parameters', // }), // { // status: 400, // headers: { // "content-type": "application/json", // }, // }, // ); // } // const p1URL = new URL(encodeURI(opts.player1)) // const p2URL = new URL(encodeURI(opts.player2)) // const p1Opts = Object.fromEntries( // Array.from(p1URL.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions // const p2Opts = Object.fromEntries( // Array.from(p2URL.searchParams.entries()) // .map(([key, value]) => [key, value.replaceAll('+', ' ')]), // ) as GenerateBattlerOptions // const p1 = await generateBattler(p1Opts); // const p2 = await generateBattler({ ...p2Opts, direction: "left" }) // // Image dimensions // const canvas = createCanvas(1920, 1080); // const context = canvas.getContext("2d"); // const Background = await loadImage( // `./assets/battlebgs/PvP.png`, // ); // context.drawImage(Background, 0, 0, canvas.width, canvas.height); // context.drawImage(p1, -140, -100, p1.width, p1.height); // context.drawImage(p2, (canvas.width / 2) - 180, -100, p2.width, p2.height); // context.textAlign = "center" // context.font = applyText(canvas, opts.username2, 675) // drawText([1450, 1000], opts.username2, opts.username2 == "homeannor" ? "#AA00FF" : "#000000", { colour: "#FFFFFF", width: 20 }, context) // context.font = applyText(canvas, opts.username1, 675) // drawText([470, 1000], opts.username1, opts.username1 == "homeannor" ? "#AA00FF" : "#000000", { colour: "#FFFFFF", width: 20 }, context) // return new Response(canvas.toBuffer("image/png"), { // headers: { // "content-type": "image/png", // }, // }); // } // return new Response(`Cannot ${req.method} ${url.pathname}`, { // status: 404, // }); // }, // }); const server = createServer(async (req, res) => { if (req.method === "OPTIONS") { res.setHeader("access-control-allow-origin", "*") return res.end(); } const url = new URL(req.url!, "https://loc.al"); console.log(req.method, url.pathname) if (req.method == "GET" && url.pathname == "/battler.png") { const opts = Object.fromEntries( Array.from(url.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions; const battler = await generateBattler(opts); res.setHeader('content-type', 'image/png'); return res.end(battler.toBuffer("image/png"), 'binary') } if (req.method == "GET" && url.pathname == "/profilebattler.png") { const opts = Object.fromEntries( Array.from(url.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions & { username: string }; const canvas = createCanvas(1280, 1280); const ctx = canvas.getContext("2d"); const battler = await generateBattler(opts) ctx.drawImage(battler, 0, 0); ctx.textAlign = "center" ctx.font = applyText(canvas, opts.username, canvas.width - 20) drawText([640, 1100], opts.username, opts.username == "homeannor" ? "#AA00FF" : "#000000", { colour: "#FFFFFF", width: 20 }, ctx) res.setHeader('content-type', 'image/png'); return res.end(canvas.toBuffer("image/png"), 'binary') } if ( req.method == "GET" && (url.pathname == "/battlesquadfight.png" || url.pathname == "/battlestart.png") ) { const opts = Object.fromEntries( Array.from(url.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions & GenerateBattleImageOptions; if (!opts.opponent) { res.writeHead(400, { 'content-type': "application/json" }) return res.end( JSON.stringify({ error: '"opponent" query parameter not specified', }) ); } // Image dimensions const canvas = createCanvas(1920, 1080); const context = canvas.getContext("2d"); if (!validOpponents.includes(opts.opponent)) opts.opponent = Opponents.None const SquadBackground = await loadImage( `./assets/battlebgs/${opts.opponent}.png`, ); context.drawImage(SquadBackground, 0, 0, canvas.width, canvas.height); const battler = await generateBattler(opts); context.drawImage(battler, -140, -100, battler.width, battler.height); context.textAlign = "center" context.font = applyText(canvas, opponents[opts.opponent].text, 875) drawText([1450, 1000], opponents[opts.opponent].text, opponents[opts.opponent].colour[1], { colour: opponents[opts.opponent].colour[0], width: 20 }, context); context.font = applyText(canvas, opts.username, 675) drawText([470, 1000], opts.username, opts.username == "homeannor" ? "#AA00FF" : "#000000", { colour: "#FFFFFF", width: 20 }, context) res.setHeader('content-type', 'image/png'); return res.end(canvas.toBuffer("image/png"), 'binary') } if ( req.method == "GET" && url.pathname == "/playeraction.png" ) { const opts = Object.fromEntries( Array.from(url.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as PlayerActionOptions; if (!opts.action) { res.writeHead(400, { 'content-type': "application/json" }) return res.end( JSON.stringify({ error: '"action" query parameter not specified', }) ); } if (!validPlayerActions.includes(opts.action)) { res.writeHead(400, { 'content-type': "application/json" }) return res.end( JSON.stringify({ error: '"action" query parameter not formatted correctly. Got "' + opts.action + '".', }) ); } // Image dimensions const canvas = createCanvas(1920, 1080); const context = canvas.getContext("2d"); const actionBackground = await loadImage( `./assets/actionbgs/${opts.action}.png`, ); context.drawImage(actionBackground, 0, 0, canvas.width, canvas.height); const pUrl = new URL(encodeURI(opts.player)) const player = Object.fromEntries( Array.from(pUrl.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions if (opts.action.endsWith("Left")) { const battler = await generateBattler(player); context.drawImage(battler, -50, -100, battler.width, battler.height); } else if (opts.action.endsWith("Right")) { const battler = await generateBattler({ ...player, direction: "left" }); context.drawImage(battler, (canvas.width / 2) - 300, -100, battler.width, battler.height); } res.setHeader('content-type', 'image/png'); return res.end(canvas.toBuffer("image/png"), 'binary') } if ( req.method == "GET" && url.pathname == "/customaction.png" ) { const opts = Object.fromEntries( Array.from(url.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as CustomActionOptions; if (!opts.background) { res.writeHead(400, { 'content-type': "application/json" }) return res.end( JSON.stringify({ error: '"background" query parameter not found', }) ); } // Image dimensions const canvas = createCanvas(1920, 1080); const context = canvas.getContext("2d"); const actionBackground = await loadImage( opts.background, ); context.drawImage(actionBackground, 0, 0, canvas.width, canvas.height); const pUrl = new URL(encodeURI(opts.player)) const player = Object.fromEntries( Array.from(pUrl.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions const battler = await generateBattler(player); if (opts.position == "middle") { context.drawImage(battler, (1920 / 2) - 640, -100, battler.width, battler.height); } else { context.drawImage(battler, -50, -100, battler.width, battler.height); } res.setHeader('content-type', 'image/png'); return res.end(canvas.toBuffer("image/png"), 'binary') } if ( req.method == "GET" && url.pathname == "/playermap.png" ) { const opts = Object.fromEntries( Array.from(url.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as { player1: string, player2: string, map: string }; if (!opts.player1 || !opts.player2 || !opts.map) { res.writeHead(400, { 'content-type': "application/json" }) return res.end( JSON.stringify({ error: 'Did not pass all parameters', }) ); } const p1URL = new URL(encodeURI(opts.player1)) const p2URL = new URL(encodeURI(opts.player2)) const p1Opts = Object.fromEntries( Array.from(p1URL.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions const p2Opts = Object.fromEntries( Array.from(p2URL.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions const p1 = await generateBattler(p1Opts); const p2 = await generateBattler({ ...p2Opts, direction: "left" }) // Image dimensions const canvas = createCanvas(1920, 1080); const context = canvas.getContext("2d"); const Background = await loadImage( `./assets/locations/${opts.map}.png`, ); context.drawImage(Background, 0, 0, canvas.width, canvas.height); context.drawImage(p1, 140, 313, p1.width / 2, p1.height / 2); context.drawImage(p2, (canvas.width / 2) + 177, 313, p2.width / 2, p2.height / 2); res.setHeader('content-type', 'image/png'); return res.end(canvas.toBuffer("image/png"), 'binary') } if ( req.method == "GET" && url.pathname == "/map.png" ) { const opts = Object.fromEntries( Array.from(url.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as { player: string, map: string }; if (!opts.player || !opts.map) { res.writeHead(400, { 'content-type': "application/json" }) return res.end( JSON.stringify({ error: 'Did not pass all parameters', }) ); } const p1URL = new URL(encodeURI(opts.player)) const p1Opts = Object.fromEntries( Array.from(p1URL.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions const p1 = await generateBattler(p1Opts); // Image dimensions const canvas = createCanvas(1920, 1080); const context = canvas.getContext("2d"); const Background = await loadImage( `./assets/locations/${opts.map}.png`, ); context.drawImage(Background, 0, 0, canvas.width, canvas.height); context.drawImage(p1, 140, 313, p1.width / 2, p1.height / 2); res.setHeader('content-type', 'image/png'); return res.end(canvas.toBuffer("image/png"), 'binary') } if ( req.method == "GET" && url.pathname == "/pvp.png" ) { const opts = Object.fromEntries( Array.from(url.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as { player1: string, player2: string, username1: string, username2: string }; if (!opts.player1 || !opts.player2 || !opts.username1 || !opts.username2) { res.writeHead(400, { 'content-type': "application/json" }) return res.end( JSON.stringify({ error: 'Did not pass all parameters', }) ); } const p1URL = new URL(encodeURI(opts.player1)) const p2URL = new URL(encodeURI(opts.player2)) const p1Opts = Object.fromEntries( Array.from(p1URL.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions const p2Opts = Object.fromEntries( Array.from(p2URL.searchParams.entries()) .map(([key, value]) => [key, value.replaceAll('+', ' ')]), ) as GenerateBattlerOptions const p1 = await generateBattler(p1Opts); const p2 = await generateBattler({ ...p2Opts, direction: "left" }) // Image dimensions const canvas = createCanvas(1920, 1080); const context = canvas.getContext("2d"); const Background = await loadImage( `./assets/battlebgs/PvP.png`, ); context.drawImage(Background, 0, 0, canvas.width, canvas.height); context.drawImage(p1, -140, -100, p1.width, p1.height); context.drawImage(p2, (canvas.width / 2) - 180, -100, p2.width, p2.height); context.textAlign = "center" context.font = applyText(canvas, opts.username2, 675) drawText([1450, 1000], opts.username2, opts.username2 == "homeannor" ? "#AA00FF" : "#000000", { colour: "#FFFFFF", width: 20 }, context) context.font = applyText(canvas, opts.username1, 675) drawText([470, 1000], opts.username1, opts.username1 == "homeannor" ? "#AA00FF" : "#000000", { colour: "#FFFFFF", width: 20 }, context) res.setHeader('content-type', 'image/png'); return res.end(canvas.toBuffer("image/png"), 'binary') } res.writeHead(404) return res.end("404 Not Found") }) server.listen(60125, () => { console.log(`Listening on localhost:60125`) })