mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-23 15:17:09 +00:00
Add loot table schema
This commit is contained in:
@@ -2,22 +2,27 @@ import { DataModel } from '../model/DataModel'
|
||||
import { TreeView } from '../view/TreeView'
|
||||
import { SourceView } from '../view/SourceView'
|
||||
import { ConditionSchema } from '../minecraft/schemas/Condition'
|
||||
import { LootTableSchema } from '../minecraft/schemas/LootTable'
|
||||
import { SandboxSchema } from './Sandbox'
|
||||
import { LOCALES } from '../Registries'
|
||||
|
||||
const predicateModel = new DataModel(ConditionSchema)
|
||||
const lootTableModel = new DataModel(LootTableSchema)
|
||||
const sandboxModel = new DataModel(SandboxSchema)
|
||||
|
||||
let model = predicateModel
|
||||
let model = lootTableModel
|
||||
|
||||
const modelSelector = document.createElement('select')
|
||||
modelSelector.value = 'predicate'
|
||||
modelSelector.innerHTML = `
|
||||
<option value="loot-table">Loot Table</option>
|
||||
<option value="predicate">Predicate</option>
|
||||
<option value="sandbox">Sandbox</option>`
|
||||
modelSelector.addEventListener('change', evt => {
|
||||
if (modelSelector.value === 'sandbox') {
|
||||
model = sandboxModel
|
||||
} else if (modelSelector.value === 'loot-table') {
|
||||
model = lootTableModel
|
||||
} else {
|
||||
model = predicateModel
|
||||
}
|
||||
|
||||
@@ -20,6 +20,40 @@ COLLECTIONS.register('conditions', [
|
||||
'survives_explosion'
|
||||
])
|
||||
|
||||
COLLECTIONS.register('loot-entries', [
|
||||
'empty',
|
||||
'item',
|
||||
'tag',
|
||||
'loot_table',
|
||||
'alternatives',
|
||||
'sequence',
|
||||
'group',
|
||||
'dynamic'
|
||||
])
|
||||
|
||||
COLLECTIONS.register('loot-functions', [
|
||||
'set_count',
|
||||
'set_damage',
|
||||
'set_name',
|
||||
'set_lore',
|
||||
'set_nbt',
|
||||
'set_attributes',
|
||||
'set_contents',
|
||||
'enchant_randomly',
|
||||
'enchant_with_levels',
|
||||
'looting_enchant',
|
||||
'limit_count',
|
||||
'furnace_smelt',
|
||||
'explosion_decay',
|
||||
'fill_player_head',
|
||||
'copy_name',
|
||||
'copy_nbt',
|
||||
'copy_state',
|
||||
'apply_bonus',
|
||||
'exploration_map',
|
||||
'set_stew_effect'
|
||||
])
|
||||
|
||||
COLLECTIONS.register('enchantments', [
|
||||
'aqua_affinity',
|
||||
'bane_of_arthropods',
|
||||
@@ -232,3 +266,56 @@ COLLECTIONS.register('entity-sources', [
|
||||
'killer',
|
||||
'killer_player'
|
||||
])
|
||||
|
||||
COLLECTIONS.register('copy-sources', [
|
||||
'block_entity',
|
||||
'this',
|
||||
'killer',
|
||||
'killer_player'
|
||||
])
|
||||
|
||||
COLLECTIONS.register('attributes', [
|
||||
'generic.max_health',
|
||||
'generic.follow_range',
|
||||
'generic.knockback_resistance',
|
||||
'generic.movement_speed',
|
||||
'generic.attack_damage',
|
||||
'generic.armor',
|
||||
'generic.armor_toughness',
|
||||
'generic.attack_speed',
|
||||
'generic.luck',
|
||||
'horse.jump_strength',
|
||||
'generic.attack_knockback',
|
||||
'generic.flying_speed',
|
||||
'zombie.spawn_reinforcements'
|
||||
])
|
||||
|
||||
COLLECTIONS.register('map-decorations', [
|
||||
'mansion',
|
||||
'monument',
|
||||
'player',
|
||||
'frame',
|
||||
'red_marker',
|
||||
'blue_marker',
|
||||
'target_x',
|
||||
'target_point',
|
||||
'player_off_map',
|
||||
'player_off_limits',
|
||||
'red_x',
|
||||
'banner_white',
|
||||
'banner_orange',
|
||||
'banner_magenta',
|
||||
'banner_light_blue',
|
||||
'banner_yellow',
|
||||
'banner_lime',
|
||||
'banner_pink',
|
||||
'banner_gray',
|
||||
'banner_light_gray',
|
||||
'banner_cyan',
|
||||
'banner_purple',
|
||||
'banner_blue',
|
||||
'banner_brown',
|
||||
'banner_green',
|
||||
'banner_red',
|
||||
'banner_black'
|
||||
])
|
||||
|
||||
247
src/minecraft/schemas/LootTable.ts
Normal file
247
src/minecraft/schemas/LootTable.ts
Normal file
@@ -0,0 +1,247 @@
|
||||
import { EnumNode } from '../../nodes/EnumNode';
|
||||
import { ResourceNode } from '../nodes/ResourceNode';
|
||||
import { NumberNode } from '../../nodes/NumberNode';
|
||||
import { BooleanNode } from '../../nodes/BooleanNode';
|
||||
import { ObjectNode, Switch, Case } from '../../nodes/ObjectNode';
|
||||
import { ListNode } from '../../nodes/ListNode';
|
||||
import { RangeNode } from '../nodes/RangeNode';
|
||||
import { MapNode } from '../../nodes/MapNode';
|
||||
import { StringNode } from '../../nodes/StringNode';
|
||||
import { ReferenceNode } from '../../nodes/ReferenceNode';
|
||||
import { SCHEMAS, COLLECTIONS } from '../../Registries';
|
||||
|
||||
import './Predicates'
|
||||
|
||||
const conditions = {
|
||||
conditions: new ListNode(
|
||||
new ReferenceNode('condition')
|
||||
)
|
||||
}
|
||||
|
||||
const functionsAndConditions = {
|
||||
functions: new ListNode(
|
||||
new ReferenceNode('loot-function')
|
||||
),
|
||||
...conditions
|
||||
}
|
||||
|
||||
SCHEMAS.register('loot-table', new ObjectNode({
|
||||
pools: new ListNode(
|
||||
new ObjectNode({
|
||||
rolls: new RangeNode(),
|
||||
entries: new ListNode(
|
||||
new ReferenceNode('loot-entry')
|
||||
)
|
||||
})
|
||||
),
|
||||
...functionsAndConditions
|
||||
}, {
|
||||
default: () => ({
|
||||
pools: [
|
||||
{
|
||||
rolls: 1,
|
||||
entries: [
|
||||
{
|
||||
type: 'item',
|
||||
name: 'minecraft:stone'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
}))
|
||||
|
||||
SCHEMAS.register('loot-entry', new ObjectNode({
|
||||
type: new EnumNode(COLLECTIONS.get('loot-entries'), {default: () => 'item'}),
|
||||
weight: new NumberNode({
|
||||
integer: true,
|
||||
min: 1,
|
||||
enable: path => path.pop().get()?.length > 1
|
||||
&& !['alternatives', 'group', 'sequence'].includes(path.push('type').get())
|
||||
}),
|
||||
[Switch]: 'type',
|
||||
[Case]: {
|
||||
'alternatives': {
|
||||
children: new ListNode(
|
||||
new ReferenceNode('loot-entry')
|
||||
),
|
||||
...functionsAndConditions
|
||||
},
|
||||
'dynamic': {
|
||||
name: new StringNode(),
|
||||
...functionsAndConditions
|
||||
},
|
||||
'group': {
|
||||
children: new ListNode(
|
||||
new ReferenceNode('loot-entry')
|
||||
),
|
||||
...functionsAndConditions
|
||||
},
|
||||
'item': {
|
||||
name: new StringNode(),
|
||||
...functionsAndConditions
|
||||
},
|
||||
'loot_table': {
|
||||
name: new StringNode(),
|
||||
...functionsAndConditions
|
||||
},
|
||||
'sequence': {
|
||||
children: new ListNode(
|
||||
new ReferenceNode('loot-entry')
|
||||
),
|
||||
...functionsAndConditions
|
||||
},
|
||||
'tag': {
|
||||
name: new StringNode(),
|
||||
expand: new BooleanNode(),
|
||||
...functionsAndConditions
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
SCHEMAS.register('loot-function', new ObjectNode({
|
||||
function: new EnumNode(COLLECTIONS.get('loot-functions'), {default: () => 'set_count'}),
|
||||
[Switch]: 'function',
|
||||
[Case]: {
|
||||
'apply_bonus': {
|
||||
enchantment: new EnumNode(COLLECTIONS.get('enchantments')),
|
||||
formula: new EnumNode([
|
||||
'uniform_bonus_count',
|
||||
'binomial_with_bonus_count',
|
||||
'ore_drops'
|
||||
]),
|
||||
parameters: new ObjectNode({
|
||||
bonusMultiplier: new NumberNode({
|
||||
enable: path => path.pop().push('formula').get() === 'uniform_bonus_count'
|
||||
}),
|
||||
extra: new NumberNode({
|
||||
enable: path => path.pop().push('formula').get() === 'binomial_with_bonus_count'
|
||||
}),
|
||||
probability: new NumberNode({
|
||||
enable: path => path.pop().push('formula').get() === 'binomial_with_bonus_count'
|
||||
})
|
||||
}, {
|
||||
enable: path => path.push('formula').get() !== 'ore_drops'
|
||||
}),
|
||||
...conditions
|
||||
},
|
||||
'copy_name': {
|
||||
source: new EnumNode(COLLECTIONS.get('copy-sources')),
|
||||
...conditions
|
||||
},
|
||||
'copy_nbt': {
|
||||
source: new EnumNode(COLLECTIONS.get('copy-sources')),
|
||||
ops: new ListNode(
|
||||
new ObjectNode({
|
||||
source: new StringNode(),
|
||||
target: new StringNode(),
|
||||
op: new EnumNode(['replace', 'append', 'merge'])
|
||||
})
|
||||
),
|
||||
...conditions
|
||||
},
|
||||
'copy_state': {
|
||||
block: new ResourceNode(COLLECTIONS.get('blocks')),
|
||||
properties: new ListNode(
|
||||
new StringNode()
|
||||
),
|
||||
...conditions
|
||||
},
|
||||
'enchant_randomly': {
|
||||
enchantments: new ListNode(
|
||||
new EnumNode(COLLECTIONS.get('enchantments'))
|
||||
),
|
||||
...conditions
|
||||
},
|
||||
'enchant_with_levels': {
|
||||
levels: new RangeNode(),
|
||||
treasure: new BooleanNode(),
|
||||
...conditions
|
||||
},
|
||||
'exploration_map': {
|
||||
destination: new EnumNode(COLLECTIONS.get('structures')),
|
||||
decoration: new EnumNode(COLLECTIONS.get('map-decorations')),
|
||||
zoom: new NumberNode({integer: true}),
|
||||
search_radius: new NumberNode({integer: true}),
|
||||
skip_existing_chunks: new BooleanNode(),
|
||||
...conditions
|
||||
},
|
||||
'fill_player_head': {
|
||||
entity: new EnumNode(COLLECTIONS.get('entity-sources')),
|
||||
...conditions
|
||||
},
|
||||
'limit_count': {
|
||||
limit: new RangeNode(),
|
||||
...conditions
|
||||
},
|
||||
'looting_enchant': {
|
||||
count: new RangeNode(),
|
||||
limit: new NumberNode({integer: true}),
|
||||
...conditions
|
||||
},
|
||||
'set_attributes': {
|
||||
modifiers: new ListNode(
|
||||
new ReferenceNode('attribute-modifier')
|
||||
),
|
||||
...conditions
|
||||
},
|
||||
'set_contents': {
|
||||
entries: new ListNode(
|
||||
new ReferenceNode('loot-entry')
|
||||
),
|
||||
...conditions
|
||||
},
|
||||
'set_count': {
|
||||
count: new RangeNode(),
|
||||
...conditions
|
||||
},
|
||||
'set_damage': {
|
||||
damage: new RangeNode(),
|
||||
...conditions
|
||||
},
|
||||
'set_lore': {
|
||||
entity: new EnumNode(COLLECTIONS.get('entity-sources')),
|
||||
lore: new ListNode(
|
||||
new StringNode()
|
||||
),
|
||||
replace: new BooleanNode(),
|
||||
...conditions
|
||||
},
|
||||
'set_name': {
|
||||
entity: new EnumNode(COLLECTIONS.get('entity-sources')),
|
||||
name: new StringNode(),
|
||||
...conditions
|
||||
},
|
||||
'set_nbt': {
|
||||
tag: new StringNode(),
|
||||
...conditions
|
||||
},
|
||||
'set_stew_effect': {
|
||||
effects: new ListNode(
|
||||
new ReferenceNode('potion-effect')
|
||||
),
|
||||
...conditions
|
||||
}
|
||||
}
|
||||
}, {
|
||||
default: () => ({
|
||||
function: 'set_count',
|
||||
count: 1
|
||||
})
|
||||
}))
|
||||
|
||||
SCHEMAS.register('attribute-modifier', new ObjectNode({
|
||||
attribute: new EnumNode(COLLECTIONS.get('attributes')),
|
||||
name: new StringNode(),
|
||||
amount: new RangeNode(),
|
||||
operation: new EnumNode([
|
||||
'addition',
|
||||
'multiply_base',
|
||||
'multiply_total'
|
||||
]),
|
||||
slot: new ListNode(
|
||||
new EnumNode(COLLECTIONS.get('slots'))
|
||||
)
|
||||
}))
|
||||
|
||||
export const LootTableSchema = SCHEMAS.get('loot-table')
|
||||
@@ -1,6 +1,11 @@
|
||||
import { DataModel, ModelListener } from "../model/DataModel"
|
||||
import { Path } from "../model/Path"
|
||||
|
||||
type SourceViewOptions = {
|
||||
indentation?: number | string,
|
||||
rows?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON representation view of the model.
|
||||
* Renders the result in a <textarea>.
|
||||
@@ -8,14 +13,17 @@ import { Path } from "../model/Path"
|
||||
export class SourceView implements ModelListener {
|
||||
model: DataModel
|
||||
target: HTMLElement
|
||||
options?: SourceViewOptions
|
||||
|
||||
/**
|
||||
* @param model data model this view represents and listens to
|
||||
* @param target DOM element to render the view
|
||||
* @param options optional options for the view
|
||||
*/
|
||||
constructor(model: DataModel, target: HTMLElement) {
|
||||
constructor(model: DataModel, target: HTMLElement, options?: SourceViewOptions) {
|
||||
this.model = model
|
||||
this.target = target
|
||||
this.options = options
|
||||
model.addListener(this)
|
||||
}
|
||||
|
||||
@@ -23,8 +31,8 @@ export class SourceView implements ModelListener {
|
||||
const transformed = this.model.schema.transform(new Path([], this.model), this.model.data)
|
||||
const textarea = document.createElement('textarea')
|
||||
textarea.style.width = 'calc(100% - 6px)'
|
||||
textarea.rows = 10
|
||||
textarea.textContent = JSON.stringify(transformed)
|
||||
textarea.rows = this.options?.rows ?? 20
|
||||
textarea.textContent = JSON.stringify(transformed, null, this.options?.indentation)
|
||||
textarea.addEventListener('change', evt => {
|
||||
const parsed = JSON.parse(textarea.value)
|
||||
this.model.reset(parsed)
|
||||
|
||||
Reference in New Issue
Block a user