using Chickensoft.AutoInject; using Chickensoft.GodotNodeInterfaces; using Chickensoft.Introspection; using Godot; using NathanHoad; using SimpleInjector.Lifestyles; using System.IO.Abstractions; using System.Threading.Tasks; using Zennysoft.Game.Abstractions; using Zennysoft.Game.Implementation; using Zennysoft.Ma.Adapter; namespace Zennysoft.Game.Ma; public interface IApp : INode, IProvide; [Meta(typeof(IAutoNode))] public partial class App : Node, IApp { public override void _Notification(int what) => this.Notify(what); public const string GAME_SCENE_PATH = "res://src/game/Game.tscn"; public const string ENEMY_VIEWER_PATH = "res://src/data_viewer/DataViewer.tscn"; [Node] private MainMenu MainMenu { get; set; } = default!; [Node] private LoadingScreen LoadingScreen { get; set; } = default!; [Node] private OptionsMenu OptionsMenu { get; set; } [Node] private GalleryMenu GalleryMenu { get; set; } IAppRepo IProvide.Value() => AppRepo; public IAppRepo AppRepo { get; set; } = default!; public IAppLogic AppLogic { get; set; } = default!; public AppLogic.IBinding AppBinding { get; set; } = default!; private Godot.Collections.Array _progress; private SimpleInjector.Container _container; private DataViewer _dataViewer; private bool _loadingGame = false; private bool _loadingEnemyViewer = false; private string _optionsSavePath = string.Empty; private string _controllerSavePath = string.Empty; private ISaveFileManager _saveFileManager; private IGame _game; private IDataViewer _enemyViewer; private double _reportedProgress = 0; public void Initialize() { _container = new SimpleInjector.Container(); _container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle(); _container.RegisterSingleton(); _container.RegisterSingleton(); _container.RegisterSingleton(); _container.RegisterSingleton(); _saveFileManager = _container.GetInstance(); _optionsSavePath = $"{OS.GetUserDataDir()}/options.json"; _controllerSavePath = $"{OS.GetUserDataDir()}/controls.json"; MainMenu.StartGame += OnStartGame; MainMenu.EnemyViewer += OnEnemyViewer; MainMenu.Gallery += OnGallery; MainMenu.Options += OnOptions; MainMenu.Quit += OnQuit; GalleryMenu.GalleryExited += GalleryExited; OptionsMenu.OptionsMenuExited += OptionsMenu_OptionsMenuExited; OptionsMenu.DeleteSaveData += DeleteSaveData; AppRepo = _container.GetInstance(); AppLogic = _container.GetInstance(); Task.Run(() => _saveFileManager.ReadFromFile(_controllerSavePath).ContinueWith((data) => { if (data.IsCompletedSuccessfully) OptionsMenu.Controller.CallDeferred(nameof(OptionsMenu.Controller.LoadControllerInput), data.Result); })); AppLogic.Set(AppRepo); AppLogic.Set(new AppLogic.Data()); AppRepo.DataViewerExited += DataViewerExited; Input.MouseMode = Input.MouseModeEnum.Visible; _progress = []; this.Provide(); } private void GameExitRequested() { AppLogic.Input(new AppLogic.Input.QuitGame()); } private void DeleteSaveData() { var saveFileManager = _container.GetInstance(); saveFileManager.DeleteSaveData(); } private void DataViewerExited() { AppLogic.Input(new AppLogic.Input.EnemyViewerExited()); } private async void OptionsMenu_OptionsMenuExited() { var saveFileManager = _container.GetInstance(); await saveFileManager.WriteToFile(OptionsMenu.OptionsData, _optionsSavePath); var controllerOutput = InputHelper.SerializeInputsForActions(); await saveFileManager.WriteToFile(controllerOutput, _controllerSavePath); OptionsMenu.Hide(); MainMenu.OptionsButton.GrabFocus(); } private void GalleryExited() { GalleryMenu.Hide(); MainMenu.GalleryButton.GrabFocus(); } public void OnReady() { AppBinding = AppLogic.Bind(); AppBinding .Handle((in AppLogic.Output.Initialize _) => { Task.Run(() => _saveFileManager.ReadFromFile(_optionsSavePath).ContinueWith((data) => { AppLogic.Input(new AppLogic.Input.SaveFileLoaded()); })); }) .Handle((in AppLogic.Output.ShowSplashScreen _) => { AppLogic.Input(new AppLogic.Input.FadeOutFinished()); }) .Handle((in AppLogic.Output.HideSplashScreen _) => { }) .Handle((in AppLogic.Output.SetupGameScene _) => { LoadingScreen.Show(); LoadGame(GAME_SCENE_PATH); }) .Handle((in AppLogic.Output.ShowMainMenu _) => { MainMenu.CallDeferred(MainMenu.MethodName.FadeIn); }) .Handle((in AppLogic.Output.CloseGame _) => { LoadingScreen.Hide(); _game.GameExitRequested -= GameExitRequested; MainMenu.StartGameButton.GrabFocus(); _game.CallDeferred(MethodName.QueueFree, []); GetTree().Paused = false; }) .Handle((in AppLogic.Output.StartLoadingSaveFile _) => { }) .Handle((in AppLogic.Output.EnemyViewerOpened _) => { LoadingScreen.Show(); MainMenu.Hide(); LoadEnemyViewer(ENEMY_VIEWER_PATH); }) .Handle((in AppLogic.Output.EnemyViewerExited _) => { LoadingScreen.Hide(); if (_enemyViewer != null && _enemyViewer is DataViewer enemyViewer) enemyViewer.CallDeferred(MethodName.QueueFree); MainMenu.Show(); MainMenu.EnemyViewerButton.GrabFocus(); }) .Handle((in AppLogic.Output.ExitGame _) => { GetTree().Quit(); }); AppLogic.Start(); } public override void _Process(double delta) { LoadingScreen.ProgressBar.Value = Mathf.RoundToInt(Mathf.Lerp(LoadingScreen.ProgressBar.Value, _reportedProgress * 100, (float)delta * 2)); } public void OnStartGame() => AppLogic.Input(new AppLogic.Input.NewGame()); private void OnEnemyViewer() => AppLogic.Input(new AppLogic.Input.EnemyViewerOpened()); private void OnGalleryViewer() => AppLogic.Input(new AppLogic.Input.GalleryOpened()); private async void LoadGame(string sceneName) { var scene = await LoadSceneInternal(sceneName); _game = scene as IGame; _game.GameLoaded += OnGameLoaded; _game.GameExitRequested += GameExitRequested; await ToSignal(GetTree().CreateTimer(0.8f), "timeout"); CallDeferred(MethodName.AddChild, scene); } private void OnGameLoaded() => LoadingScreen.Hide(); private async void LoadEnemyViewer(string sceneName) { var scene = await LoadSceneInternal(sceneName); _enemyViewer = scene as IDataViewer; await ToSignal(GetTree().CreateTimer(0.8f), "timeout"); CallDeferred(MethodName.AddChild, scene); LoadingScreen.Hide(); } private async Task LoadSceneInternal(string sceneName) { LoadingScreen.Show(); LoadingScreen.ProgressBar.Value = 0; var sceneLoader = new SceneLoader(); CallDeferred(MethodName.AddChild, sceneLoader); sceneLoader.LoadSceneRequest(sceneName); sceneLoader.SceneReportedProgress += SceneLoader_SceneReportedProgress; await ToSignal(sceneLoader, SceneLoader.SignalName.SceneLoaded); var result = sceneLoader.LoadedScene; sceneLoader.QueueFree(); return result; } private void SceneLoader_SceneReportedProgress(double progress) => _reportedProgress = progress; private async void OnOptions() { OptionsMenu.Show(); OptionsMenu.GameTab.GrabFocus(); } private async void OnGallery() { GalleryMenu.Show(); GalleryMenu.ItemButton1.GrabFocus(); } public void OnQuit() => AppLogic.Input(new AppLogic.Input.QuitGame()); public void OnSaveFileLoaded() { AppLogic.Input(new AppLogic.Input.SaveFileLoaded()); } public void OnExitTree() { AppLogic.Stop(); AppBinding.Dispose(); AppRepo.Dispose(); MainMenu.StartGame -= OnStartGame; MainMenu.EnemyViewer -= OnEnemyViewer; MainMenu.Gallery -= OnGallery; MainMenu.Options -= OnOptions; MainMenu.Quit -= OnQuit; GalleryMenu.GalleryExited -= GalleryExited; OptionsMenu.OptionsMenuExited -= OptionsMenu_OptionsMenuExited; OptionsMenu.DeleteSaveData -= DeleteSaveData; } }