Мы с другом посидели над этим в игре: подсунули в cef аризоны свой отладочный JS и прогнали штук 40 тестовых диалогов. Цвет и
&#...; тут ни при чём, всё упирается в длину строки.
В списке (style 2) первая строка должна быть не длиннее 130 байт. Если длиннее, игра текст в cef отдаёт (в
setDialogInfo он приходит целиком), но окно не показывает. Поэтому у тебя ID есть, а окна нет. На остальные строки, общий размер, msgbox и tablist это не распространяется. Первая строка на 129-130 байт открывается, на 135 уже нет. А вот вторая или последняя строка на 600 байт открывается спокойно, и 70 строк на 4270 байт тоже. Цвет вместе с тайским сущностями тоже открывается, и цвета нормальные.
Почему кажется, что виноват цвет: одна тайская буква как
ก это 7 байт, а
{RRGGBB} докидывает ещё 8.
Как сделать: гнать тайский не сущностями, а по байту на букву (CP874) внутри
[[th:...]]. SAMP примет это как обычный CP1251, а маленький хук в cef перед отрисовкой превратит обратно в тайский. Строки получаются в 7 раз короче, цвета остаются. Проверили на меню с цветами
#FFFFFF/
#FFD24A вперемешку, показывается как надо.
Сначала добавь это рядом с
utf8ToHtmlEntities:
-- Тайский (U+0E01..U+0E5B) -> [[th:<байты CP874>]], 1 байт на букву вместо 7
local function thaiPack(s)
local out, run, i = {}, {}, 1
local function flush() if #run > 0 then out[#out + 1] = '[[th:' .. table.concat(run) .. ']]'; run = {} end end
while i <= #s do
local b1, b2, b3 = s:byte(i, i + 2)
local off = (b1 == 0xE0 and (b2 == 0xB8 or b2 == 0xB9) and b3) and (b2 - 0xB8) * 64 + (b3 - 0x80) or nil
if off and off >= 1 and off <= 0x5B then
run[#run + 1] = string.char(0xA0 + off); i = i + 3
elseif b1 == 32 and #run > 0 then
run[#run + 1] = ' '; i = i + 1
else
flush(); out[#out + 1] = s:sub(i, i); i = i + 1
end
end
flush()
return table.concat(out)
end
-- JS-хук: [[th:...]] -> тайский перед отрисовкой диалога в cef
local THAI_DECODER_JS = [=[
(() => { try {
if (window.__icsThaiDec) return;
window.__icsThaiDec = 1;
const dec = new TextDecoder('windows-1251'), back = {};
for (let b = 0x80; b <= 0xFF; b++) back[dec.decode(new Uint8Array([b]))] = b;
const fix = s => typeof s !== 'string' ? s : s.replace(/\[\[th:([^\]]*)\]\]/g, (m, t) =>
[...t].map(c => { const b = back[c]; return b >= 0xA1 && b <= 0xFB ? String.fromCharCode(0x0E00 + b - 0xA0) : c; }).join(''));
const o = window.cef.setDialogInfo;
window.cef.setDialogInfo = function (id, type, header, body, b1, b2, ...rest) {
return o.call(this, id, type, fix(header), fix(body), fix(b1), fix(b2), ...rest);
};
} catch (e) {} })();
]=]
local function evalCef(code)
local bs = raknetNewBitStream()
raknetBitStreamWriteInt8(bs, 17)
raknetBitStreamWriteInt32(bs, 0)
raknetBitStreamWriteInt16(bs, #code)
raknetBitStreamWriteInt8(bs, 0)
raknetBitStreamWriteString(bs, code)
raknetEmulPacketReceiveBitStream(220, bs)
raknetDeleteBitStream(bs)
end
JS тут в
[=[ ... ]=], не в
[[ ... ]], это не просто так. В регулярке есть
]], и обычная длинная строка Lua на нём оборвётся. Я сам на этом споткнулся.
Дальше в
utf8ToHtmlEntities надо пропускать тайские буквы, чтобы их потом упаковал
thaiPack. Перед
return '&#' .. cp .. ';' вставь:
if cp >= 0x0E01 and cp <= 0x0E5B then return ch end
И сделай общий кодировщик:
local function encodeDlg(s) return thaiPack(utf8ToHtmlEntities(s)) end
В
showTranslatedDialog перед
sampShowDialog вызывай хук и кодируй через него:
evalCef(THAI_DECODER_JS) -- повторный вызов ничего не делает; после реконнекта cef хук ставится заново
-- на всякий случай: первая строка списка должна быть <= 130 байт
if d.style == 2 then
local first, rest = body:match('^([^\n]*)(.*)$')
if #encodeDlg(first) > 130 then body = stripColors(first) .. rest end
end
sampShowDialog(d.id, encodeDlg(title), encodeDlg(body), encodeDlg(b1), encodeDlg(b2), d.style)
В
layoutDialog поменяй на
local function entLen(s) return #encodeDlg(s) end, тогда страницы будут считаться по реальному размеру.
Пара мелочей. Если хук почему-то не встанет, вместо тайского увидишь
[[th:...]] с кракозябрами. Мы ставили его за полсекунды до показа диалога, так что если вылезет на первом диалоге после захода, вызови
evalCef(THAI_DECODER_JS) ещё раз в
main() после спавна. И для списков cef кладёт в inputtext текст выбранной строки, то есть тайский, а не исходный русский. Если сервер где-то смотрит на inputtext, а не на listitem, подставь в
onSendDialogResponse исходную строку из
d.args.