mirror of
https://github.com/misode/misode.github.io.git
synced 2026-05-04 14:42:53 +00:00
Add filtered node + schema selector
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header"></div>
|
||||
<hr>
|
||||
<div id="view"></div>
|
||||
<hr>
|
||||
<div id="source" style="font-family: monospace;"></div>
|
||||
|
||||
+22
-52
@@ -1,61 +1,31 @@
|
||||
import { RootNode } from '../nodes/RootNode'
|
||||
import { EnumNode } from '../nodes/EnumNode'
|
||||
import { ObjectNode } from '../nodes/ObjectNode'
|
||||
import { StringNode } from '../nodes/StringNode'
|
||||
import { DataModel } from '../model/DataModel'
|
||||
import { TreeView } from '../view/TreeView'
|
||||
import { SourceView } from '../view/SourceView'
|
||||
import { ListNode } from '../nodes/ListNode'
|
||||
import { BooleanNode } from '../nodes/BooleanNode'
|
||||
import { MapNode } from '../nodes/MapNode'
|
||||
import { NumberNode } from '../nodes/NumberNode'
|
||||
import { RangeNode } from '../nodes/custom/RangeNode'
|
||||
import { ResourceNode } from '../nodes/custom/ResourceNode'
|
||||
import { PredicateSchema } from '../schemas/PredicateSchema'
|
||||
import { SandboxSchema } from '../schemas/SandboxSchema'
|
||||
|
||||
const EntityCollection = ['sheep', 'pig']
|
||||
const predicateModel = new DataModel(PredicateSchema)
|
||||
const sandboxModel = new DataModel(SandboxSchema)
|
||||
|
||||
const predicateTree = new RootNode('predicate', {
|
||||
condition: new EnumNode(['foo', 'bar'], {
|
||||
default: () => 'bar',
|
||||
transform: (s: string) => (s === 'foo') ? {test: 'baz'} : s
|
||||
}),
|
||||
number: new NumberNode({integer: false, min: 0}),
|
||||
range: new RangeNode({
|
||||
enable: (path) => path.push('condition').get() === 'foo'
|
||||
}),
|
||||
predicate: new ObjectNode({
|
||||
type: new EnumNode(EntityCollection),
|
||||
nbt: new ResourceNode({
|
||||
default: (v) => "hahaha"
|
||||
}),
|
||||
test: new BooleanNode({force: () => true}),
|
||||
recipes: new MapNode(
|
||||
new StringNode(),
|
||||
new RangeNode({
|
||||
default: (v) => RangeNode.isExact(v) ? 2 : v
|
||||
})
|
||||
)
|
||||
}),
|
||||
effects: new ListNode(
|
||||
new ObjectNode({
|
||||
type: new EnumNode(EntityCollection),
|
||||
nbt: new StringNode()
|
||||
}, {
|
||||
default: () => ({
|
||||
type: 'sheep'
|
||||
})
|
||||
})
|
||||
)
|
||||
}, {
|
||||
default: () => ({
|
||||
condition: 'foo',
|
||||
predicate: {
|
||||
nbt: 'hi'
|
||||
}
|
||||
})
|
||||
});
|
||||
let model = predicateModel
|
||||
|
||||
const model = new DataModel(predicateTree)
|
||||
const modelSelector = document.createElement('select')
|
||||
modelSelector.value = 'predicate'
|
||||
modelSelector.innerHTML = `
|
||||
<option value="predicate">Predicate</option>
|
||||
<option value="sandbox">Sandbox</option>`
|
||||
modelSelector.addEventListener('change', evt => {
|
||||
console.log("hello?")
|
||||
if (modelSelector.value === 'sandbox') {
|
||||
model = sandboxModel
|
||||
} else {
|
||||
model = predicateModel
|
||||
}
|
||||
new TreeView(model, document!.getElementById('view')!)
|
||||
new SourceView(model, document!.getElementById('source')!)
|
||||
model.invalidate()
|
||||
})
|
||||
document.getElementById('header')?.append(modelSelector)
|
||||
|
||||
new TreeView(model, document!.getElementById('view')!)
|
||||
new SourceView(model, document!.getElementById('source')!)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { RootNode } from "../nodes/RootNode"
|
||||
import { Path } from "./Path"
|
||||
import { INode } from "../nodes/AbstractNode"
|
||||
|
||||
export interface ModelListener {
|
||||
invalidated(model: DataModel): void
|
||||
@@ -7,10 +8,10 @@ export interface ModelListener {
|
||||
|
||||
export class DataModel {
|
||||
data: any
|
||||
schema: RootNode
|
||||
schema: INode<any>
|
||||
listeners: ModelListener[]
|
||||
|
||||
constructor(schema: RootNode) {
|
||||
constructor(schema: INode<any>) {
|
||||
this.schema = schema
|
||||
this.data = schema.default()
|
||||
this.listeners = []
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { NodeMods, INode, NodeChildren, AbstractNode, RenderOptions } from './AbstractNode'
|
||||
import { IObject } from './ObjectNode'
|
||||
import { Path } from '../model/Path'
|
||||
import { TreeView } from '../view/TreeView'
|
||||
|
||||
export const Switch = Symbol('switch')
|
||||
|
||||
type NestedNodeChildren = {
|
||||
[name: string]: NodeChildren
|
||||
}
|
||||
|
||||
export type FilteredChildren = {
|
||||
[name: string]: INode<any>
|
||||
[Switch]: NestedNodeChildren
|
||||
}
|
||||
|
||||
export class FilteredNode extends AbstractNode<IObject> {
|
||||
filter: string
|
||||
fields: NodeChildren
|
||||
cases: NestedNodeChildren
|
||||
|
||||
constructor(filter: string, fields: FilteredChildren, mods?: NodeMods<IObject>) {
|
||||
super(mods)
|
||||
this.filter = filter;
|
||||
const {[Switch]: _switch, ..._fields} = fields
|
||||
this.fields = _fields
|
||||
this.cases = _switch
|
||||
}
|
||||
|
||||
transform(path: Path, value: IObject) {
|
||||
if (value === undefined) return undefined
|
||||
value = value ?? {}
|
||||
const activeCase = this.cases[value[this.filter]] ?? []
|
||||
const activeFields = {...this.fields, ...activeCase}
|
||||
let res: any = {}
|
||||
Object.keys(activeFields).forEach(f =>
|
||||
res[f] = activeFields[f].transform(path.push(f), value[f])
|
||||
)
|
||||
return res;
|
||||
}
|
||||
|
||||
renderRaw(path: Path, value: IObject, view: TreeView, options?: RenderOptions) {
|
||||
if (value === undefined) return ``
|
||||
const activeCase = this.cases[value[this.filter]] ?? []
|
||||
const activeFields = {...this.fields, ...activeCase}
|
||||
return `${options?.hideLabel ? `` : `<label>${path.last()}:</label>
|
||||
<div style="padding-left:8px">`}
|
||||
${Object.keys(activeFields).map(f => {
|
||||
return activeFields[f].render(path.push(f), value[f], view)
|
||||
}).join('')}
|
||||
${options?.hideLabel ? `` : `</div>`}`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
import { EnumNode } from '../nodes/EnumNode';
|
||||
import { ResourceNode } from '../nodes/custom/ResourceNode';
|
||||
import { NumberNode } from '../nodes/NumberNode';
|
||||
import { BooleanNode } from '../nodes/BooleanNode';
|
||||
import { FilteredNode, Switch } from '../nodes/FilteredNode';
|
||||
import { ListNode } from '../nodes/ListNode';
|
||||
import { RangeNode } from '../nodes/custom/RangeNode';
|
||||
import { MapNode } from '../nodes/MapNode';
|
||||
import { StringNode } from '../nodes/StringNode';
|
||||
import { INode } from '../nodes/AbstractNode';
|
||||
|
||||
const conditions = [
|
||||
'alternative',
|
||||
'requirements',
|
||||
'inverted',
|
||||
'reference',
|
||||
'entity_properties',
|
||||
'block_state_property',
|
||||
'match_tool',
|
||||
'damage_source_properties',
|
||||
'location_check',
|
||||
'weather_check',
|
||||
'time_check',
|
||||
'entity_scores',
|
||||
'random_chance',
|
||||
'random_chance_with_looting',
|
||||
'table_bonus',
|
||||
'killed_by_player',
|
||||
'survives_explosion'
|
||||
]
|
||||
|
||||
const enchantments = [
|
||||
'aqua_affinity',
|
||||
'bane_of_arthropods',
|
||||
'blast_protection',
|
||||
'channeling',
|
||||
'binding_curse',
|
||||
'vanishing_curse',
|
||||
'depth_strider',
|
||||
'efficiency',
|
||||
'feather_falling',
|
||||
'fire_aspect',
|
||||
'fire_protection',
|
||||
'flame',
|
||||
'fortune',
|
||||
'frost_walker',
|
||||
'impaling',
|
||||
'infinity',
|
||||
'knockback',
|
||||
'looting',
|
||||
'loyalty',
|
||||
'luck_of_the_sea',
|
||||
'lure',
|
||||
'mending',
|
||||
'multishot',
|
||||
'piercing',
|
||||
'power',
|
||||
'projectile_protection',
|
||||
'protection',
|
||||
'punch',
|
||||
'quick_charge',
|
||||
'respiration',
|
||||
'riptide',
|
||||
'sharpness',
|
||||
'silk_touch',
|
||||
'smite',
|
||||
'sweeping',
|
||||
'thorns',
|
||||
'unbreaking'
|
||||
]
|
||||
|
||||
const entitySources = ['this', 'killer', 'killer_player']
|
||||
|
||||
export let PredicateSchema: FilteredNode
|
||||
PredicateSchema = new FilteredNode('condition', {
|
||||
condition: new EnumNode(conditions, 'random_chance'),
|
||||
[Switch]: {
|
||||
'alternative': {
|
||||
// terms: new ListNode(PredicateSchema()),
|
||||
},
|
||||
'block_state_property': {
|
||||
block: new ResourceNode(),
|
||||
properties: new MapNode(
|
||||
new StringNode(),
|
||||
new StringNode()
|
||||
),
|
||||
},
|
||||
'damage_source_properties': {
|
||||
// predicate: DamageSchema,
|
||||
},
|
||||
'entity_properties': {
|
||||
entity: new EnumNode(entitySources, 'this'),
|
||||
// predicate: EntitySchema,
|
||||
},
|
||||
'entity_scores': {
|
||||
entity: new EnumNode(entitySources, 'this'),
|
||||
scores: new MapNode(
|
||||
new StringNode(),
|
||||
new RangeNode()
|
||||
)
|
||||
},
|
||||
'inverted': {
|
||||
// term: PredicateSchema,
|
||||
},
|
||||
'killed_by_player': {
|
||||
inverse: new BooleanNode()
|
||||
},
|
||||
'location_check': {
|
||||
offsetX: new NumberNode({integer: true}),
|
||||
offsetY: new NumberNode({integer: true}),
|
||||
offsetZ: new NumberNode({integer: true}),
|
||||
// predicate: LocationSchema,
|
||||
},
|
||||
'match_tool': {
|
||||
// predicate: ItemSchema,
|
||||
},
|
||||
'random_chance': {
|
||||
chance: new NumberNode({min: 0, max: 1}),
|
||||
},
|
||||
'random_chance_with_looting': {
|
||||
chance: new NumberNode({min: 0, max: 1}),
|
||||
looting_multiplier: new NumberNode(),
|
||||
},
|
||||
'reference': {
|
||||
name: new StringNode(),
|
||||
},
|
||||
'table_bonus': {
|
||||
enchantment: new EnumNode(enchantments),
|
||||
chances: new ListNode(
|
||||
new NumberNode({min: 0, max: 1})
|
||||
),
|
||||
},
|
||||
'time_check': {
|
||||
value: new RangeNode(),
|
||||
period: new NumberNode(),
|
||||
},
|
||||
'weather_check': {
|
||||
raining: new BooleanNode(),
|
||||
thrundering: new BooleanNode(),
|
||||
}
|
||||
}
|
||||
}, {
|
||||
default: () => ({
|
||||
condition: 'random_chance',
|
||||
chance: 0.5
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,53 @@
|
||||
import { ObjectNode } from '../nodes/ObjectNode';
|
||||
import { EnumNode } from '../nodes/EnumNode';
|
||||
import { ResourceNode } from '../nodes/custom/ResourceNode';
|
||||
import { NumberNode } from '../nodes/NumberNode';
|
||||
import { BooleanNode } from '../nodes/BooleanNode';
|
||||
import { RootNode } from '../nodes/RootNode';
|
||||
import { RangeNode } from '../nodes/custom/RangeNode';
|
||||
import { MapNode } from '../nodes/MapNode';
|
||||
import { StringNode } from '../nodes/StringNode';
|
||||
import { ListNode } from '../nodes/ListNode';
|
||||
|
||||
const EntityCollection = ['sheep', 'pig']
|
||||
|
||||
export const SandboxSchema = new RootNode('predicate', {
|
||||
condition: new EnumNode(['foo', 'bar'], {
|
||||
default: () => 'bar',
|
||||
transform: (s: string) => (s === 'foo') ? {test: 'baz'} : s
|
||||
}),
|
||||
number: new NumberNode({integer: false, min: 0}),
|
||||
range: new RangeNode({
|
||||
enable: (path) => path.push('condition').get() === 'foo'
|
||||
}),
|
||||
predicate: new ObjectNode({
|
||||
type: new EnumNode(EntityCollection),
|
||||
nbt: new ResourceNode({
|
||||
default: (v) => 'hahaha'
|
||||
}),
|
||||
test: new BooleanNode({force: () => true}),
|
||||
recipes: new MapNode(
|
||||
new StringNode(),
|
||||
new RangeNode({
|
||||
default: (v) => RangeNode.isExact(v) ? 2 : v
|
||||
})
|
||||
)
|
||||
}),
|
||||
effects: new ListNode(
|
||||
new ObjectNode({
|
||||
type: new EnumNode(EntityCollection),
|
||||
nbt: new StringNode()
|
||||
}, {
|
||||
default: () => ({
|
||||
type: 'sheep'
|
||||
})
|
||||
})
|
||||
)
|
||||
}, {
|
||||
default: () => ({
|
||||
condition: 'foo',
|
||||
predicate: {
|
||||
nbt: 'hi'
|
||||
}
|
||||
})
|
||||
});
|
||||
Reference in New Issue
Block a user