Нашёл причину утечки памяти

This commit is contained in:
ThomasCharester committed 2026-03-24 15:16:17 +03:00
1 parent 60c28f54f2
commit 320847af5b
229 files changed
+3094 -18282

No files matched your search

@@ -9,7 +9,6 @@ namespace Code.Infrastructure.App
public enum AppStates
{
Bootstrap,
Gameplay,
MainMenu,
Platformer
}
@@ -120,7 +120,6 @@ namespace Code.Infrastructure.App
{
container.Resolve<EventBus.EventBus>().Unsubscribe(this);
container.Resolve<AppStateMachine>().SwitchState(AppStates.Bootstrap)
.AllowStateTransition(AppStates.Gameplay)
.AllowStateTransition(AppStates.Platformer);
container.Resolve<AppStateMachineContext>().StateMachine = container.Resolve<AppStateMachine>();
}
@@ -1,37 +0,0 @@
using Code.Example.Race;
using Code.Example.Race.Racer;
using Code.Example.Race.Track;
using Code.Infrastructure.SceneLoader;
using Reflex.Core;
using Reflex.Enums;
using UnityEngine;
using Resolution = Reflex.Enums.Resolution;
namespace Code.Infrastructure.App.SceneInstallers
{
public class GameplaySceneInstaller : MonoBehaviour, IInstaller
{
[SerializeField] private RaceTrackData raceTrackData;
public void InstallBindings(ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType(typeof(RacerFactory), new[] { typeof(IRacerFactory) }, Lifetime.Scoped,
Resolution.Lazy);
containerBuilder.RegisterType(typeof(RaceScores), Lifetime.Scoped,
Resolution.Eager);
containerBuilder.RegisterValue(raceTrackData);
containerBuilder.RegisterType(typeof(RaceGame), Lifetime.Scoped,
Resolution.Lazy);
containerBuilder.RegisterType(typeof(PlayerPrefsRacePoopshitter), Lifetime.Scoped,
Resolution.Lazy);
containerBuilder.OnContainerBuilt += PostInstall;
}
private void PostInstall(Container container)
{
container.Resolve<EventBus.EventBus>()
.RaiseEvent<IOnGameplaySceneLoadedHandler>(x => x.OnGameplaySceneInitialized(container));
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: ab7d8da1f0cc44bf99ae978a6b75847a
timeCreated: 1768127778
@@ -24,6 +24,11 @@ namespace Code.Infrastructure.App.States
Context.UIService.TryLoadCreatePanel(UIPanelType.DebugSceneChooser);
Context.AudioFactory.LoadAudioClips(AudioNames.UISounds);
Context.AudioService.ChangeGroupVolume(
AudioGroupType.Music,
1f,
0.5f);
}
protected override void OnExitState()
@@ -1,188 +0,0 @@
using System.Linq;
using Code.Example.Race;
using Code.Example.Race.Racer;
using Code.Example.Race.Racer.AI;
using Code.Example.Race.Racer.Player;
using Code.Example.Race.Track;
using Code.Example.Race.UI;
using Code.Infrastructure.Audio;
using Code.Infrastructure.Camera;
using Code.Infrastructure.Camera.CameraStates;
using Code.Infrastructure.Generators;
using Code.Infrastructure.Input;
using Code.Infrastructure.Loadings;
using Code.Infrastructure.SceneLoader;
using Code.Infrastructure.UI;
using Cysharp.Threading.Tasks;
using Reflex.Core;
using Reflex.Injectors;
using Unity.Cinemachine;
using UnityEngine.SceneManagement;
// Ивенты создания панелей сломаны TODO
namespace Code.Infrastructure.App.States
{
[State(typeof(AppStates), typeof(AppStateMachineContext))]
[StateRaisingEvent]
public partial class GameplayState :
IOnGameplaySceneLoadedHandler,
IRaceGameHandle,
IRacerFactoryInitializedHandle,
ICinematicMachineHandle
{
public GameplayState(AppStateMachineContext context, EventBus.EventBus eventBus) : base(context, eventBus)
{
}
public override AppStates myState => AppStates.Gameplay;
private Loading _gameplayLoading;
protected override void OnEnterState()
{
EventBus.Subscribe(this);
Context.UIService.OpenPanel(UIPanelType.Loading);
// Scene
// RaceGame
// Factory
// PlayerCounter
// WinScreen
// ScoreScreen
// CinemachineCamera
_gameplayLoading = new Loading(7, GameplayLoadingCompleted);
Context.UIService.TryLoadCreatePanel(UIPanelType.PlayerScoreCounter);
Context.UIService.TryLoadCreatePanel(UIPanelType.WinScreen);
Context.UIService.TryLoadCreatePanel(UIPanelType.PlayerScores);
Context.SceneLoader.LoadSceneAsync(SceneId.Gameplay, LoadSceneMode.Single).Forget();
Context.InputService.EnableMap(ActionMappings.Race);
Context.CameraFactory.LoadCinemachineCamera(CameraMode.ThirdPerson).Forget();
}
private void GameplayLoadingCompleted()
{
Context.AudioService.CancelMusic(AudioNames.UISounds, 0);
_raceGame.PlaceRacers();
Context.Camera.SwitchState(CameraMode.ThirdPerson).AllowStateTransition(CameraMode.None);
// ((ThirdPersonState)Context.Camera.CurrentBaseState).SetFollowTarget(_raceGame.PlacedRacers[0].gameObject.transform, _raceGame.PlacedRacers[0].CarRigidbody);
Context.CameraFactory.GetCinematicCamera(CameraMode.ThirdPerson).transform.position = ((PlayerRacer)_raceGame.PlacedRacers[0]).CameraPosition.position;
Context.CameraFactory.GetCinematicCamera(CameraMode.ThirdPerson).transform.rotation = ((PlayerRacer)_raceGame.PlacedRacers[0]).CameraPosition.rotation;
Context.CameraFactory.GetCinematicCamera(CameraMode.ThirdPerson).Follow =
_raceGame.PlacedRacers[0].gameObject.transform;
Context.UIService.ClosePanel(UIPanelType.Loading);
_raceGame.StartRacers();
}
protected override void OnExitState()
{
Context.UIService.TryRemovePanel(UIPanelType.PlayerScoreCounter);
Context.UIService.TryRemovePanel(UIPanelType.WinScreen);
Context.UIService.TryRemovePanel(UIPanelType.PlayerScores);
Context.CameraFactory.ReleaseCinemachineCamera(CameraMode.ThirdPerson);
Context.InputService.DisableMap(ActionMappings.Race);
_raceGame = null;
EventBus.Unsubscribe(this);
}
public void OnGameplaySceneLoaded()
{
}
private RaceTrackData _raceTrackData;
private RaceGame _raceGame;
private Container UNTILTHEYFIXCONTAINERS;
public void OnGameplaySceneInitialized(Container container)
{
UNTILTHEYFIXCONTAINERS = container;
_raceTrackData = container.Resolve<RaceTrackData>();
Context.CameraFactory.GetCinematicCamera(CameraMode.None).transform.position = _raceTrackData.CameraPosition.transform.position;
Context.CameraFactory.GetCinematicCamera(CameraMode.None).transform.rotation = _raceTrackData.CameraPosition.transform.rotation;
_gameplayLoading.DoProgress();
container.Resolve<IRacerFactory>();
}
public void RaceGameReady()
{
_gameplayLoading.DoProgress();
}
public void RaceGameEnded(RaceScores scores)
{
var winScreen = (WinScreen)Context.UIService.TryGetSinglePanel(UIPanelType.WinScreen);
var id = 0;
var cachedScores = scores.GetScores();
for (var i = 0; i < cachedScores.Count; i++)
if (cachedScores[i].Key.Data.type == RacerType.Player) id = i + 1;
UNTILTHEYFIXCONTAINERS.Resolve<PlayerPrefsRacePoopshitter>().AddRace(new(_raceGame.RaceTime, id));
var winText = $@"{id} МЕСТО\n";
winScreen.SetText(winText);
var getPanel = Context.UIService.TryGetSinglePanel(UIPanelType.PlayerScores);
((PlayerScores)getPanel)
.SetText(UNTILTHEYFIXCONTAINERS.Resolve<PlayerPrefsRacePoopshitter>().GetRaces());
Context.UIService.ClosePanel(UIPanelType.PlayerScoreCounter);
Context.UIService.OpenPanel(UIPanelType.WinScreen);
EndTheGame().Forget();
}
private async UniTaskVoid EndTheGame()
{
await UniTask.WaitForSeconds(3f);
Context.UIService.ClosePanel(UIPanelType.WinScreen);
Context.UIService.OpenPanel(UIPanelType.PlayerScores);
await UniTask.WaitForSeconds(5f);
Context.UIService.OpenPanel(UIPanelType.Loading);
Context.StateMachine.SwitchState(AppStates.MainMenu).AllowStateTransition(AppStates.Gameplay);
}
public void RacerFactoryInitialized()
{
_raceGame = UNTILTHEYFIXCONTAINERS.Resolve<RaceGame>();
_gameplayLoading.DoProgress();
}
public void UILoaded(UIPanelType uiPanelType)
{
if(uiPanelType is UIPanelType.WinScreen or UIPanelType.PlayerScores)
{
_gameplayLoading.DoProgress();
return;
}
if (uiPanelType != UIPanelType.PlayerScoreCounter) return;
Context.UIService.OpenPanel(UIPanelType.PlayerScoreCounter);
_gameplayLoading.DoProgress();
}
public void CinemachineLoaded(CinemachineCamera cinemachineCamera) => _gameplayLoading.DoProgress();
public void UISinglePanelLoaded(UIPanelType uiPanelType)
{
}
public void UISinglePanelRemoved(UIPanelType uiPanelType)
{
throw new System.NotImplementedException();
}
}
}
@@ -1,3 +0,0 @@
fileFormatVersion: 2
guid: e543193800134f7b858502743ab3a43d
timeCreated: 1766436900
@@ -30,13 +30,24 @@ namespace Code.Infrastructure.App.States
// Context.AudioFactory.LoadAudioClips(AudioNames.UISounds);
Context.SceneLoader.LoadSceneAsync(SceneId.MainMenu, LoadSceneMode.Single).Forget();
Context.AudioService.PlayRepeatedly(AudioNames.UISounds,0, AudioGroupType.Music);
Context.AudioService.ChangeGroupVolume(
AudioGroupType.Music,
1f,
0.5f);
}
protected override void OnExitState()
{
// Context.AudioFactory.ReleaseAudios(AudioNames.UISounds);
Context.UIService.TryRemovePanel(UIPanelType.DebugSceneChooser);
Context.AudioService.CancelMusic(AudioNames.UISounds,0);
Context.AudioService.ChangeGroupVolume(
AudioGroupType.Music,
0,
0.5f,
() => Context.AudioService.CancelMusic(AudioNames.UISounds,0));
EventBus.Unsubscribe(this);
}
@@ -73,10 +73,15 @@ namespace Code.Infrastructure.Audio
public void ReleaseAudios(AudioNames groupName)
{
UnityEngine.Debug.LogWarning($"Audios unloaded {groupName}");
_eventBus.RaiseEvent<IAudioClipsEventHandle>(x=> x.AudioClipsUnLoaded(groupName));
if (_clipsHandles[groupName].Count == 0) return;
foreach (var handle in _clipsHandles)
foreach (var handle in _clipsHandles[groupName])
Addressables.Release(handle.Value);
_clipsHandles[groupName].Clear();
_eventBus.RaiseEvent<IAudioClipsEventHandle>(x=> x.AudioClipsUnLoaded(groupName));
}
public void Dispose()
{
@@ -87,7 +92,8 @@ namespace Code.Infrastructure.Audio
handle.Value.Release();
}
}
_clipsHandles.Clear();
_configsHandle.Release();
}
}
@@ -88,10 +88,24 @@ namespace Code.Infrastructure.Audio
_pool.ReleaseSource(audioSource);
}
private Dictionary<KeyValuePair<AudioNames, int>, CancellationTokenSource> _cancellationTokenSources = new();
public void CancelMusic(AudioNames groupName, int id) => _cancellationTokenSources[new KeyValuePair<AudioNames, int>(groupName, id)].Cancel();
public void ReleaseCancellationSource(AudioNames groupName, int id) => _cancellationTokenSources[new KeyValuePair<AudioNames, int>(groupName, id)] = null;
private Dictionary<AudioNameIdPair, CancellationTokenSource> _cancellationTokenSources = new();
public void CancelMusic(AudioNames groupName, int id)
{
var key = new AudioNameIdPair(groupName, id);
if (!_cancellationTokenSources.ContainsKey(key)) return;
_cancellationTokenSources[key].Cancel();
_cancellationTokenSources.Remove(key);
}
public void ReleaseCancellationSource(AudioNames groupName, int id)
{
// _cancellationTokenSources[new KeyValuePair<AudioNames, int>(groupName, id)] = null; никаких полумер
_cancellationTokenSources.Remove(new AudioNameIdPair(groupName, id));
}
public async UniTaskVoid PlayRepeatedly(AudioNames groupName, int id, AudioGroupType audioGroupType,
AudioSourceType sourceType = AudioSourceType.NoBlend, AudioSource audioSource = null, CancellationTokenSource cancellationTokenSource = null)
{
@@ -100,7 +114,7 @@ namespace Code.Infrastructure.Audio
if(cancellationTokenSource == null)
{
cancellationTokenSource = new CancellationTokenSource();
_cancellationTokenSources[new KeyValuePair<AudioNames, int>(groupName, id)] = cancellationTokenSource;
_cancellationTokenSources[new AudioNameIdPair(groupName, id)] = cancellationTokenSource;
}
if (!audioSource) audioSource = _pool.GetSource(sourceType);
@@ -108,11 +122,10 @@ namespace Code.Infrastructure.Audio
audioSource.outputAudioMixerGroup = _audioMixerGroups[audioGroupType];
audioSource.Play();
await UniTask.NextFrame();
// await UniTask.WaitUntil(audioSource, _ => audioSource.isPlaying);
var (isCanceled, _) = await UniTask.WaitUntilValueChanged(audioSource,
_ => !audioSource.isPlaying,
cancellationToken: cancellationTokenSource.Token).SuppressCancellationThrow();
UnityEngine.Debug.LogError("Music skipping");
if (isCanceled)
{
@@ -129,6 +142,7 @@ namespace Code.Infrastructure.Audio
}
public AudioClip GetClip(AudioNames groupName, int id) => _audioClips[groupName][id];
public bool CheckClip(AudioNames groupName, int id) => _audioClips[groupName].ContainsKey(id);
public void AudioClipsLoaded(AudioNames groupname, Dictionary<int, AudioClip> clips)
@@ -150,10 +164,37 @@ namespace Code.Infrastructure.Audio
_mixer.SetFloat(effectName, newValue);
}).OnComplete(callback);
}
public void ChangeGroupVolume(AudioGroupType groupType, float value, float time, Action callback = null)
{
ApplyParameter(_audioMixerGroups[groupType].name, Mathf.Log10(value == 0f ? 0.001f : value) * 20, time, callback);
}
private struct AudioNameIdPair : IEquatable<AudioNameIdPair>
{
public AudioNames AudioNames;
public int ID;
public AudioNameIdPair(AudioNames audioNames, int id)
{
AudioNames = audioNames;
ID = id;
}
public bool Equals(AudioNameIdPair other)
{
return AudioNames == other.AudioNames && ID == other.ID;
}
public override bool Equals(object obj)
{
return obj is AudioNameIdPair other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine((int)AudioNames, ID);
}
}
}
public interface IReadyToPlayHandle : IGlobalSubscriber
@@ -6,8 +6,6 @@ namespace Code.Infrastructure.Camera.CameraStates
// [State(typeof(CameraMode),typeof(CameraStateMachineContext))]
public abstract class BaseCameraState : BaseState<CameraMode, CameraStateMachineContext>
{
protected EventBus.EventBus EventBus;
protected BaseCameraState(CameraStateMachineContext context, EventBus.EventBus eventBus) : base(context, eventBus)
{
EventBus = eventBus;
@@ -55,7 +55,7 @@ namespace Code.Infrastructure.EventBus
{
IGlobalSubscriber subscriber = subscribers.List[i];
try
{
{
action.Invoke(subscriber as TSubscriber);
}
catch (Exception e)
@@ -47,15 +47,14 @@ namespace Code.Infrastructure.Generators
if(st.HasAttribute(typeof(UIEventOpenClose)))
{
fireStatesCode += $@"
protected override void FireOpenedEvent()
private void FireOpenedEvent()
{{
_eventBus.RaiseEvent<I{st.Name}OpenedHandle>(h => h.{st.Name}Opened(this));
}}
protected override void FireClosedEvent()
private void FireClosedEvent()
{{
_eventBus.RaiseEvent<I{st.Name}ClosedHandle>(h => h.{st.Name}Closed());
base.FireClosedEvent();
}}
";
fireStatesInterfacesCode += $@"
@@ -5,9 +5,7 @@ namespace Code.Infrastructure.SceneLoader
[SceneIdEnum]
public enum SceneId
{
MainMenu,
Gameplay,
SoundTest,
MainMenu,
Platformer,
Platformer2,
Platformer3
@@ -17,7 +17,7 @@ namespace Code.Infrastructure.UI.Panels
Tween.Color(image,shownColor, 1f).OnComplete(FireOpenedEvent);
}
public override void Close()
public override void Close(Action callback = null)
{
Tween.Color(image,hiddenColor, 1f).OnComplete(FireClosedEvent);
}
@@ -1,11 +1,10 @@
using Code.Infrastructure.Generators;
using System;
using PrimeTween;
using UnityEngine;
using UnityEngine.UI;
namespace Code.Infrastructure.UI.Panels
{
[UIEventOpenClose]
public partial class LogoPanel : UIPanel
{
[SerializeField] private Image image;
@@ -13,12 +12,12 @@ namespace Code.Infrastructure.UI.Panels
[SerializeField] private Color hiddenColor;
public override void Open()
{
Tween.Color(image,shownColor, 1f).OnComplete(FireOpenedEvent);
Tween.Color(image,shownColor, 1f);
}
public override void Close()
public override void Close(Action callback = null)
{
Tween.Color(image,hiddenColor, 1f).OnComplete(FireClosedEvent);
Tween.Color(image,hiddenColor, 1f).OnComplete(callback);
}
}
}
@@ -1,12 +1,10 @@
using Code.Debug;
using Code.Infrastructure.Audio;
using Code.Infrastructure.Generators;
using Code.Infrastructure.Audio;
using Reflex.Attributes;
using UnityEngine;
namespace Code.Infrastructure.UI.Panels
{
[UIEventOpenClose]
public partial class MenuChoosePanel : UIPanel
{
[Inject] IAudioService _audioService;
@@ -17,12 +15,6 @@ namespace Code.Infrastructure.UI.Panels
public override void Open()
{
sceneChooser.EnableButtons();
FireOpenedEvent();
}
public override void Close()
{
FireClosedEvent();
}
}
}
+2 -5
View File
@@ -1,3 +1,4 @@
using System;
using Reflex.Attributes;
using UnityEngine;
@@ -11,16 +12,12 @@ namespace Code.Infrastructure.UI
public bool InjectMeSenpai => injectMeSenpai;
[Inject] protected EventBus.EventBus _eventBus;
public abstract void Open();
public abstract void Close();
public virtual void Close(Action callback = null) => callback?.Invoke();
// Вызвать вручную \ добавить в коллбек для вызова ивента в EventBus
public virtual void FireCreatedEvent(){}
// Вызвать вручную \ добавить в коллбек для вызова ивента в EventBus
public virtual void FireRemovedEvent(){}
// Вызвать вручную \ добавить в коллбек для вызова ивента в EventBus
protected virtual void FireOpenedEvent(){}
// Вызвать вручную \ добавить в коллбек для вызова ивента в EventBus
protected virtual void FireClosedEvent(){gameObject.SetActive(false);}
}
}
+26 -24
View File
@@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Code.Infrastructure.EventBus;
using Reflex.Core;
using Reflex.Extensions;
using Reflex.Injectors;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Code.Infrastructure.UI
{
@@ -22,7 +18,7 @@ namespace Code.Infrastructure.UI
}
// Крайне неудобно пользоваться
public class UIService : IUIPanelLoadedHandle, IUIService
public class UIService : IUIPanelLoadedHandle, IUIService, IDisposable
{
private Dictionary<UIPanelType, UIPanel> _loadedSinglePanels = new();
private Dictionary<UIPanelType, List<UIPanel>> _loadedMultiplePanels = new();
@@ -49,10 +45,9 @@ namespace Code.Infrastructure.UI
_loadedSinglePanels[uiPanelType].Open();
}
// TODO Close event
public void ClosePanel(UIPanelType uiPanelType)
{
_loadedSinglePanels[uiPanelType].Close();
_loadedSinglePanels[uiPanelType].Close(() => _loadedSinglePanels[uiPanelType].gameObject.SetActive(false));
}
public void TryLoadCreatePanel(UIPanelType uiPanelType, Transform parent = null) => _factory.LoadPanel(uiPanelType, parent);
@@ -79,20 +74,31 @@ namespace Code.Infrastructure.UI
panel.FireCreatedEvent();
}
// Для единичных
public void TryRemovePanel(UIPanelType uiPanelType)
{
if (_factory.CheckIsMultiple(uiPanelType))
{
UnityEngine.Debug.LogError("Это для единичных панелей олух");
return;
}
_loadedSinglePanels[uiPanelType].Close();
if (_factory.CheckIsMultiple(uiPanelType)) return;
_loadedSinglePanels[uiPanelType].Close(() => RemovePanel(uiPanelType));
}
// Для многочисленных
public void TryRemovePanel(UIPanel panel)
{
panel.Close();
panel.Close(() => RemovePanel(panel));
}
private void RemovePanel(UIPanel panel)
{
if (!_factory.CheckIsMultiple(panel.PanelType)) return;
_loadedMultiplePanels[panel.PanelType].Remove(panel);
panel.FireRemovedEvent();
_factory.ReleasePanel(panel);
if(_loadedMultiplePanels[panel.PanelType].Count == 0) _loadedMultiplePanels.Remove(panel.PanelType);
}
// Для всех
private void RemovePanel(UIPanelType panelType)
{
if (!_factory.CheckIsMultiple(panelType))
@@ -117,17 +123,13 @@ namespace Code.Infrastructure.UI
}
}
private void RemovePanel(UIPanel panel)
{
_loadedMultiplePanels[panel.PanelType].Remove(panel);
panel.FireRemovedEvent();
_factory.ReleasePanel(panel);
if(_loadedMultiplePanels[panel.PanelType].Count == 0) _loadedMultiplePanels.Remove(panel.PanelType);
}
public UIPanel TryGetSinglePanel(UIPanelType panelType) => _loadedSinglePanels.GetValueOrDefault(panelType);
public List<UIPanel> TryGetMultiplePanels(UIPanelType panelType) => _loadedMultiplePanels.GetValueOrDefault(panelType);
public void Dispose()
{
// TODO Релизнуть всё
_eventBus.Unsubscribe(this);
}
}
}