Use spyglass DocAndNode to store current file data

This commit is contained in:
Misode
2024-10-16 04:36:59 +02:00
parent 7dbd533abb
commit 77d6323219
32 changed files with 244 additions and 240 deletions

View File

@@ -3,7 +3,7 @@ import { mat3 } from 'gl-matrix'
import { useCallback, useRef, useState } from 'preact/hooks'
import { getProjectData, useLocale, useProject, useStore, useVersion } from '../../contexts/index.js'
import { useAsync } from '../../hooks/index.js'
import { checkVersion } from '../../services/Schemas.js'
import { checkVersion } from '../../services/Versions.js'
import { Store } from '../../Store.js'
import { iterateWorld2D, randomSeed, stringToColor } from '../../Utils.js'
import { Btn, BtnMenu, NumberInput } from '../index.js'
@@ -20,7 +20,7 @@ type Layer = typeof LAYERS[number]
const DETAIL_DELAY = 300
const DETAIL_SCALE = 2
export const BiomeSourcePreview = ({ model, shown }: PreviewProps) => {
export const BiomeSourcePreview = ({ docAndNode, shown }: PreviewProps) => {
const { locale } = useLocale()
const { version } = useVersion()
const { project } = useProject()
@@ -31,18 +31,19 @@ export const BiomeSourcePreview = ({ model, shown }: PreviewProps) => {
const [focused, setFocused] = useState<string[]>([])
const [focused2, setFocused2] = useState<string[]>([])
const state = JSON.stringify(model.data)
const type: string = model.data?.generator?.biome_source?.type?.replace(/^minecraft:/, '') ?? ''
const text = docAndNode.doc.getText()
const data = JSON.parse(text)
const type: string = data?.generator?.biome_source?.type?.replace(/^minecraft:/, '') ?? ''
const hasRandomness = type === 'multi_noise' || type === 'the_end'
const { value } = useAsync(async function loadBiomeSource() {
await DEEPSLATE.loadVersion(version, getProjectData(project))
await DEEPSLATE.loadChunkGenerator(model.data?.generator?.settings, model.data?.generator?.biome_source, seed)
await DEEPSLATE.loadChunkGenerator(data?.generator?.settings, data?.generator?.biome_source, seed)
return {
biomeSource: { loaded: true },
noiseRouter: checkVersion(version, '1.19') ? DEEPSLATE.getNoiseRouter() : undefined,
}
}, [state, seed, project, version])
}, [text, seed, project, version])
const { biomeSource, noiseRouter } = value ?? {}
const actualLayer = noiseRouter ? layer : 'biomes'

View File

@@ -10,14 +10,15 @@ import { InteractiveCanvas3D } from './InteractiveCanvas3D.jsx'
const PREVIEW_ID = Identifier.parse('misode:preview')
export const BlockStatePreview = ({ model, shown }: PreviewProps) => {
export const BlockStatePreview = ({ docAndNode, shown }: PreviewProps) => {
const { version } = useVersion()
const serializedData = JSON.stringify(model.data)
const text = docAndNode.doc.getText()
const { value: resources } = useAsync(async () => {
if (!shown) return AsyncCancel
const resources = await getResources(version)
const definition = BlockDefinition.fromJson(model.data)
const definition = BlockDefinition.fromJson(JSON.parse(text))
const wrapper = new ResourceWrapper(resources, {
getBlockDefinition(id) {
if (id.equals(PREVIEW_ID)) return definition
@@ -25,7 +26,7 @@ export const BlockStatePreview = ({ model, shown }: PreviewProps) => {
},
})
return wrapper
}, [shown, version, serializedData])
}, [shown, version, text])
const renderer = useRef<StructureRenderer | undefined>(undefined)

View File

@@ -9,11 +9,12 @@ import { decorateChunk } from './Decorator.js'
import type { PreviewProps } from './index.js'
import { InteractiveCanvas2D } from './InteractiveCanvas2D.jsx'
export const DecoratorPreview = ({ model, shown }: PreviewProps) => {
export const DecoratorPreview = ({ docAndNode, shown }: PreviewProps) => {
const { locale } = useLocale()
const { version } = useVersion()
const [seed, setSeed] = useState(randomSeed())
const state = JSON.stringify(model.data)
const text = docAndNode.doc.getText()
const { context, chunkFeatures } = useMemo(() => {
const random = new LegacyRandom(seed)
@@ -32,7 +33,7 @@ export const DecoratorPreview = ({ model, shown }: PreviewProps) => {
context,
chunkFeatures: new Map<string, PlacedFeature[]>(),
}
}, [state, version, seed])
}, [text, version, seed])
const ctx = useRef<CanvasRenderingContext2D>()
const imageData = useRef<ImageData>()
@@ -49,10 +50,10 @@ export const DecoratorPreview = ({ model, shown }: PreviewProps) => {
}, [])
const onDraw = useCallback(function onDraw(transform: mat3) {
if (!ctx.current || !imageData.current || !shown) return
const data = JSON.parse(text)
iterateWorld2D(imageData.current, transform, (x, y) => {
const pos = ChunkPos.create(Math.floor(x / 16), Math.floor(-y / 16))
const features = computeIfAbsent(chunkFeatures, `${pos[0]} ${pos[1]}`, () => decorateChunk(pos, model.data, context))
const features = computeIfAbsent(chunkFeatures, `${pos[0]} ${pos[1]}`, () => decorateChunk(pos, data, context))
return features.find(f => f.pos[0] === x && f.pos[2] == -y) ?? { pos: BlockPos.create(x, 0, -y) }
}, (feature) => {
if ('color' in feature) {

View File

@@ -18,7 +18,7 @@ import { InteractiveCanvas3D } from './InteractiveCanvas3D.jsx'
const MODES = ['side', 'top', '3d'] as const
export const DensityFunctionPreview = ({ model, shown }: PreviewProps) => {
export const DensityFunctionPreview = ({ docAndNode, shown }: PreviewProps) => {
const { locale } = useLocale()
const { project } = useProject()
const { version } = useVersion()
@@ -28,13 +28,14 @@ export const DensityFunctionPreview = ({ model, shown }: PreviewProps) => {
const [seed, setSeed] = useState(randomSeed())
const [minY] = useState(0)
const [height] = useState(256)
const serializedData = JSON.stringify(model.data)
const text = docAndNode.doc.getText()
const { value: df } = useAsync(async () => {
await DEEPSLATE.loadVersion(version, getProjectData(project))
const df = DEEPSLATE.loadDensityFunction(model.data, minY, height, seed)
const df = DEEPSLATE.loadDensityFunction(JSON.parse(text), minY, height, seed)
return df
}, [version, project, minY, height, seed, serializedData])
}, [version, project, minY, height, seed, text])
// === 2D ===
const imageData = useRef<ImageData>()

View File

@@ -3,7 +3,7 @@ import type { Random } from 'deepslate/core'
import { Identifier, ItemStack, LegacyRandom } from 'deepslate/core'
import { NbtCompound, NbtInt, NbtList, NbtString, NbtTag } from 'deepslate/nbt'
import { ResolvedItem } from '../../services/ResolvedItem.js'
import type { VersionId } from '../../services/Schemas.js'
import type { VersionId } from '../../services/Versions.js'
import { clamp, getWeightedRandom, isObject, jsonToNbt } from '../../Utils.js'
export interface SlottedItem {

View File

@@ -1,7 +1,7 @@
import type { Random } from 'deepslate-1.20.4/core'
import { Enchantment, Identifier, ItemStack, LegacyRandom } from 'deepslate-1.20.4/core'
import { NbtCompound, NbtInt, NbtList, NbtShort, NbtString, NbtTag, NbtType } from 'deepslate-1.20.4/nbt'
import type { VersionId } from '../../services/Schemas.js'
import type { VersionId } from '../../services/Versions.js'
import { clamp, getWeightedRandom, isObject } from '../../Utils.js'
export interface SlottedItem {

View File

@@ -11,7 +11,7 @@ import type { PreviewProps } from './index.js'
import { generateLootTable } from './LootTable.js'
import { generateLootTable as generateLootTable1204 } from './LootTable1204.js'
export const LootTablePreview = ({ model }: PreviewProps) => {
export const LootTablePreview = ({ docAndNode }: PreviewProps) => {
const { locale } = useLocale()
const { version } = useVersion()
const use1204 = !checkVersion(version, '1.20.5')
@@ -34,13 +34,13 @@ export const LootTablePreview = ({ model }: PreviewProps) => {
])
}, [version])
const table = model.data
const state = JSON.stringify(table)
const text = docAndNode.doc.getText()
const items = useMemo(() => {
if (dependencies === undefined || loading) {
return []
}
const [itemTags, lootTables, itemComponents, enchantments, enchantmentTags] = dependencies
const table = JSON.parse(text)
if (use1204) {
return generateLootTable1204(table, {
version, seed, luck, daytime, weather,
@@ -60,7 +60,7 @@ export const LootTablePreview = ({ model }: PreviewProps) => {
getEnchantmentTag: (id) => (enchantmentTags?.get(id.replace(/^minecraft:/, '')) as any)?.values ?? [],
getBaseComponents: (id) => new Map([...(itemComponents?.get(Identifier.parse(id).toString()) ?? new Map()).entries()].map(([k, v]) => [k, jsonToNbt(v)])),
})
}, [version, seed, luck, daytime, weather, mixItems, state, dependencies, loading])
}, [version, seed, luck, daytime, weather, mixItems, text, dependencies, loading])
return <>
<div ref={overlay} class="preview-overlay">

View File

@@ -11,14 +11,15 @@ import { InteractiveCanvas3D } from './InteractiveCanvas3D.jsx'
const PREVIEW_ID = Identifier.parse('misode:preview')
const PREVIEW_DEFINITION = new BlockDefinition({ '': { model: PREVIEW_ID.toString() }}, undefined)
export const ModelPreview = ({ model, shown }: PreviewProps) => {
export const ModelPreview = ({ docAndNode, shown }: PreviewProps) => {
const { version } = useVersion()
const serializedData = JSON.stringify(model.data)
const text = docAndNode.doc.getText()
const { value: resources } = useAsync(async () => {
if (!shown) return AsyncCancel
const resources = await getResources(version)
const blockModel = BlockModel.fromJson(model.data)
const blockModel = BlockModel.fromJson(JSON.parse(text))
blockModel.flatten(resources)
const wrapper = new ResourceWrapper(resources, {
getBlockDefinition(id) {
@@ -31,7 +32,7 @@ export const ModelPreview = ({ model, shown }: PreviewProps) => {
},
})
return wrapper
}, [shown, version, serializedData])
}, [shown, version, text])
const renderer = useRef<StructureRenderer | undefined>(undefined)

View File

@@ -11,16 +11,17 @@ import { ColormapSelector } from './ColormapSelector.jsx'
import type { PreviewProps } from './index.js'
import { InteractiveCanvas2D } from './InteractiveCanvas2D.jsx'
export const NoisePreview = ({ model, shown }: PreviewProps) => {
export const NoisePreview = ({ docAndNode, shown }: PreviewProps) => {
const { locale } = useLocale()
const [seed, setSeed] = useState(randomSeed())
const state = JSON.stringify(model.data)
const text = docAndNode.doc.getText()
const noise = useMemo(() => {
const random = XoroshiroRandom.create(seed)
const params = NoiseParameters.fromJson(model.data)
const params = NoiseParameters.fromJson(JSON.parse(text))
return new NormalNoise(random, params)
}, [state, seed])
}, [text, seed])
const imageData = useRef<ImageData>()
const ctx = useRef<CanvasRenderingContext2D>()

View File

@@ -15,24 +15,25 @@ import { DEEPSLATE } from './Deepslate.js'
import type { PreviewProps } from './index.js'
import { InteractiveCanvas2D } from './InteractiveCanvas2D.jsx'
export const NoiseSettingsPreview = ({ model, shown }: PreviewProps) => {
export const NoiseSettingsPreview = ({ docAndNode, shown }: PreviewProps) => {
const { locale } = useLocale()
const { version } = useVersion()
const { project } = useProject()
const [seed, setSeed] = useState(randomSeed())
const [biome, setBiome] = useState('minecraft:plains')
const [layer, setLayer] = useState('terrain')
const state = JSON.stringify(model.data)
const text = docAndNode.doc.getText()
const { value, error } = useAsync(async () => {
const unwrapped = model.data
const data = JSON.parse(text)
await DEEPSLATE.loadVersion(version, getProjectData(project))
const biomeSource = { type: 'fixed', biome }
await DEEPSLATE.loadChunkGenerator(unwrapped, biomeSource, seed)
await DEEPSLATE.loadChunkGenerator(data, biomeSource, seed)
const noiseSettings = DEEPSLATE.getNoiseSettings()
const finalDensity = DEEPSLATE.loadDensityFunction(unwrapped?.noise_router?.final_density, noiseSettings.minY, noiseSettings.height, seed)
const finalDensity = DEEPSLATE.loadDensityFunction(data?.noise_router?.final_density, noiseSettings.minY, noiseSettings.height, seed)
return { noiseSettings, finalDensity }
}, [state, seed, version, project, biome])
}, [text, seed, version, project, biome])
const { noiseSettings, finalDensity } = value ?? {}
const imageData = useRef<ImageData>()

View File

@@ -11,7 +11,7 @@ import type { PreviewProps } from './index.js'
const ANIMATION_TIME = 1000
export const RecipePreview = ({ model }: PreviewProps) => {
export const RecipePreview = ({ docAndNode }: PreviewProps) => {
const { locale } = useLocale()
const { version } = useVersion()
const [advancedTooltips, setAdvancedTooltips] = useState(true)
@@ -29,11 +29,11 @@ export const RecipePreview = ({ model }: PreviewProps) => {
return () => clearInterval(interval)
}, [])
const recipe = model.data
const state = JSON.stringify(recipe)
const text = docAndNode.doc.getText()
const recipe = JSON.parse(text)
const items = useMemo<Map<Slot, ItemStack>>(() => {
return placeItems(version, recipe, animation, itemTags ?? new Map())
}, [state, animation, itemTags])
}, [text, animation, itemTags])
const gui = useMemo(() => {
const type = recipe.type?.replace(/^minecraft:/, '')
@@ -46,7 +46,7 @@ export const RecipePreview = ({ model }: PreviewProps) => {
} else {
return '/images/crafting_table.png'
}
}, [state])
}, [text])
return <>
<div ref={overlay} class="preview-overlay">

View File

@@ -12,17 +12,18 @@ import { DEEPSLATE } from './Deepslate.js'
import type { PreviewProps } from './index.js'
import { InteractiveCanvas2D } from './InteractiveCanvas2D.jsx'
export const StructureSetPreview = ({ model, shown }: PreviewProps) => {
export const StructureSetPreview = ({ docAndNode, shown }: PreviewProps) => {
const { locale } = useLocale()
const { version } = useVersion()
const [seed, setSeed] = useState(randomSeed())
const state = JSON.stringify(model.data)
const text = docAndNode.doc.getText()
const { value: structureSet } = useAsync(async () => {
await DEEPSLATE.loadVersion(version)
const structureSet = DEEPSLATE.loadStructureSet(model.data, seed)
const structureSet = DEEPSLATE.loadStructureSet(JSON.parse(text), seed)
return structureSet
}, [state, version, seed])
}, [text, version, seed])
const { chunkStructures, structureColors } = useMemo(() => {
return {

View File

@@ -1,4 +1,4 @@
import type { FileModel } from '../../services/index.js'
import type { DocAndNode } from '@spyglassmc/core'
export * from './BiomeSourcePreview.js'
export * from './BlockStatePreview.jsx'
@@ -12,6 +12,6 @@ export * from './RecipePreview.jsx'
export * from './StructureSetPreview.jsx'
export interface PreviewProps {
model: FileModel
docAndNode: DocAndNode
shown: boolean
}