import { DataModel } from '@mcschema/core' import type { Identifier } from 'deepslate' import { ChunkPos } from 'deepslate' import type { mat3 } from 'gl-matrix' import { useCallback, useMemo, useRef, useState } from 'preact/hooks' import type { Color } from '../../Utils.js' import { computeIfAbsent, iterateWorld2D, randomSeed, stringToColor } from '../../Utils.js' import { useLocale } from '../../contexts/index.js' import { useAsync } from '../../hooks/useAsync.js' import { Btn } from '../index.js' import { featureColors } from './Decorator.js' import { DEEPSLATE } from './Deepslate.js' import { InteractiveCanvas2D } from './InteractiveCanvas2D.jsx' import type { PreviewProps } from './index.js' export const StructureSetPreview = ({ data, version, shown }: PreviewProps) => { const { locale } = useLocale() const [seed, setSeed] = useState(randomSeed()) const state = JSON.stringify(data) const { value: structureSet } = useAsync(async () => { await DEEPSLATE.loadVersion(version) const structureSet = DEEPSLATE.loadStructureSet(DataModel.unwrapLists(data), seed) return structureSet }, [state, version, seed]) const { chunkStructures, structureColors } = useMemo(() => { return { chunkStructures: new Map(), structureColors: new Map(), } }, [structureSet]) const ctx = useRef() const imageData = useRef() const [focused, setFocused] = useState([]) const onSetup = useCallback(function onSetup(canvas: HTMLCanvasElement) { const ctx2D = canvas.getContext('2d') if (!ctx2D) return ctx.current = ctx2D }, []) const onResize = useCallback(function onResize(width: number, height: number) { if (!ctx.current) return imageData.current = ctx.current.getImageData(0, 0, width, height) }, []) const onDraw = useCallback(function onDraw(transform: mat3) { if (!ctx.current || !imageData.current || !shown || !structureSet) return const context = DEEPSLATE.getWorldgenStructureContext() if (!context) return iterateWorld2D(imageData.current, transform, (x, y) => { const pos = ChunkPos.create(x, y) const structure = computeIfAbsent(chunkStructures, `${pos[0]} ${pos[1]}`, () => structureSet?.getStructureInChunk(pos[0], pos[1], context)) return { structure, pos } }, ({ structure, pos }) => { if (structure !== undefined) { const color = computeIfAbsent(structureColors, structure.toString(), () => { const index = structureColors.size return index < featureColors.length ? featureColors[index] : stringToColor(structure.toString()) }) return [0.8 * color[0], 0.8 * color[1], 0.8 * color[2]] } if ((Math.floor(pos[0] / 32) + Math.floor(pos[1] / 32)) % 2 === 0) { return [0.85 * 256, 0.85 * 256, 0.85 * 256] } return [256, 256, 256] }) ctx.current.putImageData(imageData.current, 0, 0) }, [structureSet, chunkStructures, structureColors, shown]) const onHover = useCallback(function onHover(pos: [number, number] | undefined) { if (!pos) { setFocused([]) } else { const [x, y] = pos const context = DEEPSLATE.getWorldgenStructureContext() if (!context) return const structure = structureSet?.getStructureInChunk(x, -y, context) setFocused([...(structure ? [structure.toString().replace(/^minecraft:/, '')] : []), `X=${x << 4} Z=${(-y) << 4}`]) } }, [structureSet]) return <>
{focused.map(s => )} setSeed(randomSeed())} />
}