Начинающий
- Статус
- Оффлайн
- Регистрация
- 17 Сен 2020
- Сообщения
- 22
- Реакции
- 0
добрый день, хотел бы залить ии творение на этот сайт, играя в кс2 люди жалуются что кто то раньше них заходит на сервер и лутают сим приорити, терь не какая сучка не будет жаловаться, с любовью творения нейронки.
работает по принципу если вы копируете коннект, то будет через некоторое время с задержкой джойниться на сервер.
по всем вопросам:
tg @kolthefurry
#include <windows.h>
#include <gdiplus.h>
#include <shellapi.h>
#include <dwmapi.h>
#include <string>
#include <regex>
#include <map>
#include <cmath>
#include <mmsystem.h>
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "dwmapi.lib")
using namespace Gdiplus;
// ID ресурсов
#define IDR_FURRY_PNG 101
#define IDR_BLOOM_WAV 102
#define WM_TRAYICON (WM_USER + 1)
#define ID_TRAY_EXIT 1001
#define ID_TRAY_TOGGLE 1002
// Глобальные переменные
ULONG_PTR g_gdiplusToken = 0;
HWND g_mainHwnd = NULL;
bool g_autoConnectEnabled = true;
bool g_animationActive = false;
std::map<std::wstring, DWORD> g_connectionHistory;
const DWORD CONNECTION_COOLDOWN = 8000;
std::wstring g_lastClipboardText = L"";
std::wstring g_notificationMessage = L"";
int g_notificationDuration = 1;
// ==================== ПИКСЕЛЬНЫЙ ДЕМОН ====================
void DrawPixelDemon(Graphics& graphics, int startX, int startY, int size) {
// Цвета
Color red(255, 255, 0, 0);
Color darkRed(255, 139, 0, 0);
Color black(255, 0, 0, 0);
Color gray(255, 60, 60, 60);
Color darkGray(255, 30, 30, 30);
Color orange(255, 255, 140, 0);
Color yellow(255, 255, 255, 0);
Color white(255, 255, 255, 255);
Color purple(255, 128, 0, 128);
SolidBrush redBrush(red);
SolidBrush darkRedBrush(darkRed);
SolidBrush blackBrush(black);
SolidBrush grayBrush(gray);
SolidBrush darkGrayBrush(darkGray);
SolidBrush orangeBrush(orange);
SolidBrush yellowBrush(yellow);
SolidBrush whiteBrush(white);
SolidBrush purpleBrush(purple);
int pixelSize = size / 20;
if (pixelSize < 2) pixelSize = 2;
// Рога
graphics.FillRectangle(&darkRedBrush, startX + 8 * pixelSize, startY + 1 * pixelSize, pixelSize, pixelSize * 2);
graphics.FillRectangle(&darkRedBrush, startX + 11 * pixelSize, startY + 1 * pixelSize, pixelSize, pixelSize * 2);
graphics.FillRectangle(&redBrush, startX + 7 * pixelSize, startY + 2 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&redBrush, startX + 11 * pixelSize, startY + 2 * pixelSize, pixelSize * 2, pixelSize);
// Голова
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 5; j++) {
graphics.FillRectangle(&darkRedBrush, startX + (7 + i) * pixelSize, startY + (3 + j) * pixelSize, pixelSize, pixelSize);
}
}
// Глаза (злые)
graphics.FillRectangle(&yellowBrush, startX + 8 * pixelSize, startY + 5 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&yellowBrush, startX + 11 * pixelSize, startY + 5 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&blackBrush, startX + 9 * pixelSize, startY + 5 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&blackBrush, startX + 12 * pixelSize, startY + 5 * pixelSize, pixelSize, pixelSize);
// Зрачки (красные)
graphics.FillRectangle(&redBrush, startX + 9 * pixelSize, startY + 5 * pixelSize, pixelSize / 2, pixelSize / 2);
graphics.FillRectangle(&redBrush, startX + 12 * pixelSize, startY + 5 * pixelSize, pixelSize / 2, pixelSize / 2);
// Рот с клыками
graphics.FillRectangle(&blackBrush, startX + 9 * pixelSize, startY + 7 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&whiteBrush, startX + 8 * pixelSize, startY + 7 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&whiteBrush, startX + 11 * pixelSize, startY + 7 * pixelSize, pixelSize, pixelSize);
// Тело
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 6; j++) {
graphics.FillRectangle(&blackBrush, startX + (6 + i) * pixelSize, startY + (8 + j) * pixelSize, pixelSize, pixelSize);
}
}
// Крылья летучей мыши (слева)
graphics.FillRectangle(&purpleBrush, startX + 3 * pixelSize, startY + 10 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&purpleBrush, startX + 2 * pixelSize, startY + 11 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&purpleBrush, startX + 1 * pixelSize, startY + 12 * pixelSize, pixelSize * 2, pixelSize);
// Крылья летучей мыши (справа)
graphics.FillRectangle(&purpleBrush, startX + 15 * pixelSize, startY + 10 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&purpleBrush, startX + 16 * pixelSize, startY + 11 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&purpleBrush, startX + 17 * pixelSize, startY + 12 * pixelSize, pixelSize * 2, pixelSize);
// Хвост с наконечником
graphics.FillRectangle(&redBrush, startX + 13 * pixelSize, startY + 13 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&redBrush, startX + 14 * pixelSize, startY + 14 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&orangeBrush, startX + 15 * pixelSize, startY + 15 * pixelSize, pixelSize, pixelSize);
// Огонь вокруг
for (int i = 0; i < 3; i++) {
graphics.FillRectangle(&orangeBrush, startX + (5 + i * 2) * pixelSize, startY + 16 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&yellowBrush, startX + (6 + i * 2) * pixelSize, startY + 17 * pixelSize, pixelSize, pixelSize);
}
}
// ==================== ПОВЫШЕНИЕ ПРИОРИТЕТА ====================
void SetHighPriority() {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
timeBeginPeriod(1);
}
// ==================== ЗАГРУЗКА PNG ИЗ РЕСУРСОВ ====================
Bitmap* LoadPNGFromResource(int resourceID) {
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(resourceID), L"PNG");
if (!hResource) return NULL;
DWORD imageSize = SizeofResource(NULL, hResource);
HGLOBAL hGlobal = LoadResource(NULL, hResource);
if (!hGlobal) return NULL;
void* pData = LockResource(hGlobal);
if (!pData) return NULL;
HGLOBAL hBuffer = GlobalAlloc(GMEM_MOVEABLE, imageSize);
if (!hBuffer) return NULL;
void* pBuffer = GlobalLock(hBuffer);
if (!pBuffer) {
GlobalFree(hBuffer);
return NULL;
}
memcpy(pBuffer, pData, imageSize);
GlobalUnlock(hBuffer);
IStream* pStream = NULL;
if (CreateStreamOnHGlobal(hBuffer, TRUE, &pStream) != S_OK) {
GlobalFree(hBuffer);
return NULL;
}
Bitmap* bmp = new Bitmap(pStream);
pStream->Release();
return bmp;
}
// ==================== ПОЛУЧЕНИЕ ТЕКСТА ИЗ БУФЕРА ОБМЕНА ====================
std::wstring GetClipboardText() {
std::wstring result = L"";
if (!OpenClipboard(NULL)) return result;
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
if (hData) {
wchar_t* text = (wchar_t*)GlobalLock(hData);
if (text) {
result = text;
GlobalUnlock(hData);
}
}
CloseClipboard();
// Удаляем пробелы в начале и конце
size_t start = result.find_first_not_of(L" \t\r\n");
size_t end = result.find_last_not_of(L" \t\r\n");
if (start != std::wstring::npos && end != std::wstring::npos) {
result = result.substr(start, end - start + 1);
}
else if (start == std::wstring::npos) {
result = L"";
}
return result;
}
// ==================== ПРОИГРЫВАНИЕ ЗВУКА ИЗ РЕСУРСОВ ====================
void PlaySoundFromResource(int resourceID) {
PlaySound(MAKEINTRESOURCE(resourceID), GetModuleHandle(NULL),
SND_RESOURCE | SND_ASYNC);
}
// ==================== ДОБАВЛЕНИЕ ТЕНИ ====================
void AddWindowShadow(HWND hwnd) {
const MARGINS margins = { 1, 1, 1, 1 };
DwmExtendFrameIntoClientArea(hwnd, &margins);
BOOL enableShadow = TRUE;
DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &enableShadow, sizeof(enableShadow));
}
// ==================== ОКНО УВЕДОМЛЕНИЯ ====================
LRESULT CALLBACK NotificationProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static Bitmap* png = NULL;
static float alpha = 0.0f;
static float offset = 0.0f;
static int state = 0;
static int pauseCounter = 0;
static int pauseDuration = 0;
static std::wstring message = L"";
static int screenWidth = GetSystemMetrics(SM_CXSCREEN);
static int windowWidth = 320;
static int windowHeight = 180;
switch (msg) {
case WM_CREATE: {
png = LoadPNGFromResource(IDR_FURRY_PNG);
message = g_notificationMessage;
pauseDuration = (g_notificationDuration * 1000) / 16; // ~60fps
HRGN region = CreateRoundRectRgn(0, 0, windowWidth, windowHeight, 20, 20);
SetWindowRgn(hwnd, region, TRUE);
DeleteObject(region);
AddWindowShadow(hwnd);
alpha = 0.0f;
offset = (float)windowWidth;
state = 0;
pauseCounter = 0;
SetTimer(hwnd, 1, 16, NULL); // ~60fps
break;
}
case WM_TIMER: {
switch (state) {
case 0: // Появление
if (offset > 0) {
offset -= 15.0f;
if (offset < 0) offset = 0;
}
if (alpha < 255.0f) {
alpha += 15.0f;
if (alpha > 255.0f) alpha = 255.0f;
}
if (offset <= 0 && alpha >= 255.0f) {
state = 1;
pauseCounter = 0;
}
SetWindowPos(hwnd, HWND_TOPMOST, screenWidth - windowWidth + (int)offset, 40, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
SetLayeredWindowAttributes(hwnd, 0, (BYTE)alpha, LWA_ALPHA);
break;
case 1: // Пауза
pauseCounter++;
if (pauseCounter > pauseDuration) {
state = 2;
}
break;
case 2: // Исчезновение
if (offset < windowWidth) {
offset += 15.0f;
if (offset > windowWidth) offset = (float)windowWidth;
}
if (alpha > 0) {
alpha -= 15.0f;
if (alpha < 0) alpha = 0;
}
SetWindowPos(hwnd, HWND_TOPMOST, screenWidth - windowWidth + (int)offset, 40, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
SetLayeredWindowAttributes(hwnd, 0, (BYTE)alpha, LWA_ALPHA);
if (offset >= windowWidth && alpha <= 0) {
KillTimer(hwnd, 1);
DestroyWindow(hwnd);
return 0;
}
break;
}
InvalidateRect(hwnd, NULL, FALSE);
break;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HDC memDC = CreateCompatibleDC(hdc);
if (memDC) {
HBITMAP memBitmap = CreateCompatibleBitmap(hdc, windowWidth, windowHeight);
if (memBitmap) {
HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);
RECT rect;
GetClientRect(hwnd, &rect);
FillRect(memDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
Graphics graphics(memDC);
graphics.SetSmoothingMode(SmoothingModeHighQuality);
graphics.SetTextRenderingHint(TextRenderingHintAntiAlias);
// Адский градиентный фон
LinearGradientBrush gradientBrush(
Rect(0, 0, windowWidth, windowHeight),
Color(220, 80, 0, 0), // Темно-красный
Color(220, 40, 0, 0), // Еще темнее
LinearGradientModeVertical);
graphics.FillRectangle(&gradientBrush, 0, 0, windowWidth, windowHeight);
// Рисуем пиксельных демонов
DrawPixelDemon(graphics, 20, 15, 100);
DrawPixelDemon(graphics, 190, 20, 60);
DrawPixelDemon(graphics, 100, 90, 40);
// Рисуем PNG поверх демонов
if (png) {
// Делаем PNG полупрозрачным
ColorMatrix matrix = {
1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.6f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f
};
ImageAttributes imgAttr;
imgAttr.SetColorMatrix(&matrix);
graphics.DrawImage(png,
Rect(10, 10, windowWidth - 20, 110),
0, 0, png->GetWidth(), png->GetHeight(),
UnitPixel, &imgAttr);
}
// Текст
FontFamily fontFamily(L"Segoe UI");
Font font(&fontFamily, 14, FontStyleBold);
// Тень текста
SolidBrush shadowBrush(Color(100, 0, 0, 0));
RectF shadowRect(2, 132, windowWidth - 4, 35);
StringFormat format;
format.SetAlignment(StringAlignmentCenter);
format.SetLineAlignment(StringAlignmentCenter);
graphics.DrawString(message.c_str(), -1, &font, shadowRect, &format, &shadowBrush);
// Основной текст
SolidBrush textBrush(Color(255, 255, 255, 255));
RectF textRect(0, 130, windowWidth, 35);
graphics.DrawString(message.c_str(), -1, &font, textRect, &format, &textBrush);
BitBlt(hdc, 0, 0, windowWidth, windowHeight, memDC, 0, 0, SRCCOPY);
SelectObject(memDC, oldBitmap);
DeleteObject(memBitmap);
}
DeleteDC(memDC);
}
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY:
if (png) {
delete png;
png = NULL;
}
g_animationActive = false;
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// ==================== ПОКАЗ УВЕДОМЛЕНИЯ ====================
void ShowNotification(const std::wstring& message, int seconds) {
g_notificationMessage = message;
g_notificationDuration = seconds;
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
HWND hwnd = CreateWindowEx(
WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
L"NotificationClass",
L"",
WS_POPUP,
screenWidth,
40,
320,
180,
NULL,
NULL,
GetModuleHandle(NULL),
NULL
);
if (hwnd) {
SetLayeredWindowAttributes(hwnd, 0, 0, LWA_ALPHA);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
PlaySoundFromResource(IDR_BLOOM_WAV);
g_animationActive = true;
}
}
// ==================== ДОБАВЛЕНИЕ ИКОНКИ В ТРЕЙ ====================
void AddTrayIcon(HWND hwnd) {
NOTIFYICONDATA nid = {};
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd;
nid.uID = 1;
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
nid.uCallbackMessage = WM_TRAYICON;
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcscpy_s(nid.szTip, L"Furry Connecta");
Shell_NotifyIcon(NIM_ADD, &nid);
}
// ==================== УДАЛЕНИЕ ИКОНКИ ИЗ ТРЕЯ ====================
void RemoveTrayIcon(HWND hwnd) {
NOTIFYICONDATA nid = {};
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd;
nid.uID = 1;
Shell_NotifyIcon(NIM_DELETE, &nid);
}
// ==================== ИЗВЛЕЧЕНИЕ IP И ПОРТА ====================
std::wstring ExtractServerKey(const std::wstring& link) {
std::wsmatch match;
if (std::regex_search(link, match,
std::wregex(LR"(steam://connect/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+))"))) {
return match[1].str();
}
if (std::regex_match(link,
std::wregex(LR"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+)"))) {
return link;
}
return link;
}
// ==================== ПРОВЕРКА ССЫЛКИ ====================
bool IsServerLink(const std::wstring& text, std::wstring& outLink) {
std::wsmatch match;
// Проверяем на steam://connect/
if (text.find(L"steam://connect/") == 0) {
outLink = text;
return true;
}
// Проверяем на connect ip:port
if (std::regex_search(text, match,
std::wregex(LR"(connect\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+))", std::regex::icase)))
{
outLink = L"steam://connect/" + match[1].str();
return true;
}
// Проверяем на connect ip port
if (std::regex_search(text, match,
std::wregex(LR"(connect\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+(\d+))", std::regex::icase)))
{
outLink = L"steam://connect/" + match[1].str() + L":" + match[2].str();
return true;
}
// Проверяем на просто ip:port
if (std::regex_match(text,
std::wregex(LR"(^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$)")))
{
outLink = L"steam://connect/" + text;
return true;
}
return false;
}
// ==================== ГЛАВНОЕ ОКНО ====================
LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_TRAYICON: {
if (lParam == WM_RBUTTONUP) {
POINT pt;
GetCursorPos(&pt);
HMENU menu = CreatePopupMenu();
AppendMenu(menu, MF_STRING, ID_TRAY_TOGGLE,
g_autoConnectEnabled ? L"
Выключить авто-коннект" : L"
Включить авто-коннект");
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
AppendMenu(menu, MF_STRING, ID_TRAY_EXIT, L"
Выход");
SetForegroundWindow(hwnd);
TrackPopupMenu(menu, TPM_BOTTOMALIGN | TPM_LEFTALIGN,
pt.x, pt.y, 0, hwnd, NULL);
DestroyMenu(menu);
}
break;
}
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case ID_TRAY_EXIT:
RemoveTrayIcon(hwnd);
PostQuitMessage(0);
break;
case ID_TRAY_TOGGLE:
g_autoConnectEnabled = !g_autoConnectEnabled;
break;
}
break;
}
case WM_CLOSE:
RemoveTrayIcon(hwnd);
PostQuitMessage(0);
break;
case WM_DESTROY:
RemoveTrayIcon(hwnd);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// ==================== ОЧИСТКА СТАРЫХ ЗАПИСЕЙ ИСТОРИИ ====================
void CleanupConnectionHistory() {
DWORD currentTime = GetTickCount();
auto it = g_connectionHistory.begin();
while (it != g_connectionHistory.end()) {
if (abs((int)(currentTime - it->second)) > CONNECTION_COOLDOWN * 10) {
it = g_connectionHistory.erase(it);
}
else {
++it;
}
}
}
// ==================== ТОЧКА ВХОДА ====================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) {
SetHighPriority();
GdiplusStartupInput gdiplusStartupInput;
if (GdiplusStartup(&g_gdiplusToken, &gdiplusStartupInput, NULL) != Ok) {
return 1;
}
// Регистрируем класс главного окна
WNDCLASS mainClass = {};
mainClass.lpfnWndProc = MainWindowProc;
mainClass.hInstance = hInstance;
mainClass.lpszClassName = L"MainClass";
if (!RegisterClass(&mainClass)) {
GdiplusShutdown(g_gdiplusToken);
return 1;
}
// Регистрируем класс окна уведомлений
WNDCLASS notifyClass = {};
notifyClass.lpfnWndProc = NotificationProc;
notifyClass.hInstance = hInstance;
notifyClass.lpszClassName = L"NotificationClass";
notifyClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
if (!RegisterClass(¬ifyClass)) {
GdiplusShutdown(g_gdiplusToken);
return 1;
}
// Создаем главное окно
HWND hwnd = CreateWindowEx(
0,
L"MainClass",
L"Furry Connecta",
WS_OVERLAPPEDWINDOW,
0, 0, 300, 200,
NULL,
NULL,
hInstance,
NULL
);
if (!hwnd) {
GdiplusShutdown(g_gdiplusToken);
return 1;
}
g_mainHwnd = hwnd;
AddTrayIcon(hwnd);
// Показываем приветствие
ShowNotification(L"furry connect!", 2);
DWORD lastCleanupTime = GetTickCount();
MSG msg = {};
// Главный цикл сообщений
while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
if (g_autoConnectEnabled) {
std::wstring currentClip = GetClipboardText();
if (!currentClip.empty() && currentClip != g_lastClipboardText) {
g_lastClipboardText = currentClip;
std::wstring serverLink;
if (IsServerLink(currentClip, serverLink)) {
std::wstring serverKey = ExtractServerKey(serverLink);
DWORD currentTime = GetTickCount();
auto it = g_connectionHistory.find(serverKey);
if (it == g_connectionHistory.end() ||
abs((int)(currentTime - it->second)) > CONNECTION_COOLDOWN) {
g_connectionHistory[serverKey] = currentTime;
ShellExecute(NULL, L"open", serverLink.c_str(), NULL, NULL, SW_SHOWNORMAL);
ShowNotification(L"Подключаюсь к серверу...", 1);
}
}
}
}
// Очистка истории раз в минуту
DWORD currentTime = GetTickCount();
if (abs((int)(currentTime - lastCleanupTime)) > 60000) {
CleanupConnectionHistory();
lastCleanupTime = currentTime;
}
// Умная задержка
if (g_animationActive) {
Sleep(1);
}
else {
Sleep(10);
}
}
}
RemoveTrayIcon(hwnd);
GdiplusShutdown(g_gdiplusToken);
timeEndPeriod(1);
return (int)msg.wParam;
}
работает по принципу если вы копируете коннект, то будет через некоторое время с задержкой джойниться на сервер.
по всем вопросам:
tg @kolthefurry
#include <windows.h>
#include <gdiplus.h>
#include <shellapi.h>
#include <dwmapi.h>
#include <string>
#include <regex>
#include <map>
#include <cmath>
#include <mmsystem.h>
#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "winmm.lib")
#pragma comment(lib, "dwmapi.lib")
using namespace Gdiplus;
// ID ресурсов
#define IDR_FURRY_PNG 101
#define IDR_BLOOM_WAV 102
#define WM_TRAYICON (WM_USER + 1)
#define ID_TRAY_EXIT 1001
#define ID_TRAY_TOGGLE 1002
// Глобальные переменные
ULONG_PTR g_gdiplusToken = 0;
HWND g_mainHwnd = NULL;
bool g_autoConnectEnabled = true;
bool g_animationActive = false;
std::map<std::wstring, DWORD> g_connectionHistory;
const DWORD CONNECTION_COOLDOWN = 8000;
std::wstring g_lastClipboardText = L"";
std::wstring g_notificationMessage = L"";
int g_notificationDuration = 1;
// ==================== ПИКСЕЛЬНЫЙ ДЕМОН ====================
void DrawPixelDemon(Graphics& graphics, int startX, int startY, int size) {
// Цвета
Color red(255, 255, 0, 0);
Color darkRed(255, 139, 0, 0);
Color black(255, 0, 0, 0);
Color gray(255, 60, 60, 60);
Color darkGray(255, 30, 30, 30);
Color orange(255, 255, 140, 0);
Color yellow(255, 255, 255, 0);
Color white(255, 255, 255, 255);
Color purple(255, 128, 0, 128);
SolidBrush redBrush(red);
SolidBrush darkRedBrush(darkRed);
SolidBrush blackBrush(black);
SolidBrush grayBrush(gray);
SolidBrush darkGrayBrush(darkGray);
SolidBrush orangeBrush(orange);
SolidBrush yellowBrush(yellow);
SolidBrush whiteBrush(white);
SolidBrush purpleBrush(purple);
int pixelSize = size / 20;
if (pixelSize < 2) pixelSize = 2;
// Рога
graphics.FillRectangle(&darkRedBrush, startX + 8 * pixelSize, startY + 1 * pixelSize, pixelSize, pixelSize * 2);
graphics.FillRectangle(&darkRedBrush, startX + 11 * pixelSize, startY + 1 * pixelSize, pixelSize, pixelSize * 2);
graphics.FillRectangle(&redBrush, startX + 7 * pixelSize, startY + 2 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&redBrush, startX + 11 * pixelSize, startY + 2 * pixelSize, pixelSize * 2, pixelSize);
// Голова
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 5; j++) {
graphics.FillRectangle(&darkRedBrush, startX + (7 + i) * pixelSize, startY + (3 + j) * pixelSize, pixelSize, pixelSize);
}
}
// Глаза (злые)
graphics.FillRectangle(&yellowBrush, startX + 8 * pixelSize, startY + 5 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&yellowBrush, startX + 11 * pixelSize, startY + 5 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&blackBrush, startX + 9 * pixelSize, startY + 5 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&blackBrush, startX + 12 * pixelSize, startY + 5 * pixelSize, pixelSize, pixelSize);
// Зрачки (красные)
graphics.FillRectangle(&redBrush, startX + 9 * pixelSize, startY + 5 * pixelSize, pixelSize / 2, pixelSize / 2);
graphics.FillRectangle(&redBrush, startX + 12 * pixelSize, startY + 5 * pixelSize, pixelSize / 2, pixelSize / 2);
// Рот с клыками
graphics.FillRectangle(&blackBrush, startX + 9 * pixelSize, startY + 7 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&whiteBrush, startX + 8 * pixelSize, startY + 7 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&whiteBrush, startX + 11 * pixelSize, startY + 7 * pixelSize, pixelSize, pixelSize);
// Тело
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 6; j++) {
graphics.FillRectangle(&blackBrush, startX + (6 + i) * pixelSize, startY + (8 + j) * pixelSize, pixelSize, pixelSize);
}
}
// Крылья летучей мыши (слева)
graphics.FillRectangle(&purpleBrush, startX + 3 * pixelSize, startY + 10 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&purpleBrush, startX + 2 * pixelSize, startY + 11 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&purpleBrush, startX + 1 * pixelSize, startY + 12 * pixelSize, pixelSize * 2, pixelSize);
// Крылья летучей мыши (справа)
graphics.FillRectangle(&purpleBrush, startX + 15 * pixelSize, startY + 10 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&purpleBrush, startX + 16 * pixelSize, startY + 11 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&purpleBrush, startX + 17 * pixelSize, startY + 12 * pixelSize, pixelSize * 2, pixelSize);
// Хвост с наконечником
graphics.FillRectangle(&redBrush, startX + 13 * pixelSize, startY + 13 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&redBrush, startX + 14 * pixelSize, startY + 14 * pixelSize, pixelSize * 2, pixelSize);
graphics.FillRectangle(&orangeBrush, startX + 15 * pixelSize, startY + 15 * pixelSize, pixelSize, pixelSize);
// Огонь вокруг
for (int i = 0; i < 3; i++) {
graphics.FillRectangle(&orangeBrush, startX + (5 + i * 2) * pixelSize, startY + 16 * pixelSize, pixelSize, pixelSize);
graphics.FillRectangle(&yellowBrush, startX + (6 + i * 2) * pixelSize, startY + 17 * pixelSize, pixelSize, pixelSize);
}
}
// ==================== ПОВЫШЕНИЕ ПРИОРИТЕТА ====================
void SetHighPriority() {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
timeBeginPeriod(1);
}
// ==================== ЗАГРУЗКА PNG ИЗ РЕСУРСОВ ====================
Bitmap* LoadPNGFromResource(int resourceID) {
HRSRC hResource = FindResource(NULL, MAKEINTRESOURCE(resourceID), L"PNG");
if (!hResource) return NULL;
DWORD imageSize = SizeofResource(NULL, hResource);
HGLOBAL hGlobal = LoadResource(NULL, hResource);
if (!hGlobal) return NULL;
void* pData = LockResource(hGlobal);
if (!pData) return NULL;
HGLOBAL hBuffer = GlobalAlloc(GMEM_MOVEABLE, imageSize);
if (!hBuffer) return NULL;
void* pBuffer = GlobalLock(hBuffer);
if (!pBuffer) {
GlobalFree(hBuffer);
return NULL;
}
memcpy(pBuffer, pData, imageSize);
GlobalUnlock(hBuffer);
IStream* pStream = NULL;
if (CreateStreamOnHGlobal(hBuffer, TRUE, &pStream) != S_OK) {
GlobalFree(hBuffer);
return NULL;
}
Bitmap* bmp = new Bitmap(pStream);
pStream->Release();
return bmp;
}
// ==================== ПОЛУЧЕНИЕ ТЕКСТА ИЗ БУФЕРА ОБМЕНА ====================
std::wstring GetClipboardText() {
std::wstring result = L"";
if (!OpenClipboard(NULL)) return result;
HANDLE hData = GetClipboardData(CF_UNICODETEXT);
if (hData) {
wchar_t* text = (wchar_t*)GlobalLock(hData);
if (text) {
result = text;
GlobalUnlock(hData);
}
}
CloseClipboard();
// Удаляем пробелы в начале и конце
size_t start = result.find_first_not_of(L" \t\r\n");
size_t end = result.find_last_not_of(L" \t\r\n");
if (start != std::wstring::npos && end != std::wstring::npos) {
result = result.substr(start, end - start + 1);
}
else if (start == std::wstring::npos) {
result = L"";
}
return result;
}
// ==================== ПРОИГРЫВАНИЕ ЗВУКА ИЗ РЕСУРСОВ ====================
void PlaySoundFromResource(int resourceID) {
PlaySound(MAKEINTRESOURCE(resourceID), GetModuleHandle(NULL),
SND_RESOURCE | SND_ASYNC);
}
// ==================== ДОБАВЛЕНИЕ ТЕНИ ====================
void AddWindowShadow(HWND hwnd) {
const MARGINS margins = { 1, 1, 1, 1 };
DwmExtendFrameIntoClientArea(hwnd, &margins);
BOOL enableShadow = TRUE;
DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &enableShadow, sizeof(enableShadow));
}
// ==================== ОКНО УВЕДОМЛЕНИЯ ====================
LRESULT CALLBACK NotificationProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static Bitmap* png = NULL;
static float alpha = 0.0f;
static float offset = 0.0f;
static int state = 0;
static int pauseCounter = 0;
static int pauseDuration = 0;
static std::wstring message = L"";
static int screenWidth = GetSystemMetrics(SM_CXSCREEN);
static int windowWidth = 320;
static int windowHeight = 180;
switch (msg) {
case WM_CREATE: {
png = LoadPNGFromResource(IDR_FURRY_PNG);
message = g_notificationMessage;
pauseDuration = (g_notificationDuration * 1000) / 16; // ~60fps
HRGN region = CreateRoundRectRgn(0, 0, windowWidth, windowHeight, 20, 20);
SetWindowRgn(hwnd, region, TRUE);
DeleteObject(region);
AddWindowShadow(hwnd);
alpha = 0.0f;
offset = (float)windowWidth;
state = 0;
pauseCounter = 0;
SetTimer(hwnd, 1, 16, NULL); // ~60fps
break;
}
case WM_TIMER: {
switch (state) {
case 0: // Появление
if (offset > 0) {
offset -= 15.0f;
if (offset < 0) offset = 0;
}
if (alpha < 255.0f) {
alpha += 15.0f;
if (alpha > 255.0f) alpha = 255.0f;
}
if (offset <= 0 && alpha >= 255.0f) {
state = 1;
pauseCounter = 0;
}
SetWindowPos(hwnd, HWND_TOPMOST, screenWidth - windowWidth + (int)offset, 40, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
SetLayeredWindowAttributes(hwnd, 0, (BYTE)alpha, LWA_ALPHA);
break;
case 1: // Пауза
pauseCounter++;
if (pauseCounter > pauseDuration) {
state = 2;
}
break;
case 2: // Исчезновение
if (offset < windowWidth) {
offset += 15.0f;
if (offset > windowWidth) offset = (float)windowWidth;
}
if (alpha > 0) {
alpha -= 15.0f;
if (alpha < 0) alpha = 0;
}
SetWindowPos(hwnd, HWND_TOPMOST, screenWidth - windowWidth + (int)offset, 40, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
SetLayeredWindowAttributes(hwnd, 0, (BYTE)alpha, LWA_ALPHA);
if (offset >= windowWidth && alpha <= 0) {
KillTimer(hwnd, 1);
DestroyWindow(hwnd);
return 0;
}
break;
}
InvalidateRect(hwnd, NULL, FALSE);
break;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HDC memDC = CreateCompatibleDC(hdc);
if (memDC) {
HBITMAP memBitmap = CreateCompatibleBitmap(hdc, windowWidth, windowHeight);
if (memBitmap) {
HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap);
RECT rect;
GetClientRect(hwnd, &rect);
FillRect(memDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
Graphics graphics(memDC);
graphics.SetSmoothingMode(SmoothingModeHighQuality);
graphics.SetTextRenderingHint(TextRenderingHintAntiAlias);
// Адский градиентный фон
LinearGradientBrush gradientBrush(
Rect(0, 0, windowWidth, windowHeight),
Color(220, 80, 0, 0), // Темно-красный
Color(220, 40, 0, 0), // Еще темнее
LinearGradientModeVertical);
graphics.FillRectangle(&gradientBrush, 0, 0, windowWidth, windowHeight);
// Рисуем пиксельных демонов
DrawPixelDemon(graphics, 20, 15, 100);
DrawPixelDemon(graphics, 190, 20, 60);
DrawPixelDemon(graphics, 100, 90, 40);
// Рисуем PNG поверх демонов
if (png) {
// Делаем PNG полупрозрачным
ColorMatrix matrix = {
1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.6f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f
};
ImageAttributes imgAttr;
imgAttr.SetColorMatrix(&matrix);
graphics.DrawImage(png,
Rect(10, 10, windowWidth - 20, 110),
0, 0, png->GetWidth(), png->GetHeight(),
UnitPixel, &imgAttr);
}
// Текст
FontFamily fontFamily(L"Segoe UI");
Font font(&fontFamily, 14, FontStyleBold);
// Тень текста
SolidBrush shadowBrush(Color(100, 0, 0, 0));
RectF shadowRect(2, 132, windowWidth - 4, 35);
StringFormat format;
format.SetAlignment(StringAlignmentCenter);
format.SetLineAlignment(StringAlignmentCenter);
graphics.DrawString(message.c_str(), -1, &font, shadowRect, &format, &shadowBrush);
// Основной текст
SolidBrush textBrush(Color(255, 255, 255, 255));
RectF textRect(0, 130, windowWidth, 35);
graphics.DrawString(message.c_str(), -1, &font, textRect, &format, &textBrush);
BitBlt(hdc, 0, 0, windowWidth, windowHeight, memDC, 0, 0, SRCCOPY);
SelectObject(memDC, oldBitmap);
DeleteObject(memBitmap);
}
DeleteDC(memDC);
}
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY:
if (png) {
delete png;
png = NULL;
}
g_animationActive = false;
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// ==================== ПОКАЗ УВЕДОМЛЕНИЯ ====================
void ShowNotification(const std::wstring& message, int seconds) {
g_notificationMessage = message;
g_notificationDuration = seconds;
int screenWidth = GetSystemMetrics(SM_CXSCREEN);
HWND hwnd = CreateWindowEx(
WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
L"NotificationClass",
L"",
WS_POPUP,
screenWidth,
40,
320,
180,
NULL,
NULL,
GetModuleHandle(NULL),
NULL
);
if (hwnd) {
SetLayeredWindowAttributes(hwnd, 0, 0, LWA_ALPHA);
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
PlaySoundFromResource(IDR_BLOOM_WAV);
g_animationActive = true;
}
}
// ==================== ДОБАВЛЕНИЕ ИКОНКИ В ТРЕЙ ====================
void AddTrayIcon(HWND hwnd) {
NOTIFYICONDATA nid = {};
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd;
nid.uID = 1;
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
nid.uCallbackMessage = WM_TRAYICON;
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcscpy_s(nid.szTip, L"Furry Connecta");
Shell_NotifyIcon(NIM_ADD, &nid);
}
// ==================== УДАЛЕНИЕ ИКОНКИ ИЗ ТРЕЯ ====================
void RemoveTrayIcon(HWND hwnd) {
NOTIFYICONDATA nid = {};
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd;
nid.uID = 1;
Shell_NotifyIcon(NIM_DELETE, &nid);
}
// ==================== ИЗВЛЕЧЕНИЕ IP И ПОРТА ====================
std::wstring ExtractServerKey(const std::wstring& link) {
std::wsmatch match;
if (std::regex_search(link, match,
std::wregex(LR"(steam://connect/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+))"))) {
return match[1].str();
}
if (std::regex_match(link,
std::wregex(LR"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+)"))) {
return link;
}
return link;
}
// ==================== ПРОВЕРКА ССЫЛКИ ====================
bool IsServerLink(const std::wstring& text, std::wstring& outLink) {
std::wsmatch match;
// Проверяем на steam://connect/
if (text.find(L"steam://connect/") == 0) {
outLink = text;
return true;
}
// Проверяем на connect ip:port
if (std::regex_search(text, match,
std::wregex(LR"(connect\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+))", std::regex::icase)))
{
outLink = L"steam://connect/" + match[1].str();
return true;
}
// Проверяем на connect ip port
if (std::regex_search(text, match,
std::wregex(LR"(connect\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+(\d+))", std::regex::icase)))
{
outLink = L"steam://connect/" + match[1].str() + L":" + match[2].str();
return true;
}
// Проверяем на просто ip:port
if (std::regex_match(text,
std::wregex(LR"(^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$)")))
{
outLink = L"steam://connect/" + text;
return true;
}
return false;
}
// ==================== ГЛАВНОЕ ОКНО ====================
LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_TRAYICON: {
if (lParam == WM_RBUTTONUP) {
POINT pt;
GetCursorPos(&pt);
HMENU menu = CreatePopupMenu();
AppendMenu(menu, MF_STRING, ID_TRAY_TOGGLE,
g_autoConnectEnabled ? L"
AppendMenu(menu, MF_SEPARATOR, 0, NULL);
AppendMenu(menu, MF_STRING, ID_TRAY_EXIT, L"
SetForegroundWindow(hwnd);
TrackPopupMenu(menu, TPM_BOTTOMALIGN | TPM_LEFTALIGN,
pt.x, pt.y, 0, hwnd, NULL);
DestroyMenu(menu);
}
break;
}
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case ID_TRAY_EXIT:
RemoveTrayIcon(hwnd);
PostQuitMessage(0);
break;
case ID_TRAY_TOGGLE:
g_autoConnectEnabled = !g_autoConnectEnabled;
break;
}
break;
}
case WM_CLOSE:
RemoveTrayIcon(hwnd);
PostQuitMessage(0);
break;
case WM_DESTROY:
RemoveTrayIcon(hwnd);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// ==================== ОЧИСТКА СТАРЫХ ЗАПИСЕЙ ИСТОРИИ ====================
void CleanupConnectionHistory() {
DWORD currentTime = GetTickCount();
auto it = g_connectionHistory.begin();
while (it != g_connectionHistory.end()) {
if (abs((int)(currentTime - it->second)) > CONNECTION_COOLDOWN * 10) {
it = g_connectionHistory.erase(it);
}
else {
++it;
}
}
}
// ==================== ТОЧКА ВХОДА ====================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int) {
SetHighPriority();
GdiplusStartupInput gdiplusStartupInput;
if (GdiplusStartup(&g_gdiplusToken, &gdiplusStartupInput, NULL) != Ok) {
return 1;
}
// Регистрируем класс главного окна
WNDCLASS mainClass = {};
mainClass.lpfnWndProc = MainWindowProc;
mainClass.hInstance = hInstance;
mainClass.lpszClassName = L"MainClass";
if (!RegisterClass(&mainClass)) {
GdiplusShutdown(g_gdiplusToken);
return 1;
}
// Регистрируем класс окна уведомлений
WNDCLASS notifyClass = {};
notifyClass.lpfnWndProc = NotificationProc;
notifyClass.hInstance = hInstance;
notifyClass.lpszClassName = L"NotificationClass";
notifyClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
if (!RegisterClass(¬ifyClass)) {
GdiplusShutdown(g_gdiplusToken);
return 1;
}
// Создаем главное окно
HWND hwnd = CreateWindowEx(
0,
L"MainClass",
L"Furry Connecta",
WS_OVERLAPPEDWINDOW,
0, 0, 300, 200,
NULL,
NULL,
hInstance,
NULL
);
if (!hwnd) {
GdiplusShutdown(g_gdiplusToken);
return 1;
}
g_mainHwnd = hwnd;
AddTrayIcon(hwnd);
// Показываем приветствие
ShowNotification(L"furry connect!", 2);
DWORD lastCleanupTime = GetTickCount();
MSG msg = {};
// Главный цикл сообщений
while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
if (g_autoConnectEnabled) {
std::wstring currentClip = GetClipboardText();
if (!currentClip.empty() && currentClip != g_lastClipboardText) {
g_lastClipboardText = currentClip;
std::wstring serverLink;
if (IsServerLink(currentClip, serverLink)) {
std::wstring serverKey = ExtractServerKey(serverLink);
DWORD currentTime = GetTickCount();
auto it = g_connectionHistory.find(serverKey);
if (it == g_connectionHistory.end() ||
abs((int)(currentTime - it->second)) > CONNECTION_COOLDOWN) {
g_connectionHistory[serverKey] = currentTime;
ShellExecute(NULL, L"open", serverLink.c_str(), NULL, NULL, SW_SHOWNORMAL);
ShowNotification(L"Подключаюсь к серверу...", 1);
}
}
}
}
// Очистка истории раз в минуту
DWORD currentTime = GetTickCount();
if (abs((int)(currentTime - lastCleanupTime)) > 60000) {
CleanupConnectionHistory();
lastCleanupTime = currentTime;
}
// Умная задержка
if (g_animationActive) {
Sleep(1);
}
else {
Sleep(10);
}
}
}
RemoveTrayIcon(hwnd);
GdiplusShutdown(g_gdiplusToken);
timeEndPeriod(1);
return (int)msg.wParam;
}