257 lines
8.4 KiB
JavaScript
257 lines
8.4 KiB
JavaScript
const mojangson = require('mojangson')
|
|
const nbt = require('prismarine-nbt')
|
|
|
|
const supportedColors = {
|
|
0: 'black',
|
|
1: 'dark_blue',
|
|
2: 'dark_green',
|
|
3: 'dark_aqua',
|
|
4: 'dark_red',
|
|
5: 'dark_purple',
|
|
6: 'gold',
|
|
7: 'gray',
|
|
8: 'dark_gray',
|
|
9: 'blue',
|
|
a: 'green',
|
|
b: 'aqua',
|
|
c: 'red',
|
|
d: 'light_purple',
|
|
e: 'yellow',
|
|
f: 'white',
|
|
k: 'obfuscated',
|
|
l: 'bold',
|
|
m: 'strikethrough',
|
|
n: 'underlined',
|
|
o: 'italic',
|
|
r: 'reset'
|
|
}
|
|
|
|
function loader (registry) {
|
|
class MessageBuilder {
|
|
constructor () {
|
|
this.with = []
|
|
this.extra = []
|
|
}
|
|
|
|
/** @param {boolean} val */
|
|
setBold (val) { this.bold = val; return this }
|
|
/** @param {boolean} val */
|
|
setItalic (val) { this.italic = val; return this }
|
|
/** @param {boolean} val */
|
|
setUnderlined (val) { this.underlined = val; return this }
|
|
/** @param {boolean} val */
|
|
setStrikethrough (val) { this.strikethrough = val; return this }
|
|
/** @param {boolean} val */
|
|
setObfuscated (val) { this.obfuscated = val; return this }
|
|
/** @param {string} val */
|
|
setColor (val) { this.color = val; return this }
|
|
/** @param {string} val */
|
|
setText (val) { this.text = val; return this }
|
|
/**
|
|
* The resource location of the font for this component in the resource pack within `assets/<namespace>/font`.
|
|
* @param {string} val Defaults to `minecraft:default`
|
|
* @returns
|
|
*/
|
|
setFont (val) { this.font = val; return this }
|
|
/**
|
|
* When used, it's expected that all slots for text will be filled using .addWith()
|
|
* @param {string} val
|
|
* @returns
|
|
*/
|
|
setTranslate (val) { this.translate = val; return this }
|
|
/**
|
|
* text shown when shift clicked on message
|
|
* @param {string} val
|
|
*/
|
|
setInsertion (val) { this.insertion = val; return this }
|
|
/**
|
|
* Overrode by .setText()
|
|
* @param {string} val
|
|
* @example
|
|
* builder.setKeybind('key.inventory')
|
|
*/
|
|
setKeybind (val) { this.keybind = val; return this }
|
|
/**
|
|
* Displays a score holder's current score in an objective.
|
|
* Displays nothing if the given score holder or the given objective do not exist, or if the score holder is not tracked in the objective.
|
|
* @param {string} name if '*', show reader their own score. Otherwise, this is the player's score shown. Can be a selector string, but must never select more than one entity.
|
|
* @param {string} objective The internal name of the objective to display the player's score in.
|
|
*/
|
|
setScore (name, objective) { this.score = { name, objective }; return this }
|
|
/**
|
|
* @param {'open_url'|'run_command'|'suggest_command'|'change_page'|'copy_to_clipboard'} action
|
|
* @param {string|number} value
|
|
* @example
|
|
* builder.setClickEvent('open_url', 'https://google.com')
|
|
* builder.setClickEvent('run_command', '/say Hi!') // for signs, the slash doesn't need to be there
|
|
* builder.setClickEvent('suggest_command', '/say ')
|
|
* builder.setClickEvent('change_page', '/say Hi!') // Can only be used in written books
|
|
* builder.setClickEvent('copy_to_clipboard', 'welcome to your clipboard')
|
|
*/
|
|
setClickEvent (action, value) { this.clickEvent = { action, value }; return this }
|
|
/**
|
|
* @param {'show_text'|'show_entity'|'show_item'} action
|
|
* @param {import('prismarine-item').Item|import('prismarine-entity').Entity|MessageBuilder} data
|
|
* @param {'contents'|'value'} type [type='contents']
|
|
*/
|
|
setHoverEvent (action, data, type = 'contents') {
|
|
const hoverEvent = { action }
|
|
if (type === 'contents') {
|
|
switch (action) {
|
|
case 'show_item':
|
|
hoverEvent.contents = {
|
|
id: `minecraft:${data.name}`,
|
|
count: data.count,
|
|
tag: data.nbt ? mojangson.stringify(data.nbt) : {}
|
|
}
|
|
break
|
|
case 'show_entity':
|
|
hoverEvent.contents = {
|
|
name: data.displayName,
|
|
type: `minecraft:${data.name}`,
|
|
id: data.uuid
|
|
}
|
|
break
|
|
case 'show_text':
|
|
hoverEvent.contents = data
|
|
break
|
|
default:
|
|
throw Error('Not implemented')
|
|
}
|
|
} else if (type === 'value') {
|
|
switch (action) {
|
|
case 'show_item':
|
|
// works for 1.12.2 & 1.17
|
|
hoverEvent.value = mojangson.stringify(nbt.comp({
|
|
id: nbt.string(`minecraft:${data.name}`),
|
|
Count: nbt.byte(data.count),
|
|
tag: data.nbt || nbt.comp({}),
|
|
Damage: nbt.short(0)
|
|
}))
|
|
break
|
|
case 'show_text':
|
|
hoverEvent.value = data.toString()
|
|
break
|
|
case 'show_entity':
|
|
default:
|
|
throw Error('Not implemented')
|
|
}
|
|
}
|
|
this.hoverEvent = hoverEvent
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* appended to the end of this message object with the existing formatting.
|
|
* formatting can be overrode in child messagebuilder
|
|
* @param {Array<MessageBuilder | string>} ...args
|
|
* @returns
|
|
*/
|
|
addExtra (...args) {
|
|
for (const v of args) {
|
|
const value = typeof v === 'string' ? v : v.toJSON()
|
|
this.extra.push(value)
|
|
}
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* requires .translate to be set for this to be used
|
|
* @param {Array<MessageBuilder | string>} ...args
|
|
* @returns
|
|
*/
|
|
addWith (...args) {
|
|
for (const v of args) {
|
|
const value = typeof v === 'string' ? v : v.toJSON()
|
|
this.with.push(value)
|
|
}
|
|
return this
|
|
}
|
|
|
|
resetFormatting () {
|
|
this.setBold(false)
|
|
this.setItalic(false)
|
|
this.setUnderlined(false)
|
|
this.setStrikethrough(false)
|
|
this.setObfuscated(false)
|
|
this.setColor('reset')
|
|
}
|
|
|
|
toJSON () {
|
|
const isDef = x => x !== undefined
|
|
const obj = {}
|
|
if (isDef(this.strikethrough)) obj.strikethrough = this.strikethrough
|
|
if (isDef(this.obfuscated)) obj.obfuscated = this.obfuscated
|
|
if (isDef(this.underlined)) obj.underlined = this.underlined
|
|
if (isDef(this.clickEvent)) obj.clickEvent = this.clickEvent
|
|
if (isDef(this.hoverEvent)) obj.hoverEvent = this.hoverEvent
|
|
if (isDef(this.translate)) obj.translate = this.translate
|
|
if (isDef(this.insertion)) obj.insertion = this.insertion
|
|
if (isDef(this.italic)) obj.italic = this.italic
|
|
if (isDef(this.color)) obj.color = this.color
|
|
if (isDef(this.bold)) obj.bold = this.bold
|
|
if (isDef(this.font)) obj.font = this.font
|
|
if (isDef(this.text)) { // text > keybind > score
|
|
obj.text = this.text
|
|
} else if (isDef(this.keybind)) {
|
|
obj.keybind = this.keybind
|
|
} else if (isDef(this.score)) {
|
|
obj.score = this.score
|
|
}
|
|
if (isDef(this.translate) && this.with.length > 0) {
|
|
obj.with = this.with
|
|
}
|
|
if (this.extra.length > 0) {
|
|
obj.extra = this.extra
|
|
}
|
|
return obj
|
|
}
|
|
|
|
toString () {
|
|
return JSON.stringify(this)
|
|
}
|
|
|
|
static fromString (str, { colorSeparator = '&' } = {}) {
|
|
let lastObj = null
|
|
let currString = ''
|
|
for (let i = str.length - 1; i > -1; i--) {
|
|
const char = str.substring(i, i + 1)
|
|
if (char !== colorSeparator) currString += char
|
|
else {
|
|
const text = currString.split('').reverse()
|
|
const color = supportedColors[text.shift()]
|
|
const newObj = new MessageBuilder()
|
|
if (color === 'obfuscated') {
|
|
newObj.setObfuscated(true)
|
|
} else if (color === 'bold') {
|
|
newObj.setBold(true)
|
|
} else if (color === 'strikethrough') {
|
|
newObj.setStrikethrough(true)
|
|
} else if (color === 'underlined') {
|
|
newObj.setUnderlined(true)
|
|
} else if (color === 'italic') {
|
|
newObj.setItalic(true)
|
|
} else if (color === 'reset') {
|
|
newObj.resetFormatting()
|
|
} else {
|
|
newObj.setColor(color)
|
|
}
|
|
newObj.setText(text.join(''))
|
|
if (lastObj === null) lastObj = newObj
|
|
else lastObj = newObj.addExtra(lastObj)
|
|
currString = ''
|
|
}
|
|
}
|
|
if (currString !== '') {
|
|
const txt = currString.split('').reverse().join('')
|
|
if (lastObj !== null) lastObj = new MessageBuilder().setText(txt).addExtra(lastObj)
|
|
else lastObj = new MessageBuilder().setText(txt)
|
|
}
|
|
return lastObj
|
|
}
|
|
}
|
|
|
|
return { MessageBuilder }
|
|
}
|
|
|
|
module.exports = loader
|