Fix #596 support item tag and loot table references in loot preview

This commit is contained in:
Misode
2024-09-11 14:39:53 +02:00
parent 95f7ca7738
commit fff1b1603a
3 changed files with 47 additions and 33 deletions

View File

@@ -27,6 +27,9 @@ interface LootOptions {
daytime: number,
weather: string,
stackMixer: StackMixer,
getItemTag(id: string): string[],
getLootTable(id: string): any,
getPredicate(id: string): any,
getBaseComponents(id: string): Map<string, NbtTag>,
}
@@ -35,9 +38,6 @@ interface LootContext extends LootOptions {
luck: number
weather: string,
dayTime: number,
getItemTag(id: string): string[],
getLootTable(id: string): any,
getPredicate(id: string): any,
}
export function generateLootTable(lootTable: any, options: LootOptions) {
@@ -133,10 +133,6 @@ function createLootContext(options: LootOptions): LootContext {
luck: options.luck,
weather: options.weather,
dayTime: options.daytime,
// TODO
getItemTag: () => [],
getLootTable: () => ({ pools: [] }),
getPredicate: () => [],
}
}
@@ -207,7 +203,7 @@ function expandEntry(entry: any, ctx: LootContext, consumer: (entry: any) => voi
return true
case 'tag':
if (entry.expand) {
ctx.getItemTag(entry.tag ?? '').forEach(tagEntry => {
ctx.getItemTag(entry.name ?? '').forEach(tagEntry => {
consumer({ type: 'item', name: tagEntry })
})
} else {
@@ -243,7 +239,10 @@ function createItem(entry: any, consumer: ItemConsumer, ctx: LootContext) {
})
break
case 'loot_table':
generateTable(ctx.getLootTable(entry.name), entryConsumer, ctx)
const lootTable = typeof entry.value === 'string' ? ctx.getLootTable(entry.value) : entry.value
if (lootTable !== undefined) {
generateTable(lootTable, entryConsumer, ctx)
}
break
case 'dynamic':
// not relevant for this simulation
@@ -365,7 +364,7 @@ const LootFunctions: Record<string, (params: any) => LootFunction> = {
},
set_count: ({ count, add }) => (item, ctx) => {
const oldCount = add ? (item.count) : 0
item.count = clamp(oldCount + computeInt(count, ctx), 0, 64)
item.count = oldCount + computeInt(count, ctx)
},
set_custom_data: ({ tag }) => (item) => {
try {
@@ -638,7 +637,6 @@ function testItemPredicate(predicate: any, item: ResolvedItem, ctx: LootContext)
}
if (predicate.count !== undefined) {
const { min, max } = prepareIntRange(predicate.count, ctx)
console.log(min, max, item.count)
if (min > item.count || item.count > max) {
return false
}

View File

@@ -25,6 +25,9 @@ interface LootOptions {
daytime: number,
weather: string,
stackMixer: StackMixer,
getItemTag(id: string): string[],
getLootTable(id: string): any,
getPredicate(id: string): any,
}
interface LootContext extends LootOptions {
@@ -32,9 +35,6 @@ interface LootContext extends LootOptions {
luck: number
weather: string,
dayTime: number,
getItemTag(id: string): string[],
getLootTable(id: string): any,
getPredicate(id: string): any,
}
export function generateLootTable(lootTable: any, options: LootOptions) {
@@ -130,9 +130,6 @@ function createLootContext(options: LootOptions): LootContext {
luck: options.luck,
weather: options.weather,
dayTime: options.daytime,
getItemTag: () => [],
getLootTable: () => ({ pools: [] }),
getPredicate: () => [],
}
}
@@ -203,7 +200,7 @@ function expandEntry(entry: any, ctx: LootContext, consumer: (entry: any) => voi
return true
case 'tag':
if (entry.expand) {
ctx.getItemTag(entry.tag ?? '').forEach(tagEntry => {
ctx.getItemTag(entry.name ?? '').forEach(tagEntry => {
consumer({ type: 'item', name: tagEntry })
})
} else {
@@ -241,7 +238,10 @@ function createItem(entry: any, consumer: ItemConsumer, ctx: LootContext) {
})
break
case 'loot_table':
generateTable(ctx.getLootTable(entry.name), entryConsumer, ctx)
const lootTable = ctx.getLootTable(entry.name)
if (lootTable !== undefined) {
generateTable(lootTable, entryConsumer, ctx)
}
break
case 'dynamic':
// not relevant for this simulation
@@ -659,7 +659,6 @@ const AlwaysHasGlint = new Set([
])
export function itemHasGlint(item: ItemStack) {
console.log(item)
if (AlwaysHasGlint.has(item.id.toString())) {
return true
}

View File

@@ -2,7 +2,7 @@ import { DataModel } from '@mcschema/core'
import { useMemo, useRef, useState } from 'preact/hooks'
import { useLocale, useVersion } from '../../contexts/index.js'
import { useAsync } from '../../hooks/useAsync.js'
import { checkVersion, fetchItemComponents } from '../../services/index.js'
import { checkVersion, fetchAllPresets, fetchItemComponents } from '../../services/index.js'
import { clamp, jsonToNbt, randomSeed } from '../../Utils.js'
import { Btn, BtnMenu, NumberInput } from '../index.js'
import { ItemDisplay } from '../ItemDisplay.jsx'
@@ -14,7 +14,7 @@ import { generateLootTable as generateLootTable1204 } from './LootTable1204.js'
export const LootTablePreview = ({ data }: PreviewProps) => {
const { locale } = useLocale()
const { version } = useVersion()
const use1204 = checkVersion(version, undefined, '1.20.4')
const use1204 = !checkVersion(version, '1.20.5')
const [seed, setSeed] = useState(randomSeed())
const [luck, setLuck] = useState(0)
@@ -24,22 +24,39 @@ export const LootTablePreview = ({ data }: PreviewProps) => {
const [advancedTooltips, setAdvancedTooltips] = useState(true)
const overlay = useRef<HTMLDivElement>(null)
const { value: itemComponents } = useAsync(() => {
return use1204 ? Promise.resolve(undefined) : fetchItemComponents(version)
}, [use1204, version])
const { value: dependencies, loading } = useAsync(() => {
return Promise.all([
fetchAllPresets(version, 'tag/item'),
fetchAllPresets(version, 'loot_table'),
use1204 ? Promise.resolve(undefined) : fetchItemComponents(version),
])
}, [version])
const table = DataModel.unwrapLists(data)
const state = JSON.stringify(table)
const items = useMemo(() => {
if (use1204) {
return generateLootTable1204(table, { version, seed, luck, daytime, weather, stackMixer: mixItems ? 'container' : 'default' })
} else {
if (itemComponents === undefined) {
return []
}
return generateLootTable(table, { version, seed, luck, daytime, weather, stackMixer: mixItems ? 'container' : 'default', getBaseComponents: (id) => new Map([...(itemComponents.get(id) ?? new Map()).entries()].map(([k, v]) => [k, jsonToNbt(v)])) })
if (dependencies === undefined || loading) {
return []
}
}, [version, seed, luck, daytime, weather, mixItems, state, itemComponents])
const [itemTags, lootTables, itemComponents] = dependencies
if (use1204) {
return generateLootTable1204(table, {
version, seed, luck, daytime, weather,
stackMixer: mixItems ? 'container' : 'default',
getItemTag: (id) => (itemTags.get(id.replace(/^minecraft:/, '')) as any)?.values ?? [],
getLootTable: (id) => lootTables.get(id.replace(/^minecraft:/, '')),
getPredicate: () => undefined,
})
}
return generateLootTable(table, {
version, seed, luck, daytime, weather,
stackMixer: mixItems ? 'container' : 'default',
getItemTag: (id) => (itemTags.get(id.replace(/^minecraft:/, '')) as any)?.values ?? [],
getLootTable: (id) => lootTables.get(id.replace(/^minecraft:/, '')),
getPredicate: () => undefined,
getBaseComponents: (id) => new Map([...(itemComponents?.get(id) ?? new Map()).entries()].map(([k, v]) => [k, jsonToNbt(v)])),
})
}, [version, seed, luck, daytime, weather, mixItems, state, dependencies, loading])
return <>
<div ref={overlay} class="preview-overlay">