using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using UnityEditor; using UnityEngine; public class Defender : MonoBehaviour { private void Awake() { #if !UNITY_EDITOR StartCoroutine(CheckLicenseCoroutine()); #endif } #region DEFENCE [StructLayout(LayoutKind.Sequential)] private struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct STARTUPINFO { public int cb; public string lpReserved; public string lpDesktop; public string lpTitle; public int dwX; public int dwY; public int dwXSize; public int dwYSize; public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern bool CreateProcess( string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll", SetLastError = true)] private static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle(IntPtr hObject); private const uint WAIT_TIMEOUT = 0x00000102; private const uint WAIT_OBJECT_0 = 0x00000000; private System.Collections.IEnumerator CheckLicenseCoroutine() { // Ждём один кадр, чтобы Unity завершил инициализацию yield return null; bool licenseValid = false; bool checkCompleted = false; //bool licenseValid = true; //bool checkCompleted = true; string errorMessage = ""; // Запускаем проверку в отдельном потоке (совместимо с IL2CPP) System.Threading.Thread thread = new System.Threading.Thread(() => { try { licenseValid = CheckLicense(); } catch (Exception ex) { errorMessage = ex.Message; } finally { checkCompleted = true; } }); thread.IsBackground = true; thread.Start(); float timerest = 30f; while (!checkCompleted && timerest > 0) { timerest -= Time.deltaTime; yield return null; } if (!checkCompleted) licenseValid = false; if (!licenseValid) { yield return new WaitForSeconds(3f); #if UNITY_EDITOR EditorApplication.isPlaying = false; #else Application.Quit(); #endif } else { //exclusive Screen.fullScreenMode = FullScreenMode.ExclusiveFullScreen; Screen.SetResolution(1920, 1080, true); ClickCenter(); } } private bool CheckLicense() { try { string launcherName = "RRLauncher.exe"; string launcherPath = null; // Поиск лаунчера рядом с исполняемым файлом string baseDirectory = AppDomain.CurrentDomain.BaseDirectory; string pathInBase = Path.Combine(baseDirectory, launcherName); if (File.Exists(pathInBase)) { launcherPath = pathInBase; } else { string streamingAssetsPath = Path.Combine(Application.streamingAssetsPath, launcherName); if (File.Exists(streamingAssetsPath)) { launcherPath = streamingAssetsPath; } else { return false; } } try { STARTUPINFO si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); PROCESS_INFORMATION pi; string workingDir = Path.GetDirectoryName(launcherPath); bool success = CreateProcess( launcherPath, null, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, workingDir, ref si, out pi); if (!success) return false; uint waitResult = WaitForSingleObject(pi.hProcess, 30000); if (waitResult == WAIT_TIMEOUT) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return false; } // Получение кода возврата uint exitCode; if (!GetExitCodeProcess(pi.hProcess, out exitCode)) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return false; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); if (exitCode == 0) { ForceToFront(); return true; } return false; } catch { return false; } } catch (Exception outerEx) { Debug.LogError($"[License] CRITICAL ERROR in CheckLicense: {outerEx.Message}"); Debug.LogError($"[License] Stack trace: {outerEx.StackTrace}"); return false; } } #region FORCE TO FRONT [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hwnd); [DllImport("user32.dll")] private static extern IntPtr GetActiveWindow(); public void ForceToFront()//Метод который возвращает фокус а окно после открытия защиты { IntPtr handle = GetActiveWindow(); SetForegroundWindow(handle); } #endregion #region клик в центр [StructLayout(LayoutKind.Sequential)] public struct INPUT { public uint type; public MOUSEINPUT mi; } [StructLayout(LayoutKind.Sequential)] public struct MOUSEINPUT { public int dx; public int dy; public uint mouseData; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; } private const uint INPUT_MOUSE = 0; private const uint MOUSEEVENTF_MOVE = 0x0001; private const uint MOUSEEVENTF_ABSOLUTE = 0x8000; private const uint MOUSEEVENTF_LEFTDOWN = 0x0002; private const uint MOUSEEVENTF_LEFTUP = 0x0004; [DllImport("user32.dll")] static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); public static void ClickCenter() { int screenX = Screen.currentResolution.width / 2; int screenY = Screen.currentResolution.height / 2; // WinAPI использует координаты 0–65535 int absoluteX = (int)(screenX * 65535 / Screen.currentResolution.width); int absoluteY = (int)(screenY * 65535 / Screen.currentResolution.height); INPUT[] inputs = new INPUT[3]; // движение мыши inputs[0] = new INPUT { type = INPUT_MOUSE, mi = new MOUSEINPUT { dx = absoluteX, dy = absoluteY, dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, } }; // нажатие inputs[1] = new INPUT { type = INPUT_MOUSE, mi = new MOUSEINPUT { dwFlags = MOUSEEVENTF_LEFTDOWN } }; // отпускание inputs[2] = new INPUT { type = INPUT_MOUSE, mi = new MOUSEINPUT { dwFlags = MOUSEEVENTF_LEFTUP } }; SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT))); } #endregion #endregion }