From 1cecbf2c11430414999217315140bdf1c95dfee6 Mon Sep 17 00:00:00 2001 From: Danil Iarosh Date: Tue, 24 Feb 2026 14:02:38 +0300 Subject: [PATCH] fix: avoid logger dispose errors in free-play flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Исправлен баг `GameManager.NewGame()`: в режиме бесплатной игры (`payment.freeGame = true`) больше не выполняется проверка/списание баланса. - Добавлен явный guard для free-play перед `Balance.CanStartGame()` и `Balance.SpendBalance(...)`, чтобы не было нежелательных списаний. - Устранена ошибка закрытия лог-файла `Cannot access a disposed object`: - `FileLogger` переведен на безопасный паттерн `Dispose(bool)` с идемпотентностью; - добавлена защита от повторного закрытия/записи в уже закрытый поток; - финализатор `FileLogger` больше не выполняет managed-cleanup. - Устранен риск повторной очистки в `CompositeLogger`: - добавлен флаг `_disposed`; - `Dispose(bool)` теперь выполняется только один раз; - финализатор вызывает `Dispose(false)` вместо полного `Dispose()`. --- Assets/Scripts/Managers/GameManager.cs | 9 +++- Assets/Scripts/Utilities/CompositeLogger.cs | 11 +++-- Assets/Scripts/Utilities/FileLogger.cs | 49 +++++++++++++++------ 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/Assets/Scripts/Managers/GameManager.cs b/Assets/Scripts/Managers/GameManager.cs index f1197ca..9c7df6b 100644 --- a/Assets/Scripts/Managers/GameManager.cs +++ b/Assets/Scripts/Managers/GameManager.cs @@ -288,9 +288,10 @@ public void TogglePause() => SetPause(!IsPaused); public void NewGame() { Debug.Log("[GameManager] NewGame called"); + bool isFreeGame = Settings != null && Settings.GetBool("payment.freeGame"); // Проверка баланса перед началом игры - if (Balance != null && !Balance.CanStartGame()) + if (!isFreeGame && Balance != null && !Balance.CanStartGame()) { Logger?.Log(gameObject.name, "Cannot start game - insufficient balance"); Debug.LogWarning("[GameManager] Cannot start - insufficient balance"); @@ -300,7 +301,7 @@ public void TogglePause() => SetPause(!IsPaused); int livesToGive = StartingLives; int balanceToSpend = 0; - if (Balance != null) + if (!isFreeGame && Balance != null) { int currentBalance = Balance.CurrentBalance; int impulseCost = Settings?.GetInt("payment.paymentImpulseCost") ?? 10; @@ -331,6 +332,10 @@ public void TogglePause() => SetPause(!IsPaused); Debug.Log($"[GameManager] Spent entire balance: {balanceToSpend}, Lives given: {livesToGive}"); } + else if (isFreeGame) + { + Debug.Log("[GameManager] Free game mode enabled. Balance spend skipped."); + } Lives = livesToGive; LivesChanged?.Invoke(Lives); diff --git a/Assets/Scripts/Utilities/CompositeLogger.cs b/Assets/Scripts/Utilities/CompositeLogger.cs index 346cb32..ee93bf4 100644 --- a/Assets/Scripts/Utilities/CompositeLogger.cs +++ b/Assets/Scripts/Utilities/CompositeLogger.cs @@ -14,6 +14,7 @@ namespace RR.Common.Utility private ILogger _oldLogger; private readonly List _additiveLoggers = new(); + private bool _disposed; public void Initialize(ILogger additiveLogger = null) { @@ -329,10 +330,13 @@ namespace RR.Common.Utility private void Dispose(bool disposing) { - if (!disposing) return; + if (_disposed || !disposing) return; lock (_additiveLoggers) { + if (_disposed) + return; + foreach (ILogger additiveLogger in _additiveLoggers.ToArray()) { try @@ -346,12 +350,13 @@ namespace RR.Common.Utility } } _additiveLoggers.Clear(); + _disposed = true; } } ~CompositeLogger() { - Dispose(); + Dispose(false); } } -} \ No newline at end of file +} diff --git a/Assets/Scripts/Utilities/FileLogger.cs b/Assets/Scripts/Utilities/FileLogger.cs index 0d38a2d..9887d81 100644 --- a/Assets/Scripts/Utilities/FileLogger.cs +++ b/Assets/Scripts/Utilities/FileLogger.cs @@ -290,24 +290,45 @@ namespace RR.Common.Utility public void Dispose() { - if (_disposed) + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (!disposing || _disposed) return; lock (_lock) { + if (_disposed) + return; + try { - if (_writer == null) return; - _writer.WriteLine(); - _writer.WriteLine( - "================================================================================"); - _writer.WriteLine($"Сессия логирования завершена: {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); - _writer.WriteLine( - "================================================================================"); - _writer.Flush(); - _writer.Close(); - // _writer.Dispose(); - _writer = null; + if (_writer != null) + { + // Закрывающий блок пишем только если поток ещё доступен. + try + { + _writer.WriteLine(); + _writer.WriteLine("================================================================================"); + _writer.WriteLine($"Сессия логирования завершена: {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); + _writer.WriteLine("================================================================================"); + _writer.Flush(); + } + catch (ObjectDisposedException) + { + // Поток уже закрыт извне — это не ошибка завершения. + } + + _writer.Dispose(); + _writer = null; + } + } + catch (ObjectDisposedException) + { + // Поток уже закрыт — игнорируем. } catch (Exception ex) { @@ -322,7 +343,7 @@ namespace RR.Common.Utility ~FileLogger() { - Dispose(); + Dispose(false); } } -} \ No newline at end of file +}