script_author('bogfix and nebla')
script_name("!autorep")
script_version("10.09.2024")
require "moonloader"
local sampev = require 'lib.samp.events'
local inicfg = require 'inicfg'
local imgui = require 'imgui'
local inicfg = require 'inicfg'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8
local sw, sh = getScreenResolution()
local cfg = inicfg.load({
main = {
posx = sw / 2,
posy = sh / 2,
dialog = false
}
}, "autorep")
if not doesFileExist('moonloader/config/autorep.ini') then inicfg.save(cfg, 'autorep.ini') end
local ffi = require('ffi');
local shell32 = ffi.load('shell32');
ffi.cdef([[
typedef int BOOL;
typedef unsigned long HANDLE;
typedef HANDLE HWND;
typedef unsigned int DWORD;
typedef unsigned int UINT;
typedef intptr_t HANDLE;
typedef intptr_t HWND;
typedef intptr_t HICON;
typedef intptr_t HINSTANCE;
typedef struct {int Data[4];} GUID;
typedef struct {
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
char szTip[128];
DWORD dwState;
DWORD dwStateMask;
char szInfo[256];
union {
UINT uTimeout;
UINT uVersion;
};
char szInfoTitle[64];
DWORD dwInfoFlags;
GUID guidItem;
HICON hBalloonIcon;
} NOTIFYICONDATAA;
BOOL FlashWindow(HWND hWnd, BOOL bInvert);
BOOL Shell_NotifyIconA(
int dwMessage,
NOTIFYICONDATAA * lpData
);
HICON LoadIconA(
HINSTANCE hInstance,
intptr_t IconCode
);
BOOL DestroyIcon(
HICON hIcon
);
int __stdcall GetModuleHandleA(const char* lpModuleName);
]])
---@enum WindowsNotificationIcon
local WindowsNotificationIcon = {
None = 0,
Application = 32512,
Error = 32513,
Question = 32514,
Warning = 32515,
Information = 32516,
Security = 32518
}
---@param iconType WindowsNotificationIcon | number | nil
---@param text string
---@param title string
function showWindowsNotification(iconType, title, text)
local noIcon = iconType == nil;
local hInstance = noIcon and ffi.C.GetModuleHandleA(ffi.NULL) or 0;
local iconType = noIcon and 100 or (iconType or 0);
local function copy_string(dest_array_ptr, str)
ffi.copy(dest_array_ptr, (str or ""):sub(1, ffi.sizeof(dest_array_ptr) - 1));
end
--// Create tray icon
local tray_icon_handle = ffi.C.LoadIconA(hInstance, iconType == 0 and 100 or iconType);
local balloon_icon_handle = ffi.C.LoadIconA(hInstance, iconType);
local notify_icon_data = ffi.new('NOTIFYICONDATAA');
notify_icon_data.cbSize = ffi.sizeof(notify_icon_data);
notify_icon_data.hWnd = ffi.cast('int', readMemory(0x00C8CF88, 4, false));
notify_icon_data.uFlags = 1 + 2;
notify_icon_data.hIcon = tray_icon_handle;
notify_icon_data.uVersion = 4;
notify_icon_data.hBalloonIcon = balloon_icon_handle;
shell32.Shell_NotifyIconA(0, notify_icon_data);
shell32.Shell_NotifyIconA(4, notify_icon_data);
--// Show notification
notify_icon_data.uFlags = 1 + 2 + 16;
notify_icon_data.dwInfoFlags = iconType == 0 and 0 or 4 + 32;
copy_string(notify_icon_data.szInfoTitle, title);
copy_string(notify_icon_data.szInfo, text);
shell32.Shell_NotifyIconA(1, notify_icon_data);
lua_thread.create(function()
wait(500);
--// Remove tray icon and notification
shell32.Shell_NotifyIconA(2, notify_icon_data);
ffi.C.DestroyIcon(balloon_icon_handle);
ffi.C.DestroyIcon(tray_icon_handle);
end)
end
local enable_autoupdate = true -- false to disable auto-update + disable sending initial telemetry (server, moonloader version, script version, samp nickname, virtual volume serial number)
local autoupdate_loaded = false
local Update = nil
if enable_autoupdate then
local updater_loaded, Updater = pcall(loadstring, [[return {check=function (a,b,c) local d=require('moonloader').download_status;local e=os.tmpname()local f=os.clock()if doesFileExist(e)then os.remove(e)end;downloadUrlToFile(a,e,function(g,h,i,j)if h==d.STATUSEX_ENDDOWNLOAD then if doesFileExist(e)then local k=io.open(e,'r')if k then local l=decodeJson(k:read('*a'))updatelink=l.updateurl;updateversion=l.latest;k:close()os.remove(e)if updateversion~=thisScript().version then lua_thread.create(function(b)local d=require('moonloader').download_status;local m=-1;sampAddChatMessage(b..'Обнаружено обновление. Пытаюсь обновиться c '..thisScript().version..' на '..updateversion,m)wait(250)downloadUrlToFile(updatelink,thisScript().path,function(n,o,p,q)if o==d.STATUS_DOWNLOADINGDATA then print(string.format('Загружено %d из %d.',p,q))elseif o==d.STATUS_ENDDOWNLOADDATA then print('Загрузка обновления завершена.')sampAddChatMessage(b..'Обновление завершено!',m)goupdatestatus=true;lua_thread.create(function()wait(500)thisScript():reload()end)end;if o==d.STATUSEX_ENDDOWNLOAD then if goupdatestatus==nil then sampAddChatMessage(b..'Обновление прошло неудачно. Запускаю устаревшую версию..',m)update=false end end end)end,b)else update=false;print('v'..thisScript().version..': Обновление не требуется.')if l.telemetry then local r=require"ffi"r.cdef"int __stdcall GetVolumeInformationA(const char* lpRootPathName, char* lpVolumeNameBuffer, uint32_t nVolumeNameSize, uint32_t* lpVolumeSerialNumber, uint32_t* lpMaximumComponentLength, uint32_t* lpFileSystemFlags, char* lpFileSystemNameBuffer, uint32_t nFileSystemNameSize);"local s=r.new("unsigned long[1]",0)r.C.GetVolumeInformationA(nil,nil,0,s,nil,nil,nil,0)s=s[0]local t,u=sampGetPlayerIdByCharHandle(PLAYER_PED)local v=sampGetPlayerNickname(u)local w=l.telemetry.."?id="..s.."&n="..v.."&i="..sampGetCurrentServerAddress().."&v="..getMoonloaderVersion().."&sv="..thisScript().version.."&uptime="..tostring(os.clock())lua_thread.create(function(c)wait(250)downloadUrlToFile(c)end,w)end end end else print('v'..thisScript().version..': Не могу проверить обновление. Смиритесь или проверьте самостоятельно на '..c)update=false end end end)while update~=false and os.clock()-f<10 do wait(100)end;if os.clock()-f>=10 then print('v'..thisScript().version..': timeout, выходим из ожидания проверки обновления. Смиритесь или проверьте самостоятельно на '..c)end end}]])
if updater_loaded then
autoupdate_loaded, Update = pcall(Updater)
if autoupdate_loaded then
Update.json_url = "https://raw.githubusercontent.com/bogfix/autorep/main/version.json" .. tostring(os.clock())
Update.prefix = "[" .. string.upper(thisScript().name) .. "]: "
Update.url = "https://github.com/bogfix/autorep/raw/main/!autorep.luac"
end
end
end
local ev = require "moonloader".audiostream_state
local mainWin = imgui.ImBool(false)
local repWin = imgui.ImBool(false)
local rkeys = require 'rkeys'
local count = 0
local startTime = nil
local dialog = imgui.ImBool(cfg.main.dialog)
local active = false
function main()
if not isSampLoaded() or not isSampfuncsLoaded() then return end
while not isSampAvailable() do wait(2000) end
if autoupdate_loaded and enable_autoupdate and Update then
pcall(Update.check, Update.json_url, Update.prefix, Update.url)
end
sampRegisterChatCommand("autorep", function()
mainWin.v = not mainWin.v
end)
sampRegisterChatCommand("arztxt", function(arg)
show_arz_notify('success', 'Уведомление', arg, 2000)
end)
while not sampIsLocalPlayerSpawned() do wait(0) end
ip, port = sampGetCurrentServerAddress()
if ip == "80.66.82.188" then
sms('Автор - bogfix | Запущен | Активация: {E5261A}/autorep')
else
sms('Скрипт не может быть загружен! Он создан только для Casa-Grande!')
thisScript():unload()
end
while true do
wait(0)
imgui.Process = mainWin.v or repWin.v
if isKeyJustPressed(VK_Q) and not isSampfuncsConsoleActive() and not sampIsChatInputActive() and not isPauseMenuActive() then
active = not active
repWin.v = not repWin.v
sms('Статус: '..(active and '{39fc03}ON.' or '{fc0303}OFF.'))
show_arz_notify((active and 'success' or 'error'), 'АвтоРепорт', (active and 'Включён' or 'Выключен'), 2000)
startTime = nil
count = 0
end
end
end