chip-game/Assets/Scripts/GameManager.cs

682 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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];
}
UnityMainThreadDispatcher.Initialize();
InitializePrefs();
SettingsManager.Initialize();
GetComponent<Logger>().Initialize();
//Тестируем пока что. Не прод
ComWrapper.Initialize(ComNativeWrapper.ListPorts(), 2);
SingleWallet.Initialize();
ComWrapper.PaymentReceived += ProcessDifficultyCounter;
SettingsManager.OnSettingsChanged.AddListener(ProcessDifficultyCounter);
soundManager.Initialize();
GetComponent<NotificationSystem>().Initialize();
ProcessDifficultyCounter();
GetComponent<In>().Initialize();
GetComponent<PrizeSystem>().Initialize();
GetComponent<VideoUtility>().Initialize();
StatsService = new();
StatsService.Initialize();
#if !UNITY_EDITOR
//Билд
// Проверка лицензии при старте игры
StartCoroutine(CheckLicenseCoroutine());
dummyBots = false;
#endif
StartCoroutine(AddBotRecordEvery2Days());// добавлять каждые 2 дня запись
avatarController.GetComponent<AvatarEventBus>().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<SpriteRenderer>().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<SettingsScreen>().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<SettingsScreen>().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
}