diff --git a/package-lock.json b/package-lock.json
index b98d55dc..0446e071 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,7 +23,7 @@
"brace": "^0.11.1",
"buffer": "^6.0.3",
"comment-json": "^4.1.1",
- "deepslate": "^0.15.6",
+ "deepslate": "^0.15.7",
"deepslate-1.18": "npm:deepslate@^0.9.0-beta.9",
"deepslate-1.18.2": "npm:deepslate@^0.9.0-beta.13",
"highlight.js": "^11.5.1",
@@ -1955,9 +1955,9 @@
"dev": true
},
"node_modules/deepslate": {
- "version": "0.15.6",
- "resolved": "https://registry.npmjs.org/deepslate/-/deepslate-0.15.6.tgz",
- "integrity": "sha512-aUNkqozUTvEuR/tFWCiFCpsJ4Q8AaHyvHY33/T7K+cUY9V6wlrlUwPCgwoaP3G6AMWUm5vN57NSu+dC8ESTDww==",
+ "version": "0.15.7",
+ "resolved": "https://registry.npmjs.org/deepslate/-/deepslate-0.15.7.tgz",
+ "integrity": "sha512-HRo31wvMfw4t8osCeiX/A79W1XfP7kyQJJZKjZlKiUutoHErEnpGuEOn0XdKXc4NQXEvrbUmL2yOrNo+DCjdug==",
"dependencies": {
"gl-matrix": "^3.3.0",
"md5": "^2.3.0",
@@ -6698,9 +6698,9 @@
"dev": true
},
"deepslate": {
- "version": "0.15.6",
- "resolved": "https://registry.npmjs.org/deepslate/-/deepslate-0.15.6.tgz",
- "integrity": "sha512-aUNkqozUTvEuR/tFWCiFCpsJ4Q8AaHyvHY33/T7K+cUY9V6wlrlUwPCgwoaP3G6AMWUm5vN57NSu+dC8ESTDww==",
+ "version": "0.15.7",
+ "resolved": "https://registry.npmjs.org/deepslate/-/deepslate-0.15.7.tgz",
+ "integrity": "sha512-HRo31wvMfw4t8osCeiX/A79W1XfP7kyQJJZKjZlKiUutoHErEnpGuEOn0XdKXc4NQXEvrbUmL2yOrNo+DCjdug==",
"requires": {
"gl-matrix": "^3.3.0",
"md5": "^2.3.0",
diff --git a/package.json b/package.json
index 9b0b276a..24f442b3 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
"brace": "^0.11.1",
"buffer": "^6.0.3",
"comment-json": "^4.1.1",
- "deepslate": "^0.15.6",
+ "deepslate": "^0.15.7",
"deepslate-1.18": "npm:deepslate@^0.9.0-beta.9",
"deepslate-1.18.2": "npm:deepslate@^0.9.0-beta.13",
"highlight.js": "^11.5.1",
diff --git a/src/app/components/ItemDisplay.tsx b/src/app/components/ItemDisplay.tsx
index b3262089..6144d951 100644
--- a/src/app/components/ItemDisplay.tsx
+++ b/src/app/components/ItemDisplay.tsx
@@ -49,7 +49,13 @@ export function ItemDisplay({ item, slotDecoration, advancedTooltip }: Props) {
}
>}
-
+
+
+
}
diff --git a/src/app/components/ItemTooltip.tsx b/src/app/components/ItemTooltip.tsx
index 7c813ab9..215a26b0 100644
--- a/src/app/components/ItemTooltip.tsx
+++ b/src/app/components/ItemTooltip.tsx
@@ -1,5 +1,6 @@
import type { ItemStack } from 'deepslate'
-import { NbtList, NbtType } from 'deepslate'
+import { AttributeModifierOperation, MobEffectInstance, NbtList, NbtType, Potion } from 'deepslate'
+import { useMemo } from 'preact/hooks'
import { useVersion } from '../contexts/Version.jsx'
import { useAsync } from '../hooks/useAsync.js'
import { getEnchantmentData, MaxDamageItems } from '../previews/LootTable.js'
@@ -9,27 +10,64 @@ import { TextComponent } from './TextComponent.jsx'
interface Props {
item: ItemStack,
advanced?: boolean,
- offset?: [number, number],
- swap?: boolean,
}
-export function ItemTooltip({ item, advanced, offset = [0, 0], swap }: Props) {
+export function ItemTooltip({ item, advanced }: Props) {
const { version } = useVersion()
+
+ const isPotion = item.is('potion') || item.is('splash_potion') || item.is('lingering_potion')
+ const descriptionId = useMemo(() => {
+ const d = `${item.id.namespace}.${item.id.path}`
+ if (isPotion) {
+ return `${d}.effect.${Potion.fromNbt(item).name}`
+ }
+ return d
+ }, [item])
const { value: translatedName } = useAsync(() => {
- const key = `${item.id.namespace}.${item.id.path}`
- return getTranslation(version, `item.${key}`) ?? getTranslation(version, `block.${key}`)
- }, [version, item.id])
+ return getTranslation(version, `item.${descriptionId}`) ?? getTranslation(version, `block.${descriptionId}`)
+ }, [version, descriptionId])
const displayName = item.tag.getCompound('display').getString('Name')
const name = displayName ? JSON.parse(displayName) : (translatedName ?? fakeTranslation(item.id.path))
const maxDamage = MaxDamageItems.get(item.id.toString())
const enchantments = (item.is('enchanted_book') ? item.tag.getList('StoredEnchantments', NbtType.Compound) : item.tag.getList('Enchantments', NbtType.Compound)) ?? NbtList.create()
- return
+ const effects = isPotion ? Potion.getAllEffects(item) : []
+ const attributeModifiers = isPotion ? Potion.getAllAttributeModifiers(item) : []
+
+ return <>
0 }} />
+ {(!advanced && displayName.length === 0 && item.is('filled_map') && item.tag.hasNumber('map')) && <>
+
+ >}
+ {(item.is('filled_map') && advanced) && <>
+
+ >}
+ {isPotion && effects.length === 0
+ ?
+ : effects.map(e => {
+ const color = e.effect.category === 'harmful' ? 'red' : 'blue'
+ let component: any = { translate: `effect.${e.effect.id.namespace}.${e.effect.id.path}` }
+ if (e.amplifier > 0) {
+ component = { translate: 'potion.withAmplifier', with: [component, { translate: `potion.potency.${e.amplifier}` }] }
+ }
+ if (e.duration > 20) {
+ component = { translate: 'potion.withDuration', with: [component, MobEffectInstance.formatDuration(e)] }
+ }
+ return
+ })}
+ {attributeModifiers.length > 0 && <>
+
+
+ {attributeModifiers.map(([attr, { amount, operation }]) => {
+ const a = operation === AttributeModifierOperation.addition ? amount * 100 : amount
+ if (amount > 0) {
+ return
+ } else if (amount < 0) {
+ return
+ }
+ return null
+ })}
+ >}
{enchantments.map(enchantment => {
const id = enchantment.getString('id')
const lvl = enchantment.getNumber('lvl')
@@ -52,7 +90,7 @@ export function ItemTooltip({ item, advanced, offset = [0, 0], swap }: Props) {
{item.tag.size > 0 && }
>}
-
+ >
}
function fakeTranslation(str: string) {
diff --git a/src/app/components/TextComponent.tsx b/src/app/components/TextComponent.tsx
index 2e0b26c9..7bff3579 100644
--- a/src/app/components/TextComponent.tsx
+++ b/src/app/components/TextComponent.tsx
@@ -1,7 +1,7 @@
import { useMemo } from 'preact/hooks'
import { useVersion } from '../contexts/Version.jsx'
import { useAsync } from '../hooks/useAsync.js'
-import { getTranslation } from '../services/Resources.js'
+import { getLanguage, replaceTranslation } from '../services/Resources.js'
interface StyleData {
color?: string,
@@ -23,6 +23,8 @@ interface Props {
shadow?: boolean,
}
export function TextComponent({ component, base = { color: 'white' }, shadow = true }: Props) {
+ const { version } = useVersion()
+
const state = JSON.stringify(component)
const parts = useMemo(() => {
const parts: PartData[] = []
@@ -30,12 +32,14 @@ export function TextComponent({ component, base = { color: 'white' }, shadow = t
return parts
}, [state])
+ const { value: language } = useAsync(() => getLanguage(version), [version])
+
return
{shadow &&
- {parts.map(p => )}
+ {parts.map(p => )}
}
- {parts.map(p => )}
+ {parts.map(p => )}
}
@@ -104,17 +108,26 @@ const TextColors = {
type TextColorKey = keyof typeof TextColors
const TextColorKeys = Object.keys(TextColors)
-function TextPart({ part, shadow }: { part: PartData, shadow?: boolean }) {
+function TextPart({ part, shadow, lang }: { part: PartData, shadow?: boolean, lang: Record }) {
if (part.translate) {
- const { version } = useVersion()
- const { value: translated } = useAsync(() => {
- return getTranslation(version, part.translate!, part.with)
- }, [version, part.translate, ...part.with ?? []])
- return {translated ?? part.translate}
+ const str = resolveTranslate(part.translate, part.with, lang)
+ return {str}
}
return {part.text}
}
+function resolveTranslate(translate: string, with_: any[] | undefined, lang: Record): string {
+ const str = lang[translate]
+ if (typeof str !== 'string') return translate
+ const params = with_?.map((c): string => {
+ if (typeof c === 'string' || typeof c === 'number') return `${c}`
+ if (c.text) return c.text
+ if (c.translate) return resolveTranslate(c.translate, c.with, lang)
+ return ''
+ })
+ return replaceTranslation(str, params)
+}
+
function createStyle(style: StyleData, shadow?: boolean) {
return {
color: style.color && (TextColorKeys.includes(style.color)
diff --git a/src/app/previews/LootTable.ts b/src/app/previews/LootTable.ts
index e9ca9c52..9e1c8012 100644
--- a/src/app/previews/LootTable.ts
+++ b/src/app/previews/LootTable.ts
@@ -359,6 +359,11 @@ const LootFunctions: Record LootFunction> = {
}
} catch (e) {}
},
+ set_potion: ({ id }) => (item) => {
+ if (typeof id === 'string') {
+ item.tag.set('Potion', new NbtString(Identifier.parse(id).toString()))
+ }
+ },
}
type LootCondition = (ctx: LootContext) => boolean
diff --git a/src/styles/global.css b/src/styles/global.css
index 15d09a3e..d25d376d 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -1331,6 +1331,10 @@ hr {
top: -2px;
}
+.text-component span:empty:before {
+ content: '\200b';
+}
+
.file-view {
background-color: var(--background-2);
color: var(--text-2);