From c7134fc542a028d9f63dd526e6e29bd349d99ca3 Mon Sep 17 00:00:00 2001 From: Travis Christian Date: Mon, 13 Jun 2022 17:17:49 -0500 Subject: [PATCH 1/4] Introduce component model with CalendarComponent Move ComponentManager to the C7Engine project and namespace. Implement the CalendarComponent responsible for updating turn number and date. For now it is triggered by an event from TurnHandling and logs the date to console. --- C7/ComponentManager.cs | 46 ---------------------- C7/Game.cs | 7 ++++ C7Engine/CalendarComponent.cs | 59 ++++++++++++++++++++++++++++ C7Engine/ComponentManager.cs | 49 +++++++++++++++++++++++ C7Engine/EntryPoints/TurnHandling.cs | 4 +- 5 files changed, 118 insertions(+), 47 deletions(-) delete mode 100644 C7/ComponentManager.cs create mode 100644 C7Engine/CalendarComponent.cs create mode 100644 C7Engine/ComponentManager.cs diff --git a/C7/ComponentManager.cs b/C7/ComponentManager.cs deleted file mode 100644 index ffb5f2de..00000000 --- a/C7/ComponentManager.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -// modeled after the Unity Toolbox pattern from https://wiki.unity3d.com/index.php/Toolbox -public sealed class ComponentManager -{ - // singleton implemenation taken from example at https://csharpindepth.com/Articles/Singleton - private static readonly ComponentManager _instance = new ComponentManager(); - - static ComponentManager() - { - - } - - private ComponentManager() - { - - } - - public static ComponentManager Instance - { - get { return _instance; } - } - - // type dictionary taken from Jon Skeet's implementation at https://codeblog.jonskeet.uk/2008/10/08/mapping-from-a-type-to-an-instance-of-that-type/ - private Dictionary _components = new Dictionary(); - - public void AddComponent(T component) where T : GameComponent - { - _components.Add(typeof(T), component); - } - - public T GetComponent() where T : GameComponent - { - GameComponent component; - if (_components.TryGetValue(typeof(T), out component)) - { - return (T)component; - } - return default(T); - } -} - -public class GameComponent : Godot.Object -{ - -} \ No newline at end of file diff --git a/C7/Game.cs b/C7/Game.cs index cdf1e19a..b612a243 100644 --- a/C7/Game.cs +++ b/C7/Game.cs @@ -51,6 +51,11 @@ public override void _EnterTree() loadTimer.Start(); } + private void InitializeGameComponents() + { + ComponentManager.Instance.AddComponent(new CalendarComponent()); + } + // Called when the node enters the scene tree for the first time. // The catch should always catch any error, as it's the general catch // that gives an error if we fail to load for some reason. @@ -88,6 +93,8 @@ public override void _Ready() } } + InitializeGameComponents(); + Toolbar = GetNode("CanvasLayer/ToolBar/MarginContainer/HBoxContainer"); Player = GetNode("KinematicBody2D"); //TODO: What was this supposed to do? It throws errors and occasinally causes crashes now, because _OnViewportSizeChanged doesn't exist diff --git a/C7Engine/CalendarComponent.cs b/C7Engine/CalendarComponent.cs new file mode 100644 index 00000000..d1f42ceb --- /dev/null +++ b/C7Engine/CalendarComponent.cs @@ -0,0 +1,59 @@ +using System; + +namespace C7Engine +{ + public class TurnEventArgs : EventArgs + { + public GameTurn Turn { get; } + + public TurnEventArgs(GameTurn turn) + { + Turn = turn; + } + } + + public class GameTurn + { + public int TurnNumber { get; } + public string TurnDate { get; } + + public GameTurn(int num, string date) + { + TurnNumber = num; + TurnDate = date; + } + } + + public class CalendarComponent : GameComponent + { + public event EventHandler TurnStarted; + public GameTurn CurrentTurn { get; private set; } + //TODO add interace for turn settings + + public CalendarComponent() + { + CurrentTurn = GetGameTurn(EngineStorage.gameData.turn); + TurnHandling.TurnEnded += (obj, args) => AdvanceTurn(); + Console.WriteLine("Initialized CalendarComponent at turn " + CurrentTurn.TurnNumber); + } + + private void AdvanceTurn() + { + Console.WriteLine("Ending turn " + CurrentTurn.TurnNumber); + int nextTurnNumber = CurrentTurn.TurnNumber + 1; + CurrentTurn = GetGameTurn(nextTurnNumber); + EngineStorage.gameData.turn = nextTurnNumber; + Console.WriteLine("Date is now " + CurrentTurn.TurnDate); + TurnStarted?.Invoke(this, new TurnEventArgs(CurrentTurn)); + } + + public GameTurn GetGameTurn(int turnNumber) + { + // TODO use some interface to calculate the date + // based on turn settings in the rules + int year = -4000 + (50 * (turnNumber-1)); + string era = year < 0 ? "BC" : "AD"; + return new GameTurn(turnNumber, $"{Math.Abs(year)} {era}"); + } + } +} \ No newline at end of file diff --git a/C7Engine/ComponentManager.cs b/C7Engine/ComponentManager.cs new file mode 100644 index 00000000..af4c0da9 --- /dev/null +++ b/C7Engine/ComponentManager.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +// modeled after the Unity Toolbox pattern from https://wiki.unity3d.com/index.php/Toolbox +namespace C7Engine +{ + public sealed class ComponentManager + { + // singleton implemenation taken from example at https://csharpindepth.com/Articles/Singleton + private static readonly ComponentManager _instance = new ComponentManager(); + + static ComponentManager() + { + + } + + private ComponentManager() + { + + } + + public static ComponentManager Instance + { + get { return _instance; } + } + + // type dictionary taken from Jon Skeet's implementation at https://codeblog.jonskeet.uk/2008/10/08/mapping-from-a-type-to-an-instance-of-that-type/ + private Dictionary _components = new Dictionary(); + + public void AddComponent(T component) where T : GameComponent + { + _components.Add(typeof(T), component); + } + + public T GetComponent() where T : GameComponent + { + GameComponent component; + if (_components.TryGetValue(typeof(T), out component)) + { + return (T)component; + } + return default(T); + } + } + + public class GameComponent + { + + } +} \ No newline at end of file diff --git a/C7Engine/EntryPoints/TurnHandling.cs b/C7Engine/EntryPoints/TurnHandling.cs index a8b8d1f1..8c7ef4b9 100644 --- a/C7Engine/EntryPoints/TurnHandling.cs +++ b/C7Engine/EntryPoints/TurnHandling.cs @@ -6,6 +6,7 @@ namespace C7Engine using System; public class TurnHandling { + public static event EventHandler TurnEnded; internal static void OnBeginTurn() { GameData gameData = EngineStorage.gameData; @@ -131,7 +132,8 @@ internal static void AdvanceTurn() // END Production phase - gameData.turn++; + //gameData.turn++; + TurnEnded?.Invoke(null, null); OnBeginTurn(); } } From ae72b88e4fcbdc2bedd572e44036c8136156b9cc Mon Sep 17 00:00:00 2001 From: Travis Christian Date: Mon, 13 Jun 2022 17:59:01 -0500 Subject: [PATCH 2/4] Connect CalendarComponent to UI for demonstration purposes. Need to refactor game scene and init sequence to better manage data and callbacks. --- C7/Game.cs | 8 +------- C7/UIElements/GameStatus/GameStatus.cs | 9 +++++++-- C7/UIElements/GameStatus/LowerRightInfoBox.cs | 4 ++-- C7Engine/CalendarComponent.cs | 11 +++++++---- C7Engine/EntryPoints/CreateGame.cs | 6 ++++++ C7Engine/EntryPoints/TurnHandling.cs | 2 -- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/C7/Game.cs b/C7/Game.cs index b612a243..ec293bc3 100644 --- a/C7/Game.cs +++ b/C7/Game.cs @@ -51,11 +51,6 @@ public override void _EnterTree() loadTimer.Start(); } - private void InitializeGameComponents() - { - ComponentManager.Instance.AddComponent(new CalendarComponent()); - } - // Called when the node enters the scene tree for the first time. // The catch should always catch any error, as it's the general catch // that gives an error if we fail to load for some reason. @@ -93,12 +88,11 @@ public override void _Ready() } } - InitializeGameComponents(); - Toolbar = GetNode("CanvasLayer/ToolBar/MarginContainer/HBoxContainer"); Player = GetNode("KinematicBody2D"); //TODO: What was this supposed to do? It throws errors and occasinally causes crashes now, because _OnViewportSizeChanged doesn't exist // GetTree().Root.Connect("size_changed", this, "_OnViewportSizeChanged"); + GetNode("CanvasLayer/GameStatus").RegisterEvents(); // Hide slideout bar on startup _on_SlideToggle_toggled(false); diff --git a/C7/UIElements/GameStatus/GameStatus.cs b/C7/UIElements/GameStatus/GameStatus.cs index 4132061f..5b74adb8 100644 --- a/C7/UIElements/GameStatus/GameStatus.cs +++ b/C7/UIElements/GameStatus/GameStatus.cs @@ -1,5 +1,5 @@ using Godot; -using System; +using C7Engine; using C7GameData; public class GameStatus : MarginContainer @@ -17,6 +17,11 @@ public override void _Ready() MarginTop = -(137 + 1); AddChild(LowerRightInfoBox); } + + public void RegisterEvents() + { + ComponentManager.Instance.GetComponent().TurnStarted += (obj, args) => LowerRightInfoBox.SetTurn(args.Turn.TurnDate); + } public void OnNewUnitSelected(ParameterWrapper wrappedMapUnit) { @@ -33,7 +38,7 @@ private void OnTurnEnded() private void OnTurnStarted(int turnNumber) { //Oh hai, we do need this handler here! - LowerRightInfoBox.SetTurn(turnNumber); + //LowerRightInfoBox.SetTurn(turnNumber); } private void OnNoMoreAutoselectableUnits() diff --git a/C7/UIElements/GameStatus/LowerRightInfoBox.cs b/C7/UIElements/GameStatus/LowerRightInfoBox.cs index 1274cfca..e24d0a3b 100644 --- a/C7/UIElements/GameStatus/LowerRightInfoBox.cs +++ b/C7/UIElements/GameStatus/LowerRightInfoBox.cs @@ -155,9 +155,9 @@ public void UpdateUnitInfo(MapUnit NewUnit, TerrainType terrain) ///This is going to evolve a lot over time. Probably this info box will need to keep some local state. ///But for now it'll show the changing turn number, providing some interactivity - public void SetTurn(int turnNumber) + public void SetTurn(string turn) { - yearAndGold.Text = "Turn " + turnNumber + " 10 Gold (+0 per turn)"; + yearAndGold.Text = turn + " 10 Gold (+0 per turn)"; } // // Called every frame. 'delta' is the elapsed time since the previous frame. diff --git a/C7Engine/CalendarComponent.cs b/C7Engine/CalendarComponent.cs index d1f42ceb..dfcbf5e7 100644 --- a/C7Engine/CalendarComponent.cs +++ b/C7Engine/CalendarComponent.cs @@ -1,4 +1,5 @@ using System; +using C7GameData; namespace C7Engine { @@ -28,21 +29,23 @@ public class CalendarComponent : GameComponent { public event EventHandler TurnStarted; public GameTurn CurrentTurn { get; private set; } + private GameData _gameData; //TODO add interace for turn settings - public CalendarComponent() + public CalendarComponent(GameData gameData) { - CurrentTurn = GetGameTurn(EngineStorage.gameData.turn); + _gameData = gameData; + CurrentTurn = GetGameTurn(_gameData.turn); TurnHandling.TurnEnded += (obj, args) => AdvanceTurn(); Console.WriteLine("Initialized CalendarComponent at turn " + CurrentTurn.TurnNumber); } private void AdvanceTurn() { - Console.WriteLine("Ending turn " + CurrentTurn.TurnNumber); int nextTurnNumber = CurrentTurn.TurnNumber + 1; + _gameData.turn = nextTurnNumber; CurrentTurn = GetGameTurn(nextTurnNumber); - EngineStorage.gameData.turn = nextTurnNumber; + Console.WriteLine("Date is now " + CurrentTurn.TurnDate); TurnStarted?.Invoke(this, new TurnEventArgs(CurrentTurn)); } diff --git a/C7Engine/EntryPoints/CreateGame.cs b/C7Engine/EntryPoints/CreateGame.cs index 26bdf89c..d20386aa 100644 --- a/C7Engine/EntryPoints/CreateGame.cs +++ b/C7Engine/EntryPoints/CreateGame.cs @@ -23,11 +23,17 @@ public static Player createGame(string loadFilePath, string defaultBicPath) var humanPlayer = save.GameData.CreateDummyGameData(EngineStorage.rules); EngineStorage.uiControllerID = humanPlayer.guid; + InitializeGameComponents(); TurnHandling.OnBeginTurn(); // Call for the first turn TurnHandling.AdvanceTurn(); EngineStorage.gameDataMutex.ReleaseMutex(); return humanPlayer; } + + private static void InitializeGameComponents() + { + ComponentManager.Instance.AddComponent(new CalendarComponent(EngineStorage.gameData)); + } } } diff --git a/C7Engine/EntryPoints/TurnHandling.cs b/C7Engine/EntryPoints/TurnHandling.cs index 8c7ef4b9..b2c2b94a 100644 --- a/C7Engine/EntryPoints/TurnHandling.cs +++ b/C7Engine/EntryPoints/TurnHandling.cs @@ -131,8 +131,6 @@ internal static void AdvanceTurn() } // END Production phase - - //gameData.turn++; TurnEnded?.Invoke(null, null); OnBeginTurn(); } From 7c68770c51ab162d64fa29833021b0a171dc0e8a Mon Sep 17 00:00:00 2001 From: Travis Christian Date: Wed, 15 Jun 2022 23:50:12 -0500 Subject: [PATCH 3/4] Updating ComponentManager Moved ComponentManager and components into new folder and namespace, gave GameComponent an Initialize method, and allowed chaining ComponentManager method calls --- C7/UIElements/GameStatus/GameStatus.cs | 2 +- C7Engine/{ => Components}/CalendarComponent.cs | 6 +++++- C7Engine/{ => Components}/ComponentManager.cs | 16 ++++++++++++---- C7Engine/EntryPoints/CreateGame.cs | 5 ++++- 4 files changed, 22 insertions(+), 7 deletions(-) rename C7Engine/{ => Components}/CalendarComponent.cs (95%) rename C7Engine/{ => Components}/ComponentManager.cs (77%) diff --git a/C7/UIElements/GameStatus/GameStatus.cs b/C7/UIElements/GameStatus/GameStatus.cs index 5b74adb8..7bdc6013 100644 --- a/C7/UIElements/GameStatus/GameStatus.cs +++ b/C7/UIElements/GameStatus/GameStatus.cs @@ -1,5 +1,5 @@ using Godot; -using C7Engine; +using C7Engine.Components; using C7GameData; public class GameStatus : MarginContainer diff --git a/C7Engine/CalendarComponent.cs b/C7Engine/Components/CalendarComponent.cs similarity index 95% rename from C7Engine/CalendarComponent.cs rename to C7Engine/Components/CalendarComponent.cs index dfcbf5e7..6d5e2212 100644 --- a/C7Engine/CalendarComponent.cs +++ b/C7Engine/Components/CalendarComponent.cs @@ -1,7 +1,7 @@ using System; using C7GameData; -namespace C7Engine +namespace C7Engine.Components { public class TurnEventArgs : EventArgs { @@ -36,6 +36,10 @@ public CalendarComponent(GameData gameData) { _gameData = gameData; CurrentTurn = GetGameTurn(_gameData.turn); + } + + public void Initialize() + { TurnHandling.TurnEnded += (obj, args) => AdvanceTurn(); Console.WriteLine("Initialized CalendarComponent at turn " + CurrentTurn.TurnNumber); } diff --git a/C7Engine/ComponentManager.cs b/C7Engine/Components/ComponentManager.cs similarity index 77% rename from C7Engine/ComponentManager.cs rename to C7Engine/Components/ComponentManager.cs index af4c0da9..a1e0586a 100644 --- a/C7Engine/ComponentManager.cs +++ b/C7Engine/Components/ComponentManager.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Linq; + // modeled after the Unity Toolbox pattern from https://wiki.unity3d.com/index.php/Toolbox -namespace C7Engine +namespace C7Engine.Components { public sealed class ComponentManager { @@ -26,9 +28,10 @@ public static ComponentManager Instance // type dictionary taken from Jon Skeet's implementation at https://codeblog.jonskeet.uk/2008/10/08/mapping-from-a-type-to-an-instance-of-that-type/ private Dictionary _components = new Dictionary(); - public void AddComponent(T component) where T : GameComponent + public ComponentManager AddComponent(T component) where T : GameComponent { _components.Add(typeof(T), component); + return this; } public T GetComponent() where T : GameComponent @@ -40,10 +43,15 @@ public T GetComponent() where T : GameComponent } return default(T); } + + public void InitializeComponents() + { + _components.ToList().ForEach(c => c.Value.Initialize()); + } } - public class GameComponent + public interface GameComponent { - + public void Initialize(); } } \ No newline at end of file diff --git a/C7Engine/EntryPoints/CreateGame.cs b/C7Engine/EntryPoints/CreateGame.cs index d20386aa..41ea6c8c 100644 --- a/C7Engine/EntryPoints/CreateGame.cs +++ b/C7Engine/EntryPoints/CreateGame.cs @@ -2,6 +2,7 @@ namespace C7Engine { using System; using C7GameData; + using C7Engine.Components; public class CreateGame { @@ -33,7 +34,9 @@ public static Player createGame(string loadFilePath, string defaultBicPath) private static void InitializeGameComponents() { - ComponentManager.Instance.AddComponent(new CalendarComponent(EngineStorage.gameData)); + ComponentManager.Instance + .AddComponent(new CalendarComponent(EngineStorage.gameData)) + .InitializeComponents(); } } } From 1df52d353089f696e82715b540e597651dfb543c Mon Sep 17 00:00:00 2001 From: Travis Christian Date: Wed, 15 Jun 2022 23:52:20 -0500 Subject: [PATCH 4/4] Add AutosaveComponent Created a stub implementation for AutosaveComponent, reacting to TurnStarted events by generating an autosave filename --- C7Engine/Components/AutosaveComponent.cs | 43 ++++++++++++++++++++++++ C7Engine/EntryPoints/CreateGame.cs | 1 + 2 files changed, 44 insertions(+) create mode 100644 C7Engine/Components/AutosaveComponent.cs diff --git a/C7Engine/Components/AutosaveComponent.cs b/C7Engine/Components/AutosaveComponent.cs new file mode 100644 index 00000000..3d15ac56 --- /dev/null +++ b/C7Engine/Components/AutosaveComponent.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; +using System.Linq; +using C7GameData; + +namespace C7Engine.Components +{ + public class GameSaveEventArgs : EventArgs + { + public string SaveFilePath { get; } + + public GameSaveEventArgs(string path) + { + SaveFilePath = path; + } + } + + public class AutosaveComponent : GameComponent + { + public event EventHandler AutosaveCreated; + private GameData _gameData; + + public AutosaveComponent(GameData gameData) + { + _gameData = gameData; + } + + public void Initialize() + { + ComponentManager.Instance.GetComponent().TurnStarted += OnTurnStarted; + } + + public void OnTurnStarted(object source, TurnEventArgs args) + { + string date = args.Turn.TurnDate; + date = String.Concat(date.Where(c => !char.IsWhiteSpace(c))); + date = String.Join("_", date.Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries)); + string filename = $"auto_{date}.json"; + Console.WriteLine($"I would save {filename} right now if I knew how..."); + AutosaveCreated?.Invoke(this, new GameSaveEventArgs(filename)); + } + } +} \ No newline at end of file diff --git a/C7Engine/EntryPoints/CreateGame.cs b/C7Engine/EntryPoints/CreateGame.cs index 41ea6c8c..45c2a88a 100644 --- a/C7Engine/EntryPoints/CreateGame.cs +++ b/C7Engine/EntryPoints/CreateGame.cs @@ -36,6 +36,7 @@ private static void InitializeGameComponents() { ComponentManager.Instance .AddComponent(new CalendarComponent(EngineStorage.gameData)) + .AddComponent(new AutosaveComponent(EngineStorage.gameData)) .InitializeComponents(); } }