local imgui = require "imgui" local encoding = require 'encoding' local json = require 'dkjson' encoding.default = 'CP1251' u8 = encoding.UTF8 -- Variable to store the server data local serverData = nil local lastUpdate = nil -- Notification system variables local notifications = {} local NOTIFICATION_DURATION = 3.0 -- seconds local NOTIFICATION_FADE_TIME = 0.5 -- seconds local LINK_OPEN_DELAY = 2000 -- milliseconds (2 seconds) -- Notification dimensions local NOTIFICATION_WIDTH = 700 -- Increased width local NOTIFICATION_HEIGHT = 30 -- Increased height local NOTIFICATION_PADDING = 5 -- Padding inside notification local VK_ESCAPE = 0x1B -- Virtual key code for ESC function onWindowMessage(message, wparam, lparam) if imgui.Process then if message == 0x100 and wparam == VK_ESCAPE then consumeWindowMessage(true, true) imgui.Process = false return false end end return true end addEventHandler('onWindowMessage', onWindowMessage) -- Function to add a new notification function addNotification(text, type) table.insert(notifications, { text = text, type = type or "info", creation_time = os.clock(), alpha = 1.0 }) end -- Function to open URL with delay function openURLWithDelay(url) lua_thread.create(function() addNotification("Se deschide " .. url .. " in browser, baga jocul in bara!", "info") wait(LINK_OPEN_DELAY) os.execute('start ' .. url) end) end -- Function to render notifications function renderNotifications() local currentTime = os.clock() local screenW, screenH = getScreenResolution() local startY = 80 -- Slightly higher starting position -- Process each notification for i = #notifications, 1, -1 do local notif = notifications[i] local elapsedTime = currentTime - notif.creation_time -- Calculate alpha for fade effect if elapsedTime > NOTIFICATION_DURATION - NOTIFICATION_FADE_TIME then notif.alpha = 1.0 - (elapsedTime - (NOTIFICATION_DURATION - NOTIFICATION_FADE_TIME)) / NOTIFICATION_FADE_TIME end -- Remove expired notifications if elapsedTime > NOTIFICATION_DURATION then table.remove(notifications, i) else -- Set notification color based on type with slightly adjusted opacity local bgColor if notif.type == "success" then bgColor = imgui.ImVec4(0.2, 0.7, 0.2, 0.95 * notif.alpha) elseif notif.type == "error" then bgColor = imgui.ImVec4(0.7, 0.2, 0.2, 0.95 * notif.alpha) else -- info bgColor = imgui.ImVec4(0.2, 0.2, 0.7, 0.95 * notif.alpha) end -- Create a new window for each notification imgui.PushStyleVar(imgui.StyleVar.Alpha, notif.alpha) imgui.PushStyleColor(imgui.Col.WindowBg, bgColor) imgui.PushStyleVar(imgui.StyleVar.WindowPadding, imgui.ImVec2(NOTIFICATION_PADDING, NOTIFICATION_PADDING)) imgui.PushStyleVar(imgui.StyleVar.WindowRounding, 8.0) -- Rounded corners -- Center the notification horizontally local notifX = (screenW - NOTIFICATION_WIDTH) / 2 -- Set window position and flags imgui.SetNextWindowPos(imgui.ImVec2(notifX, startY)) imgui.SetNextWindowSize(imgui.ImVec2(NOTIFICATION_WIDTH, NOTIFICATION_HEIGHT)) local windowFlags = imgui.WindowFlags.NoTitleBar + imgui.WindowFlags.NoResize + imgui.WindowFlags.NoMove + imgui.WindowFlags.NoScrollbar + imgui.WindowFlags.NoCollapse imgui.Begin("##notification" .. i, nil, windowFlags) -- Center the text both vertically and horizontally local textWidth = imgui.CalcTextSize(u8(notif.text)) -- Remove NOTIFICATION_PADDING from calculations since it's handled by WindowPadding local textX = (NOTIFICATION_WIDTH - textWidth.x) / 2 local textY = (NOTIFICATION_HEIGHT - textWidth.y) / 2 -- Set larger font scale for better readability imgui.SetWindowFontScale(1.5) -- Don't subtract padding from cursor position imgui.SetCursorPos(imgui.ImVec2(textX, textY)) imgui.TextWrapped(u8(notif.text)) imgui.End() imgui.PopStyleVar(3) -- Pop WindowPadding, WindowRounding, and Alpha imgui.PopStyleColor() startY = startY + NOTIFICATION_HEIGHT + 10 -- Gap between notifications end end end function main() while not isSampAvailable() do wait(0) end -- Register the command to show the window sampRegisterChatCommand("servere", function() async_http_request('https://teemo.uk/servere', '', function(response) if response then local success, decoded = pcall(json.decode, response) if success and decoded then serverData = decoded lastUpdate = os.date("%H:%M:%S") imgui.Process = true addNotification("Lista de servere s-a deschis!", "success") else sampAddChatMessage("[Server List] Error: Could not parse server data.", 0xFF0000) end end end) end) while true do wait(0) end end function imgui.OnDrawFrame() -- Render any active notifications renderNotifications() if imgui.Process and serverData then local sw, sh = getScreenResolution() imgui.SetNextWindowPos(imgui.ImVec2(sw / 2, sh / 2), imgui.Cond.FirstUseEver, imgui.ImVec2(0.5, 0.5)) imgui.SetNextWindowSize(imgui.ImVec2(800, 300), imgui.Cond.FirstUseEver) -- Set window style imgui.PushStyleColor(imgui.Col.WindowBg, imgui.ImVec4(0.1, 0.1, 0.1, 0.9)) imgui.PushStyleColor(imgui.Col.TitleBg, imgui.ImVec4(0.2, 0.2, 0.5, 1.0)) imgui.PushStyleColor(imgui.Col.TitleBgActive, imgui.ImVec4(0.3, 0.3, 0.6, 1.0)) imgui.Begin(u8"Lista servere SAMP romanesti - Last Update: " .. (lastUpdate or "N/A"), nil, imgui.WindowFlags.NoCollapse) imgui.SetWindowFontScale(1.3) imgui.PushStyleVar(imgui.StyleVar.FramePadding, imgui.ImVec2(2, 0)) imgui.PushStyleVar(imgui.StyleVar.ButtonTextAlign, imgui.ImVec2(0.5, 0.5)) -- Text part imgui.PushStyleColor(imgui.Col.Text, imgui.ImVec4(1, 0.843, 0, 1)) imgui.Text(u8"Lista live de pe ") imgui.PopStyleColor() imgui.SameLine(0, 0) -- Set both parameters to 0 to remove extra spacing -- Link colors local linkNormalColor = imgui.ImVec4(0.0, 0.5, 1.0, 1.0) local linkHoverColor = imgui.ImVec4(0.2, 0.7, 1.0, 1.0) -- Store button position local buttonScreenPos = imgui.GetCursorScreenPos() -- Push transparent button styles imgui.PushStyleColor(imgui.Col.Button, imgui.ImVec4(0, 0, 0, 0)) imgui.PushStyleColor(imgui.Col.ButtonHovered, imgui.ImVec4(0, 0, 0, 0)) imgui.PushStyleColor(imgui.Col.ButtonActive, imgui.ImVec4(0, 0, 0, 0)) -- Create a boolean for button hover state local buttonHovered = false -- First, push the normal color imgui.PushStyleColor(imgui.Col.Text, linkNormalColor) -- Create the button local clicked = imgui.Button(u8"moduri.ro/servere##link") -- After creating the button, check if it's hovered buttonHovered = imgui.IsItemHovered() -- If hovered, immediately draw with hover color if buttonHovered then -- Pop the normal color imgui.PopStyleColor() -- Push the hover color imgui.PushStyleColor(imgui.Col.Text, linkHoverColor) -- Draw the button again with hover color imgui.SetCursorScreenPos(buttonScreenPos) imgui.Button(u8"moduri.ro/servere##link_hover") end -- Handle click if clicked then openURLWithDelay("https://moduri.ro/servere") end -- Get text size for underline local textSize = imgui.CalcTextSize(u8"moduri.ro/servere") -- Draw underline if hovered if buttonHovered then local drawList = imgui.GetWindowDrawList() -- Position underline 1 pixel below the text local underlineY = buttonScreenPos.y + textSize.y + 1 drawList:AddLine( imgui.ImVec2(buttonScreenPos.x, underlineY), imgui.ImVec2(buttonScreenPos.x + textSize.x, underlineY), imgui.GetColorU32(buttonHovered and linkHoverColor or linkNormalColor), 1 ) end -- Pop all remaining style colors (either 4 or 5 depending on hover state) if buttonHovered then imgui.PopStyleColor(4) else imgui.PopStyleColor(4) end imgui.PopStyleVar(2) imgui.SetWindowFontScale(1.0) -- Reset font size for separator imgui.Separator() imgui.Spacing() -- Rest of your code remains the same... imgui.SetWindowFontScale(1.3) imgui.PushStyleColor(imgui.Col.Header, imgui.ImVec4(0.2, 0.2, 0.5, 1.0)) imgui.Columns(4, "ServerColumns", true) imgui.Text("Server Name") imgui.NextColumn() imgui.Text("Playeri online") imgui.NextColumn() imgui.Text("Record azi") imgui.NextColumn() imgui.Text("Adresa server") imgui.NextColumn() imgui.Separator() imgui.PopStyleColor() -- Display server information in columns with larger font imgui.SetWindowFontScale(1.2) for _, server in ipairs(serverData) do imgui.Text(u8(server.name)) imgui.NextColumn() local playerRatio = server.players_online / server.record local playerColor = imgui.ImVec4( 1 - playerRatio, playerRatio, 0, 1 ) imgui.PushStyleColor(imgui.Col.Text, playerColor) imgui.Text(tostring(server.players_online)) imgui.PopStyleColor() imgui.NextColumn() imgui.Text(tostring(server.record)) imgui.NextColumn() imgui.Text(server.address) imgui.NextColumn() end imgui.Columns(1) imgui.Separator() imgui.SetWindowFontScale(1.2) if imgui.Button(u8"Refresh data", imgui.ImVec2(120, 30)) then async_http_request('https://teemo.uk/servere', '', function(response) if response then serverData = json.decode(response) lastUpdate = os.date("%H:%M:%S") sampAddChatMessage("Lista online actualizata la secunda!", -1) addNotification("Lista online a fost actualizata!") end end) end imgui.SameLine() if imgui.Button(u8"Close", imgui.ImVec2(100, 30)) then imgui.Process = false end imgui.End() imgui.PopStyleColor(3) end end function async_http_request(url, post_data, callback) lua_thread.create(function() local request = require('requests') local success, response = pcall(function() return request.get(url) end) if not success then -- Handle connection errors/timeouts sampAddChatMessage("[Server List] Error: Could not connect to the server. The service might be down.", 0xFF0000) addNotification("Could not connect to the server. The service might be down.", "error") return end if response and response.status_code then if response.status_code == 200 then -- Try to decode the JSON to ensure it's valid local success_json, decoded = pcall(json.decode, response.text) if success_json and decoded then callback(response.text) else sampAddChatMessage("[Server List] Error: Received invalid data from server.", 0xFF0000) addNotification("Received invalid data from server.", "error") end else sampAddChatMessage("[Server List] Error: Failed to fetch server data. Status: " .. response.status_code, 0xFF0000) addNotification("Failed to fetch server data. Status: " .. response.status_code, "error") end else sampAddChatMessage("[Server List] Error: Invalid response from server.", 0xFF0000) addNotification("Invalid response from server.", "error") end end) end