From e7fb692ac45ef4b4797940200ca1a34da2e5a3cd Mon Sep 17 00:00:00 2001 From: Misode Date: Sat, 30 May 2020 20:54:27 +0200 Subject: [PATCH] Add loot table schema --- src/app/app.ts | 7 +- src/minecraft/schemas/Collections.ts | 87 ++++++++++ src/minecraft/schemas/LootTable.ts | 247 +++++++++++++++++++++++++++ src/view/SourceView.ts | 14 +- 4 files changed, 351 insertions(+), 4 deletions(-) create mode 100644 src/minecraft/schemas/LootTable.ts diff --git a/src/app/app.ts b/src/app/app.ts index 25763aeb..fd0c618c 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -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 = ` + ` modelSelector.addEventListener('change', evt => { if (modelSelector.value === 'sandbox') { model = sandboxModel + } else if (modelSelector.value === 'loot-table') { + model = lootTableModel } else { model = predicateModel } diff --git a/src/minecraft/schemas/Collections.ts b/src/minecraft/schemas/Collections.ts index 8121c836..40534f75 100644 --- a/src/minecraft/schemas/Collections.ts +++ b/src/minecraft/schemas/Collections.ts @@ -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' +]) diff --git a/src/minecraft/schemas/LootTable.ts b/src/minecraft/schemas/LootTable.ts new file mode 100644 index 00000000..893c6a4f --- /dev/null +++ b/src/minecraft/schemas/LootTable.ts @@ -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') diff --git a/src/view/SourceView.ts b/src/view/SourceView.ts index 85b90a02..1bea7618 100644 --- a/src/view/SourceView.ts +++ b/src/view/SourceView.ts @@ -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