diff --git a/datxchng.dpr b/datxchng.dpr new file mode 100644 index 0000000..911d489 --- /dev/null +++ b/datxchng.dpr @@ -0,0 +1,220 @@ +library datxchng; + +uses + SysUtils, StrUtils, IniFiles, + Classes; + +{$R *.res} + +type TRecord = record + Key: shortstring; + Value: shortstring; + end; + +type TPRecord = record + Key: PChar; + Value: PChar; + end; + +type TDB = record + Count: integer; + Records: array [0..255] of TRecord; + end; + PTDB = ^TDB; + +const + EBU: array [128..254] of Char = + ('','a','','e','','i','','o','','u','N','','','','I', #0, + '','','e','','','i','','','u','','n','','', #0,'i', #0, + #0, #0,'','', #0,'','','', #0, #0, #0,'$', #0, #0, #0, #0, + #0, #0, #0, #0,'','I','','','','?','','', #0, #0, #0,'', + '','A','','E','','I','','O','','U','','','','','','L', + '','','E','','','I','','','U','','','','','','','l', + #0, #0, #0, #0, #0,'', #0, #0, #0, #0,'','','','', #0, #0, + #0, #0, #0, #0, #0,'', #0, #0, #0, #0,'','','','', #0); + +var + Param1: array [0..1023] of char; + Param2: array [0..1023] of char; + WorkDir: string; + +function ReadValue(Key: PChar; DBPointer: PTDB): PChar; stdcall; +var a,i: integer; + SKey: shortstring; +begin +Result:=''; +SKey:=shortstring(Key); +a:=DBPointer^.Count; +if (a>length(DBPointer^.Records)) then a:=length(DBPointer^.Records); //ochrana +for i:=1 to a do + begin + if (DBPointer^.Records[i-1].Key=SKey) then + begin Result:=StrPCopy(Param1,DBPointer^.Records[i-1].Value); exit; end; + end; +end; + +function ReadRecord(Index: integer; DBPointer: PTDB): TPRecord; stdcall; +begin +if (Index>=DBPointer^.Count) or (Index>=length(DBPointer^.Records)) then + begin + Result.Key:=''; + Result.Value:=''; + end else begin + Result.Key:=StrPCopy(Param1,DBPointer^.Records[Index].Key); + Result.Value:=StrPCopy(Param2,DBPointer^.Records[Index].Value); + end; +end; + +procedure AddValue(Key, Value: PChar; DBPointer: PTDB); stdcall; +var a,i: integer; + SKey, SValue: shortstring; + ASValue: string; +begin +SKey:=shortstring(Key); +ASValue:=Value; +if (length(ASValue)>255) then ASValue:=LeftStr(ASValue,252)+'...'; +SValue:=shortstring(ASValue); +a:=DBPointer^.Count; +if (a>length(DBPointer^.Records)) then a:=length(DBPointer^.Records); //ochrana +for i:=1 to a do + begin + if (DBPointer^.Records[i-1].Key=SKey) then + begin DBPointer^.Records[i-1].Value:=SValue; exit; end; + end; +if (alength(DBPointer^.Records)) then a:=length(DBPointer^.Records); +Result:=a; +end; + +procedure SavePChar(Filename, Section, Key, Value: PChar); stdcall; +var Reg: TIniFile; +begin +Chdir(WorkDir); +try + Reg:=TIniFile.Create(string(Filename)); + try + Reg.WriteString(string(Section), string(Key), string(Value)); + finally + Reg.Free; + end; + except + end; +end; + +procedure SaveInteger(Filename, Section, Key: Pchar; Value: integer); stdcall; +var Reg: TIniFile; +begin +Chdir(WorkDir); +try + Reg:=TIniFile.Create(string(Filename)); + try + Reg.WriteInteger(string(Section), string(Key), Value); + finally + Reg.Free; + end; + except + end; +end; + +procedure SaveBoolean(Filename, Section, Key: Pchar; Value: boolean); stdcall; +var Reg: TIniFile; +begin +Chdir(WorkDir); +try + Reg:=TIniFile.Create(string(Filename)); + try + Reg.WriteBool(string(Section), string(Key), Value); + finally + Reg.Free; + end; + except + end; +end; + +function LoadPChar(Filename, Section, Key, DefaultValue: PChar): PChar; stdcall; +var Reg: TIniFile; +begin +Chdir(WorkDir); +Result:=DefaultValue; +try + Reg:=TIniFile.Create(string(Filename)); + try + Result:=StrPCopy(Param1,Reg.ReadString(string(Section), string(Key), string(DefaultValue))); + finally + Reg.Free; + end; + except + end; +end; + +function LoadInteger(Filename, Section, Key: Pchar; DefaultValue: integer): integer; stdcall; +var Reg: TIniFile; +begin +Chdir(WorkDir); +Result:=DefaultValue; +try + Reg:=TIniFile.Create(string(Filename)); + try + Result:=Reg.ReadInteger(string(Section), string(Key), DefaultValue); + finally + Reg.Free; + end; + except + end; +end; + +function LoadBoolean(Filename, Section, Key: Pchar; DefaultValue: boolean): boolean; stdcall; +var Reg: TIniFile; +begin +Chdir(WorkDir); +Result:=DefaultValue; +try + Reg:=TIniFile.Create(string(Filename)); + try + Result:=Reg.ReadBool(string(Section), string(Key), DefaultValue); + finally + Reg.Free; + end; + except + end; +end; + +function CharConv(Ch, CT: Byte): Byte; stdcall; +begin +Result:=Ch; +if (Ch>=128) and (Ch<255) then + if (EBU[Ch]<>#0) then Result:=Ord(EBU[Ch]); +end; + +Exports + ReadValue, ReadRecord, AddValue, ResetValues, CountRecords, + SavePChar, SaveInteger, SaveBoolean, LoadPChar, LoadInteger, LoadBoolean, + CharConv; + +begin +WorkDir:=ExtractFilePath(ParamStr(0)); +end. + diff --git a/docs/Commands.md b/docs/Commands.md new file mode 100644 index 0000000..edf9215 --- /dev/null +++ b/docs/Commands.md @@ -0,0 +1,3 @@ +# Commands + +Just wanted to tell you that they also have a "SUPERPI" command, the param is just the hex encoded pi text ("AAAA") \ No newline at end of file diff --git a/docs/spyapi.pdf b/docs/spyapi.pdf new file mode 100644 index 0000000..e03bece Binary files /dev/null and b/docs/spyapi.pdf differ diff --git a/examples/ert.lua b/examples/ert.lua index 5a47631..c52122e 100644 --- a/examples/ert.lua +++ b/examples/ert.lua @@ -1,18 +1,23 @@ -ert_group = -1 -ert_string = string.rep(" ", 128) +local ert_group = -1 +local ert_string = string.rep("_", 128) +local ert_last_carriage = -1 +local ert_console_log = false function command(cmd, param) - if cmd:lower() == "request" then + if cmd:lower() == "request" and param:lower() == "decoderdata" then local cr_pos = ert_string:find("\r", 1, true) -- true means "plain search" (faster) local display_text - if cr_pos then - display_text = ert_string:sub(1, cr_pos - 1) - else - -- No CR found yet, show the whole 128 bytes (trimmed of trailing spaces) - display_text = ert_string:gsub("%s+$", "") + if cr_pos then display_text = ert_string:sub(1, cr_pos - 1) + else display_text = ert_string:gsub("%s+$", "") end db.add_value("ERT", display_text) + elseif cmd:lower() == "resetdata" then + ert_group = -1 + ert_string = string.rep("_", 128) + ert_last_carriage = -1 + if ert_console_log then log("ERT data reset.") + else set_console_mode(true) end end end @@ -20,7 +25,7 @@ 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 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 @@ -41,5 +46,18 @@ function group(stream, b_corr, a, b, c, d) 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 ~= ert_last_carriage and ert_carriage ~= nil and ert_console_log then + log("New ERT string received.") + ert_last_carriage = ert_carriage + elseif not ert_console_log then + local display_text + + if ert_carriage then display_text = ert_string:sub(1, ert_carriage - 1) + else display_text = ert_string:gsub("%s+$", "") end + + set_console(string.format("ERT: %s", display_text)) + end end end \ No newline at end of file diff --git a/plugin.c b/plugin.c index bb90762..c6a18bb 100644 --- a/plugin.c +++ b/plugin.c @@ -47,6 +47,7 @@ static lua_State* L = NULL; static HWND hEditControl = NULL; static TDB* g_DBPointer = NULL; + static const unsigned char EBU[127] = { 0xE1, 'a', 0xE9, 'e', 0xED, 'i', 0xF3, 'o', 0xFA, 'u', 'N', 0xC7, 0xAA, 0xDF, 'I', 0x00, 0xE2, 0xE4, 'e', 0xEB, 0xEE, 'i', 0xF4, 0xF6, 'u', 0xFC, 'n', 0xE7, 0xBA, 0x00, 'i', 0x00, @@ -58,6 +59,13 @@ static const unsigned char EBU[127] = { 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE6, 0x9C, 0x9F, 0x00 }; +static unsigned int console_mode = 0; + +const char* int_to_string(int value) { + static char buffer[16]; + snprintf(buffer, sizeof(buffer), "%d", value); + return buffer; +} unsigned char CharConv(unsigned char Ch) { if (Ch >= 128 && Ch < 255) { @@ -67,6 +75,105 @@ unsigned char CharConv(unsigned char Ch) { return Ch; } +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CLOSE: + ShowWindow(hwnd, SW_HIDE); + return 0; + case WM_DESTROY: + hWnd = NULL; + return 0; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +void CreatePluginWindow(HWND hOwner) { + WNDCLASS wc = {0}; + wc.lpfnWndProc = WndProc; + wc.hInstance = hInst; + wc.lpszClassName = "LuaHostPlugin"; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + RegisterClass(&wc); + + hWnd = CreateWindowEx( + 0, + "LuaHostPlugin", + "Lua Host Console", + WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, + CW_USEDEFAULT, CW_USEDEFAULT, + 480, 320, + hOwner, + NULL, + hInst, + NULL + ); + + hEditControl = CreateWindowEx( + WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | WS_VSCROLL | + ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY, + 10, 10, 480-30, 320-50, + 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"); + SendMessage(hEditControl, 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); + if (!hIconBig) hIconBig = (HICON)GetClassLongPtr(hOwner, GCLP_HICON); + if (!hIconSmall) hIconSmall = (HICON)GetClassLongPtr(hOwner, GCLP_HICONSM); + SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIconBig); + SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSmall); + + UpdateWindow(hWnd); +} + +void AppendText(const char* text) { + if (hEditControl != NULL) { + int len = GetWindowTextLength(hEditControl); + SendMessage(hEditControl, EM_SETSEL, len, len); + SendMessageA(hEditControl, EM_REPLACESEL, FALSE, (LPARAM)text); + } +} + +void SetText(const char* text) { + if (hEditControl != NULL) SetWindowTextA(hEditControl, text); +} + +int lua_log(lua_State* localL) { + if(console_mode != 0) return luaL_error(localL, "Invalid log"); + const char* data = luaL_checkstring(localL, 1); + AppendText(data); + AppendText("\r\n"); + return 0; +} + +int lua_set_console(lua_State* localL) { + if(console_mode != 1) return luaL_error(localL, "Invalid log"); + const char* data = luaL_checkstring(localL, 1); + SetText(data); + return 0; +} + +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)); + int mode = lua_toboolean(localL, 1); + SetText(""); + console_mode = mode; + return 0; +} + +int lua_MessageBox(lua_State* localL) { + const char* data = luaL_checkstring(localL, 1); + const char* title = luaL_checkstring(localL, 2); + MessageBoxA(NULL, data, title, MB_OK | MB_TOPMOST); + return 0; +} + int lua_ReadValue(lua_State* localL) { if (g_DBPointer == NULL) { lua_pushnil(localL); @@ -116,15 +223,15 @@ int lua_ReadRecord(lua_State* localL) { int lua_AddValue(lua_State* localL) { if (g_DBPointer == NULL) return 0; - + const char* key = luaL_checkstring(localL, 1); const char* value = luaL_checkstring(localL, 2); - + ShortString skey, svalue; skey.len = strlen(key); if (skey.len > 255) skey.len = 255; memcpy(skey.data, key, skey.len); - + svalue.len = strlen(value); if (svalue.len > 252) { svalue.len = 252; @@ -132,10 +239,10 @@ int lua_AddValue(lua_State* localL) { memcpy(svalue.data + 252, "...", 3); svalue.len = 255; } else memcpy(svalue.data, value, svalue.len); - + int count = g_DBPointer->Count; if (count > 255) count = 255; - + for (int i = 0; i < count; i++) { if (g_DBPointer->Records[i].Key.len == skey.len && memcmp(g_DBPointer->Records[i].Key.data, skey.data, skey.len) == 0) { @@ -143,7 +250,7 @@ int lua_AddValue(lua_State* localL) { return 0; } } - + if (count < 254) { g_DBPointer->Records[count].Key = skey; g_DBPointer->Records[count].Value = svalue; @@ -152,7 +259,7 @@ int lua_AddValue(lua_State* localL) { g_DBPointer->Records[254].Key = skey; g_DBPointer->Records[254].Value = svalue; } - + return 0; } @@ -167,7 +274,7 @@ int lua_CountRecords(lua_State* localL) { lua_pushinteger(localL, 0); return 1; } - + int count = g_DBPointer->Count; if (count > 255) count = 255; lua_pushinteger(localL, count); @@ -185,7 +292,7 @@ int lua_SaveString(lua_State* localL) { const char* section = luaL_checkstring(localL, 2); const char* key = luaL_checkstring(localL, 3); const char* value = luaL_checkstring(localL, 4); - + char path[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path))) { char fullPath[MAX_PATH]; @@ -200,10 +307,10 @@ int lua_SaveInteger(lua_State* localL) { const char* section = luaL_checkstring(localL, 2); const char* key = luaL_checkstring(localL, 3); int value = luaL_checkinteger(localL, 4); - + char valueStr[32]; snprintf(valueStr, 32, "%d", value); - + char path[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path))) { char fullPath[MAX_PATH]; @@ -218,7 +325,7 @@ int lua_SaveBoolean(lua_State* localL) { const char* section = luaL_checkstring(localL, 2); const char* key = luaL_checkstring(localL, 3); int value = lua_toboolean(localL, 4); - + char path[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path))) { char fullPath[MAX_PATH]; @@ -233,10 +340,10 @@ int lua_LoadString(lua_State* localL) { const char* section = luaL_checkstring(localL, 2); const char* key = luaL_checkstring(localL, 3); const char* defaultValue = luaL_optstring(localL, 4, ""); - + char buffer[1024]; char path[MAX_PATH]; - + if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path))) { char fullPath[MAX_PATH]; snprintf(fullPath, MAX_PATH, "%s\\RDS Spy\\%s", path, filename); @@ -251,7 +358,7 @@ int lua_LoadInteger(lua_State* localL) { const char* section = luaL_checkstring(localL, 2); const char* key = luaL_checkstring(localL, 3); int defaultValue = luaL_optinteger(localL, 4, 0); - + char path[MAX_PATH]; if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path))) { char fullPath[MAX_PATH]; @@ -267,10 +374,10 @@ int lua_LoadBoolean(lua_State* localL) { const char* section = luaL_checkstring(localL, 2); const char* key = luaL_checkstring(localL, 3); int defaultValue = lua_toboolean(localL, 4); - + char buffer[16]; char path[MAX_PATH]; - + if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path))) { char fullPath[MAX_PATH]; snprintf(fullPath, MAX_PATH, "%s\\RDS Spy\\%s", path, filename); @@ -280,82 +387,6 @@ int lua_LoadBoolean(lua_State* localL) { return 1; } -LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case WM_CLOSE: - ShowWindow(hwnd, SW_HIDE); - return 0; - case WM_DESTROY: - hWnd = NULL; - return 0; - } - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -void CreatePluginWindow(HWND hOwner) -{ - WNDCLASS wc = {0}; - wc.lpfnWndProc = WndProc; - wc.hInstance = hInst; - wc.lpszClassName = "RDSPluginWindow"; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - RegisterClass(&wc); - - hWnd = CreateWindowEx( - 0, - "RDSPluginWindow", - "RDS Plugin", - WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU, - CW_USEDEFAULT, CW_USEDEFAULT, - 400, 300, - hOwner, - NULL, - hInst, - NULL - ); - - hEditControl = CreateWindowEx( - WS_EX_CLIENTEDGE, "EDIT", "", - WS_CHILD | WS_VISIBLE | WS_VSCROLL | - ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY, - 10, 10, 370, 250, - hWnd, NULL, hInst, NULL - ); - - HFONT hFont = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Segoe UI"); - SendMessage(hEditControl, WM_SETFONT, (WPARAM)hFont, TRUE); - UpdateWindow(hWnd); -} - -void AppendText(const char* text) { - if (hEditControl != NULL) { - int len = GetWindowTextLength(hEditControl); - SendMessage(hEditControl, EM_SETSEL, len, len); - SendMessageA(hEditControl, EM_REPLACESEL, FALSE, (LPARAM)text); - } -} - -void SetText(const char* text) { - if (hEditControl != NULL) SetWindowTextA(hEditControl, text); -} - -int lua_log(lua_State* localL) { - const char* data = luaL_checkstring(localL, 1); - AppendText(data); - AppendText("\r\n"); - return 0; -} - -int lua_MessageBox(lua_State* localL) { - const char* data = luaL_checkstring(localL, 1); - const char* title = luaL_checkstring(localL, 2); - MessageBoxA(NULL, data, title, MB_OK | MB_TOPMOST); - return 0; -} - void lua_call_command(const char* Cmd, const char* Param) { lua_getglobal(L, "command"); @@ -412,50 +443,83 @@ __declspec(dllexport) void __stdcall Command(const char* Cmd, const char* Param) else if (_stricmp(Cmd, "SHOW") == 0) ShowWindow(hWnd, SW_SHOW); else if (_stricmp(Cmd, "MINIMIZE") == 0) ShowWindow(hWnd, SW_MINIMIZE); else if (_stricmp(Cmd, "RESTORE") == 0) ShowWindow(hWnd, SW_RESTORE); - else lua_call_command(Cmd, Param); + else if (_stricmp(Cmd, "OPENWORKSPACE") == 0) { + if(hWnd != NULL) { + int value = GetPrivateProfileIntA("luahost", "Visible", 0, Param); + if(value == 1) ShowWindow(hWnd, SW_SHOW); + else if(value == 0) ShowWindow(hWnd, SW_HIDE); + int x = GetPrivateProfileIntA("luahost", "Left", 320, Param); + int y = GetPrivateProfileIntA("luahost", "Top", 240, Param); + SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE); + } + lua_call_command(Cmd, Param); // still call + } else if (_stricmp(Cmd, "SAVEWORKSPACE") == 0) { + if(hWnd != NULL) { + RECT rect; // get rect + if (GetWindowRect(hWnd, &rect)) { + WritePrivateProfileStringA("luahost", "Left", int_to_string(rect.left), Param); + WritePrivateProfileStringA("luahost", "Top", int_to_string(rect.top), Param); + } + WritePrivateProfileStringA("luahost", "Visible", IsWindowVisible(hWnd) ? "1" : "0", Param); + } + lua_call_command(Cmd, Param); // still call + } 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)); + 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)); + AppendText(msg_buffer); + lua_pop(L, 1); + } + } + } else lua_call_command(Cmd, 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"); } @@ -467,6 +531,8 @@ __declspec(dllexport) int __stdcall Initialize(HANDLE hHandle, TDB* DBPointer) { luaL_openlibs(L); 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); diff --git a/plugin.lua b/plugin.lua index 7df5f7d..85c92e6 100644 --- a/plugin.lua +++ b/plugin.lua @@ -20,10 +20,17 @@ function group(stream, block_b_correction, a, b, c, d) end ---@param title string function message_box(body, title) end ----Logs a string inside the host console +---Logs a string inside the host console. Requires console mode to be false. ---@param data string function log(data) end +---Sets the whole text of the console for display. Requires console mode to be true. +---@param data string +function set_console(data) end + +---@param mode boolean +function set_console_mode(mode) end + db = {} ---@param key string