Fix recipe preview on 1.21.2, add enchantment tag generator (#595)

* Add enchantment tag generator

* Update Lithostitched partner

* Fix recipe preview on 1.21.2

* Add enchantment tag icon

* Fix nested tags

---------

Co-authored-by: Misode <misoloo64@gmail.com>
This commit is contained in:
Apollo
2024-09-10 20:47:14 -04:00
committed by GitHub
parent fd6de2ac85
commit 944dc890e8
3 changed files with 54 additions and 24 deletions

View File

@@ -20,6 +20,7 @@ export const Icons = {
recipe: <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M20 2H12V10L20 10V2ZM10 2V10H2V4C2 2.89543 2.89543 2 4 2H10ZM2 20L2 12H10V20H2ZM2 22L2 28C2 29.1046 2.89543 30 4 30H10V22H2ZM12 22V30H20V22L12 22ZM22 22V30H28C29.1046 30 30 29.1046 30 28V22H22ZM30 20V12H22V20H30ZM20 20L12 20V12L20 12V20ZM30 4V10H22V2H28C29.1046 2 30 2.89543 30 4ZM4 0C1.79086 0 0 1.79086 0 4V28C0 30.2091 1.79086 32 4 32H28C30.2091 32 32 30.2091 32 28V4C32 1.79086 30.2091 0 28 0H4Z"/></svg>,
'tag/block': TAG,
'tag/damage_type': TAG,
'tag/enchantment': TAG,
'tag/entity_type': TAG,
'tag/fluid': TAG,
'tag/game_event': TAG,

View File

@@ -1,9 +1,10 @@
import { DataModel } from '@mcschema/core'
import { Identifier, ItemStack } from 'deepslate'
import { useEffect, useMemo, useRef, useState } from 'preact/hooks'
import { useLocale, useVersion } from '../../contexts/index.js'
import { useLocale } from '../../contexts/index.js'
import { useAsync } from '../../hooks/useAsync.js'
import { fetchAllPresets } from '../../services/index.js'
import type { VersionId } from '../../services/index.js'
import { checkVersion, fetchAllPresets } from '../../services/index.js'
import { jsonToNbt } from '../../Utils.js'
import { Btn, BtnMenu } from '../index.js'
import { ItemDisplay } from '../ItemDisplay.jsx'
@@ -11,9 +12,8 @@ import type { PreviewProps } from './index.js'
const ANIMATION_TIME = 1000
export const RecipePreview = ({ data }: PreviewProps) => {
export const RecipePreview = ({ data, version }: PreviewProps) => {
const { locale } = useLocale()
const { version } = useVersion()
const [advancedTooltips, setAdvancedTooltips] = useState(true)
const [animation, setAnimation] = useState(0)
const overlay = useRef<HTMLDivElement>(null)
@@ -32,7 +32,7 @@ export const RecipePreview = ({ data }: PreviewProps) => {
const recipe = DataModel.unwrapLists(data)
const state = JSON.stringify(recipe)
const items = useMemo<Map<Slot, ItemStack>>(() => {
return placeItems(recipe, animation, itemTags ?? new Map())
return placeItems(version, recipe, animation, itemTags ?? new Map())
}, [state, animation, itemTags])
const gui = useMemo(() => {
@@ -101,7 +101,7 @@ function slotStyle(slot: Slot) {
}
}
function placeItems(recipe: any, animation: number, itemTags: Map<string, any>) {
function placeItems(version: VersionId, recipe: any, animation: number, itemTags: Map<string, any>) {
const items = new Map<Slot, ItemStack>()
const type: string = recipe.type?.replace(/^minecraft:/, '')
if (!type || type.startsWith('crafting_special') || type === 'crafting_decorated_pot') {
@@ -111,7 +111,7 @@ function placeItems(recipe: any, animation: number, itemTags: Map<string, any>)
if (type === 'crafting_shapeless') {
const ingredients: any[] = Array.isArray(recipe.ingredients) ? recipe.ingredients : []
ingredients.forEach((ingredient, i) => {
const choices = allIngredientChoices(ingredient, itemTags)
const choices = allIngredientChoices(version, ingredient, itemTags)
if (i >= 0 && i < 9 && choices.length > 0) {
const choice = choices[(3 * i + animation) % choices.length]
items.set(`crafting.${i}` as Slot, choice)
@@ -120,7 +120,7 @@ function placeItems(recipe: any, animation: number, itemTags: Map<string, any>)
} else if (type === 'crafting_shaped') {
const keys = new Map<string, ItemStack>()
for (const [key, ingredient] of Object.entries(recipe.key ?? {})) {
const choices = allIngredientChoices(ingredient, itemTags)
const choices = allIngredientChoices(version, ingredient, itemTags)
if (choices.length > 0) {
const choice = choices[animation % choices.length]
keys.set(key, choice)
@@ -137,20 +137,20 @@ function placeItems(recipe: any, animation: number, itemTags: Map<string, any>)
}
}
} else if (type === 'smelting' || type === 'smoking' || type === 'blasting' || type === 'campfire_cooking') {
const choices = allIngredientChoices(recipe.ingredient, itemTags)
const choices = allIngredientChoices(version, recipe.ingredient, itemTags)
if (choices.length > 0) {
const choice = choices[animation % choices.length]
items.set('smelting.ingredient' as Slot, choice)
}
} else if (type === 'stonecutting') {
const choices = allIngredientChoices(recipe.ingredient, itemTags)
const choices = allIngredientChoices(version, recipe.ingredient, itemTags)
if (choices.length > 0) {
const choice = choices[animation % choices.length]
items.set('stonecutting.ingredient' as Slot, choice)
}
} else if (type === 'smithing_transform' || type === 'smithing_trim') {
for (const ingredient of ['template', 'base', 'addition'] as const) {
const choices = allIngredientChoices(recipe[ingredient], itemTags)
const choices = allIngredientChoices(version, recipe[ingredient], itemTags)
if (choices.length > 0) {
const choice = choices[animation % choices.length]
items.set(`smithing.${ingredient}`, choice)
@@ -189,23 +189,43 @@ function placeItems(recipe: any, animation: number, itemTags: Map<string, any>)
return items
}
function allIngredientChoices(ingredient: any, itemTags: Map<string, any>): ItemStack[] {
function allIngredientChoices(version: VersionId, ingredient: any, itemTags: Map<string, any>): ItemStack[] {
if (Array.isArray(ingredient)) {
return ingredient.flatMap(i => allIngredientChoices(i, itemTags))
return ingredient.flatMap(i => allIngredientChoices(version, i, itemTags))
}
if (typeof ingredient === 'object' && ingredient !== null) {
if (typeof ingredient.item === 'string') {
return [new ItemStack(Identifier.parse(ingredient.item), 1)]
} else if (typeof ingredient.tag === 'string') {
const tag: any = itemTags.get(ingredient.tag.replace(/^minecraft:/, ''))
if (typeof tag === 'object' && tag !== null && Array.isArray(tag.values)) {
return tag.values.flatMap((value: any) => {
if (typeof value !== 'string') return []
if (value.startsWith('#')) return allIngredientChoices({ tag: value.slice(1) }, itemTags)
return [new ItemStack(Identifier.parse(value), 1)]
})
if (checkVersion(version, '1.21.2')) {
if (ingredient !== null) {
if (typeof ingredient === 'string') {
if (ingredient.startsWith('#')) {
return parseTag(version, ingredient.slice(1), itemTags)
}
return [new ItemStack(Identifier.parse(ingredient), 1)]
}
}
return [new ItemStack(Identifier.create('stone'), 1)]
} else {
if (typeof ingredient === 'object' && ingredient !== null) {
if (typeof ingredient.item === 'string') {
return [new ItemStack(Identifier.parse(ingredient.item), 1)]
} else if (typeof ingredient.tag === 'string') {
return parseTag(version, ingredient.tag, itemTags)
}
}
}
return []
}
function parseTag(version: VersionId, tagId: any, itemTags: Map<string, any>): ItemStack[] {
const tag: any = itemTags.get(tagId.replace(/^minecraft:/, ''))
if (typeof tag === 'object' && tag !== null && Array.isArray(tag.values)) {
return tag.values.flatMap((value: any) => {
if (typeof value !== 'string') return []
if (value.startsWith('#')) return parseTag(version, value.slice(1), itemTags)
return [new ItemStack(Identifier.parse(value), 1)]
})
}
return []
}

View File

@@ -445,6 +445,15 @@
"schema": "block_tag",
"wiki": "https://minecraft.wiki/w/Tag#Java_Edition"
},
{
"id": "tag/enchantment",
"url": "tags/enchantment",
"tags": ["tags"],
"path": "tags/enchantment",
"schema": "enchantment_tag",
"minVersion": "1.20.5",
"wiki": "https://minecraft.wiki/w/Tag#Java_Edition"
},
{
"id": "tag/entity_type",
"url": "tags/entity-type",