mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-23 07:10:41 +00:00
Validate block states
This commit is contained in:
6
package-lock.json
generated
6
package-lock.json
generated
@@ -5033,9 +5033,9 @@
|
||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz",
|
||||
"integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ=="
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
|
||||
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg=="
|
||||
},
|
||||
"union-value": {
|
||||
"version": "1.0.1",
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"selfsigned": "^1.10.8",
|
||||
"split.js": "^1.5.11",
|
||||
"ts-loader": "^7.0.4",
|
||||
"typescript": "^3.9.3",
|
||||
"typescript": "^4.1.3",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as java17 from '@mcschema/java-1.17'
|
||||
import { LocalStorageProperty } from './state/LocalStorageProperty';
|
||||
import { Property } from './state/Property';
|
||||
import { Preview } from './preview/Preview';
|
||||
import { RegistryFetcher } from './RegistryFetcher';
|
||||
import { fetchData } from './DataFetcher';
|
||||
import { BiomeNoisePreview } from './preview/BiomeNoisePreview';
|
||||
import { NoiseSettingsPreview } from './preview/NoiseSettingsPreview';
|
||||
import { DecoratorPreview } from './preview/DecoratorPreview';
|
||||
@@ -14,7 +14,7 @@ import { locale, Locales } from './Locales';
|
||||
import { Tracker } from './Tracker';
|
||||
import { Settings } from './Settings';
|
||||
|
||||
const Versions: {
|
||||
export const Versions: {
|
||||
[versionId: string]: {
|
||||
getCollections: () => CollectionRegistry,
|
||||
getSchemas: (collections: CollectionRegistry) => SchemaRegistry,
|
||||
@@ -40,6 +40,17 @@ export const Models: {
|
||||
config.models.filter(m => m.schema)
|
||||
.forEach(m => Models[m.id] = new DataModel(ObjectNode({})))
|
||||
|
||||
export const BlockStateRegistry: {
|
||||
[block: string]: {
|
||||
properties: {
|
||||
[key: string]: string[]
|
||||
},
|
||||
default: {
|
||||
[key: string]: string
|
||||
}
|
||||
}
|
||||
} = {}
|
||||
|
||||
export const App = {
|
||||
version: new LocalStorageProperty('schema_version', config.versions[config.versions.length - 1].id)
|
||||
.watch(Tracker.dimVersion),
|
||||
@@ -96,7 +107,7 @@ App.mobilePanel.watchRun((value) => {
|
||||
|
||||
async function updateSchemas(version: string) {
|
||||
const collections = Versions[version].getCollections()
|
||||
await RegistryFetcher(collections, version)
|
||||
await fetchData(collections, version)
|
||||
const schemas = Versions[version].getSchemas(collections)
|
||||
config.models
|
||||
.filter(m => m.schema)
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { CollectionRegistry } from '@mcschema/core'
|
||||
import { checkVersion } from './App'
|
||||
import { BlockStateRegistry, checkVersion } from './App'
|
||||
import config from '../config.json'
|
||||
|
||||
type VersionConfig = {
|
||||
id: string,
|
||||
mcdata_ref: string
|
||||
}
|
||||
|
||||
type RegistryConfig = {
|
||||
id: string
|
||||
minVersion?: string
|
||||
@@ -13,24 +18,39 @@ const localStorageCache = (version: string) => `cache_${version}`
|
||||
declare var __MCDATA_MASTER_HASH__: string;
|
||||
|
||||
const baseUrl = 'https://raw.githubusercontent.com/Arcensoth/mcdata'
|
||||
export const mcdata = (ref: string, registry: string) => {
|
||||
const mcdata = (ref: string, registry: string) => {
|
||||
return `${baseUrl}/${ref}/processed/reports/registries/${registry}/data.min.json`
|
||||
}
|
||||
|
||||
export const RegistryFetcher = async (target: CollectionRegistry, versionId: string) => {
|
||||
export const fetchData = async (target: CollectionRegistry, versionId: string) => {
|
||||
const version = config.versions.find(v => v.id === versionId)
|
||||
if (!version) return
|
||||
|
||||
const cache = JSON.parse(localStorage.getItem(localStorageCache(versionId)) ?? '{}')
|
||||
const cacheValid = version.mcdata_ref !== 'master' || cache.mcdata_hash === __MCDATA_MASTER_HASH__
|
||||
let cacheDirty = false
|
||||
|
||||
if (checkVersion('1.15', versionId)) {
|
||||
const cacheDirty = (await Promise.all([
|
||||
fetchRegistries(target, version, cache, cacheValid),
|
||||
fetchBlockStateMap(version, cache, cacheValid)
|
||||
])).some(v => v)
|
||||
|
||||
if (cacheDirty) {
|
||||
if (version.mcdata_ref === 'master') {
|
||||
cache.mcdata_hash = __MCDATA_MASTER_HASH__
|
||||
}
|
||||
localStorage.setItem(localStorageCache(versionId), JSON.stringify(cache))
|
||||
}
|
||||
}
|
||||
|
||||
const fetchRegistries = async (target: CollectionRegistry, version: VersionConfig, cache: any, cacheValid: boolean) => {
|
||||
let cacheDirty = false
|
||||
if (!cache.registries) cache.registries = {}
|
||||
if (checkVersion('1.15', version.id)) {
|
||||
const url = `${baseUrl}/${version.mcdata_ref}/generated/reports/registries.json`
|
||||
if (cacheValid && cache.registries) {
|
||||
config.registries.forEach((r: string | RegistryConfig) => {
|
||||
if (typeof r === 'string') r = { id: r }
|
||||
if (!checkVersion(versionId, r.minVersion, r.maxVersion)) return
|
||||
if (!checkVersion(version.id, r.minVersion, r.maxVersion)) return
|
||||
|
||||
target.register(r.id, cache.registries[r.id])
|
||||
})
|
||||
@@ -40,26 +60,22 @@ export const RegistryFetcher = async (target: CollectionRegistry, versionId: str
|
||||
const data = await res.json()
|
||||
config.registries.forEach(async (r: string | RegistryConfig) => {
|
||||
if (typeof r === 'string') r = { id: r }
|
||||
if (!checkVersion(versionId, r.minVersion, r.maxVersion)) return
|
||||
if (!checkVersion(version.id, r.minVersion, r.maxVersion)) return
|
||||
|
||||
if (!cache.registries) cache.registries = {}
|
||||
const values = Object.keys(data[`minecraft:${r.id}`].entries)
|
||||
target.register(r.id, values)
|
||||
cache.registries[r.id] = values
|
||||
cacheDirty = true
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn(`Error occurred while fetching registries for version ${versionId}`)
|
||||
console.warn(`Error occurred while fetching registries for version ${version.id}`)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await Promise.all(config.registries.map(async (r: string | RegistryConfig) => {
|
||||
if (typeof r === 'string') r = { id: r }
|
||||
|
||||
if (r.minVersion && !checkVersion(versionId, r.minVersion)) return
|
||||
if (r.maxVersion && !checkVersion(r.maxVersion, versionId)) return
|
||||
|
||||
if (!cache.registries) cache.registries = {}
|
||||
if (!checkVersion(version.id, r.minVersion, r.maxVersion)) return
|
||||
|
||||
if (cacheValid && cache.registries?.[r.id]) {
|
||||
target.register(r.id, cache.registries[r.id])
|
||||
return
|
||||
@@ -81,11 +97,33 @@ export const RegistryFetcher = async (target: CollectionRegistry, versionId: str
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
if (cacheDirty) {
|
||||
if (version.mcdata_ref === 'master') {
|
||||
cache.mcdata_hash = __MCDATA_MASTER_HASH__
|
||||
}
|
||||
localStorage.setItem(localStorageCache(versionId), JSON.stringify(cache))
|
||||
}
|
||||
return cacheDirty
|
||||
}
|
||||
|
||||
const fetchBlockStateMap = async (version: VersionConfig, cache: any, cacheValid: boolean) => {
|
||||
if (cacheValid && cache.block_state_map) {
|
||||
Object.keys(cache.block_state_map).forEach(block => {
|
||||
BlockStateRegistry[block] = cache.block_state_map[block]
|
||||
})
|
||||
return false
|
||||
}
|
||||
|
||||
const url = (checkVersion(version.id, undefined, '1.15'))
|
||||
? `${baseUrl}/${version.mcdata_ref}/generated/reports/blocks.json`
|
||||
: `${baseUrl}/${version.mcdata_ref}/processed/reports/blocks/data.min.json`
|
||||
|
||||
const res = await fetch(url)
|
||||
const data = await res.json()
|
||||
|
||||
cache.block_state_map = {}
|
||||
Object.keys(data).forEach(block => {
|
||||
const res = {
|
||||
properties: data[block].properties,
|
||||
default: data[block].states.find((s: any) => s.default).properties
|
||||
}
|
||||
BlockStateRegistry[block] = res
|
||||
cache.block_state_map[block] = res
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
36
src/app/hooks/customValidation.ts
Normal file
36
src/app/hooks/customValidation.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Errors, Hook, relativePath } from '@mcschema/core'
|
||||
import { BlockStateRegistry } from '../App'
|
||||
import { walk } from './walk'
|
||||
|
||||
export const customValidation: Hook<[any, Errors], void> = walk<[Errors]>({
|
||||
base() {},
|
||||
|
||||
boolean() {},
|
||||
|
||||
choice() {},
|
||||
|
||||
list() {},
|
||||
|
||||
map({ config }, path, value) {
|
||||
if (config.validation?.validator === 'block_state_map') {
|
||||
const block = relativePath(path, config.validation.params.id).get()
|
||||
const errors = path.getModel().errors
|
||||
|
||||
const requiredProps = BlockStateRegistry[block].properties ?? {}
|
||||
const existingKeys = Object.keys(value ?? {})
|
||||
Object.keys(requiredProps).forEach(p => {
|
||||
if (!existingKeys.includes(p)) {
|
||||
errors.add(path, 'error.block_state.missing_property', p)
|
||||
} else if (!requiredProps[p].includes(value[p])) {
|
||||
errors.add(path.push(p), 'error.invalid_enum_option', value[p])
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
number() {},
|
||||
|
||||
object() {},
|
||||
|
||||
string() {}
|
||||
})
|
||||
39
src/app/hooks/walk.ts
Normal file
39
src/app/hooks/walk.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Hook } from '@mcschema/core'
|
||||
|
||||
type Args = any[]
|
||||
|
||||
export const walk = <U extends Args> (hook: Hook<[any, ...U], void>): Hook<[any, ...U], void> => ({
|
||||
...hook,
|
||||
|
||||
choice(params, path, value, ...args) {
|
||||
hook.choice(params, path, value, ...args)
|
||||
params.switchNode.hook(this, path, value, ...args)
|
||||
},
|
||||
|
||||
list(params, path, value, ...args) {
|
||||
hook.list(params, path, value, ...args)
|
||||
if (!Array.isArray(value)) return
|
||||
value.forEach((e, i) =>
|
||||
params.children.hook(this, path.push(i), value, ...args)
|
||||
)
|
||||
},
|
||||
|
||||
map(params, path, value, ...args) {
|
||||
hook.map(params, path, value, ...args)
|
||||
if (typeof value !== 'object') return
|
||||
Object.keys(value).forEach(f =>
|
||||
params.children.hook(this, path.push(f), value[f], ...args)
|
||||
)
|
||||
},
|
||||
|
||||
object(params, path, value, ...args) {
|
||||
hook.object(params, path, value, ...args)
|
||||
if (value === null || typeof value !== 'object') return
|
||||
const activeFields = params.getActiveFields(path)
|
||||
Object.keys(activeFields)
|
||||
.filter(f => activeFields[f].enabled(path))
|
||||
.forEach(f => {
|
||||
activeFields[f].hook(this, path.push(f), value[f], ...args)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -6,6 +6,8 @@ import { Errors } from '../components/Errors'
|
||||
import { TreePanel } from '../components/panels/TreePanel'
|
||||
import { SourcePanel } from '../components/panels/SourcePanel'
|
||||
import { PreviewPanel } from '../components/panels/PreviewPanel'
|
||||
import { customValidation } from '../hooks/customValidation'
|
||||
import { ModelPath, Path } from '@mcschema/core'
|
||||
|
||||
export const Generator = (view: View): string => {
|
||||
const model = Models[App.model.get()!.id]
|
||||
@@ -26,7 +28,10 @@ export const Generator = (view: View): string => {
|
||||
}
|
||||
}
|
||||
model.addListener({
|
||||
invalidated: validatePreview
|
||||
invalidated: () => {
|
||||
validatePreview()
|
||||
model.schema.hook(customValidation, new ModelPath(model, new Path()), model.data, model.errors)
|
||||
}
|
||||
})
|
||||
App.schemasLoaded.watch((value) => {
|
||||
if (value) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"dimension-type": "Dimension Type",
|
||||
"dimension": "Dimension",
|
||||
"download": "Download",
|
||||
"error.block_state.missing_property": "Missing block property \"%0%\"",
|
||||
"fields": "Fields",
|
||||
"item-modifier": "Item Modifier",
|
||||
"language": "Language",
|
||||
|
||||
Reference in New Issue
Block a user