From 7dbd533abb60b43339c708823bc5ef061e53abdb Mon Sep 17 00:00:00 2001 From: Misode Date: Tue, 15 Oct 2024 23:25:56 +0200 Subject: [PATCH] Add mcmeta-summary symbol registrar and initialize remaining --- package-lock.json | 88 ++++++++++++ package.json | 6 +- .../components/generator/SchemaGenerator.tsx | 4 +- src/app/services/DataFetcher.ts | 8 ++ src/app/services/Spyglass.ts | 132 +++++++++++++++++- 5 files changed, 231 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3cc57471..a3105a5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,11 @@ "dependencies": { "@giscus/react": "^2.2.3", "@spyglassmc/core": "^0.4.14", + "@spyglassmc/java-edition": "^0.3.17", + "@spyglassmc/json": "^0.3.16", + "@spyglassmc/locales": "^0.3.8", "@spyglassmc/mcdoc": "^0.3.17", + "@spyglassmc/nbt": "^0.3.17", "@zip.js/zip.js": "^2.4.5", "brace": "^0.11.1", "buffer": "^6.0.3", @@ -753,6 +757,29 @@ "whatwg-url": "^14.0.0" } }, + "node_modules/@spyglassmc/java-edition": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@spyglassmc/java-edition/-/java-edition-0.3.17.tgz", + "integrity": "sha512-XO7bX/xowN21lwdtqP+6NsGAtfrdXWRcXoe8ByHUxHqtFXwp1ifSY7Lg76nlUm/FSOMM2QXUEh3QDj2Wr0wJyA==", + "dependencies": { + "@spyglassmc/core": "0.4.14", + "@spyglassmc/json": "0.3.16", + "@spyglassmc/locales": "0.3.8", + "@spyglassmc/mcdoc": "0.3.17", + "@spyglassmc/mcfunction": "0.2.16", + "@spyglassmc/nbt": "0.3.17" + } + }, + "node_modules/@spyglassmc/json": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@spyglassmc/json/-/json-0.3.16.tgz", + "integrity": "sha512-rBOeXWjPn1xsuaYECqkX+iclNf0EYqCq6jj8zb1+9IeaEeYSVOEUevKvYNqtk0++5UPBruXbBAOuJI08GRMQWQ==", + "dependencies": { + "@spyglassmc/core": "0.4.14", + "@spyglassmc/locales": "0.3.8", + "@spyglassmc/mcdoc": "0.3.17" + } + }, "node_modules/@spyglassmc/locales": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@spyglassmc/locales/-/locales-0.3.8.tgz", @@ -767,6 +794,25 @@ "@spyglassmc/locales": "0.3.8" } }, + "node_modules/@spyglassmc/mcfunction": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/@spyglassmc/mcfunction/-/mcfunction-0.2.16.tgz", + "integrity": "sha512-Iwo8Akp/MuIsDkzzCumHfPNK9zgxsVw5sVEq1H6f3RWPJFrnhwx0bQRR80pqjiHhIuli/g2pxv195wsAU1PDHA==", + "dependencies": { + "@spyglassmc/core": "0.4.14", + "@spyglassmc/locales": "0.3.8" + } + }, + "node_modules/@spyglassmc/nbt": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@spyglassmc/nbt/-/nbt-0.3.17.tgz", + "integrity": "sha512-Jk8yjN5HFy/GF6fUjP0oJatz4oNJ1EE6NtfpctjeznQLNG51Xj/FDeJybnKYksM+V/nj7eth9mLyRjkMcTUcAw==", + "dependencies": { + "@spyglassmc/core": "0.4.14", + "@spyglassmc/locales": "0.3.8", + "@spyglassmc/mcdoc": "0.3.17" + } + }, "node_modules/@types/diff": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.2.2.tgz", @@ -5176,6 +5222,29 @@ "whatwg-url": "^14.0.0" } }, + "@spyglassmc/java-edition": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@spyglassmc/java-edition/-/java-edition-0.3.17.tgz", + "integrity": "sha512-XO7bX/xowN21lwdtqP+6NsGAtfrdXWRcXoe8ByHUxHqtFXwp1ifSY7Lg76nlUm/FSOMM2QXUEh3QDj2Wr0wJyA==", + "requires": { + "@spyglassmc/core": "0.4.14", + "@spyglassmc/json": "0.3.16", + "@spyglassmc/locales": "0.3.8", + "@spyglassmc/mcdoc": "0.3.17", + "@spyglassmc/mcfunction": "0.2.16", + "@spyglassmc/nbt": "0.3.17" + } + }, + "@spyglassmc/json": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@spyglassmc/json/-/json-0.3.16.tgz", + "integrity": "sha512-rBOeXWjPn1xsuaYECqkX+iclNf0EYqCq6jj8zb1+9IeaEeYSVOEUevKvYNqtk0++5UPBruXbBAOuJI08GRMQWQ==", + "requires": { + "@spyglassmc/core": "0.4.14", + "@spyglassmc/locales": "0.3.8", + "@spyglassmc/mcdoc": "0.3.17" + } + }, "@spyglassmc/locales": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@spyglassmc/locales/-/locales-0.3.8.tgz", @@ -5190,6 +5259,25 @@ "@spyglassmc/locales": "0.3.8" } }, + "@spyglassmc/mcfunction": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/@spyglassmc/mcfunction/-/mcfunction-0.2.16.tgz", + "integrity": "sha512-Iwo8Akp/MuIsDkzzCumHfPNK9zgxsVw5sVEq1H6f3RWPJFrnhwx0bQRR80pqjiHhIuli/g2pxv195wsAU1PDHA==", + "requires": { + "@spyglassmc/core": "0.4.14", + "@spyglassmc/locales": "0.3.8" + } + }, + "@spyglassmc/nbt": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@spyglassmc/nbt/-/nbt-0.3.17.tgz", + "integrity": "sha512-Jk8yjN5HFy/GF6fUjP0oJatz4oNJ1EE6NtfpctjeznQLNG51Xj/FDeJybnKYksM+V/nj7eth9mLyRjkMcTUcAw==", + "requires": { + "@spyglassmc/core": "0.4.14", + "@spyglassmc/locales": "0.3.8", + "@spyglassmc/mcdoc": "0.3.17" + } + }, "@types/diff": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.2.2.tgz", diff --git a/package.json b/package.json index 9ba12431..bfda0f0b 100644 --- a/package.json +++ b/package.json @@ -17,15 +17,19 @@ "dependencies": { "@giscus/react": "^2.2.3", "@spyglassmc/core": "^0.4.14", + "@spyglassmc/java-edition": "^0.3.17", + "@spyglassmc/json": "^0.3.16", + "@spyglassmc/locales": "^0.3.8", "@spyglassmc/mcdoc": "^0.3.17", + "@spyglassmc/nbt": "^0.3.17", "@zip.js/zip.js": "^2.4.5", "brace": "^0.11.1", "buffer": "^6.0.3", "comment-json": "^4.1.1", + "deepslate": "^0.22.3", "deepslate-1.18": "npm:deepslate@0.9.0-beta.9", "deepslate-1.18.2": "npm:deepslate@0.9.0", "deepslate-1.20.4": "npm:deepslate@0.20.1", - "deepslate": "^0.22.3", "diff": "^7.0.0", "highlight.js": "^11.5.1", "howler": "^2.2.3", diff --git a/src/app/components/generator/SchemaGenerator.tsx b/src/app/components/generator/SchemaGenerator.tsx index 0872c960..b3c4663b 100644 --- a/src/app/components/generator/SchemaGenerator.tsx +++ b/src/app/components/generator/SchemaGenerator.tsx @@ -32,8 +32,8 @@ export function SchemaGenerator({ gen, allowedVersions }: Props) { useEffect(() => Store.visitGenerator(gen.id), [gen.id]) useEffect(() => { - setupSpyglass() - }, []) + setupSpyglass(version) + }, [version]) const [currentPreset, setCurrentPreset] = useSearchParam('preset') const [sharedSnippetId, setSharedSnippetId] = useSearchParam(SHARE_KEY) diff --git a/src/app/services/DataFetcher.ts b/src/app/services/DataFetcher.ts index 748aeb4c..66ea62ab 100644 --- a/src/app/services/DataFetcher.ts +++ b/src/app/services/DataFetcher.ts @@ -40,6 +40,14 @@ async function validateCache(version: RefInfo) { } } +export function getVersionChecksum(versionId: VersionId) { + const version = config.versions.find(v => v.id === versionId)! + if (version.dynamic) { + return (localStorage.getItem(CACHE_LATEST_VERSION) ?? '').toString() + } + return version.ref +} + export async function fetchVanillaMcdoc() { try { // TODO: enable refresh diff --git a/src/app/services/Spyglass.ts b/src/app/services/Spyglass.ts index 373320f2..f38e45c1 100644 --- a/src/app/services/Spyglass.ts +++ b/src/app/services/Spyglass.ts @@ -1,8 +1,18 @@ import * as core from '@spyglassmc/core' import { BrowserExternals } from '@spyglassmc/core/lib/browser.js' +import type { McmetaSummary } from '@spyglassmc/java-edition/lib/dependency/index.js' +import { Fluids, ReleaseVersion, symbolRegistrar } from '@spyglassmc/java-edition/lib/dependency/index.js' +import * as jeJson from '@spyglassmc/java-edition/lib/json/index.js' +import * as jeMcf from '@spyglassmc/java-edition/lib/mcfunction/index.js' +import * as json from '@spyglassmc/json' +import { localize } from '@spyglassmc/locales' import * as mcdoc from '@spyglassmc/mcdoc' +import * as nbt from '@spyglassmc/nbt' import * as zip from '@zip.js/zip.js' -import { fetchVanillaMcdoc } from './index.js' +import type { ConfigVersion } from '../Config.js' +import siteConfig from '../Config.js' +import type { VersionId } from './index.js' +import { fetchBlockStates, fetchRegistries, fetchVanillaMcdoc, getVersionChecksum } from './index.js' const externals: core.Externals = { ...BrowserExternals, @@ -21,7 +31,9 @@ const externals: core.Externals = { }, } -export async function setupSpyglass() { +export async function setupSpyglass(versionId: VersionId) { + const version = siteConfig.versions.find(v => v.id === versionId)! + const gameVersion = version.ref ?? version.id const logger: core.Logger = console const profilers = new core.ProfilerFactory(logger, [ 'project#init', @@ -37,7 +49,10 @@ export async function setupSpyglass() { projectRoots: ['file:project/'], externals: externals, defaultConfig: core.ConfigService.merge(core.VanillaConfig, { - env: { dependencies: ['@vanilla-mcdoc'] }, + env: { + gameVersion: gameVersion, + dependencies: ['@vanilla-mcdoc'], + }, }), initializers: [mcdoc.initialize, initialize], }, @@ -52,7 +67,7 @@ export async function setupSpyglass() { } const initialize: core.ProjectInitializer = async (ctx) => { - const { meta, externals, cacheRoot } = ctx + const { config, logger, meta, externals, cacheRoot } = ctx meta.registerDependencyProvider('@vanilla-mcdoc', async () => { const uri: string = new core.Uri('downloads/vanilla-mcdoc.tar.gz', cacheRoot).toString() @@ -60,4 +75,113 @@ const initialize: core.ProjectInitializer = async (ctx) => { await core.fileUtil.writeFile(externals, uri, new Uint8Array(buffer)) return { info: { startDepth: 1 }, uri } }) + + const release = config.env.gameVersion as ReleaseVersion + const version = siteConfig.versions.find(v => { + return v.ref ? v.ref === release : v.id === release + }) + if (version === undefined) { + logger.error(`[initialize] Failed finding game version matching ${release}.`) + return + } + + const summary: McmetaSummary = { + registries: Object.fromEntries((await fetchRegistries(version.id)).entries()), + blocks: Object.fromEntries([...(await fetchBlockStates(version.id)).entries()] + .map(([id, data]) => [id, [data.properties, data.default]])), + fluids: Fluids, + commands: { type: 'root', children: {} }, + } + + meta.registerSymbolRegistrar('mcmeta-summary', { + checksum: getVersionChecksum(version.id), + registrar: symbolRegistrar(summary), + }) + + registerAttributes(meta, release) + + json.initialize(ctx) + jeJson.initialize(ctx) + jeMcf.initialize(ctx, summary.commands, release) + nbt.initialize(ctx) + + return { loadedVersion: release } +} + +// Duplicate these from spyglass for now, until they are exported separately +function registerAttributes(meta: core.MetaRegistry, release: ReleaseVersion) { + mcdoc.runtime.registerAttribute(meta, 'since', mcdoc.runtime.attribute.validator.string, { + filterElement: (config, ctx) => { + if (!config.startsWith('1.')) { + ctx.logger.warn(`Invalid mcdoc attribute for "since": ${config}`) + return true + } + return ReleaseVersion.cmp(release, config as ReleaseVersion) >= 0 + }, + }) + mcdoc.runtime.registerAttribute(meta, 'until', mcdoc.runtime.attribute.validator.string, { + filterElement: (config, ctx) => { + if (!config.startsWith('1.')) { + ctx.logger.warn(`Invalid mcdoc attribute for "until": ${config}`) + return true + } + return ReleaseVersion.cmp(release, config as ReleaseVersion) < 0 + }, + }) + mcdoc.runtime.registerAttribute( + meta, + 'deprecated', + mcdoc.runtime.attribute.validator.optional(mcdoc.runtime.attribute.validator.string), + { + mapField: (config, field, ctx) => { + if (config === undefined) { + return { ...field, deprecated: true } + } + if (!config.startsWith('1.')) { + ctx.logger.warn(`Invalid mcdoc attribute for "deprecated": ${config}`) + return field + } + if (ReleaseVersion.cmp(release, config as ReleaseVersion) >= 0) { + return { ...field, deprecated: true } + } + return field + }, + }, + ) + const packFormats = new Map() + for (const version of siteConfig.versions) { + packFormats.set(version.pack_format, version) + } + mcdoc.runtime.registerAttribute(meta, 'pack_format', () => undefined, { + checker: (_, typeDef) => { + if (typeDef.kind !== 'literal' || typeof typeDef.value.value !== 'number') { + return undefined + } + const target = typeDef.value.value + return (node, ctx) => { + const targetVersion = packFormats.get(target) + if (!targetVersion) { + ctx.err.report( + localize('java-edition.pack-format.unsupported', target), + node, + core.ErrorSeverity.Warning, + ) + } else if (targetVersion.id !== release) { + ctx.err.report( + localize('java-edition.pack-format.not-loaded', target, release), + node, + core.ErrorSeverity.Warning, + ) + } + } + }, + numericCompleter: (_, ctx) => { + return [...packFormats.values()].map((v, i) => ({ + range: core.Range.create(ctx.offset), + label: `${v.pack_format}`, + labelSuffix: ` (${v.id})`, + sortText: `${i}`.padStart(4, '0'), + } as core.CompletionItem)) + }, + }) }