From f7afbada19004bc7873c447229b44eca688fa287 Mon Sep 17 00:00:00 2001 From: frto027 <602706150@qq.com> Date: Wed, 19 Jan 2022 15:36:09 +0800 Subject: [PATCH 1/5] added support for newline of UTF8 characters --- eid_api.lua | 107 +++++++++++++++++++++++++++++++++++++++++++-------- eid_data.lua | 4 ++ main.lua | 2 +- 3 files changed, 96 insertions(+), 17 deletions(-) diff --git a/eid_api.lua b/eid_api.lua index 9c0ea8dd..e0229533 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -720,28 +720,103 @@ end -- Fits a given string to a specific width -- returns the string as a table of lines -function EID:fitTextToWidth(str, textboxWidth) +function EID:fitTextToWidth(str, textboxWidth, breakUtf8Chars) local formatedLines = {} local curLength = 0 local text = "" - for word in string.gmatch(str, "([^%s]+)") do - local colorFiltered = EID:filterColorMarkup(word, EID:getTextColor()) - local filteredWord = "" - for _, filtered in ipairs(colorFiltered) do - filteredWord = filteredWord .. filtered[1] - end - local strFiltered, spriteTable = EID:filterIconMarkup(filteredWord, 0, 0) - local wordLength = EID:getStrWidth(strFiltered) - if curLength + wordLength <= textboxWidth or curLength < 12 then - text = text .. word .. " " - curLength = curLength + wordLength - else - table.insert(formatedLines, text) - text = word .. " " - curLength = wordLength + local cursor = 1 + local word_begin_index = 1 + + local byte = string.byte -- for speed up + local sub = string.sub + local byte_space = string.byte(' ') + + while cursor <= #str do + -- ascii word: 0x0xxxxxxx + -- utf8 word (sequence): 0x11xxxxxx 0x10xxxxxx 0x10xxxxxx ... 0x10xxxxxx + -- see https://en.wikipedia.org/wiki/UTF-8 + -- we can only break after space, or before 0x11xxxxxx + local can_break_after_cursor = false + local cur, next = byte(str,cursor), byte(str,cursor+1) + if + -- cond#1: we can break at the end of string + cursor == #str or + -- cond#2: we can break after space + cur == byte_space or + -- handle utf8 characters + (breakUtf8Chars and( + -- cond#3: we can break if the next character is 0x11xxxxxx + ((next & 0xC0) == 0xC0) or + -- cond#4: we can also break if the current is 0x10xxxxxx while the next is ascii but not space + (((cur & 0xC0) == 0x80) and (next~= byte_space and (next & 0x80) == 0x00)) + )) + then + + --[[ + -------------------ascii only--------------- + word will be separated by spaces. + wordA |wordB |wordC |^%@&Q%#^&#@!! |aksldj + ↑ + cond#2 + we may break after every space. + spaces | | | | | |woops + ↑ + cond#2 + -------------------UTF8 only---------------- + word is 0x11xxxxxx followed by several 0x10xxxxxx until the next 0x11xxxxxx (not included) + 你|好|,|世|界|!|↑|↑|↑|↑ + ↑ + cond#3 + byte data of a word: + [0x11xxxxxx,0x10xxxxxx,0x10xxxxxx, (next is 0x11xxxxxx, cond#3)] + --------------------ascii->utf8------------ + utf8 word must start with 0x11xxxxxx, so cond#3 split before it. + word|世|界 + | ↑ + ↑ cond#3 + cond#3 + + world |means |世|界 + ↑ + cond#2 + -------------------utf8->ascii-------------- + 世|界|是|world + | ↑ + ↑ cond#4 + cond#3 + 世|界|是 |world + | ↑ + ↑ cond#4 + cond#3 + ]] + + -- we can break after str[cursor] + local word = sub(str, word_begin_index, cursor) + + local colorFiltered = EID:filterColorMarkup(word, EID:getTextColor()) + local filteredWord = "" + for _, filtered in ipairs(colorFiltered) do + filteredWord = filteredWord .. filtered[1] + end + local strFiltered, spriteTable = EID:filterIconMarkup(filteredWord, 0, 0) + local wordLength = EID:getStrWidth(strFiltered) + + if curLength + wordLength <= textboxWidth or curLength < 12 then + text = text .. word + curLength = curLength + wordLength + else + table.insert(formatedLines, text) + text = word + curLength = wordLength + end + + -- next word starts here + word_begin_index = cursor + 1 end + cursor = cursor + 1 end + table.insert(formatedLines, text) return formatedLines end diff --git a/eid_data.lua b/eid_data.lua index 9e8e699e..2cc6dc9e 100644 --- a/eid_data.lua +++ b/eid_data.lua @@ -498,3 +498,7 @@ EID.GoldenTrinketData = { -- Lil Clot, Swallowed M80, The Twins (default text), Cricket Leg (17%, 1 in 6), Apollyon's Best Friend, Broken Glasses [176] = 1, [178] = {t={50},mult=2}, [183] = 0, [185] = 17, [186] = 1, [187] = {t={50,50}, mult=2}, } + +EID.BreakUtf8CharsLanguage = { + ['zh_cn'] = true +} diff --git a/main.lua b/main.lua index 8dd1c69e..c97e211e 100644 --- a/main.lua +++ b/main.lua @@ -512,7 +512,7 @@ function EID:printBulletPoints(description, renderPos) local textScale = Vector(EID.Scale, EID.Scale) description = EID:replaceShortMarkupStrings(description) for line in string.gmatch(description, "([^#]+)") do - local formatedLines = EID:fitTextToWidth(line, textboxWidth) + local formatedLines = EID:fitTextToWidth(line, textboxWidth, EID.BreakUtf8CharsLanguage[EID.Config["Language"]]) local textColor = EID:getTextColor() for i, lineToPrint in ipairs(formatedLines) do -- render bulletpoint From e0407f635535b0b9cfa928372b50144f8a51d36d Mon Sep 17 00:00:00 2001 From: frto027 <602706150@qq.com> Date: Wed, 19 Jan 2022 21:18:53 +0800 Subject: [PATCH 2/5] optimize performance for fitTextToWidth --- eid_api.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/eid_api.lua b/eid_api.lua index e0229533..4ffcacb8 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -723,7 +723,7 @@ end function EID:fitTextToWidth(str, textboxWidth, breakUtf8Chars) local formatedLines = {} local curLength = 0 - local text = "" + local text = {} local cursor = 1 local word_begin_index = 1 @@ -740,7 +740,7 @@ function EID:fitTextToWidth(str, textboxWidth, breakUtf8Chars) local can_break_after_cursor = false local cur, next = byte(str,cursor), byte(str,cursor+1) if - -- cond#1: we can break at the end of string + -- cond#1: we can break at the end of string cursor == #str or -- cond#2: we can break after space cur == byte_space or @@ -803,11 +803,11 @@ function EID:fitTextToWidth(str, textboxWidth, breakUtf8Chars) local wordLength = EID:getStrWidth(strFiltered) if curLength + wordLength <= textboxWidth or curLength < 12 then - text = text .. word + table.insert(text, word) curLength = curLength + wordLength else - table.insert(formatedLines, text) - text = word + table.insert(formatedLines, table.concat(text)) + text = { word } curLength = wordLength end @@ -817,7 +817,7 @@ function EID:fitTextToWidth(str, textboxWidth, breakUtf8Chars) cursor = cursor + 1 end - table.insert(formatedLines, text) + table.insert(formatedLines, table.concat(text)) return formatedLines end From 4b703c07c1291603a390a494c0df464629821c3d Mon Sep 17 00:00:00 2001 From: frto027 <602706150@qq.com> Date: Wed, 19 Jan 2022 21:32:53 +0800 Subject: [PATCH 3/5] use string.rep in generatePlaceholderString --- eid_api.lua | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/eid_api.lua b/eid_api.lua index 4ffcacb8..0dfbcf51 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -530,11 +530,7 @@ end -- Generates a string with the defined pixel-length using a custom 1px wide character -- This will only work for this specific custom font function EID:generatePlaceholderString(length) - local placeholder = "" - for i = 1, length do - placeholder = placeholder .. "¤" - end - return placeholder + return string.rep("¤", length) end -- Returns the inlineIcon object of a given Iconstring @@ -795,11 +791,11 @@ function EID:fitTextToWidth(str, textboxWidth, breakUtf8Chars) local word = sub(str, word_begin_index, cursor) local colorFiltered = EID:filterColorMarkup(word, EID:getTextColor()) - local filteredWord = "" + local filteredWord = {} for _, filtered in ipairs(colorFiltered) do - filteredWord = filteredWord .. filtered[1] + table.insert(filteredWord, filtered[1]) end - local strFiltered, spriteTable = EID:filterIconMarkup(filteredWord, 0, 0) + local strFiltered, spriteTable = EID:filterIconMarkup(table.concat(filteredWord), 0, 0) local wordLength = EID:getStrWidth(strFiltered) if curLength + wordLength <= textboxWidth or curLength < 12 then From 14f76982d5f16c16903ea3118036d9eb799d8aa6 Mon Sep 17 00:00:00 2001 From: frto027 <602706150@qq.com> Date: Wed, 19 Jan 2022 22:00:46 +0800 Subject: [PATCH 4/5] fix comment in fitTextToWidth --- eid_api.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eid_api.lua b/eid_api.lua index 0dfbcf51..44fffed1 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -748,7 +748,6 @@ function EID:fitTextToWidth(str, textboxWidth, breakUtf8Chars) (((cur & 0xC0) == 0x80) and (next~= byte_space and (next & 0x80) == 0x00)) )) then - --[[ -------------------ascii only--------------- word will be separated by spaces. @@ -783,7 +782,7 @@ function EID:fitTextToWidth(str, textboxWidth, breakUtf8Chars) cond#3 世|界|是 |world | ↑ - ↑ cond#4 + ↑ cond#2 cond#3 ]] From 06a35103d4659e966c207332452ba66a7832fd1a Mon Sep 17 00:00:00 2001 From: frto027 <602706150@qq.com> Date: Wed, 19 Jan 2022 22:20:06 +0800 Subject: [PATCH 5/5] configure 'textboxWidth' for each font --- descriptions/ab+/en_us.lua | 2 +- descriptions/ab+/ko_kr.lua | 2 +- descriptions/ab+/zh_cn.lua | 2 +- eid_api.lua | 1 + mod_config_menu.lua | 1 + 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/descriptions/ab+/en_us.lua b/descriptions/ab+/en_us.lua index e2dff692..1195b2c4 100644 --- a/descriptions/ab+/en_us.lua +++ b/descriptions/ab+/en_us.lua @@ -16,7 +16,7 @@ EID.descriptions[languageCode].custom = {} -- table for custom entity descriptio EID.descriptions[languageCode].languageName = "English" -- Fonts to be used with this language pack -EID.descriptions[languageCode].fonts = {{name="default", lineHeight=11}, {name="inverted", lineHeight=11}, {name="borderless", lineHeight=11}} +EID.descriptions[languageCode].fonts = {{name="default", lineHeight=11, textboxWidth = 115}, {name="inverted", lineHeight=11, textboxWidth = 115}, {name="borderless", lineHeight=11, textboxWidth = 115}} ---------- Collectibles ---------- EID.descriptions[languageCode].collectibles={ diff --git a/descriptions/ab+/ko_kr.lua b/descriptions/ab+/ko_kr.lua index f7e284c8..3c000259 100644 --- a/descriptions/ab+/ko_kr.lua +++ b/descriptions/ab+/ko_kr.lua @@ -29,7 +29,7 @@ EID.descriptions[languageCode].languageName = "Korean" korean_galmoori9, korean_galmoori11 is added for community request. ]] -EID.descriptions[languageCode].fonts = {{name="korean_hcrdotum", lineHeight=11}, {name="korean_lanapixel", lineHeight=12}, {name="korean_soyakkoma", lineHeight=13}, {name="korean_soyakkoma_borderless", lineHeight=13}, {name="korean_soyakkoma_inverted", lineHeight=13}, {name="korean_soyanon", lineHeight=12}, {name="korean_galmoori9", lineHeight=12}, {name="korean_galmoori11", lineHeight=14}} +EID.descriptions[languageCode].fonts = {{name="korean_hcrdotum", lineHeight=11, textboxWidth = 115}, {name="korean_lanapixel", lineHeight=12, textboxWidth = 115}, {name="korean_soyakkoma", lineHeight=13, textboxWidth = 115}, {name="korean_soyakkoma_borderless", lineHeight=13, textboxWidth = 115}, {name="korean_soyakkoma_inverted", lineHeight=13, textboxWidth = 115}, {name="korean_soyanon", lineHeight=12, textboxWidth = 115}, {name="korean_galmoori9", lineHeight=12, textboxWidth = 115}, {name="korean_galmoori11", lineHeight=14, textboxWidth = 115}} ---------- Collectibles ---------- EID.descriptions[languageCode].collectibles={ diff --git a/descriptions/ab+/zh_cn.lua b/descriptions/ab+/zh_cn.lua index 778ef20b..97072791 100644 --- a/descriptions/ab+/zh_cn.lua +++ b/descriptions/ab+/zh_cn.lua @@ -16,7 +16,7 @@ EID.descriptions[languageCode].custom = {} -- table for custom entity descriptio EID.descriptions[languageCode].languageName = "Chinese" -- Fonts to be used with this languagepack -EID.descriptions[languageCode].fonts = {{name = "default_cn", lineHeight = 14}} +EID.descriptions[languageCode].fonts = {{name = "default_cn", lineHeight = 14, textboxWidth = 150}} ---------- Collectibles ---------- EID.descriptions[languageCode].collectibles={ diff --git a/eid_api.lua b/eid_api.lua index 44fffed1..12c05697 100644 --- a/eid_api.lua +++ b/eid_api.lua @@ -1111,6 +1111,7 @@ function EID:fixDefinedFont() end EID.Config["FontType"] = EID.descriptions[curLang].fonts[1].name EID.lineHeight = EID.descriptions[curLang].fonts[1].lineHeight + EID.Config["TextboxWidth"] = EID.descriptions[curLang].fonts[1].textboxWidth return true end diff --git a/mod_config_menu.lua b/mod_config_menu.lua index 26204ef4..695fdd56 100644 --- a/mod_config_menu.lua +++ b/mod_config_menu.lua @@ -1014,6 +1014,7 @@ if MCMLoaded then OnChange = function(currentNum) EID.Config["FontType"] = fontNames[currentNum] EID.lineHeight = fonts[currentNum].lineHeight + EID.Config["TextboxWidth"] = fonts[currentNum].textboxWidth EID:fixDefinedFont() local fontFile = EID.Config["FontType"] or "default" EID:loadFont(EID.modPath .. "resources/font/eid_"..fontFile..".fnt")