diff --git a/ChickenGameTest.csproj b/ChickenGameTest.csproj index ecfe2fb..59fe145 100644 --- a/ChickenGameTest.csproj +++ b/ChickenGameTest.csproj @@ -39,7 +39,7 @@ - + @@ -47,21 +47,23 @@ - + - - - + + + - - - + + + - - - - - + + + + + + + @@ -70,9 +72,9 @@ - + - + diff --git a/RTSCamera.cs b/RTSCamera.cs index 3d56e4e..5215b4d 100755 --- a/RTSCamera.cs +++ b/RTSCamera.cs @@ -1,8 +1,20 @@ using Godot; using System; using SJK.Math; +using Chickensoft.SaveFileBuilder; +using Chickensoft.Introspection; +using Chickensoft.Serialization; -public partial class RTSCamera : Node3D + +[Meta, Id("save_data")] +public partial class SaveData +{ + [Save("player_transform")] + public Transform3D Transform3D {get;set;} + [Save("player_camera")] + public Transform3D CameraTransform {get;set;} +} +public partial class RTSCamera : Node3D, ISaveable { [Export] public Camera3D camera; @@ -53,7 +65,7 @@ public partial class RTSCamera : Node3D { CancelUpdateFunc(); } - GD.PrintS(positionStartPos,positionOffsetPos,lastTransalation,LastMouseGroundPlanePositon,LastMousePostition,cameraTargetOffset,scrollAmount); + // GD.PrintS(positionStartPos,positionOffsetPos,lastTransalation,LastMouseGroundPlanePositon,LastMousePostition,cameraTargetOffset,scrollAmount); Update_CurrentFunc(); Update_CameraScroll((float)delta); LastMousePostition = GetViewport().GetMousePosition(); @@ -113,7 +125,7 @@ public partial class RTSCamera : Node3D { cameraTargetOffset += dir * scrollAmount; } - DebugDraw3D.DrawArrow(Vector3.Zero,cameraTargetOffset); + // DebugDraw3D.DrawArrow(Vector3.Zero,cameraTargetOffset); Vector3 lastCameraPosition = camera.Position; camera.Position = camera.Position.Lerp(camera.Position + cameraTargetOffset, delta); cameraTargetOffset -= camera.Position - lastCameraPosition; @@ -153,6 +165,13 @@ public partial class RTSCamera : Node3D ); LastMousePostition = hitpos = GetViewport().GetMousePosition(); } + + public SaveData Save() => new(){Transform3D = Transform, CameraTransform = camera.Transform}; + public void Load(in SaveData data) + { + Transform = data.Transform3D; + camera.Transform = data.CameraTransform; + } } public static partial class SJKMath diff --git a/addons.jsonc b/addons.jsonc index 2925576..0545c5b 100644 --- a/addons.jsonc +++ b/addons.jsonc @@ -20,7 +20,19 @@ "url": "https://github.com/DmitriySalnikov/godot_debug_draw_3d/releases/download/1.7.3/debug-draw-3d_1.7.3.zip/", "source": "zip", // optional — this is the default // "checkout": "master", // optional — this is the default - // "subfolder": "addons/debug_draw_3d" // optional — defaults to "/" + // "subfolder": "" // optional — defaults to "/" }, + "controller_icons": { + "url": "https://github.com/jembawls/controller_icons_csharp/releases/download/v3.1.6/controller_icons_csharp-3.1.6.zip", + "source": "zip", // optional — this is the default + // "checkout": "master", // optional — this is the default + "subfolder": "controller_icons_csharp-3.1.6/addons/controller_icons/" // optional — defaults to "/" + }, + // "editor_theme_explorer": { + // "url": "https://github.com/YuriSizov/godot-editor-theme-explorer/releases/godot-editor-theme-explorer-2.1.1.zip", + // "source": "zip", // optional — this is the default + // // "checkout": "master", // optional — this is the default + // // "subfolder": "controller_icons_csharp-3.1.6/addons/controller_icons/" // optional — defaults to "/" + // }, } } diff --git a/mods/modA/mod.json b/mods/modA/mod.json new file mode 100644 index 0000000..4b849db --- /dev/null +++ b/mods/modA/mod.json @@ -0,0 +1 @@ +"Hello" diff --git a/mods/modB/mod.json b/mods/modB/mod.json new file mode 100644 index 0000000..1cf718a --- /dev/null +++ b/mods/modB/mod.json @@ -0,0 +1 @@ +"World" diff --git a/project.godot b/project.godot index a44370a..daec0ed 100644 --- a/project.godot +++ b/project.godot @@ -19,6 +19,10 @@ run/main_scene="res://src/Main.tscn" config/features=PackedStringArray("4.6", "C#", "Mobile") config/icon="res://icon.png" +[autoload] + +ControllerIcons="*uid://cvqaxgmq6by3f" + [debug_draw_3d] settings/addon_root_folder="res://addons/debug_draw_3d" @@ -41,7 +45,7 @@ naming/scene_name_casing=1 [editor_plugins] -enabled=PackedStringArray("res://addons/imrp/plugin.cfg") +enabled=PackedStringArray("res://addons/controller_icons/plugin.cfg", "res://addons/explore-editor-theme/plugin.cfg", "res://addons/imrp/plugin.cfg") [gui] @@ -54,6 +58,7 @@ theme/default_theme_scale=2.0 move_forward={ "deadzone": 0.2, "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) +, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null) ] } move_back={ diff --git a/src/App/App.cs b/src/App/App.cs new file mode 100644 index 0000000..7b6ada9 --- /dev/null +++ b/src/App/App.cs @@ -0,0 +1,474 @@ +namespace FoodFactory; + +using Godot; +using Chickensoft.AutoInject; +using Chickensoft.Introspection; +using Chickensoft.GodotNodeInterfaces; +using Chickensoft.LogicBlocks.Auto; +using Chickensoft.LogicBlocks; +using System; +using System.Threading.Tasks; +using Chickensoft.UMLGenerator; +using System.Collections.Generic; +using System.Linq; +using FoodFactory.Modding; +using System.IO.Abstractions; +using Chickensoft.Sync.Primitives; +using Chickensoft.SaveFileBuilder; +using System.IO; +using System.Text.Json; +using Chickensoft.Serialization; +using Chickensoft.Collections; +using Chickensoft.Serialization.Godot; +using SJK.Functional; + +// using Shouldly; + +public interface IApp : ICanvasLayer, IProvide, IProvide, IProvide; +[Meta(typeof(IAutoNode))] +[ClassDiagram(UseVSCodePaths = true)] +public partial class App : CanvasLayer, IApp +{ + public const string GAME_PATH = "res://src/Game/Game.tscn"; + public override void _Notification(int what) => this.Notify(what); + + [Node] public ISubViewport GameViewPort { get; private set; } = default!; + [Node] public Menu.IMainMenu MainMenu {get;set;} = default!; + [Node] public ICreateGameMenu CreateGameMenu {get;set;} = default!; + [Node] public ILoadingGameMenu LoadingGameMenu {get;set;} = default!; + [Node] public IOptionsMenu OptionsMenu {get;set;} = default!; + [Node] public IModMenu ModsMenu {get;set;} = default!; + + public IGame Game { get; set; } = default!; + + public IAppRepo AppRepo { get; set; } = default!; + public IOptionConfig OptionConfig { get; set; } = default!; + public IAppLogic AppLogic { get; set; } = default!; + public LogicBlock.Binding AppBinding { get; set; } = default!; + IAppRepo IProvide.Value() => AppRepo; + IOptionConfig IProvide.Value() => OptionConfig; + private AutoChannel.Binding _binding; + private static JsonSerializerOptions _serializerOptions = new JsonSerializerOptions() + { + Converters = { + new SerializableTypeConverter(new Blackboard()) + }, + TypeInfoResolver = new SerializableTypeResolver(), + WriteIndented = true + }; + public ISaveService SaveService { get; set; } = new SaveService(){ + FilePath =Path.Join(OS.GetUserDataDir(), "saves", "game.json.gz"), + CurrentSave = + Chickensoft.SaveFileBuilder.SaveFile.CreateGZipJsonFile( + Path.Join(OS.GetUserDataDir(), "saves", "game.json.gz"), + // Create a standard JsonSerializerOptions with our introspective type + // resolver and the logic blocks converter. + _serializerOptions + ) + }; + private Dictionary> _settingsBind = []; + public void BindSetting<[MustBeVariant] T>(IOptionKey option, Action action) => _settingsBind.Add(option, variant => action(variant.As())); + + public void Initialize() + { + GodotSerialization.Setup(); + var fileSystem =new FileSystem(); + AppRepo = new AppRepo() + { + ModManger = new ModManger() + { + AllMods = new AllMods("/home/ronnie/Documents/Godot/Projects/ChickenGameTest/mods", fileSystem), + Profiles = new ModProfiles() + } + }; + AppRepo.ModManger.Profiles.Add(("base", [.. AppRepo.ModManger.AllMods.GetMods()])); + AppRepo.ModManger.Profiles.Add(("test", [])); + // GD.Print(string.Join(',', AppRepo.ModManger.AllMods.GetMods())); + AppLogic = new AppLogic(); + AppLogic.Set(AppRepo); + + OptionConfig = new TestConfig(); + ((TestConfig)OptionConfig).OnSettingChanged += AppRepo.OnSettingChanged; + BindSetting(OptionConfig.SettingKeys.Video.RenderQuality, value => GameViewPort.Scaling3DScale = value); + BindSetting(OptionConfig.SettingKeys.Video.FullScreen, value => DisplayServer.WindowSetMode(value ? DisplayServer.WindowMode.Fullscreen : DisplayServer.WindowMode.Windowed)); + _binding = AppRepo.AutoChannel.Bind(); + _binding.On((in setting) => + { + GD.Print(setting); + if (_settingsBind.GetValue(setting.Setting).HasValue(out var action)){ + action(setting.Value); + } + return; + if (setting.Setting is OptionKey key && key.Key == "FullScreen") + { + DisplayServer.WindowSetMode(setting.Value.As() ? DisplayServer.WindowMode.Fullscreen : DisplayServer.WindowMode.Windowed ); + } + if (setting.Setting is OptionKey key2 && key2.Key == "RenderQuality") + { + GameViewPort.Scaling3DScale = setting.Value.As() / 100f; + } + }); + _binding.On((in IAppRepo.GameExiting exiting) => + { + AppLogic.Input(new AppLogicState.Input.EndGame(ExitGameReason.QuitToMenu)); + }); + MainMenu.NewGame += OnNewGame; + MainMenu.LastGame += () => + { + var path = fileSystem.File.ReadAllText(Path.Combine(OS.GetUserDataDir(), "lastGame.txt")); + AppLogic.Input(new AppLogicState.Input.LoadGame()); + OnLoadSaveGame(path); + }; + MainMenu.LoadGame += OnLoadGame; + MainMenu.Options += OnOptions; + MainMenu.Exit += () => GetTree().Quit(); + + MainMenu.Mods += OnMods; + + // => + // { + // var vbox = new VBoxContainer(); + // vbox.SetAnchorsPreset(Control.LayoutPreset.Center); + // foreach (var item in AppRepo.ModManger.AllMods.GetMods()) + // { + // var b = new Button(){Text = item.ModName}; + // b.Pressed += () => + // { + // var p = AppRepo.ModManger.Profiles; + // if (p.Current.Contains(item)) + // { + // p.Current.Remove(item); + // } + // else + // { + // p.Current.Add(item); + // } + // b.Text += "a"; + // }; + // vbox.AddChild(b); + // } + // MainMenu.AddChild(vbox); + // }; + OptionsMenu.OnMenuExit += OnMenuExit; + CreateGameMenu.Exit += OnMenuExit; + CreateGameMenu.NewGame += OnNewGame; + CreateGameMenu.LevelSelected += (index) => GD.Print("selected ",index); + + LoadingGameMenu.Exit += OnMenuExit; + LoadingGameMenu.LoadGame += index => OnLoadSaveGame(GetSaves()[index]); + + MainMenu.SetLastGameVisible(fileSystem.File.Exists(Path.Combine(OS.GetUserDataDir(), "lastGame.txt"))); + + this.Provide(); + } + + private void OnLastGame() + { + AppLogic.Input(new AppLogicState.Input.LoadGame()); + + AppLogic.Input(new AppLogicState.Input.LoadSave()); + } + + private void OnMenuExit() => AppLogic.Input(new AppLogicState.Input.ExitMenu()); + private void OnNewGame() => AppLogic.Input(new AppLogicState.Input.NewGame()); + private void OnLoadGame() => AppLogic.Input(new AppLogicState.Input.LoadGame()); + private void OnLoadSaveGame(string path) + { + SaveService.FilePath = path; + SaveService.CurrentSave = Chickensoft.SaveFileBuilder.SaveFile.CreateGZipJsonFile( + path, + _serializerOptions); + // Game.LoadExistingGame(GetSaves()[arg]); + GD.Print("save ", path, " loaded."); + AppLogic.Input(new AppLogicState.Input.LoadSave()); + } + + private void OnOptions() => AppLogic.Input(new AppLogicState.Input.Options()); + private void OnMods() => AppLogic.Input(new AppLogicState.Input.Mods()); + + public void OnReady() + { + AppBinding = AppLogic.Bind(); + AppBinding + .OnOutput((in AppLogicState.Output.ShowMainMenu _) => + { + HideMenus(); + MainMenu.Show(); + //Fade In from black + }) + .OnOutput((in AppLogicState.Output.StartLoadingSaveFile save) => + { + Game.SaveFileLoaded += OnSaveFileLoaded; + Game.LoadGame(); + }) + .OnOutput((in AppLogicState.Output.RemoveExistingGame _) => + { + GameViewPort.RemoveChildEx(Game); + Game.QueueFree(); + Game = default!; + }) + .OnOutput((in AppLogicState.Output.SetUpGameScene _) => + { + Game = GD.Load(GAME_PATH).Instantiate(); + Game.Visible = false; + GameViewPort.AddChildEx(Game); + }) + .OnOutput((in AppLogicState.Output.ShowGameCreationWindow _) => + { + HideMenus(); + CreateGameMenu.Initialize([.. GetLevels()]); + CreateGameMenu.Show(); + }) + .OnOutput((in AppLogicState.Output.ShowGameLoadingWindow _) => + { + HideMenus(); + LoadingGameMenu.Initialize(GetSaves()); + LoadingGameMenu.Show(); + }) + .OnOutput((in AppLogicState.Output.ShowGame _) => + { + HideMenus(); + Game.Show(); + }) + .OnOutput((in AppLogicState.Output.QuitGame _) => + { + GetTree().CallDeferred(SceneTree.MethodName.Quit); + }) + .OnOutput((in AppLogicState.Output.ShowOptionMenu _) => + { + HideMenus(); + OptionsMenu.Show(); + }) + .OnOutput((in AppLogicState.Output.ShowModsMenu _) => + { + HideMenus(); + ModsMenu.Show(); + }) + + ; + AppLogic.Start(); + } + + private IReadOnlyList GetSaves() + { + var fileSystem = new FileSystem(); + var saves = fileSystem.Directory.EnumerateFiles(Path.Join(OS.GetUserDataDir(), "saves")); + return [.. saves]; + + } + + private void OnSaveFileLoaded() + { + Game.SaveFileLoaded -= OnSaveFileLoaded; + AppLogic.Input(new AppLogicState.Input.SaveFileLoaded()); + } + + public void Setup() + { + + } + public void OnExitTree() + { + AppLogic.Stop(); + AppLogic.Dispose(); + AppRepo.Dispose(); + MainMenu.NewGame -= OnNewGame; + MainMenu.LoadGame -= OnLoadGame; + MainMenu.Options -= OnOptions; + MainMenu.Mods -= OnMods; + OptionsMenu.OnMenuExit -= OnMenuExit; + } + + + public void OnResolved() + { + + } + + public void HideMenus() + { + // Splash.Hide(); + MainMenu.Hide(); + CreateGameMenu.Hide(); + LoadingGameMenu.Hide(); + OptionsMenu.Hide(); + ModsMenu.Hide(); + } + + + public IEnumerable GetLevels() + { +yield return new LevelEntry("Level1", "res://assets/kenney_conveyor-kit/Sample.png"); +yield return new LevelEntry("Level2", "res://assets/KayKit_Restaurant_Bits_1.0_FREE/sample.png"); +yield return new LevelEntry("Level3", "res://assets/KayKit_Restaurant_Bits_1.0_FREE/contents.png"); + } + + public ISaveService Value() => SaveService; + + + + + + + + // public override void _Ready()//=> new Test().TestECS(); + // { + // // TestButton = GetNode