using System; using System.Collections.Generic; using System.Linq; using BriarQueen.Data.Identifiers; using BriarQueen.Framework.Coordinators.Events; using BriarQueen.Framework.Events.UI; using BriarQueen.Framework.Managers.Hints.Data; using BriarQueen.Framework.Managers.Interaction; using BriarQueen.Framework.Managers.IO; using BriarQueen.Framework.Managers.Player; using BriarQueen.Framework.Managers.Player.Data.Codex; using BriarQueen.Framework.Services.Destruction; using BriarQueen.Framework.Services.Puzzles.Base; using BriarQueen.Framework.Services.Settings; using BriarQueen.Framework.Services.Tutorials; using Cysharp.Threading.Tasks; using NaughtyAttributes; using UnityEngine; using UnityEngine.UI; using VContainer; using SettingsService = BriarQueen.Framework.Services.Settings.SettingsService; #if UNITY_EDITOR using UnityEditor; #endif namespace BriarQueen.Framework.Managers.Levels.Data { public class BaseLevel : MonoBehaviour { [Header("General")] [SerializeField] private LevelKey _levelKey; [SerializeField] private string _levelName; [Header("Items")] [SerializeField] public List Pickups; public List CodexTriggers; [Header("Puzzles")] [SerializeField] public List Puzzles; [Header("Setup")] [SerializeField] protected GraphicRaycaster _raycaster; protected DestructionService DestructionService; protected EventCoordinator EventCoordinator; protected InteractManager InteractManager; protected PlayerManager PlayerManager; protected SaveManager SaveManager; protected SettingsService SettingsService; protected TutorialService TutorialService; public virtual string SceneID => AssetKeyIdentifiers.Get(SceneKey.GameScene); public string LevelID => AssetKeyIdentifiers.Get(_levelKey); public virtual string LevelName => _levelName; public virtual int CurrentLevelHintStage { get; set; } public virtual Dictionary Hints { get; } [Inject] public void Construct(EventCoordinator eventCoordinator, InteractManager interactManager, SaveManager saveManager, DestructionService destructionService, SettingsService settingsService, PlayerManager playerManager, TutorialService tutorialService) { EventCoordinator = eventCoordinator; InteractManager = interactManager; SaveManager = saveManager; DestructionService = destructionService; SettingsService = settingsService; PlayerManager = playerManager; TutorialService = tutorialService; } public async UniTask PostLoad() { InteractManager.AddUIRaycaster(_raycaster); EventCoordinator.Publish(new UIToggleHudEvent(true)); await PostLoadInternal(); } /// /// Called after Level Load, but before activating. Override for Implementations /// /// protected virtual UniTask PostLoadInternal() { return UniTask.CompletedTask; } public async UniTask PostActivate() { await PostActivateInternal(); } /// /// Called after a level is activated. Override for implementations. /// /// protected virtual UniTask PostActivateInternal() { return UniTask.CompletedTask; } public async UniTask PreUnload() { InteractManager.RemoveUIRaycaster(_raycaster); await PreUnloadInternal(); } /// /// Called before the level is destroyed. Override for cleanup, etc. /// /// protected virtual UniTask PreUnloadInternal() { return UniTask.CompletedTask; } #if UNITY_EDITOR [Button("Discover Level References")] private void DiscoverLevelReferences() { Undo.RecordObject(this, "Discover Level References"); var discoveredCodexTriggers = GetComponentsInChildren(true) .Where(trigger => trigger != null) .OrderBy(GetHierarchyPath, StringComparer.Ordinal) .ToList(); var discoveredPickups = GetComponentsInChildren(true) .Where(item => item != null && item is not CodexTrigger) .OrderBy(GetHierarchyPath, StringComparer.Ordinal) .ToList(); var discoveredPuzzles = GetComponentsInChildren(true) .Where(puzzle => puzzle != null) .OrderBy(GetHierarchyPath, StringComparer.Ordinal) .ToList(); Pickups = discoveredPickups; CodexTriggers = discoveredCodexTriggers; Puzzles = discoveredPuzzles; EditorUtility.SetDirty(this); PrefabUtility.RecordPrefabInstancePropertyModifications(this); Debug.Log( $"[BaseLevel] Discovery complete for '{name}'. Pickups: {Pickups.Count}, CodexTriggers: {CodexTriggers.Count}, Puzzles: {Puzzles.Count}", this); } private static string GetHierarchyPath(Component component) { if (component == null) { return string.Empty; } var names = new Stack(); var current = component.transform; while (current != null) { names.Push(current.name); current = current.parent; } return string.Join("/", names); } #endif public void OnValidate() { #if UNITY_EDITOR CanvasScaler scaler = GetComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.matchWidthOrHeight = 0.5f; scaler.referenceResolution = new Vector2(1920, 1200); GraphicRaycaster raycaster = GetComponent(); _raycaster = raycaster; #endif } } }