From 91c4ebd6c7af6caa9d8b01353cccecd80396cc82 Mon Sep 17 00:00:00 2001 From: KubaPro010 Date: Thu, 1 Jan 2026 20:18:50 +0100 Subject: [PATCH] events --- Makefile | 4 +- examples/ert.lua | 69 --------------- examples/test.lua | 70 +++++++++++++++ plugin.c | 219 ++++++++++++++++++++++++++++++++++------------ plugin.lua | 7 ++ 5 files changed, 240 insertions(+), 129 deletions(-) delete mode 100644 examples/ert.lua create mode 100644 examples/test.lua diff --git a/Makefile b/Makefile index 86a3b44..12895f7 100644 --- a/Makefile +++ b/Makefile @@ -4,9 +4,9 @@ liblua: rm *.o build: liblua - gcc -O2 -shared -static -o MyPlugin.dll plugin.c liblua -lgdi32 -luser32 -lshell32 \ + gcc -O2 -shared -static -o luahost.dll plugin.c liblua -lgdi32 -luser32 -lshell32 \ -Wl,--add-stdcall-alias \ -ffunction-sections -fdata-sections install: build - cp MyPlugin.dll "/c/Program Files (x86)/RDS Spy/plugins" \ No newline at end of file + cp luahost.dll "/c/Program Files (x86)/RDS Spy/plugins" \ No newline at end of file diff --git a/examples/ert.lua b/examples/ert.lua deleted file mode 100644 index b2cdf38..0000000 --- a/examples/ert.lua +++ /dev/null @@ -1,69 +0,0 @@ -local ert_string = string.rep("_", 128) -local ert_last_carriage = -1 -local ert_console_log = false -- not state - -local odas = {} -local oda_string = "" -local ert_display = "" - -function command(cmd, param) - if cmd:lower() == "request" and param:lower() == "decoderdata" then - db.add_value("ERT", ert_display) - elseif cmd:lower() == "resetdata" then - ert_string = string.rep("_", 128) - ert_last_carriage = -1 - odas = {} - oda_string = "" - ert_display = "" - if ert_console_log then log("ERT data reset.") - else set_console_mode(true) end - end -end - -local function getKeyByValue(t, targetValue) - for key, value in pairs(t) do - if value == targetValue then - return key - end - end - return nil -- Return nil if the value isn't found -end - -function group(stream, b_corr, a, b, c, d) - if stream ~= 0 and a ~= 0 then return - elseif stream ~= 0 and not db.load_boolean("rdsspy.ini", "General", "Tunnelling", false) then return end - - if b_corr or b < 0 or c < 0 or d < 0 then return end - - local group = (b & 0xf000) >> 12 - local group_version = (b & 0x800) >> 11 - - if group == 3 and group_version == 0 then - local oda_group = (b & 0x1f) >> 1 - local oda_group_version = b & 1 - if odas[oda_group] == nil then odas[oda_group] = d end - oda_string = "" - for key, value in pairs(odas) do - oda_string = oda_string .. string.format("%d: %X |", key, value) - end - elseif group == getKeyByValue(odas, 0x6552) and group_version == 0 then - local ert_state = b & 0x1f - local char1 = string.char((c >> 8) & 0xff) - local char2 = string.char(c & 0xff) - local char3 = string.char((d >> 8) & 0xff) - local char4 = string.char(d & 0xff) - local new_chars = char1..char2..char3..char4 - local start_pos = (ert_state * 4) + 1 - ert_string = ert_string:sub(1, start_pos - 1) .. new_chars .. ert_string:sub(start_pos + 4) - - local ert_carriage = ert_string:find("\r", 1, true) - if ert_carriage then ert_display = ert_string:sub(1, ert_carriage - 1) - else ert_display = ert_string:gsub("%s+$", "") end - - if ert_carriage ~= ert_last_carriage and ert_carriage ~= nil and ert_console_log then - log("New ERT string received.") - ert_last_carriage = ert_carriage - end - end - set_console(string.format("ODAs: %s\r\nERT: %s", oda_string, ert_display)) -end \ No newline at end of file diff --git a/examples/test.lua b/examples/test.lua new file mode 100644 index 0000000..b823ca9 --- /dev/null +++ b/examples/test.lua @@ -0,0 +1,70 @@ +set_console_mode(true) +set_font_size(24) + +local ert_string = string.rep("_", 128) + +local odas = {} +local oda_string = "" +local ert_display = "" + +local last_event = -1 + +function event(event) + last_event = event +end + +function command(cmd, param) + if cmd:lower() == "request" and param:lower() == "decoderdata" then + db.add_value("ERT", ert_display) + elseif cmd:lower() == "resetdata" then + ert_string = string.rep("_", 128) + odas = {} + oda_string = "" + ert_display = "" + end +end + +local function findODAByAID(t, targetAID) + for grp, data in pairs(t) do + if data.aid == targetAID then return grp, data.version end + end + return nil, nil +end + +function group(stream, b_corr, a, b, c, d) + if stream ~= 0 and a ~= 0 then return + elseif stream ~= 0 and not db.load_boolean("rdsspy.ini", "General", "Tunnelling", false) then return end + + if b_corr or b < 0 or c < 0 or d < 0 then return end + + local group_type = (b & 0xf000) >> 12 + local group_version = (b & 0x800) >> 11 + + if group_type == 3 and group_version == 0 then + local target_group = (b & 0x1f) >> 1 + + if odas[target_group] == nil then odas[target_group] = { aid = d, version = (b & 1) } end + + oda_string = "" + for grp, data in pairs(odas) do + local ver_char = (data.version == 0) and "A" or "B" + oda_string = oda_string .. string.format("%d%s - %04X | ", grp, ver_char, data.aid) + end + + else + local ert_grp, ert_ver = findODAByAID(odas, 0x6552) + + if ert_grp and group_type == ert_grp and group_version == ert_ver then + local ert_state = b & 0x1f + local new_chars = string.char((c >> 8) & 0xff) .. string.char(c & 0xff) .. string.char((d >> 8) & 0xff) .. string.char(d & 0xff) + local start_pos = (ert_state * 4) + 1 + ert_string = ert_string:sub(1, start_pos - 1) .. new_chars .. ert_string:sub(start_pos + 4) + + local ert_carriage = ert_string:find("\r", 1, true) + if ert_carriage then ert_display = ert_string:sub(1, ert_carriage - 1) + else ert_display = ert_string:gsub("%s+$", "") end + end + end + + set_console(string.format("ODAs: %s\r\n\r\nERT: %s\r\n\r\nLast event: %d", oda_string:sub(1, #oda_string-2), ert_display, last_event)) +end \ No newline at end of file diff --git a/plugin.c b/plugin.c index c6a18bb..6f67713 100644 --- a/plugin.c +++ b/plugin.c @@ -47,6 +47,10 @@ static lua_State* L = NULL; static HWND hEditControl = NULL; static TDB* g_DBPointer = NULL; +static HFONT g_hCurrentFont = NULL; +#define FONT_NAME "Segoe UI" + +#define IDC_MAIN_BUTTON 101 static const unsigned char EBU[127] = { 0xE1, 'a', 0xE9, 'e', 0xED, 'i', 0xF3, 'o', 0xFA, 'u', 'N', 0xC7, 0xAA, 0xDF, 'I', 0x00, @@ -75,6 +79,8 @@ unsigned char CharConv(unsigned char Ch) { return Ch; } +void InitLua(); +void lua_event(int event); LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) @@ -82,6 +88,15 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_CLOSE: ShowWindow(hwnd, SW_HIDE); return 0; + case WM_COMMAND: + if (HIWORD(wParam) == BN_CLICKED) + { + int controlId = LOWORD(wParam); + + if (controlId == IDC_MAIN_BUTTON) InitLua(); + else if (controlId > IDC_MAIN_BUTTON && controlId <= IDC_MAIN_BUTTON + 5) lua_event(controlId - IDC_MAIN_BUTTON); + } + break; case WM_DESTROY: hWnd = NULL; return 0; @@ -115,12 +130,62 @@ void CreatePluginWindow(HWND hOwner) { WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY, - 10, 10, 480-30, 320-50, + 10, 10, 480-25, 320-75, hWnd, NULL, hInst, NULL ); - HFONT hFont = CreateFont(18, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Segoe UI"); + HWND hButton = CreateWindowEx( + 0, "BUTTON", "Reload", + WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, + 10, 258, + 70, 30, hWnd, + (HMENU)IDC_MAIN_BUTTON, hInst, NULL + ); + + HWND hButton_event1 = CreateWindowEx( + 0, "BUTTON", "Event 1", + WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, + 10+(75*1), 258, + 70, 30, hWnd, + (HMENU)(IDC_MAIN_BUTTON + 1), hInst, NULL + ); + HWND hButton_event2 = CreateWindowEx( + 0, "BUTTON", "Event 2", + WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, + 10+(75*2), 258, + 70, 30, hWnd, + (HMENU)(IDC_MAIN_BUTTON + 2), hInst, NULL + ); + HWND hButton_event3 = CreateWindowEx( + 0, "BUTTON", "Event 3", + WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, + 10+(75*3), 258, + 70, 30, hWnd, + (HMENU)(IDC_MAIN_BUTTON + 3), hInst, NULL + ); + HWND hButton_event4 = CreateWindowEx( + 0, "BUTTON", "Event 4", + WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, + 10+(75*4), 258, + 70, 30, hWnd, + (HMENU)(IDC_MAIN_BUTTON + 4), hInst, NULL + ); + HWND hButton_event5 = CreateWindowEx( + 0, "BUTTON", "Event 5", + WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, + 10+(75*5), 258, + 70, 30, hWnd, + (HMENU)(IDC_MAIN_BUTTON + 5), hInst, NULL + ); + + HFONT hFont = CreateFont(18, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, FONT_NAME); SendMessage(hEditControl, WM_SETFONT, (WPARAM)hFont, TRUE); + SendMessage(hButton, WM_SETFONT, (WPARAM)hFont, TRUE); + SendMessage(hButton_event1, WM_SETFONT, (WPARAM)hFont, TRUE); + SendMessage(hButton_event2, WM_SETFONT, (WPARAM)hFont, TRUE); + SendMessage(hButton_event3, WM_SETFONT, (WPARAM)hFont, TRUE); + SendMessage(hButton_event4, WM_SETFONT, (WPARAM)hFont, TRUE); + SendMessage(hButton_event5, WM_SETFONT, (WPARAM)hFont, TRUE); HICON hIconBig = (HICON)SendMessage(hOwner, WM_GETICON, ICON_BIG, 0); HICON hIconSmall = (HICON)SendMessage(hOwner, WM_GETICON, ICON_SMALL, 0); @@ -160,13 +225,29 @@ int lua_set_console(lua_State* localL) { } int lua_set_console_mode(lua_State* localL) { - if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1)); + if (!lua_isboolean(localL, 1)) return luaL_error(localL, "boolean expected, got %s", luaL_typename(localL, 1)); int mode = lua_toboolean(localL, 1); SetText(""); console_mode = mode; return 0; } +int lua_set_font_size(lua_State* localL) { + int size = luaL_checkinteger(localL, 1); + + HFONT hNewFont = CreateFont(size, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, FONT_NAME); + + if (hNewFont && hEditControl) { + SendMessage(hEditControl, WM_SETFONT, (WPARAM)hNewFont, TRUE); + + if (g_hCurrentFont != NULL) DeleteObject(g_hCurrentFont); + + g_hCurrentFont = hNewFont; + } + + return 0; +} + int lua_MessageBox(lua_State* localL) { const char* data = luaL_checkstring(localL, 1); const char* title = luaL_checkstring(localL, 2); @@ -395,7 +476,7 @@ void lua_call_command(const char* Cmd, const char* Param) { lua_pushstring(L, Param); if (lua_pcall(L, 2, 0, 0) != LUA_OK) { char msg_buffer[255]; - sprintf(msg_buffer, "Lua error: %s at '%s'\n", lua_tostring(L, -1), "command"); + snprintf(msg_buffer, sizeof(msg_buffer), "Lua error: %s at '%s'\n", lua_tostring(L, -1), "command"); AppendText(msg_buffer); lua_pop(L, 1); } @@ -414,7 +495,21 @@ void lua_call_group() { lua_pushinteger(L, Group.Blk4); if (lua_pcall(L, 6, 0, 0) != LUA_OK) { char msg_buffer[255]; - sprintf(msg_buffer, "Lua error: %s at '%s'\r\n", lua_tostring(L, -1), "command"); + snprintf(msg_buffer, sizeof(msg_buffer), "Lua error: %s at '%s'\r\n", lua_tostring(L, -1), "group"); + AppendText(msg_buffer); + lua_pop(L, 1); + } + } else lua_pop(L, 1); +} + +void lua_event(int event) { + lua_getglobal(L, "event"); + + if (lua_isfunction(L, -1)) { + lua_pushinteger(L, event); + if (lua_pcall(L, 1, 0, 0) != LUA_OK) { + char msg_buffer[255]; + snprintf(msg_buffer, sizeof(msg_buffer), "Lua error: %s at '%s'\r\n", lua_tostring(L, -1), "event"); AppendText(msg_buffer); lua_pop(L, 1); } @@ -466,12 +561,12 @@ __declspec(dllexport) void __stdcall Command(const char* Cmd, const char* Param) } else if (_stricmp(Cmd, "LUASCRIPT") == 0) { // custom char msg_buffer[255]; if (luaL_loadfile(L, Param) != LUA_OK) { - sprintf(msg_buffer, "Lua error loading file: %s\r\n", lua_tostring(L, -1)); + snprintf(msg_buffer, sizeof(msg_buffer), "Lua error loading file: %s\r\n", lua_tostring(L, -1)); AppendText(msg_buffer); lua_pop(L, 1); } else { if (lua_pcall(L, 0, 0, 0) != LUA_OK) { - sprintf(msg_buffer, "Init error: %s\r\n", lua_tostring(L, -1)); + snprintf(msg_buffer, sizeof(msg_buffer), "Init error: %s\r\n", lua_tostring(L, -1)); AppendText(msg_buffer); lua_pop(L, 1); } @@ -481,60 +576,60 @@ __declspec(dllexport) void __stdcall Command(const char* Cmd, const char* Param) __declspec(dllexport) const char* __stdcall PluginName(void) { return "Lua Host"; } -void RegisterDBFunctions(lua_State* localL) { - lua_newtable(localL); - - lua_pushcfunction(localL, lua_ReadValue); - lua_setfield(localL, -2, "read_value"); - - lua_pushcfunction(localL, lua_ReadRecord); - lua_setfield(localL, -2, "read_record"); - - lua_pushcfunction(localL, lua_AddValue); - lua_setfield(localL, -2, "add_value"); - - lua_pushcfunction(localL, lua_ResetValues); - lua_setfield(localL, -2, "reset_values"); - - lua_pushcfunction(localL, lua_CountRecords); - lua_setfield(localL, -2, "count_records"); - - lua_pushcfunction(localL, lua_CharConv); - lua_setfield(localL, -2, "char_conv"); - - lua_pushcfunction(localL, lua_SaveString); - lua_setfield(localL, -2, "save_string"); - - lua_pushcfunction(localL, lua_SaveInteger); - lua_setfield(localL, -2, "save_integer"); - - lua_pushcfunction(localL, lua_SaveBoolean); - lua_setfield(localL, -2, "save_boolean"); - - lua_pushcfunction(localL, lua_LoadString); - lua_setfield(localL, -2, "load_string"); - - lua_pushcfunction(localL, lua_LoadInteger); - lua_setfield(localL, -2, "load_integer"); - - lua_pushcfunction(localL, lua_LoadBoolean); - lua_setfield(localL, -2, "load_boolean"); - - lua_setglobal(localL, "db"); -} - -__declspec(dllexport) int __stdcall Initialize(HANDLE hHandle, TDB* DBPointer) { - CreatePluginWindow(hHandle); - AppendText(LUA_COPYRIGHT); - AppendText("\r\n"); +void InitLua() { + if(L != NULL) { + lua_close(L); + L = NULL; + } L = luaL_newstate(); luaL_openlibs(L); + lua_register(L, "set_font_size", lua_set_font_size); lua_register(L, "message_box", lua_MessageBox); lua_register(L, "log", lua_log); lua_register(L, "set_console", lua_set_console); lua_register(L, "set_console_mode", lua_set_console_mode); - g_DBPointer = DBPointer; - RegisterDBFunctions(L); + + lua_newtable(L); + + lua_pushcfunction(L, lua_ReadValue); + lua_setfield(L, -2, "read_value"); + + lua_pushcfunction(L, lua_ReadRecord); + lua_setfield(L, -2, "read_record"); + + lua_pushcfunction(L, lua_AddValue); + lua_setfield(L, -2, "add_value"); + + lua_pushcfunction(L, lua_ResetValues); + lua_setfield(L, -2, "reset_values"); + + lua_pushcfunction(L, lua_CountRecords); + lua_setfield(L, -2, "count_records"); + + lua_pushcfunction(L, lua_CharConv); + lua_setfield(L, -2, "char_conv"); + + lua_pushcfunction(L, lua_SaveString); + lua_setfield(L, -2, "save_string"); + + lua_pushcfunction(L, lua_SaveInteger); + lua_setfield(L, -2, "save_integer"); + + lua_pushcfunction(L, lua_SaveBoolean); + lua_setfield(L, -2, "save_boolean"); + + lua_pushcfunction(L, lua_LoadString); + lua_setfield(L, -2, "load_string"); + + lua_pushcfunction(L, lua_LoadInteger); + lua_setfield(L, -2, "load_integer"); + + lua_pushcfunction(L, lua_LoadBoolean); + lua_setfield(L, -2, "load_boolean"); + + lua_setglobal(L, "db"); + + console_mode = 0; char path[MAX_PATH]; char fullPath[MAX_PATH]; @@ -543,21 +638,29 @@ __declspec(dllexport) int __stdcall Initialize(HANDLE hHandle, TDB* DBPointer) { else { MessageBoxA(NULL, "Could not get the local app data path", "Error", MB_ICONERROR | MB_OK | MB_TOPMOST); AppendText("Could not get the local app data path\r\n"); - return (int)hWnd; + return; } char msg_buffer[255]; if (luaL_loadfile(L, fullPath) != LUA_OK) { - sprintf(msg_buffer, "Lua error loading file: %s\r\n", lua_tostring(L, -1)); + snprintf(msg_buffer, sizeof(msg_buffer), "Lua error loading file: %s\r\n", lua_tostring(L, -1)); AppendText(msg_buffer); lua_pop(L, 1); } else { if (lua_pcall(L, 0, 0, 0) != LUA_OK) { - sprintf(msg_buffer, "Init error: %s\r\n", lua_tostring(L, -1)); + snprintf(msg_buffer, sizeof(msg_buffer), "Lua error: %s\r\n", lua_tostring(L, -1)); AppendText(msg_buffer); lua_pop(L, 1); } } +} + +__declspec(dllexport) int __stdcall Initialize(HANDLE hHandle, TDB* DBPointer) { + CreatePluginWindow(hHandle); + AppendText(LUA_COPYRIGHT); + AppendText("\r\n"); + g_DBPointer = DBPointer; + InitLua(); return (int)hWnd; } diff --git a/plugin.lua b/plugin.lua index 85c92e6..96a3504 100644 --- a/plugin.lua +++ b/plugin.lua @@ -15,11 +15,18 @@ function command(cmd, param) end ---@param d integer function group(stream, block_b_correction, a, b, c, d) end +---This function should be defined by the user in the script +---@param event integer +function event(event) end + ---Open a information message box to the user ---@param body string ---@param title string function message_box(body, title) end +---@param size integer +function set_font_size(size) end + ---Logs a string inside the host console. Requires console mode to be false. ---@param data string function log(data) end