import type { DataModel } from '@mcschema/core' import { Path } from '@mcschema/core' import rfdc from 'rfdc' import config from '../config.json' export function isPromise(obj: any): obj is Promise { return typeof (obj as any)?.then === 'function' } export function isObject(obj: any) { return typeof obj === 'object' && obj !== null } const dec2hex = (dec: number) => ('0' + dec.toString(16)).substr(-2) export function hexId(length = 12) { var arr = new Uint8Array(length / 2) window.crypto.getRandomValues(arr) return Array.from(arr, dec2hex).join('') } export function randomSeed() { return BigInt(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)) } export function newSeed(model: DataModel) { const seed = Math.floor(Math.random() * (4294967296)) - 2147483648 const dimensions = model.get(new Path(['dimensions'])) model.set(new Path(['seed']), seed, true) if (typeof dimensions === 'object' && dimensions !== null) { Object.keys(dimensions).forEach(id => { model.set(new Path(['dimensions', id, 'generator', 'seed']), seed, true) model.set(new Path(['dimensions', id, 'generator', 'biome_source', 'seed']), seed, true) }) } model.set(new Path(['generator', 'seed']), seed, true) model.set(new Path(['generator', 'biome_source', 'seed']), seed) } export function htmlEncode(str: string) { return str.replace(/&/g, '&').replace(//g, '>') .replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/') } export function hashString(s: string) { let h = 0 for(let i = 0; i < s.length; i++) h = Math.imul(31, h) + s.charCodeAt(i) | 0 return h } export function cleanUrl(url: string) { return `/${url}/`.replaceAll('//', '/') } export function getGenerator(url: string) { const trimmedUrl = url.replace(/^\//, '').replace(/\/$/, '') return config.generators.find(g => g.url === trimmedUrl) } export function stringToColor(str: string): [number, number, number] { const h = Math.abs(hashString(str)) return [h % 256, (h >> 8) % 256, (h >> 16) % 256] } export function square(a: number) { return a * a } export function clamp(a: number, b: number, c: number) { return Math.max(a, Math.min(b, c)) } export function clampedLerp(a: number, b: number, c: number): number { if (c < 0) { return a } else if (c > 1) { return b } else { return lerp(c, a, b) } } export function lerp(a: number, b: number, c: number): number { return b + a * (c - b) } export function lerp2(a: number, b: number, c: number, d: number, e: number, f: number): number { return lerp(b, lerp(a, c, d), lerp(a, e, f)) } export function lerp3(a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) { return lerp(c, lerp2(a, b, d, e, f, g), lerp2(a, b, h, i, j, k)) } export function smoothstep(x: number): number { return x * x * x * (x * (x * 6 - 15) + 10) } export function message(e: unknown): string { if (e instanceof Error) return e.message return `${e}` } export const deepClone = rfdc() /** * MIT License * * Copyright (c) 2017 Evgeny Poberezkin * * https://github.com/epoberezkin/fast-deep-equal/blob/master/LICENSE */ export function deepEqual(a: any, b: any) { if (a === b) return true if (a && b && typeof a == 'object' && typeof b == 'object') { if (a.constructor !== b.constructor) return false let length, i if (Array.isArray(a)) { length = a.length if (length != b.length) return false for (i = 0; i < length; i++) { if (!deepEqual(a[i], b[i])) return false } return true } if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf() if (a.toString !== Object.prototype.toString) return a.toString() === b.toString() const keys = Object.keys(a) length = keys.length if (length !== Object.keys(b).length) return false for (i = length; i-- !== 0;) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false for (i = length; i-- !== 0;) { const key = keys[i] if (!deepEqual(a[key], b[key])) return false } return true } return a !== a && b !== b } export function unwrapLists(value: any): any { if (Array.isArray(value)) { return value.map(v => unwrapLists(v.node)) } else if (typeof value === 'object' && value !== null) { const res: Record = {} Object.entries(value).map(([k, v]) => { res[k] = unwrapLists(v) }) return res } else { return value } }