Skip to content

Commit

Permalink
Fix rendering of custom names and more text display options (#233)
Browse files Browse the repository at this point in the history
Fix rendering of custom names of normal entities and add more text display options. Newly supported options for text displays:
- background color
- text opacity

Also exclude `mcDataTypes.ts` from linting and fix a possible exception due to no `entityData` being defined
  • Loading branch information
Phoenix616 authored Nov 22, 2024
1 parent c97dbbd commit 50f35cf
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 8 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ generated
dist
public
**/*/rsbuildSharedConfig.ts
src/mcDataTypes.ts
50 changes: 42 additions & 8 deletions prismarine-viewer/viewer/lib/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,27 @@ export const TWEEN_DURATION = 120

type PlayerObjectType = PlayerObject & { animation?: PlayerAnimation }

function getUsernameTexture (username: string, { fontFamily = 'sans-serif' }: any) {
function toRgba (color?: string) {
if (!color || parseInt(color, 10) === 0) {
return 'rgba(0, 0, 0, 0)'
}
const hex = parseInt(color, 10).toString(16)
const r = parseInt(hex.slice(1, 3), 16)
const g = parseInt(hex.slice(3, 5), 16)
const b = parseInt(hex.slice(5, 7), 16)
if (hex.length === 9) {
const a = parseInt(hex.slice(7, 9), 16) / 255
return `rgba(${r}, ${g}, ${b}, ${a})`
} else {
return `rgb(${r}, ${g}, ${b})`
}
}

function getUsernameTexture ({
username,
nameTagBackgroundColor = 'rgba(0, 0, 0, 0.3)',
nameTagTextOpacity = 255
}: any, { fontFamily = 'sans-serif' }: any) {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
if (!ctx) throw new Error('Could not get 2d context')
Expand All @@ -42,11 +62,11 @@ function getUsernameTexture (username: string, { fontFamily = 'sans-serif' }: an
canvas.width = textWidth
canvas.height = (fontSize + padding * 2) * lines.length

ctx.fillStyle = 'rgba(0, 0, 0, 0.3)'
ctx.fillStyle = nameTagBackgroundColor
ctx.fillRect(0, 0, canvas.width, canvas.height)

ctx.font = `${fontSize}px ${fontFamily}`
ctx.fillStyle = 'white'
ctx.fillStyle = `rgba(255, 255, 255, ${nameTagTextOpacity / 255})`
let i = 0
for (const line of lines) {
i++
Expand All @@ -59,7 +79,7 @@ function getUsernameTexture (username: string, { fontFamily = 'sans-serif' }: an
const addNametag = (entity, options, mesh) => {
if (entity.username !== undefined) {
if (mesh.children.some(c => c.name === 'nametag')) return // todo update
const canvas = getUsernameTexture(entity.username, options)
const canvas = getUsernameTexture(entity, options)
const tex = new THREE.Texture(canvas)
tex.needsUpdate = true
const spriteMat = new THREE.SpriteMaterial({ map: tex })
Expand Down Expand Up @@ -304,6 +324,9 @@ export class Entities extends EventEmitter {
parseEntityLabel (jsonLike) {
if (!jsonLike) return
try {
if (jsonLike.type === 'string') {
return jsonLike.value
}
const parsed = typeof jsonLike === 'string' ? mojangson.simplify(mojangson.parse(jsonLike)) : nbt.simplify(jsonLike)
const text = flat(parsed).map(x => x.text)
return text.join('')
Expand Down Expand Up @@ -467,10 +490,21 @@ export class Entities extends EventEmitter {
}
// ---
// not player
const displayTextRaw = meta.custom_name_visible || getSpecificEntityMetadata('text_display', entity)?.text
const displayText = displayTextRaw && this.parseEntityLabel(displayTextRaw)
const textDisplayMeta = getSpecificEntityMetadata('text_display', entity)
const displayTextRaw = textDisplayMeta?.text || meta.custom_name_visible && meta.custom_name
const displayText = this.parseEntityLabel(displayTextRaw)
if (entity.name !== 'player' && displayText) {
addNametag({ ...entity, username: displayText }, this.entitiesOptions, this.entities[entity.id].children.find(c => c.name === 'mesh'))
const nameTagBackgroundColor = textDisplayMeta && toRgba(textDisplayMeta.background_color)
let nameTagTextOpacity: any
if (textDisplayMeta?.text_opacity) {
const rawOpacity = parseInt(textDisplayMeta?.text_opacity, 10)
nameTagTextOpacity = rawOpacity > 0 ? rawOpacity : 256 - rawOpacity
}
addNametag(
{ ...entity, username: displayText, nameTagBackgroundColor, nameTagTextOpacity },
this.entitiesOptions,
this.entities[entity.id].children.find(c => c.name === 'mesh')
)
}

// todo handle map, map_chunks events
Expand Down Expand Up @@ -556,7 +590,7 @@ function getGeneralEntitiesMetadata (entity: { name; metadata }): Partial<UnionT
const entityData = loadedData.entitiesByName[entity.name]
return new Proxy({}, {
get (target, p, receiver) {
if (typeof p !== 'string') return
if (typeof p !== 'string' || !entityData) return
const index = entityData.metadataKeys?.indexOf(p)
return entity.metadata[index ?? -1]
},
Expand Down

0 comments on commit 50f35cf

Please sign in to comment.