using System; using UnityEngine; public static class MachineCountersService { private const string CountersFileName = "machine-counters.json"; private static MachineCountersData _data; private static double _sessionStartedAt; private static GameMode _pendingGameMode; private static bool _sessionArmed; private static bool _sessionActive; public static string CountersFilePath => System.IO.Path.Combine(Application.persistentDataPath, CountersFileName); public static void Initialize() { PaymentSystem.OnRevenueReceived -= RecordRevenue; PaymentSystem.OnRevenueReceived += RecordRevenue; PrizeSystem.PrizeSystemManager.OnPrizeIssued -= RecordPrizeIssued; PrizeSystem.PrizeSystemManager.OnPrizeIssued += RecordPrizeIssued; GameManager.OnGameStarted -= RecordGameStarted; GameManager.OnGameStarted += RecordGameStarted; GameManager.OnGameFinished -= RecordGameFinished; GameManager.OnGameFinished += RecordGameFinished; Load(); _sessionArmed = false; _sessionActive = false; } public static MachineCounterSet GetLifetimeCounters() { EnsureInitialized(); return _data.lifetime.Clone(); } public static MachineCounterSet GetResettableCounters() { EnsureInitialized(); return _data.resettable.Clone(); } public static void RecordFirstMove() { if (_sessionArmed == false || _sessionActive) return; EnsureInitialized(); IncreaseGamesStarted(_data.lifetime, _pendingGameMode); IncreaseGamesStarted(_data.resettable, _pendingGameMode); _sessionStartedAt = Time.realtimeSinceStartupAsDouble; _sessionActive = true; Save(); } public static void RecordBotResult(bool playerWon) { EnsureInitialized(); if (CharacterSystem.CharactersController.HasActiveCharacter == false) return; int botIndex = CharacterSystem.CharactersController.CharacterIndex; int difficultyIndex = GetCurrentDifficultyIndex(); IncreaseBotResult(_data.lifetime, botIndex, difficultyIndex, playerWon); IncreaseBotResult(_data.resettable, botIndex, difficultyIndex, playerWon); Save(); } public static void ResetResettableCounters() { EnsureInitialized(); _data.resettable = new MachineCounterSet(); PlayerPrefs.SetInt(PrefsKeyVault.CASH_COUNTER_NUL, 0); PlayerPrefs.SetInt(PrefsKeyVault.PRIZES_GIVEN_COUNTER_NUL, 0); PrizeSystem.PrizeSystemManager.ResetPrizeCounters(); PlayerPrefs.Save(); Save(); } private static void RecordRevenue(int amount) { if (amount <= 0) return; EnsureInitialized(); _data.lifetime.revenue += amount; _data.resettable.revenue += amount; Save(); } private static void RecordPrizeIssued() { EnsureInitialized(); _data.lifetime.prizesIssued++; _data.resettable.prizesIssued++; Save(); } private static void RecordGameStarted(GameMode mode) { EnsureInitialized(); _pendingGameMode = mode; _sessionArmed = true; _sessionActive = false; } private static void RecordGameFinished(GameMode mode) { _sessionArmed = false; if (_sessionActive == false) return; EnsureInitialized(); double duration = Math.Max(0d, Time.realtimeSinceStartupAsDouble - _sessionStartedAt); AddCompletedSession(_data.lifetime, duration); AddCompletedSession(_data.resettable, duration); _sessionActive = false; Save(); } private static void IncreaseGamesStarted(MachineCounterSet counters, GameMode mode) { counters.gamesStarted++; if (mode == GameMode.pve) counters.pveGamesStarted++; else counters.pvpGamesStarted++; } private static void AddCompletedSession(MachineCounterSet counters, double duration) { counters.completedSessions++; counters.totalSessionDurationSeconds += duration; } private static void IncreaseBotResult( MachineCounterSet counters, int botIndex, int difficultyIndex, bool playerWon) { counters.NormalizeBotCounters(); int[] values = playerWon ? counters.GetBotWins(difficultyIndex) : counters.GetBotLosses(difficultyIndex); values[botIndex]++; } private static int GetCurrentDifficultyIndex() { if (SettingsManager.GetString(SettingKey.DIFFICULTY_MODE) == "Заработок") return MachineCounterSet.HardDifficultyIndex; return SettingsManager.GetString(SettingKey.DIFFICULTY) switch { "Легкая" => MachineCounterSet.EasyDifficultyIndex, "Сложная" => MachineCounterSet.HardDifficultyIndex, _ => MachineCounterSet.MediumDifficultyIndex }; } private static void EnsureInitialized() { if (_data == null) Load(); } private static void Load() { var loadResult = FileUtil.LoadJson(CountersFileName, FileUtil.AppDirectory.Persistent); if (loadResult.OK && loadResult.Data != null) { _data = loadResult.Data; _data.lifetime ??= new MachineCounterSet(); _data.resettable ??= new MachineCounterSet(); _data.lifetime.NormalizeBotCounters(); _data.resettable.NormalizeBotCounters(); return; } _data = CreateFromLegacyCounters(); Save(); } private static MachineCountersData CreateFromLegacyCounters() { int lifetimePrizes = Mathf.Max( PlayerPrefs.GetInt(PrefsKeyVault.PRIZES_GIVEN_COUNTER, 0), GetLegacyPrizeTotal(false)); int resettablePrizes = Mathf.Max( PlayerPrefs.GetInt(PrefsKeyVault.PRIZES_GIVEN_COUNTER_NUL, 0), GetLegacyPrizeTotal(true)); return new MachineCountersData { lifetime = new MachineCounterSet { revenue = PlayerPrefs.GetInt(PrefsKeyVault.CASH_COUNTER, 0), prizesIssued = lifetimePrizes }, resettable = new MachineCounterSet { revenue = PlayerPrefs.GetInt(PrefsKeyVault.CASH_COUNTER_NUL, 0), prizesIssued = resettablePrizes } }; } private static int GetLegacyPrizeTotal(bool resettable) { string suffix = resettable ? "Nullable" : string.Empty; return PlayerPrefs.GetInt(PrefsKeyVault.HOPPER_GIVEN_COUNTER + suffix, 0) + PlayerPrefs.GetInt(PrefsKeyVault.MARBLES_GIVEN_COUNTER + suffix, 0) + PlayerPrefs.GetInt(PrefsKeyVault.TICKET_GIVEN_COUNTER + suffix, 0) + PlayerPrefs.GetInt(PrefsKeyVault.SPECIAL_GIVEN_COUNTER + suffix, 0); } private static void Save() { var saveResult = FileUtil.SaveJson(CountersFileName, FileUtil.AppDirectory.Persistent, _data); if (saveResult.OK == false) Debug.LogError(saveResult.Message); } } [Serializable] public sealed class MachineCountersData { public MachineCounterSet lifetime = new MachineCounterSet(); public MachineCounterSet resettable = new MachineCounterSet(); } [Serializable] public sealed class MachineCounterSet { public const int BotCount = 5; public const int EasyDifficultyIndex = 0; public const int MediumDifficultyIndex = 1; public const int HardDifficultyIndex = 2; public long revenue; public int prizesIssued; public int gamesStarted; public int pveGamesStarted; public int pvpGamesStarted; public int completedSessions; public double totalSessionDurationSeconds; public int[] easyBotWins = new int[BotCount]; public int[] easyBotLosses = new int[BotCount]; public int[] mediumBotWins = new int[BotCount]; public int[] mediumBotLosses = new int[BotCount]; public int[] hardBotWins = new int[BotCount]; public int[] hardBotLosses = new int[BotCount]; public double AverageSessionDurationSeconds => completedSessions == 0 ? 0d : totalSessionDurationSeconds / completedSessions; public int[] GetBotWins(int difficultyIndex) { return difficultyIndex switch { EasyDifficultyIndex => easyBotWins, HardDifficultyIndex => hardBotWins, _ => mediumBotWins }; } public int[] GetBotLosses(int difficultyIndex) { return difficultyIndex switch { EasyDifficultyIndex => easyBotLosses, HardDifficultyIndex => hardBotLosses, _ => mediumBotLosses }; } public void NormalizeBotCounters() { easyBotWins = NormalizeArray(easyBotWins); easyBotLosses = NormalizeArray(easyBotLosses); mediumBotWins = NormalizeArray(mediumBotWins); mediumBotLosses = NormalizeArray(mediumBotLosses); hardBotWins = NormalizeArray(hardBotWins); hardBotLosses = NormalizeArray(hardBotLosses); } public MachineCounterSet Clone() { return new MachineCounterSet { revenue = revenue, prizesIssued = prizesIssued, gamesStarted = gamesStarted, pveGamesStarted = pveGamesStarted, pvpGamesStarted = pvpGamesStarted, completedSessions = completedSessions, totalSessionDurationSeconds = totalSessionDurationSeconds, easyBotWins = (int[])easyBotWins.Clone(), easyBotLosses = (int[])easyBotLosses.Clone(), mediumBotWins = (int[])mediumBotWins.Clone(), mediumBotLosses = (int[])mediumBotLosses.Clone(), hardBotWins = (int[])hardBotWins.Clone(), hardBotLosses = (int[])hardBotLosses.Clone() }; } private static int[] NormalizeArray(int[] values) { if (values != null && values.Length == BotCount) return values; var normalized = new int[BotCount]; if (values != null) Array.Copy(values, normalized, Math.Min(values.Length, normalized.Length)); return normalized; } }