Skip to content

Instantly share code, notes, and snippets.

@ReinforceZwei
Last active April 14, 2020 12:59
Show Gist options
  • Save ReinforceZwei/8e35610d5b6eef632b32da457cedfb81 to your computer and use it in GitHub Desktop.
Save ReinforceZwei/8e35610d5b6eef632b32da457cedfb81 to your computer and use it in GitHub Desktop.
Minecraft Chat Parser for parsing json from the protocol packet to readable text
// ANSI color code outputs for strings
var ANSI_CODES = {
"off": 0,
"bold": 1,
"italic": 3,
"underline": 4,
"blink": 5,
"inverse": 7,
"hidden": 8,
// colors
"gray": 90,
"red": 91,
"green": 92,
"yellow": 93,
"blue": 94,
"magenta": 95,
"cyan": 96,
"black": 30,
"dark_red": 31,
"dark_aqua": 32,
"dark_green": 33,
"dark_blue": 34,
"dark_purple": 35,
"white": 37,
// gackgrounds
"black_bg": 40,
"red_bg": 41,
"green_bg": 42,
"yellow_bg": 43,
"blue_bg": 44,
"magenta_bg": 45,
"cyan_bg": 46,
"white_bg": 47
};
export default function color(str: string, color: string): string {
if (!color) return str;
var color_attrs = color.split("+");
var ansi_str = "";
for (var i = 0, attr; attr = color_attrs[i]; i++) {
ansi_str += "\u001b[" + ANSI_CODES[attr] + "m";
}
ansi_str += str + "\u001b[" + ANSI_CODES["off"] + "m";
return ansi_str;
};
/*
* Minecraft Chat Parser - by Reinforce Zwei
*/
import color from './AnsiColor';
import * as util from 'util';
let Translation = require('./lang/zh_tw.json'); // the translation file
// You can follow https://www.reddit.com/r/Minecraft/comments/ak57gu/other_language_files/
// to get the translation file
let oldColorCodeReg = /§[0-f,k-o,r]/gm;
interface ChatObject {
bold?: boolean,
italic?: boolean,
underlined?: boolean,
strikethrough?: boolean,
obfuscated?: boolean,
color?: Colors,
text?: string,
translate?: string,
with?: Array<ChatObject>,
insertion?: string,
clickEvent?: clickEvent,
hoverEvent?: hoverEvent,
extra?: Array<ChatObject>
}
interface clickEvent {
open_url?: string,
run_command?: string,
suggest_command?: string,
change_page?: string
}
interface hoverEvent {
show_text?: string,
show_item?: string,
show_entity?: string
}
enum Colors {
black = 'black+white_bg',
dark_blue = 'dark_blue',
dark_green = 'dark_green',
dark_aqua = 'dark_aqua',
dark_red = 'dark_red',
dark_purple = 'dark_purple',
gold = 'yellow',
gray = 'gray',
dark_gray = 'gray',
blue = 'blue',
green = 'green',
aqua = 'cyan',
red = 'red',
light_purple = 'magenta',
yellow = 'yellow',
white = 'white',
reset = 'white+black_bg'
}
enum Styles {
obfuscated = 'blink',
bold = 'bold',
strikethrough = '',
underlined = 'underlined',
italic = ''
}
export default function ParseChat(chat: ChatObject, parentStyle?: { colors?:Array<string>, style?:Array<string>}) {
let colors: Array<string> = new Array<string>(); // color stack, clear on new style
let style: Array<string> = new Array<string>(); // style stack, clear on new style
let text: string = ''; // will store with color code
if (parentStyle && (parentStyle.colors.length > 0 || parentStyle.style.length > 0)) {
colors = colors.concat(parentStyle.colors);
style = style.concat(parentStyle.style);
}
if (chat.bold) style.push(Styles.bold);
if (chat.italic) style.push(Styles.italic);
if (chat.underlined) style.push(Styles.underlined);
if (chat.strikethrough) style.push(Styles.strikethrough);
if (chat.obfuscated) style.push(Styles.obfuscated);
if (chat.color) colors.push(Colors[chat.color]);
if (colors.length > 1) colors.shift();
//if (style.length > 1) style.shift();
if (chat.text) {
// handle § color
if (chat.text.match(oldColorCodeReg)) {
let txtpart = chat.text.split(oldColorCodeReg);
let colorCode = chat.text.match(oldColorCodeReg);
let tmp = new Array<string>();
tmp.push(txtpart[0]);
colorCode.forEach((e, i) => {
e = e.slice(1);
let tmpColor: string;
switch (e) {
case '0': tmpColor = Colors.black; break;
case '1': tmpColor = Colors.dark_blue; break;
case '2': tmpColor = Colors.dark_green; break;
case '3': tmpColor = Colors.dark_aqua; break;
case '4': tmpColor = Colors.dark_red; break;
case '5': tmpColor = Colors.dark_purple; break;
case '6': tmpColor = Colors.gold; break;
case '7': tmpColor = Colors.gray; break;
case '8': tmpColor = Colors.dark_gray; break;
case '9': tmpColor = Colors.blue; break;
case 'a': tmpColor = Colors.green; break;
case 'b': tmpColor = Colors.aqua; break;
case 'c': tmpColor = Colors.red; break;
case 'd': tmpColor = Colors.light_purple; break;
case 'e': tmpColor = Colors.yellow; break;
case 'f': tmpColor = Colors.white; break;
case 'r': tmpColor = Colors.reset; break;
}
tmp.push(color(txtpart[i + 1], tmpColor));
});
if (tmp[0] == '') tmp.shift();
text += tmp.join('');
} else {
text += color(chat.text, colors.concat(style).join('+'));
}
}
if (chat.translate) {
let translatedText = Translation[chat.translate].replace(/%\d\$s/gm, '%s');
if (chat.with) {
let args: Array<string> = new Array<string>();
chat.with.forEach(e => {
args.push(ParseChat(e));
});
text += color(util.format(translatedText, ...args), colors.concat(style).join('+'));
} else {
text += color(translatedText, colors.concat(style).join('+'));
}
}
if (chat.extra) {
chat.extra.forEach(e => {
text += ParseChat(e, { colors, style });
});
}
return text;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment