Essentials + extra crap

Loadings
Startups
Movement
Camera
This commit is contained in:
ThomasCharester committed 2026-01-12 18:43:51 +03:00
1 parent 662f4a1d05
commit 5f5ace1b52
734 files changed
+107323 -1713

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 378d32559e654d4b91e761f7f5d4cee6
timeCreated: 1765572320
@@ -0,0 +1,25 @@
using Code.Infrastructure.Camera;
using Reflex.Attributes;
namespace Code.Infrastructure.App
{
public enum AppStates
{
Bootstrap,
Gameplay,
MainMenu
}
public class AppStateMachineContext
{
[Inject] public SceneLoader.SceneLoader SceneLoader { get; set; }
[Inject] public CameraStateMachine Camera { get; set; }
}
[Generators.StateMachine(typeof(AppStateMachineContext),typeof(AppStates))]
public partial class AppStateMachine
{
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5627248405434f028be921cb7916f823
timeCreated: 1765572329
@@ -0,0 +1,69 @@
using Code.Infrastructure.Camera;
using Code.Infrastructure.Configs;
using Code.Infrastructure.Input;
using Code.Infrastructure.Loadings;
using Code.Infrastructure.SceneLoader;
using Reflex.Core;
using UnityEngine;
namespace Code.Infrastructure.App
{
public class PapaInstaller : MonoBehaviour, IInstaller, ISceneConfigsLoadedHandle, IInputServiceInitializedHandle, ICameraInitializedHandle
{
public void InstallBindings(ContainerBuilder containerBuilder)
{
containerBuilder.AddSingleton(typeof(EventBus.EventBus));
containerBuilder.AddSingleton(typeof(ConfigLocator), typeof(IConfigLocator));
containerBuilder.AddSingleton(typeof(SceneLoader.SceneLoader));
containerBuilder.AddSingleton(typeof(InputService),typeof(IInputService));
containerBuilder.OnContainerBuilt += Bootstrap;
containerBuilder.AddSingleton(typeof(AppStateMachine));
containerBuilder.AddSingleton(typeof(AppStateMachineContext));
containerBuilder.AddSingleton(typeof(CameraFactory));
containerBuilder.AddSingleton(typeof(CameraStateMachine));
containerBuilder.AddSingleton(typeof(CameraStateMachineContext));
}
private Loading initialLoading;
private Container _thatRightContainer;
private void Bootstrap(Container container)
{
_thatRightContainer = container;
container.Resolve<EventBus.EventBus>().Subscribe(this);
container.Resolve<SceneLoader.SceneLoader>();
container.Resolve<IInputService>();
container.Resolve<CameraFactory>().CreateCameraStateMachine(container.Resolve<CameraStateMachine>()).Forget();
initialLoading = new Loading(3, () => EssentialLoadEnded(container));
}
private void EssentialLoadEnded(Container container)
{
container.Resolve<AppStateMachine>().SwitchState(AppStates.Bootstrap).AllowStateTransition(AppStates.Gameplay);
container.Resolve<EventBus.EventBus>().Unsubscribe(this);
}
public void SceneConfigsLoaded()
{
initialLoading.DoProgress();
}
public void InputServiceInitialized()
{
initialLoading.DoProgress();
}
public void CameraInitialized(CameraStateMachineContext.CameraLoadedData data)
{
_thatRightContainer.Resolve<CameraStateMachineContext>().cameraLoadedData = data;
_thatRightContainer.Resolve<CameraStateMachine>().SwitchState(CameraMode.None)
.AllowStateTransition(CameraMode.FirstPerson);
initialLoading.DoProgress();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e62d9c9e01334727887a684e008440a6
timeCreated: 1765572590
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 30a683bd88f74628b64f7e17315b0c5d
timeCreated: 1766393607
@@ -0,0 +1,19 @@
using Reflex.Core;
using UnityEngine;
namespace Code.Infrastructure.App.SceneInstallers
{
public class GameplaySceneInstaller : MonoBehaviour, IInstaller
{
public void InstallBindings(ContainerBuilder containerBuilder)
{
containerBuilder.OnContainerBuilt += PostInstall;
}
private void PostInstall(Container container)
{
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ab7d8da1f0cc44bf99ae978a6b75847a
timeCreated: 1768127778
@@ -0,0 +1,20 @@
using Code.Example;
using Reflex.Core;
using UnityEngine;
namespace Code.Infrastructure.App.SceneInstallers
{
public class MainMenuSceneInstaller : MonoBehaviour, IInstaller
{
public void InstallBindings(ContainerBuilder containerBuilder)
{
containerBuilder.OnContainerBuilt += PostInstall;
}
private void PostInstall(Container container)
{
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 067978788f51445ca3af5381eafec386
timeCreated: 1766393632
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 778cb4118a914d9c8b1cac8bef4295a5
timeCreated: 1765572459
@@ -0,0 +1,38 @@
using Code.Infrastructure.Camera;
using Code.Infrastructure.Generators;
using Code.Infrastructure.SceneLoader;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Code.Infrastructure.App.States
{
[State(typeof(AppStates),typeof(AppStateMachineContext))]
[StateRaisingEvent]
public partial class BootstrapState : IOnGameplaySceneLoadedHandler
{
private EventBus.EventBus _eventBus;
public BootstrapState(AppStateMachineContext context, EventBus.EventBus eventBus) : base(context,eventBus)
{
_eventBus = eventBus;
}
public override AppStates myState => AppStates.Bootstrap;
protected override void OnEnterState()
{
_eventBus.Subscribe(this);
Context.Camera.SwitchState(CameraMode.FirstPerson).AllowStateTransition(CameraMode.None);
Context.SceneLoader.LoadSceneAsync(SceneId.Gameplay, LoadSceneMode.Single).Forget();
}
protected override void OnExitState()
{
_eventBus.Unsubscribe(this);
}
public void OnGameplaySceneLoaded()
{
Debug.Log("Spermageddon");
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 71df5370ea2e4819bfbdb9cbb8e6c0ab
timeCreated: 1765572469
@@ -0,0 +1,31 @@
using Code.Infrastructure.Camera;
using Code.Infrastructure.Generators;
using Code.Infrastructure.SceneLoader;
using UnityEngine;
namespace Code.Infrastructure.App.States
{
[State(typeof(AppStates),typeof(AppStateMachineContext))]
[StateRaisingEvent]
public partial class GameplayState : IOnGameplaySceneLoadedHandler
{
public GameplayState(AppStateMachineContext context, EventBus.EventBus eventBus) : base(context, eventBus)
{
}
public override AppStates myState => AppStates.Gameplay;
protected override void OnEnterState()
{
Context.Camera.SwitchState(CameraMode.FirstPerson).AllowStateTransition(CameraMode.None);
}
protected override void OnExitState()
{
}
public void OnGameplaySceneLoaded()
{
Debug.Log("Spermageddon");
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e543193800134f7b858502743ab3a43d
timeCreated: 1766436900
@@ -0,0 +1,22 @@
using Code.Infrastructure.Generators;
namespace Code.Infrastructure.App.States
{
[State(typeof(AppStates),typeof(AppStateMachineContext))]
[StateRaisingEvent]
public partial class MainMenuState
{
public MainMenuState(AppStateMachineContext context, EventBus.EventBus eventBus) : base(context,eventBus)
{
}
public override AppStates myState => AppStates.MainMenu;
protected override void OnEnterState()
{
}
protected override void OnExitState()
{
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5a17221ff27a400e80c42a2ea60bb4ee
timeCreated: 1766436796
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b7c28b6e1fe145b189d52cb829e06521
timeCreated: 1766655751
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Code.Infrastructure.Configs;
using Cysharp.Threading.Tasks;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using Object = UnityEngine.Object;
namespace Code.Infrastructure.Camera
{
public class CameraFactory : IDisposable
{
private AsyncOperationHandle<GameCameraConfig> _configHandle;
private GameCameraConfig _config;
private AssetReference _gameCameraConfigReference;
private AsyncOperationHandle<IList<CameraSettingsConfig>> _settingsConfigsHandle;
private Dictionary<CameraMode, CameraSettingsConfig> _settingsConfigs;
private string _cameraConfigsLabel;
private EventBus.EventBus _eventBus;
private UnityEngine.Camera _camera;
private IDisposable _disposableImplementation;
public CameraFactory(IConfigLocator configLocator, EventBus.EventBus eventBus)
{
_gameCameraConfigReference = configLocator.TryGetConfigAssetReference<GameCameraConfig>();
_cameraConfigsLabel = configLocator.TryGetManyConfigAssetReferences<CameraSettingsConfig>();
_eventBus = eventBus;
}
public async UniTaskVoid CreateCameraStateMachine(CameraStateMachine stateMachine)
{
_settingsConfigsHandle = Addressables
.LoadAssetsAsync<CameraSettingsConfig>(_cameraConfigsLabel, null, Addressables.MergeMode.Union);
await _settingsConfigsHandle.ToUniTask();
_settingsConfigs = _settingsConfigsHandle.Result.ToDictionary(x => x.cameraMode);
_configHandle = Addressables.LoadAssetAsync<GameCameraConfig>(_gameCameraConfigReference);
await _configHandle.ToUniTask();
_config = _configHandle.Result;
var cameraObject = await Addressables.InstantiateAsync(_config.Camera).ToUniTask();
_camera = cameraObject.GetComponent<UnityEngine.Camera>();
cameraObject.GetComponent<CameraStateMachineRunner>().StateMachine = stateMachine;
Object.DontDestroyOnLoad(cameraObject);
_eventBus.RaiseEvent<ICameraInitializedHandle>(x => x.CameraInitialized(new(_camera, _settingsConfigs)));
}
public void Dispose()
{
Addressables.Release(_configHandle);
Addressables.Release(_settingsConfigsHandle);
Addressables.ReleaseInstance(_camera.gameObject);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4c05e01628b742be94dfd0bbbdfb87fa
timeCreated: 1767302222
@@ -0,0 +1,38 @@
using Code.Infrastructure.Generators;
using UnityEngine;
namespace Code.Infrastructure.Camera
{
[Config("Configs/Camera/CameraSettings", true)]
public class CameraSettings
{
// Расстояния от персонажа до камеры
[ToConfig] public float defaultDistance = 6f; // Стандартное расстояние камеры от цели
[ToConfig] public float minDistance = 3f; // Минимальное расстояние при зуме
[ToConfig] public float maxDistance = 10f; // Максимальное расстояние при зуме
[ToConfig] public float distanceMovementSpeed = 5f; // Множитель скорости изменения дистанции при зуме
// Скорость поворота камеры
[ToConfig] public float rotationSpeed = 0.3f;
[ToConfig] public float rotationSharpness = 100f; // Коэффициент плавности вращения камеры (чем выше - тем резче)
[ToConfig] public float followSharpness = 100f; // Коэффициент плавности следования за движущейся целью (чем выше - тем резче)
[ToConfig] public float minVerticalAngle = -70f; // Минимальный угол наклона камеры (вниз)
[ToConfig] public float maxVerticalAngle = 70f; // Максимальный угол наклона камеры (вверх)
[ToConfig] public float defaultVerticalAngle = 10f; // Стандартный угол наклона камеры
[ToConfig] public float fov = 60; // Комментарии оставляет только нейросеть и долбаёбы, никому и так не будет понятно, что ты высрал
[ToConfig] public CameraMode cameraMode;
// Позиция следования по умолчанию
[ToConfig] public Vector3 defaultFollowPosition = Vector3.zero;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5442de773645443b99f8b0733199a854
timeCreated: 1766657458
@@ -0,0 +1,54 @@
using System.Collections.Generic;
using Code.Infrastructure.EventBus;
using Code.Infrastructure.Generators;
using Code.Infrastructure.Input;
using Reflex.Attributes;
using UnityEngine.AddressableAssets;
namespace Code.Infrastructure.Camera
{
public enum CameraMode
{
None,
FirstPerson,
Static,
Cinematic
}
[Config("Configs/Camera/CameraConfig")]
public class GameCamera
{
[ToConfig] public AssetReference Camera;
}
public interface ICameraInitializedHandle : IGlobalSubscriber
{
void CameraInitialized(CameraStateMachineContext.CameraLoadedData data);
}
public class CameraStateMachineContext
{
public class CameraLoadedData
{
public UnityEngine.Camera Camera;
public Dictionary<CameraMode, CameraSettingsConfig> SettingsConfigs;
public CameraLoadedData(UnityEngine.Camera camera, Dictionary<CameraMode, CameraSettingsConfig> settingsConfigs)
{
Camera = camera;
SettingsConfigs = settingsConfigs;
}
}
public CameraLoadedData cameraLoadedData;
[Inject] public IInputService InputService;
[Inject] public EventBus.EventBus EventBus;
}
[Generators.StateMachine(typeof(CameraStateMachineContext), typeof(CameraMode))]
public partial class CameraStateMachine
{
public UnityEngine.Camera Camera => StateMachineContext.cameraLoadedData.Camera;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b220b02510c34ea08257cc951d949fd7
timeCreated: 1761671720
@@ -0,0 +1,20 @@
using Code.Infrastructure.Camera.CameraStates;
using UnityEngine;
namespace Code.Infrastructure.Camera
{
public class CameraStateMachineRunner : MonoBehaviour
{
public CameraStateMachine StateMachine;
private void Update()
{
((BaseCameraState)StateMachine.CurrentBaseState).Update();
}
private void LateUpdate()
{
((BaseCameraState)StateMachine.CurrentBaseState).LateUpdate();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 293de8ebc2f54fa097ba2f1be8c8ed41
timeCreated: 1767277431
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d7399e433dff42a185f62d79b546b059
timeCreated: 1761671908
@@ -0,0 +1,48 @@
using Code.Infrastructure.StateMachine;
using UnityEngine;
namespace Code.Infrastructure.Camera.CameraStates
{
// [State(typeof(CameraMode),typeof(CameraStateMachineContext))]
public abstract class BaseCameraState : BaseState<CameraMode, CameraStateMachineContext>
{
protected EventBus.EventBus _eventBus;
// Трансформ объекта, за которым следует камера
protected Transform FollowTransform;
// Позиция следования: текущая сглаженная позиция и горизонтальное направление камеры
protected Vector3 CurrentFollowPosition;
// Целевой вертикальный угол камеры (наклон вверх/вниз)
protected float TargetVerticalAngle;
// Текущая и целевая дистанция камеры от цели
protected float CurrentDistance, TargetDistance;
// Исходные значения дистанции для восстановления
protected float OriginalDefaultDistance, OriginalMinDistance, OriginalMaxDistance;
// Горизонтальное направление камеры (проекция forward на плоскость)
protected Vector3 PlanarDirection { get; set; }
protected BaseCameraState(CameraStateMachineContext context, EventBus.EventBus eventBus) : base(context, eventBus)
{
_eventBus = eventBus;
}
// Основной метод обновления камеры, вызываемый извне каждый кадр
protected void UpdateWithInput(float deltaTime, Vector3 rotationInput)
{
// Обработка ввода и позиционирования
HandleRotationInput(deltaTime, rotationInput, out var targetRotation);
HandlePosition(deltaTime , targetRotation);
}
protected abstract void HandlePosition(float deltaTime, object o);
protected abstract void HandleRotationInput(float deltaTime, Vector3 rotationInput, out Quaternion q);
public abstract void Update();
public abstract void LateUpdate();
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7901175f2c0646fda8741c4c269ce54b
timeCreated: 1767127681
@@ -0,0 +1,110 @@
using Code.Example.Liminal.Player;
using Code.Infrastructure.Generators;
using Code.Infrastructure.Input;
using UnityEngine;
using UnityEngine.InputSystem;
namespace Code.Infrastructure.Camera.CameraStates
{
[State(typeof(CameraMode),typeof(CameraStateMachineContext), true)]
public partial class FirstPersonCameraState : BaseCameraState
{
private CameraSettingsConfig _settings;
public FirstPersonCameraState(CameraStateMachineContext context, EventBus.EventBus eventBus) : base(context, eventBus)
{
}
public override CameraMode myState => CameraMode.FirstPerson;
protected override void OnEnterState()
{
_settings = Context.cameraLoadedData.SettingsConfigs[myState];
Context.InputService.BindActionPerformed((int)ActionMappings.Gameplay, (int) GameplayActions.Look, OnLookPerformed);
Context.InputService.BindActionCancel((int)ActionMappings.Gameplay, (int) GameplayActions.Look, OnLookCanceled);
}
protected override void HandleRotationInput(float deltaTime, Vector3 rotationInput, out Quaternion targetRotation)
{
// Вращение вокруг вертикальной оси (горизонтальный поворот)
var rotationFromInput = Quaternion.Euler(Vector3.up * (rotationInput.x * _settings.rotationSpeed));
PlanarDirection = rotationFromInput * PlanarDirection;
var planarRotation = Quaternion.LookRotation(PlanarDirection, FollowTransform.up);
// Вращение вокруг горизонтальной оси (вертикальный наклон)
TargetVerticalAngle -= rotationInput.y * _settings.rotationSpeed;
TargetVerticalAngle = Mathf.Clamp(TargetVerticalAngle, _settings.minVerticalAngle, _settings.maxVerticalAngle);
var verticalRotation = Quaternion.Euler(TargetVerticalAngle, 0, 0);
// Интерполяция к целевому вращению для плавности
targetRotation = Quaternion.Slerp(Context.cameraLoadedData.Camera.transform.rotation, planarRotation * verticalRotation, deltaTime * _settings.rotationSharpness);
// Применение финального вращения
Context.cameraLoadedData.Camera.transform.rotation = targetRotation;
}
protected override void OnExitState()
{
}
protected override void HandlePosition(float deltaTime, object targetRotation)
{
// Плавное следование за целью с использованием экспоненциального сглаживания
// CurrentFollowPosition = Vector3.Lerp(CurrentFollowPosition, FollowTransform.position, 1f - Mathf.Exp(-_settings.followSharpness * deltaTime));
// В FirstPerson режиме камера находится прямо на позиции цели Да ну нахуй чё правда пиздец
// var targetPosition = CurrentFollowPosition;
// Установка финальной позиции камеры Да ну нахуй чё правда пиздец
Context.cameraLoadedData.Camera.transform.position = FollowTransform.position;
}
private Vector2 _lookInput;
private void OnLookPerformed(InputAction.CallbackContext context)
{
_lookInput = context.ReadValue<Vector2>();
}
private void OnLookCanceled(InputAction.CallbackContext context)
{
_lookInput = Vector2.zero;
}
public override void Update()
{
}
public override void LateUpdate()
{
// Обновляем камеру только если есть цель для следования
// if (FollowTransform)
// {
// UpdateWithInput(Time.deltaTime, _lookInput);
// }
if (_playerMovementController)
{
UpdateWithInput(Time.deltaTime, _lookInput);
_playerMovementController.SetCameraRotation(Context.cameraLoadedData.Camera.transform.rotation);
}
}
public void SetFollowTransform(Transform t)
{
FollowTransform = t;
CurrentFollowPosition = t.position;
PlanarDirection = t.forward; // Начальное направление совпадает с направлением цели
}
private PlayerMovementController _playerMovementController;
public void SetPlayer(PlayerMovementController playerMovementController)
{
_playerMovementController = playerMovementController;
FollowTransform = _playerMovementController.PlayerHeadPoint;
CurrentFollowPosition = _playerMovementController.PlayerHeadPoint.position;
PlanarDirection = _playerMovementController.PlayerHeadPoint.forward; // Начальное направление совпадает с направлением цели
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 850f6325ab66480e9f7d1c03dbb37030
timeCreated: 1767346203
@@ -0,0 +1,40 @@
using Code.Infrastructure.Generators;
using UnityEngine;
namespace Code.Infrastructure.Camera.CameraStates
{
[State(typeof(CameraMode),typeof(CameraStateMachineContext), true)]
public partial class NoneCameraState : BaseCameraState
{
public NoneCameraState(CameraStateMachineContext context, EventBus.EventBus eventBus) : base(context, eventBus)
{
}
public override CameraMode myState => CameraMode.None;
protected override void OnEnterState()
{
}
protected override void OnExitState()
{
}
protected override void HandlePosition(float deltaTime, object targetRotation)
{
throw new System.NotImplementedException();
}
protected override void HandleRotationInput(float deltaTime, Vector3 rotationInput, out Quaternion q)
{
throw new System.NotImplementedException();
}
public override void Update()
{
}
public override void LateUpdate()
{
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cb14de48ff13488c8edb4431ac34e5be
timeCreated: 1767301090
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ef0499dec5324e12b82f8688c6d3b3d8
timeCreated: 1765711304
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using Code.Infrastructure.SceneLoader;
using Cysharp.Threading.Tasks;
using Reflex.Core;
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace Code.Infrastructure.Configs
{
public partial class ConfigLocator : IConfigLocator
{
private Dictionary<Type, AssetReference> _singleConfigReferences = new();
private Dictionary<Type, string> _multipleConfigReferences = new();
public AssetReference TryGetConfigAssetReference<T>() => _singleConfigReferences.GetValueOrDefault(typeof(T), null);
public string TryGetManyConfigAssetReferences<T>() => _multipleConfigReferences.GetValueOrDefault(typeof(T), null);
partial void LoadConfigs();
public ConfigLocator()
{
LoadSystemConfigs();
LoadConfigs();
}
private void LoadSystemConfigs()
{
SystemConfigsReferences systemConfigsReferences = Resources.Load<SystemConfigsReferences>("SystemConfigsReferences");
_singleConfigReferences.Add(typeof(ScenesAssetReferences), systemConfigsReferences.scenesAssetReferences);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 42496064fd5d42fea1c889f91e6a7e98
timeCreated: 1765711330
@@ -0,0 +1,11 @@
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace Code.Infrastructure.Configs
{
[CreateAssetMenu(fileName = "SystemConfigsReferences", menuName = "Configs/SystemConfigsReferences")]
public partial class SystemConfigsReferences : ScriptableObject
{
public AssetReference scenesAssetReferences;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 728b0ad306a64bd28d47fc4d052c5e81
timeCreated: 1766325607
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7b34014c0c80c914baed6d14ef39dada
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
namespace Code.Infrastructure.EventBus
{
public class EventBus
{
private Dictionary<Type, SubscribersList<IGlobalSubscriber>> s_Subscribers
= new();
public void Subscribe(IGlobalSubscriber subscriber)
{
List<Type> subscriberTypes = EventBusHelper.GetSubscriberTypes(subscriber);
foreach (Type t in subscriberTypes)
{
if (!s_Subscribers.ContainsKey(t))
{
s_Subscribers[t] = new SubscribersList<IGlobalSubscriber>();
}
s_Subscribers[t].Add(subscriber);
}
}
public void Unsubscribe(IGlobalSubscriber subscriber)
{
List<Type> subscriberTypes = EventBusHelper.GetSubscriberTypes(subscriber);
foreach (Type t in subscriberTypes)
{
if (s_Subscribers.ContainsKey(t))
s_Subscribers[t].Remove(subscriber);
}
}
public void RaiseEvent<TSubscriber>(Action<TSubscriber> action)
where TSubscriber : class, IGlobalSubscriber
{
if (!s_Subscribers.ContainsKey(typeof(TSubscriber))) return;
SubscribersList<IGlobalSubscriber> subscribers = s_Subscribers[typeof(TSubscriber)];
subscribers.Executing = true;
InvokeSubscribers(action, subscribers);
subscribers.Executing = false;
subscribers.Cleanup();
}
private void InvokeSubscribers<TSubscriber>(Action<TSubscriber> action, SubscribersList<IGlobalSubscriber> subscribers)
where TSubscriber : class, IGlobalSubscriber
{
for ( int i = 0; i < subscribers.List.Count; i++)
{
Debug.Log("Invoking " + typeof(TSubscriber).Name);
IGlobalSubscriber subscriber = subscribers.List[i];
try
{
action.Invoke(subscriber as TSubscriber);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b0547f2543ccf5e47b9ec486f35aa2df
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Code.Infrastructure.EventBus
{
internal static class EventBusHelper
{
private static Dictionary<Type, List<Type>> s_CashedSubscriberTypes =
new();
public static List<Type> GetSubscriberTypes(
IGlobalSubscriber globalSubscriber)
{
Type type = globalSubscriber.GetType();
if (s_CashedSubscriberTypes.ContainsKey(type))
{
return s_CashedSubscriberTypes[type];
}
List<Type> subscriberTypes = type
.GetInterfaces()
.Where(t => t.GetInterfaces()
.Contains(typeof(IGlobalSubscriber)))
.ToList();
s_CashedSubscriberTypes[type] = subscriberTypes;
return subscriberTypes;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ab2b1bcff76d5614dbda77a3c7b24158
@@ -0,0 +1,5 @@
namespace Code.Infrastructure.EventBus
{
public interface IGlobalSubscriber
{ }
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: fe414b0de24841347b03eec77d1855c0
@@ -0,0 +1,46 @@
using System.Collections.Generic;
namespace Code.Infrastructure.EventBus
{
internal class SubscribersList<TSubscriber> where TSubscriber : class
{
private bool m_NeedsCleanUp;
public bool Executing;
public readonly List<TSubscriber> List = new(); // TODO Weakptr
public void Add(TSubscriber subscriber)
{
List.Add(subscriber);
}
public void Remove(TSubscriber subscriber)
{
if (Executing)
{
var i = List.IndexOf(subscriber);
if (i >= 0)
{
m_NeedsCleanUp = true;
List[i] = null;
}
}
else
{
List.Remove(subscriber);
}
}
public void Cleanup()
{
if (!m_NeedsCleanUp)
{
return;
}
List.RemoveAll(s => s == null);
m_NeedsCleanUp = false;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d364e9c8ac1c255428486d5892d23c1d
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 56928494c304465d8dea6fe4bac75de2
timeCreated: 1765563811
@@ -0,0 +1,49 @@
using System;
namespace Code.Infrastructure.Generators
{
public class StateMachine : Attribute
{
public Type StateMachineContextType;
public Type StateMachineEnumType;
public StateMachine(Type stateMachineContextType, Type stateMachineEnumType)
{
StateMachineContextType = stateMachineContextType;
StateMachineEnumType = stateMachineEnumType;
}
}
public class State : Attribute
{
public Type StateEnum;
public Type StateMachineContext;
public bool SilentBitch; // Поэтому нейминг переменных очень важен
public State(Type stateEnum,Type stateMachineContext, bool silentBitch = false)
{
StateEnum = stateEnum;
StateMachineContext = stateMachineContext;
SilentBitch = silentBitch;
}
}
public class StateRaisingEvent : Attribute
{
}
public class Config : Attribute
{
public bool Multiple;
public string MenuName;
public Config(string menuName, bool multiple = false)
{
Multiple = multiple;
MenuName = menuName;
}
}
public class ToConfig : Attribute
{
}
public class SceneIdEnum : Attribute
{
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 03e07712b53c4a3d8f6c8033af003369
timeCreated: 1765563884
@@ -0,0 +1,109 @@
using System.Linq;
using Unity.VisualScripting;
using UnityCodeGen;
using UnityEditor;
namespace Code.Infrastructure.Generators
{
[Generator]
public class ConfigGenerator : ICodeGenerator
{
public void Execute(GeneratorContext context)
{
var configs = TypeCache.GetTypesWithAttribute<Config>();
var configsCode = "";
var configAddCode = "";
var configReferencesCode = "";
var configReferencesUsingsCode = "";
var configOfConfigsCode = "";
foreach (var cfg in configs)
{
var configFields = "";
var configUsings = "";
var mem = cfg.GetFields();
var members = mem.Where(m => m.HasAttribute<ToConfig>()).ToList();
foreach (var m in members)
{
configUsings += $"using {m.FieldType.Namespace};\n";
configFields += $"public {m.FieldType.FullName} {m.Name};\n";
}
var attribute = cfg.GetAttribute<Config>();
configUsings += @"
using UnityEngine;
using UnityEngine.AddressableAssets;
";
var configCode = $@"
#pragma warning disable CS0105
{configUsings}
namespace {cfg.Namespace}{{
#pragma warning restore CS0105
[CreateAssetMenu(fileName = ""{cfg.Name}Config"", menuName = ""{attribute.MenuName}"")]
public class {cfg.Name}Config : ScriptableObject
{{
{configFields}
}}
}}
";
context.AddCode($"{cfg.Name}Config.Generated.cs", configCode);
configReferencesUsingsCode += $"using {cfg.Namespace};\n";
if (attribute.Multiple)
{
configReferencesCode += $"public string {cfg.Name};\n";
configAddCode += $@"
_multipleConfigReferences.Add(typeof({cfg.FullName}Config), systemConfigsReferences.{cfg.Name});
";
}
else
{
configReferencesCode += $"public AssetReference {cfg.Name};\n";
configAddCode += $@"
_singleConfigReferences.Add(typeof({cfg.FullName}Config), systemConfigsReferences.{cfg.Name});
";
}
}
configsCode += $@"
#pragma warning disable CS0105
{configReferencesUsingsCode}
using UnityEngine;
#pragma warning restore CS0105
namespace Code.Infrastructure.Configs
{{
public partial class ConfigLocator
{{
partial void LoadConfigs()
{{
SystemConfigsReferences systemConfigsReferences = Resources.Load<SystemConfigsReferences>(""SystemConfigsReferences"");
{configAddCode}
//_singleConfigReferences.Add(typeof(ScenesAssetReferences), systemConfigsReferences.scenesAssetReferences);
}}
}}
}}
";
context.AddCode($"ConfigLocator.Generated.cs", configsCode);
configOfConfigsCode += $@"
#pragma warning disable CS0105
{configReferencesUsingsCode}
using UnityEngine.AddressableAssets;
#pragma warning restore CS0105
namespace Code.Infrastructure.Configs{{
public partial class SystemConfigsReferences
{{
{configReferencesCode}
}}
}}
";
context.AddCode($"SystemConfigsReferences.Generated.cs", configOfConfigsCode);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 026403be8eae4546adcb407308031c1d
timeCreated: 1765660396
@@ -0,0 +1,148 @@
using System.Linq;
using Unity.VisualScripting;
using UnityCodeGen;
using UnityEditor;
using UnityEngine;
namespace Code.Infrastructure.Generators
{
[Generator]
public class SceneLoaderGenerator : ICodeGenerator
{
public void Execute(GeneratorContext context)
{
var Enum = TypeCache.GetTypesWithAttribute<SceneIdEnum>();
var loaderCode = "";
var dictionaryCode = "";
var interfacesCode = "";
var interfacesUsingsCode = $@"
using Code.Infrastructure.EventBus;
";
foreach (var en in Enum)
{
if (!en.IsEnum) return;
var members = en.GetFields();
foreach (var member in members)
{
if(member.FieldType.FullName != en.FullName) continue;
interfacesCode += $@"
public interface IOn{member.Name}SceneLoadedHandler : IGlobalSubscriber
{{
void On{member.Name}SceneLoaded();
}}
";
dictionaryCode += $@"
_scenesActions.Add(SceneId.{member.Name},() => _eventBus.RaiseEvent<IOn{member.Name}SceneLoadedHandler>(h=> h.On{member.Name}SceneLoaded()));
";
}
}
loaderCode = $@"
#pragma warning disable CS0105
{interfacesUsingsCode}
#pragma warning restore CS0105
namespace Code.Infrastructure.SceneLoader
{{
public partial class SceneLoader{{
partial void SetupScenesInfo(){{
{dictionaryCode}
}}
}}
{interfacesCode}
}}
";
context.AddCode($"SceneLoader.Generated.cs", loaderCode);
// var configsCode = "";
// var configCode = "";
// var configUsings = "";
// var configFields = "";
// var configAddCode = "";
// var configReferencesCode = "";
// var configReferencesUsingsCode = "";
// var configOfConfigsCode = "";
//
// foreach (var cfg in configs)
// {
// var mem = cfg.GetFields();
// var members = mem.Where(m => m.HasAttribute<ToConfig>()).ToList();
// foreach (var m in members)
// {
// configUsings += $"using {m.FieldType.Namespace};\n";
// configFields += $"public {m.FieldType.FullName} {m.Name};\n";
// }
//
// var attribute = cfg.GetAttribute<Config>();
//
// configUsings += @"
// using UnityEngine;
// using UnityEngine.AddressableAssets;
// ";
// configCode = $@"
// {configUsings}
// namespace {cfg.Namespace}{{
// [CreateAssetMenu(fileName = ""{cfg.Name}Config"", menuName = ""{attribute.MenuName}"")]
// public class {cfg.Name}Config : ScriptableObject
// {{
// {configFields}
// }}
// }}
// ";
// context.AddCode($"{cfg.Name}Config.Generated.cs", configCode);
//
// configReferencesUsingsCode += $"using {cfg.Namespace};\n";
//
// if (attribute.Multiple)
// {
// configReferencesCode += $"public String {cfg.Name};\n";
// configAddCode += $@"
// _multipleConfigReferences.Add(typeof({cfg.FullName}), systemConfigsReferences.{cfg.Name});
// ";
// }
// else
// {
// configReferencesCode += $"public AssetReference {cfg.Name};\n";
// configAddCode += $@"
// _singleConfigReferences.Add(typeof({cfg.FullName}Config), systemConfigsReferences.{cfg.Name});
// ";
// }
// }
// configsCode += $@"
// {configReferencesUsingsCode}
// using UnityEngine;
//
// namespace Code.Infrastructure.Configs
// {{
//
// public partial class ConfigLocator
// {{
// partial void LoadConfigs()
// {{
// SystemConfigsReferences systemConfigsReferences = Resources.Load<SystemConfigsReferences>(""SystemConfigsReferences"");
// {configAddCode}
// //_singleConfigReferences.Add(typeof(ScenesAssetReferences), systemConfigsReferences.scenesAssetReferences);
// }}
// }}
// }}
// ";
// context.AddCode($"ConfigLocator.Generated.cs", configsCode);
//
// configOfConfigsCode += $@"
// {configReferencesUsingsCode}
// using UnityEngine.AddressableAssets;
//
// namespace Code.Infrastructure.Configs{{
// public partial class SystemConfigsReferences
// {{
// {configReferencesCode}
// }}
// }}
// ";
// context.AddCode($"SystemConfigsReferences.Generated.cs", configOfConfigsCode);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 92ec56ffd46d4a569bb9a7d436790439
timeCreated: 1766423754
@@ -0,0 +1,131 @@
using System.Linq;
using Unity.VisualScripting;
using UnityCodeGen;
using UnityEditor;
namespace Code.Infrastructure.Generators
{
[Generator]
public class StateMachineGenerator : ICodeGenerator
{
public void Execute(GeneratorContext context)
{
GenerateStates(context);
GenerateStateMachine(context);
}
private void GenerateStateMachine(GeneratorContext context)
{
var stateMachines = TypeCache.GetTypesWithAttribute<StateMachine>();
foreach (var sm in stateMachines)
{
var attribute = sm.GetAttribute<StateMachine>();
var states = TypeCache.GetTypesWithAttribute<State>()
.Where(st =>
st.GetAttribute<State>().StateMachineContext.FullName ==
attribute.StateMachineContextType.FullName);
var statesCode = "";
var statesNamespacesCode = "";
foreach (var st in states)
{
statesNamespacesCode += $@"
using {st.Namespace};
";
statesCode += $@"
var state{st.Name} = new {st.Name}(StateMachineContext,eventBus);
States.Add(state{st.Name}.myState, state{st.Name});
";
}
var stateMachineCode =
$@"
// <auto-generated/>
#pragma warning disable CS0105
using Code.Infrastructure.StateMachine;
{statesNamespacesCode}
#pragma warning restore CS0105
namespace {sm.Namespace}
{{
public partial class {sm.Name} : AbstractStateMachine<{attribute.StateMachineEnumType.FullName},{attribute.StateMachineContextType.FullName}>
{{
public {sm.Name}({attribute.StateMachineContextType.FullName} context, EventBus.EventBus eventBus) : base(context)
{{
{statesCode}
}}
protected override bool CheckTransitionAllowed({attribute.StateMachineEnumType.FullName} nextState) => AllowedStates.HasFlag(nextState);
protected override void ResetAllowedTransitions() => AllowedStates = 0;
}}
public static class {sm.Name}Extensions
{{
public static AbstractStateMachine<{attribute.StateMachineEnumType.FullName}, {attribute.StateMachineContextType.FullName}> AllowStateTransition(
this AbstractStateMachine<{attribute.StateMachineEnumType.FullName}, {attribute.StateMachineContextType.FullName}> stateMachine, {attribute.StateMachineEnumType.FullName} state)
{{
if (stateMachine == null) return null;
stateMachine.AllowedStates |= state;
return stateMachine;
}}
}}
}}
";
context.AddCode($"{sm.FullName}.Generated.cs", stateMachineCode);
}
}
private void GenerateStates(GeneratorContext context)
{
var states = TypeCache.GetTypesWithAttribute<State>();
var statesCode = "";
foreach (var st in states)
{
var attribute = st.GetAttribute<State>();
var fireStatesCode = "";
if(st.HasAttribute<StateRaisingEvent>()) fireStatesCode = $@"
protected override void _fireEnterState()
{{
EventBus.RaiseEvent<IEnterStateHandle<{st.FullName}>>(h => h.EnterState());
}}
protected override void _fireExitState()
{{
EventBus.RaiseEvent<IExitStateHandle<{st.FullName}>>(h => h.ExitState());
}}
";
var genetics = "";
if(!attribute.SilentBitch) genetics = $@" : BaseState<{attribute.StateEnum.FullName}, {attribute.StateMachineContext.FullName}>";
statesCode = $@"
// retard-generated
using Code.Infrastructure.StateMachine;
namespace {st.Namespace}
{{
public partial class {st.Name} {genetics}
{{
{fireStatesCode}
}}
}}
";
context.AddCode($"{st.FullName}.Generated.cs", statesCode);
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9fb4b6961cd0471d8183511316c15000
timeCreated: 1765563824
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 629db0b5c4ac4624b5bde7022e167b3b
timeCreated: 1766612368
@@ -0,0 +1,26 @@
namespace Code.Infrastructure.Input
{
public enum ActionMappings
{
MainMenu,
Gameplay,
Debug
}
public enum GameplayActions
{
Move,
Crouch,
Look,
Zoom
}
public enum DebugActions
{
Debug1,
Debug2,
Debug3,
Debug4,
Debug5,
Debug6,
Debug7
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: dc62fec94fde411ab1420155a5087d64
timeCreated: 1766613550
@@ -0,0 +1,15 @@
using System;
using UnityEngine.InputSystem;
namespace Code.Infrastructure.Input
{
public interface IInputService
{
void EnableMap(ActionMappings actionMap);
void DisableMap(ActionMappings actionMap);
void BindActionPerformed(int mapId, int actionId, Action<InputAction.CallbackContext> action);
void BindActionCancel(int mapId, int actionId, Action<InputAction.CallbackContext> action);
void UnbindActionPerformed(int mapId, int actionId, Action<InputAction.CallbackContext> action);
void UnbindActionCanceled(int mapId, int actionId, Action<InputAction.CallbackContext> action);
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9443ed0c0d76423f8ecebbd9398bacf3
timeCreated: 1766614201
@@ -0,0 +1,62 @@
using System;
using Code.Infrastructure.Configs;
using Code.Infrastructure.EventBus;
using Code.Infrastructure.Generators;
using Cysharp.Threading.Tasks;
using UnityEngine.AddressableAssets;
using UnityEngine.InputSystem;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace Code.Infrastructure.Input
{
[Config("Configs/InputService")]
public class InputService : IInputService
{
[ToConfig] public InputActionAsset inputActionAsset;
private EventBus.EventBus _eventBus;
public InputService(IConfigLocator configLocator, EventBus.EventBus eventBus)
{
_eventBus = eventBus;
LoadConfigs(configLocator.TryGetConfigAssetReference<InputServiceConfig>()).Forget();
}
private AsyncOperationHandle<InputServiceConfig> _configHandle;
private async UniTaskVoid LoadConfigs(AssetReference configReference)
{
_configHandle = Addressables.LoadAssetAsync<InputServiceConfig>(configReference);
await _configHandle.ToUniTask();
inputActionAsset = _configHandle.Result.inputActionAsset;
inputActionAsset.actionMaps[(int)ActionMappings.Debug].Enable();
inputActionAsset.actionMaps[(int)ActionMappings.Gameplay].Enable();
_eventBus.RaiseEvent<IInputServiceInitializedHandle>(h => h.InputServiceInitialized());
}
public void EnableMap(ActionMappings actionMap) => inputActionAsset.actionMaps[(int)actionMap].Enable();
public void DisableMap(ActionMappings actionMap) => inputActionAsset.actionMaps[(int)actionMap].Disable();
public void BindActionPerformed(int mapId, int actionId, Action<InputAction.CallbackContext> action) => inputActionAsset
.actionMaps[mapId].actions[actionId].performed += action;
public void BindActionCancel(int mapId, int actionId, Action<InputAction.CallbackContext> action) => inputActionAsset
.actionMaps[mapId].actions[actionId].canceled += action;
public void UnbindActionPerformed(int mapId, int actionId, Action<InputAction.CallbackContext> action) =>
inputActionAsset
.actionMaps[mapId].actions[actionId].performed -= action;
public void UnbindActionCanceled(int mapId, int actionId, Action<InputAction.CallbackContext> action) =>
inputActionAsset
.actionMaps[mapId].actions[actionId].canceled -= action;
}
public interface IInputServiceInitializedHandle : IGlobalSubscriber
{
void InputServiceInitialized();
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2755e684d68a4f79994f0f92e8327a73
timeCreated: 1766612399
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d78dfc7c05e54743bfa99dfeaa7dc064
timeCreated: 1766483099
@@ -0,0 +1,29 @@
using System;
namespace Code.Infrastructure.Loadings
{
public class Loading
{
private int _progress;
private Action _completed;
private Action<Loading> _loadProgress;
public Loading(int maxProgress, Action completed, Action<Loading> loadProgress = null)
{
_progress = maxProgress;
MaxProgress = maxProgress;
_completed = completed;
_loadProgress = loadProgress;
}
public int CurrentProgress => _progress;
public int MaxProgress { get; }
public void DoProgress()
{
_progress--;
_loadProgress?.Invoke(this);
if(_progress <= 0) _completed();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a1707a55b78d4218b1557d42adb7d961
timeCreated: 1766483205
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b7568293a2874477b2faeb918157ca94
timeCreated: 1766325345
@@ -0,0 +1,11 @@
using Code.Infrastructure.Generators;
namespace Code.Infrastructure.SceneLoader
{
[SceneIdEnum]
public enum SceneId
{
MainMenu,
Gameplay
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: af1da0e870d542f2a864d7ddbbe9fb4c
timeCreated: 1766396924
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using Code.Infrastructure.Configs;
using Code.Infrastructure.EventBus;
using Code.Infrastructure.Generators;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.SceneManagement;
namespace Code.Infrastructure.SceneLoader
{
[Config("Configs/SceneConfig",true)]
public class SceneInfo
{
[ToConfig] public AssetReference SceneAsset;
[ToConfig] public SceneId SceneId;
}
public partial class SceneLoader : IDisposable
{
private Dictionary<SceneId, SceneInfo> _sceneInfos = new();
private Dictionary<SceneId, Action> _scenesActions = new();
private EventBus.EventBus _eventBus;
partial void SetupScenesInfo();
private AsyncOperationHandle<IList<SceneInfoConfig>> _loadHandle;
public SceneLoader(EventBus.EventBus eventBus, IConfigLocator configLocator)
{
_eventBus = eventBus;
LoadConfigs(configLocator.TryGetManyConfigAssetReferences<SceneInfoConfig>()).Forget();
}
// TODO типилище
public async UniTaskVoid LoadSceneAsync(SceneId id, LoadSceneMode loadMode)
{
await Addressables.LoadSceneAsync(_sceneInfos[id].SceneAsset, loadMode);
_scenesActions[id]();
}
private AsyncOperationHandle<IList<SceneInfoConfig>> _configHandle;
private async UniTaskVoid LoadConfigs(string configReferences)
{
_configHandle = Addressables.LoadAssetsAsync<SceneInfoConfig>(configReferences, OnSceneConfigLoaded, Addressables.MergeMode.Union);
await _configHandle.ToUniTask();
SetupScenesInfo();
_eventBus.RaiseEvent<ISceneConfigsLoadedHandle>(h => h.SceneConfigsLoaded());
}
private void OnSceneConfigLoaded(SceneInfoConfig sceneInfoConfig)
{
SceneInfo sceneInfo = new();
sceneInfo.SceneId = sceneInfoConfig.SceneId;
sceneInfo.SceneAsset = sceneInfoConfig.SceneAsset;
_sceneInfos.Add(sceneInfoConfig.SceneId, sceneInfo);
}
public void Dispose()
{
Addressables.Release(_configHandle);
}
}
public interface ISceneConfigsLoadedHandle : IGlobalSubscriber
{
void SceneConfigsLoaded();
}
public interface ILoadedSceneHandle : IGlobalSubscriber
{
void SceneLoaded(SceneId sceneId);
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 760817ac86164799ac58327509052257
timeCreated: 1766325358
@@ -0,0 +1,11 @@
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace Code.Infrastructure.SceneLoader
{
[CreateAssetMenu(fileName = "ScenesAssetReferences", menuName = "Configs/ScenesAssetReferences")]
public class ScenesAssetReferences : ScriptableObject
{
public AssetReference gameplaySceneReference;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9759979f397044a5bcb03ded0d1c9561
timeCreated: 1766325404
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f1c4dc7e83794f978e68900a1be81bc2
timeCreated: 1765563491
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using Code.Infrastructure.EventBus;
namespace Code.Infrastructure.StateMachine
{
public abstract class AbstractStateMachine<TStateEnum, TStateMachineContext>
where TStateMachineContext : new()
{
protected AbstractStateMachine(TStateMachineContext stateMachineContext )
{
StateMachineContext = stateMachineContext;
}
public TStateEnum CurrentState { get; protected set; }
public BaseState<TStateEnum, TStateMachineContext> CurrentBaseState { get; private set; }
private BaseState<TStateEnum, TStateMachineContext> _previousBaseState;
protected Dictionary<TStateEnum, BaseState<TStateEnum, TStateMachineContext>> States = new();
protected Dictionary<TStateEnum, Type> StatesTypes = new();
public TStateEnum AllowedStates { get; set; }
protected TStateMachineContext StateMachineContext { get; }
// Костыли 2 шт. для флагового енама в шаблонах
protected abstract bool CheckTransitionAllowed(TStateEnum nextState);
protected abstract void ResetAllowedTransitions();
// TODO Если в EnterState вызывается ExitState, то будет гарантированная поломка
public AbstractStateMachine<TStateEnum, TStateMachineContext> SwitchState(TStateEnum nextState)
{
if (!CheckTransitionAllowed(nextState) && CurrentBaseState != null)
{
return null;
}
ResetAllowedTransitions();
_previousBaseState = CurrentBaseState;
CurrentBaseState = States[nextState];
_previousBaseState?.ExitState();
CurrentBaseState.EnterState();
CurrentState = nextState;
return this;
}
}
public interface IEnterStateHandle<TState> : IGlobalSubscriber
{
void EnterState();
}
public interface IExitStateHandle<TState> : IGlobalSubscriber
{
void ExitState();
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8f6ce15c93464753a99851fc5d46440f
timeCreated: 1765563731
@@ -0,0 +1,37 @@
namespace Code.Infrastructure.StateMachine
{
public abstract class BaseState<TEnum, TStateMachineContext>
{
public abstract TEnum myState { get; }
protected BaseState(TStateMachineContext context, EventBus.EventBus eventBus)
{
Context = context;
EventBus = eventBus;
}
protected EventBus.EventBus EventBus;
protected TStateMachineContext Context { get; }
protected virtual void _fireEnterState()
{
}
protected virtual void _fireExitState()
{
}
protected abstract void OnEnterState();
protected abstract void OnExitState();
public void EnterState()
{
OnEnterState();
_fireEnterState();
}
public void ExitState()
{
OnExitState();
_fireExitState();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0c348c251b644c3c941d2bd91bbb290c
timeCreated: 1765563748