mirror of
https://github.com/misode/misode.github.io.git
synced 2026-04-24 07:37:10 +00:00
Render items with custom colors + update deepslate
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
import type { ItemStack } from 'deepslate'
|
||||
import { Identifier } from 'deepslate-1.18.2'
|
||||
import { useEffect, useRef, useState } from 'preact/hooks'
|
||||
import { useVersion } from '../contexts/Version.jsx'
|
||||
import { useAsync } from '../hooks/useAsync.js'
|
||||
import type { Item } from '../previews/LootTable.js'
|
||||
import { MaxDamageItems } from '../previews/LootTable.js'
|
||||
import { getAssetUrl } from '../services/DataFetcher.js'
|
||||
import { itemHasGlint, MaxDamageItems } from '../previews/LootTable.js'
|
||||
import { renderItem } from '../services/Resources.js'
|
||||
import { getCollections } from '../services/Schemas.js'
|
||||
import { ItemTooltip } from './ItemTooltip.jsx'
|
||||
import { Octicon } from './Octicon.jsx'
|
||||
|
||||
interface Props {
|
||||
item: Item,
|
||||
item: ItemStack,
|
||||
slotDecoration?: boolean,
|
||||
advancedTooltip?: boolean,
|
||||
}
|
||||
@@ -32,7 +32,7 @@ export function ItemDisplay({ item, slotDecoration, advancedTooltip }: Props) {
|
||||
return () => el.current?.removeEventListener('mousemove', onMove)
|
||||
}, [])
|
||||
|
||||
const maxDamage = MaxDamageItems.get(item.id)
|
||||
const maxDamage = MaxDamageItems.get(item.id.toString())
|
||||
|
||||
return <div class="item-display" ref={el}>
|
||||
<ItemItself item={item} />
|
||||
@@ -43,23 +43,22 @@ export function ItemDisplay({ item, slotDecoration, advancedTooltip }: Props) {
|
||||
</svg>
|
||||
</>}
|
||||
{slotDecoration && <>
|
||||
{(maxDamage && (item.tag?.Damage ?? 0) > 0) && <svg class="item-durability" width="100%" height="100%" viewBox="0 0 18 18">
|
||||
{(maxDamage && item.tag.getNumber('Damage') > 0) && <svg class="item-durability" width="100%" height="100%" viewBox="0 0 18 18">
|
||||
<rect x="3" y="14" width="13" height="2" fill="#000" />
|
||||
<rect x="3" y="14" width={`${(maxDamage - item.tag.Damage) / maxDamage * 13}`} height="1" fill={`hsl(${(maxDamage - item.tag.Damage) / maxDamage * 120}deg, 100%, 50%)`} />
|
||||
<rect x="3" y="14" width={`${(maxDamage - item.tag.getNumber('Damage')) / maxDamage * 13}`} height="1" fill={`hsl(${(maxDamage - item.tag.getNumber('Damage')) / maxDamage * 120}deg, 100%, 50%)`} />
|
||||
</svg>}
|
||||
<div class="item-slot-overlay"></div>
|
||||
</>}
|
||||
<ItemTooltip {...item} advanced={advancedTooltip} offset={tooltipOffset} swap={tooltipSwap} />
|
||||
<ItemTooltip item={item} advanced={advancedTooltip} offset={tooltipOffset} swap={tooltipSwap} />
|
||||
</div>
|
||||
}
|
||||
|
||||
function ItemItself({ item }: Props) {
|
||||
const { version } = useVersion()
|
||||
const [errored, setErrored] = useState(false)
|
||||
|
||||
const isEnchanted = (item.tag?.Enchantments?.length ?? 0) > 0 || (item.tag?.StoredEnchantments?.length ?? 0) > 0
|
||||
const hasGlint = itemHasGlint(item)
|
||||
|
||||
if (errored || (item.id.includes(':') && !item.id.startsWith('minecraft:'))) {
|
||||
if (item.id.namespace !== Identifier.DEFAULT_NAMESPACE) {
|
||||
return Octicon.package
|
||||
}
|
||||
|
||||
@@ -69,31 +68,22 @@ function ItemItself({ item }: Props) {
|
||||
return null
|
||||
}
|
||||
|
||||
const texturePath = `item/${item.id.replace(/^minecraft:/, '')}`
|
||||
if (collections.get('texture').includes('minecraft:' + texturePath)) {
|
||||
const src = getAssetUrl(version, 'textures', texturePath)
|
||||
return <>
|
||||
<img src={src} alt="" onError={() => setErrored(true)} draggable={false} />
|
||||
{isEnchanted && <div class="item-glint" style={{'--mask-image': `url("${src}")`}}></div>}
|
||||
</>
|
||||
}
|
||||
|
||||
const modelPath = `item/${item.id.replace(/^minecraft:/, '')}`
|
||||
const modelPath = `item/${item.id.path}`
|
||||
if (collections.get('model').includes('minecraft:' + modelPath)) {
|
||||
return <RenderedItem item={item} isEnchanted={isEnchanted} />
|
||||
return <RenderedItem item={item} hasGlint={hasGlint} />
|
||||
}
|
||||
|
||||
return Octicon.package
|
||||
}
|
||||
|
||||
function RenderedItem({ item, isEnchanted }: Props & { isEnchanted: boolean }) {
|
||||
function RenderedItem({ item, hasGlint }: Props & { hasGlint: boolean }) {
|
||||
const { version } = useVersion()
|
||||
const { value: src } = useAsync(() => renderItem(version, item.id), [version, item])
|
||||
const { value: src } = useAsync(() => renderItem(version, item), [version, item])
|
||||
|
||||
if (src) {
|
||||
return <>
|
||||
<img src={src} alt={item.id} class="model" draggable={false} />
|
||||
{isEnchanted && <div class="item-glint" style={{'--mask-image': `url("${src}")`}}></div>}
|
||||
<img src={src} alt={item.id.toString()} class="model" draggable={false} />
|
||||
{hasGlint && <div class="item-glint" style={{'--mask-image': `url("${src}")`}}></div>}
|
||||
</>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { ItemStack } from 'deepslate'
|
||||
import { Identifier, NbtList, NbtType } from 'deepslate'
|
||||
import { useVersion } from '../contexts/Version.jsx'
|
||||
import { useAsync } from '../hooks/useAsync.js'
|
||||
import { getEnchantmentData, MaxDamageItems } from '../previews/LootTable.js'
|
||||
@@ -5,31 +7,32 @@ import { getTranslation } from '../services/Resources.js'
|
||||
import { TextComponent } from './TextComponent.jsx'
|
||||
|
||||
interface Props {
|
||||
id: string,
|
||||
tag?: any,
|
||||
item: ItemStack,
|
||||
advanced?: boolean,
|
||||
offset?: [number, number],
|
||||
swap?: boolean,
|
||||
}
|
||||
export function ItemTooltip({ id, tag, advanced, offset = [0, 0], swap }: Props) {
|
||||
export function ItemTooltip({ item, advanced, offset = [0, 0], swap }: Props) {
|
||||
const { version } = useVersion()
|
||||
const { value: translatedName } = useAsync(() => {
|
||||
const key = id.split(':').join('.')
|
||||
const key = `${item.id.namespace}.${item.id.path}`
|
||||
return getTranslation(version, `item.${key}`) ?? getTranslation(version, `block.${key}`)
|
||||
}, [version, id])
|
||||
const displayName = tag?.display?.Name
|
||||
const name = displayName ? JSON.parse(displayName) : (translatedName ?? fakeTranslation(id))
|
||||
}, [version, item.id])
|
||||
const displayName = item.tag.getCompound('display').getString('Name')
|
||||
const name = displayName ? JSON.parse(displayName) : (translatedName ?? fakeTranslation(item.id.path))
|
||||
|
||||
const maxDamage = MaxDamageItems.get(id)
|
||||
const enchantments = (id === 'minecraft:enchanted_book' ? tag?.StoredEnchantments : tag?.Enchantments) ?? []
|
||||
const maxDamage = MaxDamageItems.get(item.id.toString())
|
||||
const enchantments = (item.id.equals(Identifier.create('enchanted_book')) ? item.tag.getList('StoredEnchantments', NbtType.Compound) : item.tag.getList('Enchantments', NbtType.Compound)) ?? NbtList.create()
|
||||
|
||||
return <div class="item-tooltip" style={offset && {
|
||||
left: (swap ? undefined : `${offset[0]}px`),
|
||||
right: (swap ? `${offset[0]}px` : undefined),
|
||||
top: `${offset[1]}px`,
|
||||
}}>
|
||||
<TextComponent component={name} base={{ color: 'white' }} />
|
||||
{enchantments.map(({ id, lvl }: { id: string, lvl: number }) => {
|
||||
<TextComponent component={name} base={{ color: 'white', italic: displayName.length > 0 }} />
|
||||
{enchantments.map(enchantment => {
|
||||
const id = enchantment.getString('id')
|
||||
const lvl = enchantment.getNumber('lvl')
|
||||
const ench = getEnchantmentData(id)
|
||||
const component: any[] = [{ translate: `enchantment.${id.replace(':', '.')}`, color: ench?.curse ? 'red' : 'gray' }]
|
||||
if (lvl !== 1 || ench?.maxLevel !== 1) {
|
||||
@@ -37,24 +40,23 @@ export function ItemTooltip({ id, tag, advanced, offset = [0, 0], swap }: Props)
|
||||
}
|
||||
return <TextComponent component={component} />
|
||||
})}
|
||||
{tag?.display && <>
|
||||
{tag?.display?.color && (advanced
|
||||
? <TextComponent component={{ translate: 'item.color', with: [`#${tag.display.color.toString(16).padStart(6, '0')}`], color: 'gray' }} />
|
||||
{item.tag.hasCompound('display') && <>
|
||||
{item.tag.getCompound('display').hasNumber('color') && (advanced
|
||||
? <TextComponent component={{ translate: 'item.color', with: [`#${item.tag.getCompound('display').getNumber('color').toString(16).padStart(6, '0')}`], color: 'gray' }} />
|
||||
: <TextComponent component={{ translate: 'item.dyed', color: 'gray' }} />)}
|
||||
{(tag?.display?.Lore ?? []).map((line: any) => <TextComponent component={JSON.parse(line)} base={{ color: 'dark_purple', italic: true }} />)}
|
||||
{(item.tag.getCompound('display').getList('Lore', NbtType.String)).map((line) => <TextComponent component={JSON.parse(line.getAsString())} base={{ color: 'dark_purple', italic: true }} />)}
|
||||
</>}
|
||||
{tag?.Unbreakable === true && <TextComponent component={{ translate: 'item.unbreakable', color: 'blue' }} />}
|
||||
{(advanced && (tag?.Damage ?? 0) > 0 && maxDamage) && <TextComponent component={{ translate: 'item.durability', with: [`${maxDamage - tag.Damage}`, `${maxDamage}`] }} />}
|
||||
{item.tag.getBoolean('Unbreakable') && <TextComponent component={{ translate: 'item.unbreakable', color: 'blue' }} />}
|
||||
{(advanced && item.tag.getNumber('Damage') > 0 && maxDamage) && <TextComponent component={{ translate: 'item.durability', with: [`${maxDamage - item.tag.getNumber('Damage')}`, `${maxDamage}`] }} />}
|
||||
{advanced && <>
|
||||
<TextComponent component={{ text: id, color: 'dark_gray'}} />
|
||||
{tag && <TextComponent component={{ translate: 'item.nbt_tags', with: [Object.keys(tag).length], color: 'dark_gray' }} />}
|
||||
<TextComponent component={{ text: item.id.toString(), color: 'dark_gray'}} />
|
||||
{item.tag.size > 0 && <TextComponent component={{ translate: 'item.nbt_tags', with: [item.tag.size], color: 'dark_gray' }} />}
|
||||
</>}
|
||||
</div>
|
||||
}
|
||||
|
||||
function fakeTranslation(str: string) {
|
||||
const colon = str.indexOf(':')
|
||||
return str.slice(colon + 1)
|
||||
return str
|
||||
.replace(/[_\/]/g, ' ')
|
||||
.split(' ')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
|
||||
Reference in New Issue
Block a user