using System; using System.IO; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using System.Collections; #if UNITY_EDITOR using UnityEditor; #endif public enum GameMode { pve, pvp } public class GameManager : MonoBehaviour { #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 #region MAIN public PlayerStatsService StatsService; public bool dummyBots = false; public int botsAmount = 5; public DifficultyPreset dummyPreset; public DifficultyPreset MistressPreset; [Header("General")] public GameStateMachine stateMachine; public Transform slotLeftTop; public static FieldModel fieldModel; public static GameManager instance; public GameObject AdminPanel, NumberPanel, SettingsPointer; public TimerManager timerManager; public VFX_manager effect; public RulesController rulesController; [Header("Menu")] public bool menuOpened = true; public GameMode gameMode; public Transform label, buttonLeft, buttonRight, coinPanel, label2, board, noPrizeLabel; public GameObject mainMenu; public TMP_FontAsset russo_font; [Header("Scores")] public int player1score = 0, player2score = 0, vsBotScore = 0; public int vsBotMoves; public float vsBotThinkTime; public VictoryScale botScale, Player1Scale, Player2Scale; [HideInInspector] public UnityEvent OnNoMoney = new UnityEvent(); public CheckResult lastResult; [Header("Gameplay")] public GameObject player1Chip; public GameObject player2Chip; public GameObject botChip; [HideInInspector] public GameObject currentChip; public Sprite chipPointer, selectedPanel, deselectedPanel; public RectTransform EngamePanel, TimerImage; public RectTransform smallPrizesOut; public Image ReplayButton, MenuButton; public DrawVisual DrawVisual; public TextMeshProUGUI RestartButton; public TextMeshProUGUI TimerLabel; //до выхода в меню.. public TextMeshProUGUI ToMenuLabel; //это же public WinPanel winPanel; [HideInInspector] public CellState currentPlayer = CellState.Player2; public int currentColumnIndex = 0; public float stepX = 1.215f; public float stepY = 1.24f; public float startY; public bool moveMade = false; public float chipXSpeed = 10, chipYSpeed = 0, chipAcceleration = 20; public Transform[,] chipTransforms; // Кешированные компоненты для избежания GetComponent в DrawAnimation [Header("Панели ввода")] public TextInput nameInput; public TextInput ValutaNameInput; public TextInput specialPrizeInput; public NumberInput pricePveInput; public NumberInput pricePvpInput; public NumberInput pricePveRevengeInput; public NumberInput prizesAvailableInput; public NumberInput pulsesToResetDifficultyInput; public NumberInput valutaPerPulseInput; public Leaderboard leaderboard; public GameObject CharactersConfigurator; public GameObject fastCheckCounters; public GameObject checkQrPanel; public DualAvatarController avatarController; public PvpPointer pvpPointer; public MovesAndTimeCounter movesAndTimeCounter; public GameObject setPasswordPanel; public EnterPasswordPanel enterPasswordPanel; public SoundManager soundManager; void Awake() { Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; Instantiate(new GameObject()).AddComponent(typeof(VfxPrefab)); if (instance == null) { Application.targetFrameRate = 60; instance = this; fieldModel = new FieldModel(7, 6); chipTransforms = new Transform[6, 7]; } InitializePrefs(); SettingsManager.Initialize(); GetComponent().Initialize(); GetComponent().Initialize(); ComWrapper.onPulseRecieved.AddListener(ProcessDifficultyCounter); SettingsManager.OnSettingsChanged.AddListener(ProcessDifficultyCounter); soundManager.Initialize(); GetComponent().Initialize(); ProcessDifficultyCounter(); GetComponent().Initialize(); GetComponent().Initialize(); GetComponent().Initialize(); StatsService = new(); StatsService.Initialize(); #if !UNITY_EDITOR //Билд // Проверка лицензии при старте игры StartCoroutine(CheckLicenseCoroutine()); dummyBots = false; #endif StartCoroutine(AddBotRecordEvery2Days());// добавлять каждые 2 дня запись avatarController.GetComponent().Initialize(); avatarController.Initialize(); } private static void InitializePrefs() { PlayerPrefs.SetString("Serial", ExternalFilesGetter.GetSerial()); PlayerPrefs.SetInt("NeedSpecialPrize", 0); if (!PlayerPrefs.HasKey("SpecialPrize")) PlayerPrefs.SetString("SpecialPrize", "5000р"); if (!PlayerPrefs.HasKey("Number")) PlayerPrefs.SetString("Number", "70000000000"); if (!PlayerPrefs.HasKey("ValutaPerImpulse")) PlayerPrefs.SetInt("ValutaPerImpulse", 10); if (!PlayerPrefs.HasKey("ValutaName")) PlayerPrefs.SetString("ValutaName", "руб."); if (!PlayerPrefs.HasKey("PricePVP")) PlayerPrefs.SetInt("PricePVP", 10); if (!PlayerPrefs.HasKey("PricePVE")) PlayerPrefs.SetInt("PricePVE", 10); if (!PlayerPrefs.HasKey("PriceRevenge")) PlayerPrefs.SetInt("PriceRevenge", 10); } private void Start() { stateMachine.ChangeState(new MenuState()); SettingsManager.OnSettingsChanged.AddListener(pullSettings); pullSettings(); Instantiate(new GameObject()).AddComponent(typeof(VfxPrefab)); } void pullSettings() { SetupCoinPanel(); } #if UNITY_EDITOR private void Update() { if (Input.GetKeyDown(KeyCode.G)) { PrizeSystem.GivePrize(new Prize(PrizeType.Hopper, 1)); } if (Input.GetKeyDown(KeyCode.O)) { PlayerPrefs.SetInt("PrizeGivenBuffer", 1); } } #endif public void SetupCoinPanel() { bool shouldShowCoinCounter = !SettingsManager.GetBool("Freeplay", false); coinPanel.gameObject.SetActive(shouldShowCoinCounter); } public void spawnChip() { GameObject chipToSpawn; if (gameMode == GameMode.pvp) chipToSpawn = currentPlayer == CellState.Player1 ? player1Chip : player2Chip; else chipToSpawn = currentPlayer == CellState.Player1 ? player1Chip : botChip; currentChip = Instantiate(chipToSpawn, new Vector2(0, 20), Quaternion.identity); if (currentPlayer == CellState.Player2) currentChip.GetComponentInChildren().sprite = CharacterController.CurrentChipImage; } public void setChipTransformToArray(int row, int col, Transform entryTransform) { chipTransforms[row, col] = entryTransform; } public void SwitchPlayer() { currentPlayer = currentPlayer == CellState.Player1 ? CellState.Player2 : CellState.Player1; } public void SetMode(GameMode mode) => gameMode = mode; public void InitVictoryScales() { //Включить и обнулить нужные шкалы player1score = 0; player2score = 0; vsBotScore = 0; switch (gameMode) { case GameMode.pvp: botScale.gameObject.SetActive(false); Player1Scale.gameObject.SetActive(true); Player2Scale.gameObject.SetActive(true); Player1Scale.SetSlotsCount(5); Player2Scale.SetSlotsCount(5); Player1Scale.ResetScale(); Player2Scale.ResetScale(); break; case GameMode.pve: botScale.gameObject.SetActive(true); botScale.SetSlotsCount(botsAmount); Player1Scale.gameObject.SetActive(false); Player2Scale.gameObject.SetActive(false); botScale.ResetScale(); break; } } public int GetMovesCount() { if (chipTransforms == null) return 0; int count = 0; int rows = chipTransforms.GetLength(0); int cols = chipTransforms.GetLength(1); for (int r = 0; r < rows; r++) for (int c = 0; c < cols; c++) if (chipTransforms[r, c] != null) count++; return count; } public void ProcessDifficultyCounter()//вызывается каждый раз, когда приходит COIN с платы или обновились настройки { string previous = PlayerPrefs.GetString("PreviousBaseBotDifficulty", "Обычная"); string difficultyType = SettingsManager.GetString("BaseBotDifficulty", "?"); //Инициализация if(!PlayerPrefs.HasKey("PulsesToResetDifficulty")) PlayerPrefs.SetInt("PulsesToResetDifficulty", 100); //если переход с повышенной на обычную - сброс счетчика if (previous == "Повышенная" && difficultyType != previous) { PlayerPrefs.SetInt("PulsesCounter", 0); } PlayerPrefs.SetString("PreviousBaseBotDifficulty", difficultyType); if (difficultyType == "Повышенная") { int pulses = PlayerPrefs.GetInt("PulsesCounter", 0); int pulsesToResetDifficulty = PlayerPrefs.GetInt("PulsesToResetDifficulty", 10); if (pulses >= pulsesToResetDifficulty) { PlayerPrefs.SetInt("PulsesCounter", 0); Setting difficultySetting = SettingsManager.Container.TryGetSetting("BaseBotDifficulty"); difficultySetting.StringValue = "Обычная"; SettingsManager.OnSettingsChanged?.Invoke(); SettingsManager.SaveContainerToFile(); AdminPanel.GetComponent().RefreshViews(); print("Сложность сброшена"); } } } public void upgradeFeeshkaDifficulty() { string difficultyType = SettingsManager.GetString("BaseBotDifficulty", "Обычная"); if (difficultyType == "Обычная") { PlayerPrefs.SetInt("PulsesCounter", 0); Setting difficultySetting = SettingsManager.Container.TryGetSetting("BaseBotDifficulty"); difficultySetting.StringValue = "Повышенная"; SettingsManager.OnSettingsChanged?.Invoke(); SettingsManager.SaveContainerToFile(); AdminPanel.GetComponent().RefreshViews(); print("Сложность повышена"); } } IEnumerator AddBotRecordEvery2Days() { while (true) { yield return new WaitForSeconds(3600f); // ✅ Проверка каждый час double lastRecordTime = PlayerPrefs.GetFloat("LastBotRecord", 0); double currentTime = GetUnixTimestamp(); if (currentTime - lastRecordTime >= 172800f) { StatsService.AddDailyRecord(); PlayerPrefs.SetFloat("LastBotRecord", (float)currentTime); PlayerPrefs.Save(); } } } double GetUnixTimestamp() => (DateTime.UtcNow - new System.DateTime(1970, 1, 1)).TotalSeconds; #endregion }