diff --git a/src/build/dataUrlPlugin.ts b/src/build/dataUrlPlugin.ts deleted file mode 100644 index 827367a..0000000 --- a/src/build/dataUrlPlugin.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { plugin, type BunPlugin } from "bun"; - -const dataUrlPlugin: BunPlugin = { - name: "Data-url loader", - async setup(build) { - build.onLoad({ filter: /\.(png)$/ }, async (args) => { - const arrayBuffer = await Bun.file(args.path).arrayBuffer(); - const buffer = Buffer.from(arrayBuffer); - - return { - contents: `data:;base64,${buffer.toString('base64')}`, - loader: 'text', - }; - }); - } -}; - -plugin(dataUrlPlugin); - -export default dataUrlPlugin; \ No newline at end of file diff --git a/src/build/html.ts b/src/build/html.ts index f5fb311..8d91d7d 100644 --- a/src/build/html.ts +++ b/src/build/html.ts @@ -1,7 +1,7 @@ import path from 'path'; import { minify } from 'html-minifier'; -import dataUrlPlugin from './dataUrlPlugin'; +import imagePlugin from './imagePlugin'; import fontPlugin from './fontPlugin'; import lightningcss from 'bun-lightningcss'; @@ -22,7 +22,7 @@ export async function buildHTML(game: string, production = false) { GAMES: JSON.stringify(await getGames()), }, plugins: [ - dataUrlPlugin, + imagePlugin, fontPlugin, lightningcss(), ] diff --git a/src/build/imagePlugin.ts b/src/build/imagePlugin.ts new file mode 100644 index 0000000..8ccb90d --- /dev/null +++ b/src/build/imagePlugin.ts @@ -0,0 +1,24 @@ +import { plugin, type BunPlugin } from "bun"; + +const imagePlugin: BunPlugin = { + name: "Image loader", + async setup(build) { + build.onLoad({ filter: /\.(png|jpe?g)$/ }, async (args) => { + const arrayBuffer = await Bun.file(args.path).arrayBuffer(); + const buffer = Buffer.from(arrayBuffer); + const src = `data:;base64,${buffer.toString('base64')}`; + return { + contents: ` + const img = new Image(); + img.src = (${JSON.stringify(src)}); + export default img; + `, + loader: 'js', + }; + }); + } +}; + +plugin(imagePlugin); + +export default imagePlugin; \ No newline at end of file diff --git a/src/games/text-dungeon/assets/WebPlus_IBM_VGA_8x16.woff b/src/common/assets/WebPlus_IBM_VGA_8x16.woff similarity index 100% rename from src/games/text-dungeon/assets/WebPlus_IBM_VGA_8x16.woff rename to src/common/assets/WebPlus_IBM_VGA_8x16.woff diff --git a/src/games/text-dungeon/assets/vga.font.css b/src/common/assets/vga.font.css similarity index 100% rename from src/games/text-dungeon/assets/vga.font.css rename to src/common/assets/vga.font.css diff --git a/src/common/types.d.ts b/src/common/types.d.ts new file mode 100644 index 0000000..319f497 --- /dev/null +++ b/src/common/types.d.ts @@ -0,0 +1,12 @@ +declare module "*.png" { + const image: HTMLImageElement; + export default image; +} +declare module "*.jpg" { + const image: HTMLImageElement; + export default image; +} +declare module "*.jpeg" { + const image: HTMLImageElement; + export default image; +} \ No newline at end of file diff --git a/src/common/utils.ts b/src/common/utils.ts index 26f86b7..c3436c7 100644 --- a/src/common/utils.ts +++ b/src/common/utils.ts @@ -1,3 +1,22 @@ export const delay = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); export const nextFrame = async (): Promise => new Promise((resolve) => requestAnimationFrame(resolve)); -export const randInt = (min: number, max: number) => Math.round(min + (max - min - 1) * Math.random()); \ No newline at end of file + +export const randInt = (min: number, max: number) => Math.round(min + (max - min - 1) * Math.random()); +export const choice = (array: any[]) => array[randInt(0, array.length)]; + +export const range = (size: number | string) => Object.keys((new Array(+size)).fill(0)).map(k => +k); + +export const prevent = (e: Event) => (e.preventDefault(), false); + +export const intHash = (seed: number, ...parts: number[]) => { + let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; + for (let i = 0; i < parts.length; i++) { + const ch = parts[i]; + h1 = Math.imul(h1 ^ ch, 2654435761); + h2 = Math.imul(h2 ^ ch, 1597334677); + } + h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507); + h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); + return h1; +}; +export const sinHash = (...data: number[]) => data.reduce((hash, n) => Math.sin((hash * 123.12 + n) * 756.12), 0) / 2 + 0.5; diff --git a/src/games/binario/game.ts b/src/games/binario/game.ts index c095ba6..215a37f 100644 --- a/src/games/binario/game.ts +++ b/src/games/binario/game.ts @@ -1,9 +1,10 @@ import Graphics from "./graphics"; import UI from "./ui"; import World from "./world"; -import { pointsEquals, prevent } from "./utils"; +import { pointsEquals } from "./utils"; +import { prevent } from "@common/utils"; -export default class Binario implements IGame { +export default class Binario { private running = false; private mouseDown: false | number = false; private graphics; diff --git a/src/games/binario/graphics.ts b/src/games/binario/graphics.ts index 2baac80..851835f 100644 --- a/src/games/binario/graphics.ts +++ b/src/games/binario/graphics.ts @@ -11,7 +11,6 @@ export default class Graphics { private offset: Point = [0, 0]; private highlighted: Point = [0, 0]; private tooltip: [Point, string] | null = null; - private firstStyleReset = false; constructor(private canvas: HTMLCanvasElement) { this.context = this.canvas.getContext('2d')!; diff --git a/src/games/binario/renderer.ts b/src/games/binario/renderer.ts index 6e64aa6..f266491 100644 --- a/src/games/binario/renderer.ts +++ b/src/games/binario/renderer.ts @@ -1,12 +1,12 @@ -import { type Tile, TileType, getPortDirections, PortDirection, LIMITS, type Resource, getTileOutput, ResourceType } from "./world"; +import { type Tile, TileType, getPortDirections, PortDirection, type Resource, getTileOutput, ResourceType } from "./world"; -import { ALL_DIRECTIONS, Direction, makeImage, movePoint } from "./utils"; +import { ALL_DIRECTIONS, Direction, movePoint } from "./utils"; -import emptySrc from './assets/img/empty.png'; -import extractorSrc from './assets/img/extractor.png'; -import notSrc from './assets/img/not.png'; -import andSrc from './assets/img/and.png'; -import orSrc from './assets/img/or.png'; +import emptyImage from './assets/img/empty.png'; +import extractorImage from './assets/img/extractor.png'; +import notImage from './assets/img/not.png'; +import andImage from './assets/img/and.png'; +import orImage from './assets/img/or.png'; export interface ViewConfig { tileSize: number; @@ -19,12 +19,6 @@ type Renderers = { [K in Tile['type']]?: Renderer> } -const emptyImage = makeImage(emptySrc); -const extractorImage = makeImage(extractorSrc); -const notImage = makeImage(notSrc); -const andImage = makeImage(andSrc); -const orImage = makeImage(orSrc); - export const renderResource = (ctx: CanvasRenderingContext2D, view: ViewConfig, tile: Tile) => { let resources: [Direction, Resource | undefined][] | undefined; if (tile.type === TileType.SOURCE) { diff --git a/src/games/binario/ui.tsx b/src/games/binario/ui.tsx index 1ddbdb5..37feb5f 100644 --- a/src/games/binario/ui.tsx +++ b/src/games/binario/ui.tsx @@ -1,14 +1,14 @@ import React, { render } from 'preact'; import cn from 'classnames'; -import { range } from './utils'; import { TileType } from './world'; import styles from './assets/ui.module.css'; -import conveyorSrc from './assets/img/conveyor.png'; -import extractorSrc from './assets/img/extractor.png'; -import notSrc from './assets/img/not.png'; -import andSrc from './assets/img/and.png'; -import orSrc from './assets/img/or.png'; +import conveyorImage from './assets/img/conveyor.png'; +import extractorImage from './assets/img/extractor.png'; +import notImage from './assets/img/not.png'; +import andImage from './assets/img/and.png'; +import orImage from './assets/img/or.png'; +import { range } from '@common/utils'; export enum ToolType { SELECT, @@ -30,31 +30,31 @@ const TOOLS: (Tool | null)[] = [ { type: ToolType.EXTRACTOR, title: 'Extractor', - icon: extractorSrc, + icon: extractorImage.src, tileType: TileType.EXTRACTOR, }, { type: ToolType.CONVEYOR, title: 'Conveyor', - icon: conveyorSrc, + icon: conveyorImage.src, tileType: TileType.CONVEYOR, }, { type: ToolType.NOT, title: 'Logical NOT', - icon: notSrc, + icon: notImage.src, tileType: TileType.NOT, }, { type: ToolType.AND, title: 'Logical AND', - icon: andSrc, + icon: andImage.src, tileType: TileType.AND, }, { type: ToolType.OR, title: 'Logical OR', - icon: orSrc, + icon: orImage.src, tileType: TileType.OR, }, null, // 6 diff --git a/src/games/binario/utils.ts b/src/games/binario/utils.ts index 2595c51..a1e1f24 100644 --- a/src/games/binario/utils.ts +++ b/src/games/binario/utils.ts @@ -105,22 +105,6 @@ export function trunc(input: Point): Point { const EPS = 0.001; export const pointsEquals = (a: Point, b: Point) => Math.abs(a[0] - b[0]) < EPS && Math.abs(a[1] - b[1]) < EPS; -export const prevent = (e: Event) => (e.preventDefault(), false); - -export const cyrb32 = (seed: number, ...parts: number[]) => { - let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; - for (let i = 0; i < parts.length; i++) { - const ch = parts[i]; - h1 = Math.imul(h1 ^ ch, 2654435761); - h2 = Math.imul(h2 ^ ch, 1597334677); - } - h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507); - h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); - return h1; -}; -export const sinHash = (...data: number[]) => data.reduce((hash, n) => Math.sin((hash * 123.12 + n) * 756.12), 0) / 2 + 0.5; -export const range = (size: number | string) => Object.keys((new Array(+size)).fill(0)).map(k => +k); - export const getDirection = (point: Point): Direction => { const [x, y] = point; const absX = Math.abs(x); @@ -157,10 +141,4 @@ export const ALL_DIRECTIONS = [Direction.NORTH, Direction.EAST, Direction.SOUTH, export const movePoint = (point: Point, direction: Direction, scale: number = 1): Point => [ point[0] + DIRECTION_VECTORS[direction][0] * scale, point[1] + DIRECTION_VECTORS[direction][1] * scale, -]; - -export const makeImage = (src: string): HTMLImageElement => { - const image = new Image(); - image.src = src; - return image; -} \ No newline at end of file +]; \ No newline at end of file diff --git a/src/games/binario/world.ts b/src/games/binario/world.ts index 1548846..ed2edc3 100644 --- a/src/games/binario/world.ts +++ b/src/games/binario/world.ts @@ -1,4 +1,5 @@ -import { ALL_DIRECTIONS, Direction, NEXT_DIRECTION, cyrb32, exp, getDirection, getOppositeDirection, isDirection, movePoint, pointsEquals, trunc } from "./utils"; +import { intHash } from "@common/utils"; +import { ALL_DIRECTIONS, Direction, NEXT_DIRECTION, exp, getDirection, getOppositeDirection, isDirection, movePoint, pointsEquals, trunc } from "./utils"; export enum TileType { DESTINATION, @@ -343,7 +344,7 @@ export default class World { } private genTile(position: Point): Tile | null { - const hash = cyrb32(this.seed, ...position); + const hash = intHash(this.seed, ...position); if ([42, 69, 0x42, 0x69].includes(hash & 0xFF)) { let mask = 1; diff --git a/src/games/text-dungeon/index.ts b/src/games/text-dungeon/index.ts index 30c455b..a2e84ba 100644 --- a/src/games/text-dungeon/index.ts +++ b/src/games/text-dungeon/index.ts @@ -1,7 +1,5 @@ - - +import '@common/assets/vga.font.css'; import './assets/style.css'; -import './assets/vga.font.css'; export default async function run(canvas: HTMLCanvasElement) { canvas.remove(); diff --git a/src/games/text-dungeon/utils.ts b/src/games/text-dungeon/utils.ts index 8e887ad..47368d7 100644 --- a/src/games/text-dungeon/utils.ts +++ b/src/games/text-dungeon/utils.ts @@ -6,8 +6,6 @@ export const randChar = (min = ' ', max = '~') => max.charCodeAt(0) + 1, )); -export const choice = (array: any[]) => array[randInt(0, array.length)]; - export const generateColors = () => { const colors: string[] = []; for (let i = 0; i < 16; i++) { diff --git a/src/types.d.ts b/src/types.d.ts index 93c375f..ef49af1 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -3,10 +3,6 @@ type Rect = [number, number, number, number]; type RunGame = (canvas: HTMLCanvasElement) => Promise; -declare module "*.png" { - const content: string; - export default content; -} declare module '*.module.css' { const classes: { [key: string]: string }; export default classes;