- 48
- 3
Доброго дня, использую скрипт webcore.asi(для вывода html, css, js в samp). Сделал чат всё работает кроме одного. Когда я пишу в инпут нажимаю enter js не отправляет в lua.
Код:
const chat1 = [];
let currentColor = "#FFFFFF"; // Цвет по умолчанию
// Добавление сообщения в чат
function addMessageToChat(message, color = currentColor) {
const formattedMessage = HTMLstringify(colorify(message, color));
const chatLog = document.querySelector(".chatlog");
if (chatLog) {
chatLog.innerHTML += formattedMessage;
chatLog.scrollTop = chatLog.scrollHeight; // Автопрокрутка
}
chat1.push({ message, color });
}
// Парсинг строки с цветом (#FF0000Текст)
function colorify(message, defaultColor = "#FFFFFF") {
let result = '';
let lastIndex = 0;
const regex = /#([0-9A-F]{6}|[0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{5})([^#]*)/gi;
let match;
while ((match = regex.exec(message)) !== null) {
const [fullMatch, hex, text] = match;
// Если длина <6, дополним до 6 (например, #F00 → #FF0000)
let fullHex = hex;
if (hex.length === 3) {
fullHex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
} else if (hex.length < 6) {
fullHex += '0'.repeat(6 - hex.length);
}
// Текст до цвета
if (message.slice(lastIndex, match.index).length > 0) {
result += `<span style="color:${defaultColor}">${message.slice(lastIndex, match.index)}</span>`;
}
// Цветной текст
result += `<span style="color:#${fullHex}">${text}</span>`;
lastIndex = match.index + fullMatch.length;
}
// Оставшийся текст после последнего цвета
if (lastIndex < message.length) {
result += `<span style="color:${defaultColor}">${message.slice(lastIndex)}</span>`;
}
return result;
}
// Создание HTML из строки
function HTMLstringify(line) {
return `<p>${line}</p>`;
}
function addMessageToSAMP(message) {
console.log("Отправка в SAMP:", message);
// Проверяем, доступна ли функция
if (typeof sendMessage === "function") {
sendMessage([message]); // Отправка через CEF → Lua
} else {
console.warn("❌ sendMessage не определена");
}
}
document.addEventListener("DOMContentLoaded", () => {
console.log("✅ DOM загружен");
const input = document.getElementById('chat-input');
if (input) {
input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
const value = input.value.trim();
if (value.length > 0) {
addMessageToSAMP(value);
input.value = '';
}
}
});
}
// Проверка доступности sendMessage
setTimeout(() => {
if (typeof sendMessage === 'function') {
console.log("✅ sendMessage доступна");
} else {
console.warn("❌ sendMessage ещё не определена");
}
}, 1000);
});
Код:
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local memory = require 'memory'
local sampev = require 'lib.samp.events'
local ffi = require 'ffi'
local bit = require 'bit'
local hasWebcore, webcore = pcall(require, 'webcore')
local browser = nil
local json = require 'cjson'
local inicfg = require 'inicfg'
local chatActive = false
local hook = {hooks = {}}
addEventHandler('onScriptTerminate', function(scr)
if scr == script.this then
for i, hook in ipairs(hook.hooks) do
if hook.status then
hook.stop()
end
end
end
end)
local CHAT_VISIBLE_ADDR = 0xCAA65C
ffi.cdef [[
int __stdcall VirtualProtect(void* lpAddress, unsigned long dwSize, unsigned long flNewProtect, unsigned long* lpflOldProtect);
]]
function hook.new(cast, callback, hook_addr, size)
local size = size or 5
local new_hook = {}
local detour_addr = tonumber(ffi.cast('intptr_t', ffi.cast('void*', ffi.cast(cast, callback))))
local void_addr = ffi.cast('void*', hook_addr)
local old_prot = ffi.new('unsigned long[1]')
local org_bytes = ffi.new('uint8_t[?]', size)
ffi.copy(org_bytes, void_addr, size)
local hook_bytes = ffi.new('uint8_t[?]', size, 0x90)
hook_bytes[0] = 0xE9
ffi.cast('uint32_t*', hook_bytes + 1)[0] = detour_addr - hook_addr - 5
new_hook.call = ffi.cast(cast, hook_addr)
new_hook.status = false
local function set_status(bool)
new_hook.status = bool
ffi.C.VirtualProtect(void_addr, size, 0x40, old_prot)
ffi.copy(void_addr, bool and hook_bytes or org_bytes, size)
ffi.C.VirtualProtect(void_addr, size, old_prot[0], old_prot)
end
new_hook.stop = function() set_status(false) end
new_hook.start = function() set_status(true) end
new_hook.start()
table.insert(hook.hooks, new_hook)
return setmetatable(new_hook, {
__call = function(self, ...)
self.stop()
local res = self.call(...)
self.start()
return res
end
})
end
function convertSampColorToHtml(text)
if type(text) ~= "string" then return "" end
return text:gsub("{(%x%x%x%x%x%x)}", "#%1")
end
function sendToCEFChat(text)
if not browser then return end
text = convertSampColorToHtml(text)
text = text:gsub('"', '\\"'):gsub("'", "\\'"):gsub("\n", "\\n")
browser:execute_js(string.format('addMessageToChat("%s")', text))
end
local activateChatAddr = getModuleHandle("samp.dll") + 0x64F50
function main()
if not isSampfuncsLoaded() or not isSampLoaded() then return end -- Скрываем вывод сообщений SAMP
while not isSampAvailable() do wait(100) end
memory.setuint8(sampGetBase() + 0x71480, 0xEB, true)
local sampBase = getModuleHandle('samp.dll')
if sampBase == 0 then return end
-- Правильный адрес функции CChat::Activate
local activateChatAddr = sampBase + 0x657E0
-- Хук на функцию активации чата
hook.new(
'void(__thiscall *)(void* this)',
function(this)
-- Не вызываем оригинальную функцию — тем самым блокируем открытие чата
sampAddChatMessage(u8:decode("Попытка открыть чат заблокирован"), -1)
end,
activateChatAddr,
5 -- размер JMP инструкции
)
if not hasWebcore then
sampAddChatMessage(u8:decode("Ошибка: WebCore.asi не загружен!"), -1)
return
end
sampAddChatMessage(u8:decode("WebCore версия: ") .. webcore.version(), -1)
while not webcore.inited() do wait(100) end
browser = webcore:create_fullscreen("about:blank")
browser:add_function("sendMessage", function(args)
local msg = args and args[1]
if msg then
print("Lua получил сообщение из JS: " .. msg)
sampSendChat(msg)
end
end)
browser:set_create_cb(function()
browser:load_url("file:///cef/chat/chat.html")
end)
browser:set_loading_cb(function(_, status)
if status == 0 then
print("CEF: Страница загружена")
browser:execute_js([[
console.log("CEF JS готов!");
const input = document.getElementById('chat-input');
if (input) input.focus();
]])
end
end)
while true do
if browser and not browser:input_active() then
if isKeyJustPressed(0x42) then -- B
browser:set_input(true)
browser:execute_js('toggleCEFChat(true)')
wait(100)
browser:execute_js([[
var input = document.getElementById('chat-input');
if (input) {
input.focus();
}
]])
end
if browser ~= nil then
end
end
wait(0)
end
end
-- Обработка событий из JS
function sampev.onServerMessage(color, text)
if text then
-- Извлекаем RGB из цвета
-- Формируем hex-строку #RRGGBB
local hexColor = bit.tohex(bit.rshift(color, 8), 6)
-- Добавляем цвет в начало сообщения
local formattedText = "#" .. hexColor .. text
-- Отправляем в CEF
sendToCEFChat(u8:encode(formattedText))
end
end
function onScriptTerminate(s, q)
if s == thisScript() then
webcore:close(browser) -- close without callback
browser = nil
end
end