Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions C7/ComponentManager.cs

This file was deleted.

1 change: 1 addition & 0 deletions C7/Game.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public override void _Ready()
Player = GetNode<KinematicBody2D>("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<GameStatus>("CanvasLayer/GameStatus").RegisterEvents();

// Hide slideout bar on startup
_on_SlideToggle_toggled(false);
Expand Down
9 changes: 7 additions & 2 deletions C7/UIElements/GameStatus/GameStatus.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Godot;
using System;
using C7Engine.Components;
using C7GameData;

public class GameStatus : MarginContainer
Expand All @@ -17,6 +17,11 @@ public override void _Ready()
MarginTop = -(137 + 1);
AddChild(LowerRightInfoBox);
}

public void RegisterEvents()
{
ComponentManager.Instance.GetComponent<CalendarComponent>().TurnStarted += (obj, args) => LowerRightInfoBox.SetTurn(args.Turn.TurnDate);
}

public void OnNewUnitSelected(ParameterWrapper wrappedMapUnit)
{
Expand All @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably can take this method out now, I think... or maybe we should leave it for now since there are other things that will need updated as we add more features?

}

private void OnNoMoreAutoselectableUnits()
Expand Down
4 changes: 2 additions & 2 deletions C7/UIElements/GameStatus/LowerRightInfoBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
43 changes: 43 additions & 0 deletions C7Engine/Components/AutosaveComponent.cs
Original file line number Diff line number Diff line change
@@ -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<CalendarComponent>().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...");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In part that's part of card #223 , in part it would use SaveFormat.Save in the C7GameData project. But I could also see having a component for saving/loading (not just autosaving...), and that's really slightly beyond this proof-of-concept.

(Also slightly beyond, but it occurred to me that this method, or at least the file name creation part of it, would lend itself nicely to some self-documenting units tests)

AutosaveCreated?.Invoke(this, new GameSaveEventArgs(filename));
}
}
}
66 changes: 66 additions & 0 deletions C7Engine/Components/CalendarComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;
using C7GameData;

namespace C7Engine.Components
{
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<TurnEventArgs> TurnStarted;
public GameTurn CurrentTurn { get; private set; }
private GameData _gameData;
//TODO add interace for turn settings

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);
}

private void AdvanceTurn()
{
int nextTurnNumber = CurrentTurn.TurnNumber + 1;
_gameData.turn = nextTurnNumber;
CurrentTurn = GetGameTurn(nextTurnNumber);

Console.WriteLine("Date is now " + CurrentTurn.TurnDate);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably ought to switch these to Serilogs now that we have that in the engine.

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}");
}
}
}
57 changes: 57 additions & 0 deletions C7Engine/Components/ComponentManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;

// modeled after the Unity Toolbox pattern from https://wiki.unity3d.com/index.php/Toolbox
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the Unity 3D Wiki moved, or maybe is down; when I try to go to that site I get wiki.unity3d.com’s server IP address could not be found.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the original tutorial was but this looks somewhat related https://learn.unity.com/project/65de084fedbc2a0699d68bfb

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's the archive of the wiki page: https://web.archive.org/web/20210304075110/https://wiki.unity3d.com/index.php/Toolbox
It's really just the concept of having a dumb Singleton container to hold unique instances of classes instead of making them all Singletons themselves. There may be a more Godot canonical way of achieving that part.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me clarify, the Unity and Godot references are irrelevant here; this is pure C# in the engine layer. Even the Unity implementation was derived from the original source on an IBM blog, now mirrored here: https://gurkantech.blogspot.com/2008/10/use-your-singletons-wisely_02.html
The core idea here is that being a Singleton has messy implications, so you make the Singleton itself as simple as possible and have it keep references to other arbitrary objects that you want to make globally accessible. I've seen similar implementations elsewhere: for example, Android's Context.getSystemService takes a class or name and returns the corresponding "service" object which is an arbitrarily typed resource that is unique to some scope but not a Singleton.

namespace C7Engine.Components
{
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<Type, GameComponent> _components = new Dictionary<Type, GameComponent>();

public ComponentManager AddComponent<T>(T component) where T : GameComponent
{
_components.Add(typeof(T), component);
return this;
}

public T GetComponent<T>() where T : GameComponent
{
GameComponent component;
if (_components.TryGetValue(typeof(T), out component))
{
return (T)component;
}
return default(T);
}

public void InitializeComponents()
{
_components.ToList().ForEach(c => c.Value.Initialize());
}
}

public interface GameComponent
{
public void Initialize();
}
}
10 changes: 10 additions & 0 deletions C7Engine/EntryPoints/CreateGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ namespace C7Engine
{
using System;
using C7GameData;
using C7Engine.Components;

public class CreateGame
{
Expand All @@ -23,11 +24,20 @@ 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<CalendarComponent>(new CalendarComponent(EngineStorage.gameData))
.AddComponent<AutosaveComponent>(new AutosaveComponent(EngineStorage.gameData))
.InitializeComponents();
}
}
}
4 changes: 2 additions & 2 deletions C7Engine/EntryPoints/TurnHandling.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace C7Engine
using System;
public class TurnHandling
{
public static event EventHandler TurnEnded;
internal static void OnBeginTurn()
{
GameData gameData = EngineStorage.gameData;
Expand Down Expand Up @@ -130,8 +131,7 @@ internal static void AdvanceTurn()
}

// END Production phase

gameData.turn++;
TurnEnded?.Invoke(null, null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason the sender argument is null here, but this in the other event invocations?

OnBeginTurn();
}
}
Expand Down