-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
389 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using DataInterfaceConsole.Types.Exceptions; | ||
using FiveDChessDataInterface; | ||
using System; | ||
using System.Linq; | ||
using System.Threading; | ||
|
||
namespace DataInterfaceConsole.Actions | ||
{ | ||
internal abstract class BaseAction | ||
{ | ||
public abstract string Name { get; } | ||
protected DataInterface di; | ||
|
||
public static BaseAction[] GetAndInstantiateAllActions() => typeof(BaseAction).Assembly.GetTypes() | ||
.Where(x => typeof(BaseAction).IsAssignableFrom(x) && typeof(BaseAction) != x) | ||
.Select(t => (BaseAction)Activator.CreateInstance(t)) | ||
.ToArray(); | ||
|
||
public void Run(DataInterface di) | ||
{ | ||
this.di = di ?? throw new ArgumentNullException(nameof(di)); | ||
Run(); | ||
} | ||
|
||
protected abstract void Run(); | ||
|
||
/// <summary> | ||
/// Raises an exception which terminates the currently executing <see cref="BaseAction"/>, if the datainterface has become invalid, likely due to a game crash. | ||
/// </summary> | ||
protected void AbortIfDiInvalid() | ||
{ | ||
if (!this.di.IsValid()) | ||
throw new DataInterfaceClosedException("The DataInterface instance is not, or no longer, valid."); | ||
} | ||
|
||
protected string ConsoleReadLineWhileDiValid() => Util.ConsoleReadLineWhileDiValid(this.di); | ||
|
||
protected void WaitForIngame() | ||
{ | ||
bool shown = false; | ||
while (!this.di.IsGameRunning()) | ||
{ | ||
if (!shown) | ||
{ | ||
Console.WriteLine("Waiting for a match to be started."); | ||
shown = true; | ||
} | ||
AbortIfDiInvalid(); | ||
Thread.Sleep(150); | ||
} | ||
Console.WriteLine("A match has started. Continuing..."); | ||
} | ||
|
||
protected void WriteLineIndented(string s, int level = 1) | ||
{ | ||
Console.WriteLine($"{new string(' ', level * 2)}{s}"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
using FiveDChessDataInterface.Variants; | ||
using System; | ||
|
||
namespace DataInterfaceConsole.Actions | ||
{ | ||
class LoadPredefinedVariant : BaseAction | ||
{ | ||
public override string Name => "Load Predefined Variant"; | ||
|
||
protected override void Run() | ||
{ | ||
WaitForIngame(); | ||
var variants = GithubVariantGetter.GetAllVariants(); | ||
|
||
WriteLineIndented("Select a variant from the following:"); | ||
for (int i = 0; i < variants.Length; i++) | ||
{ | ||
WriteLineIndented($"{(i + 1).ToString().PadLeft((int)Math.Ceiling(Math.Log10(variants.Length)))}. {variants[i].Name} by {variants[i].Author}"); | ||
} | ||
|
||
if (int.TryParse(Util.ConsoleReadLineWhile(() => this.di.IsValid()), out int input) && input > 0 && input <= variants.Length) | ||
{ | ||
var chosenVariant = variants[input - 1]; | ||
WriteLineIndented($"Loading variant '{chosenVariant.Name}'..."); | ||
var gb = chosenVariant.GetGameBuilder(); | ||
this.di.SetChessBoardArrayFromBuilder(gb); | ||
WriteLineIndented($"Variant loaded and written to memory."); | ||
} | ||
else | ||
{ | ||
WriteLineIndented("Invalid input. Not loading any variant."); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>netcoreapp3.1</TargetFramework> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\FiveDChessDataInterface\FiveDChessDataInterface.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
using DataInterfaceConsole.Actions; | ||
using DataInterfaceConsole.Types; | ||
using DataInterfaceConsole.Types.Exceptions; | ||
using FiveDChessDataInterface; | ||
using System; | ||
using System.Globalization; | ||
using System.Linq; | ||
using System.Threading; | ||
|
||
namespace DataInterfaceConsole | ||
{ | ||
class Program | ||
{ | ||
internal static Program instance = new Program(); | ||
private Thread backgroundThread; | ||
private DataInterface di; | ||
|
||
static void Main() | ||
{ | ||
ConsoleNonBlocking.Init(); | ||
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US"); | ||
instance.Run(); | ||
} | ||
|
||
private void Run() | ||
{ | ||
Console.WriteLine("Some output will occasionally be provided via the console title."); | ||
|
||
this.backgroundThread = new Thread(BackgroundThreadRun) | ||
{ | ||
Name = "BackgroundThread" | ||
}; | ||
this.backgroundThread.Start(); | ||
|
||
var actions = BaseAction.GetAndInstantiateAllActions().Select((x, i) => (i, x)).ToDictionary(a => a.i + 1, a => a.x); | ||
var idWidth = (int)Math.Log10(actions.Count) + 1; | ||
|
||
Thread.Sleep(200); | ||
while (true) | ||
{ | ||
if (this.di?.IsValid() != true) | ||
Console.WriteLine("Please launch the game..."); | ||
|
||
SpinWait.SpinUntil(() => this.di?.IsValid() == true); // wait till the datainterface instance is valid | ||
Console.WriteLine($"Select an action from the following (by typing the number to the left and pressing enter):\n" + | ||
$"{string.Join("\n", actions.Select(a => $"[{a.Key.ToString().PadLeft(idWidth)}] {a.Value.Name}"))}"); | ||
try | ||
{ | ||
while (true) | ||
{ | ||
var choice = Util.ConsoleReadLineThrowIfDiInvalid(this.di); | ||
if (int.TryParse(choice, out int res) && res > 0 && res <= actions.Count) | ||
{ | ||
var a = actions[res]; | ||
var header = $"====== Executing action: {a.Name} ======"; | ||
Console.WriteLine(header); | ||
try | ||
{ | ||
a.Run(this.di); | ||
|
||
Console.WriteLine($"Action executed. Returning to menu...\n{new string('=', header.Length)}"); | ||
Thread.Sleep(1000); | ||
} | ||
catch (DataInterfaceClosedException ex) | ||
{ | ||
Util.WriteColored($"Execution of the current action '{a.Name}' was aborted because the game closed or crashed: \n{ex}\n" + | ||
$"To continue, please press ENTER.", ConsoleColor.Red); | ||
ConsoleNonBlocking.ClearInputLines(); | ||
} | ||
break; | ||
} | ||
else | ||
{ | ||
Console.WriteLine("Invalid number entered. Please try again."); | ||
} | ||
} | ||
} | ||
catch (DataInterfaceClosedException ex) | ||
{ | ||
Util.WriteColored($"Execution of the current action selection was aborted because the game closed or crashed: \n{ex}\nTo continue, please press ENTER.", ConsoleColor.Red); | ||
ConsoleNonBlocking.ClearInputLines(); | ||
} | ||
} | ||
} | ||
|
||
private void BackgroundThreadRun() | ||
{ | ||
while (true) | ||
{ | ||
bool tooManyProcesses = false; | ||
if (this.di?.IsValid() != true) | ||
{ | ||
if (!DataInterface.TryCreateAutomatically(out this.di, out int procCnt)) | ||
{ | ||
if (procCnt > 1) | ||
{ | ||
tooManyProcesses = true; | ||
} | ||
} | ||
else | ||
{ | ||
this.di.Initialize(); | ||
} | ||
} | ||
|
||
if (tooManyProcesses) | ||
{ | ||
SetConsoleTitleWithPrefix($"Too many game instances found!"); | ||
} | ||
else | ||
{ | ||
var isValid = this.di?.IsValid(); | ||
string gameStatus = isValid switch | ||
{ | ||
true => $"Running - ProcessId: {this.di.GameProcess.Id}", | ||
false => "closed", | ||
null => "Not found" | ||
}; | ||
|
||
SetConsoleTitleWithPrefix($"GameProcess: {gameStatus}"); | ||
} | ||
|
||
Thread.Sleep(500); | ||
} | ||
} | ||
|
||
private void SetConsoleTitleWithPrefix(string s) | ||
{ | ||
Console.Title = $"5D Data Interface Console - {s}"; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.IO; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace DataInterfaceConsole.Types | ||
{ | ||
internal static class ConsoleNonBlocking | ||
{ | ||
private static readonly ConcurrentQueue<string> readLines = new ConcurrentQueue<string>(); | ||
|
||
internal static void Init() | ||
{ | ||
Task.Run(ReadLines); | ||
} | ||
|
||
private static async Task ReadLines() | ||
{ | ||
while (true) | ||
{ | ||
var s = new StreamReader(Console.OpenStandardInput(), Console.InputEncoding); | ||
var l = await s.ReadLineAsync(); | ||
readLines.Enqueue(l); | ||
} | ||
} | ||
|
||
public static int Count => readLines.Count; | ||
public static bool TryPeek(out string val) => readLines.TryPeek(out val); | ||
public static bool TryDequeue(out string val) => readLines.TryDequeue(out val); | ||
|
||
public static string ReadLineBlocking() | ||
{ | ||
string s = null; | ||
SpinWait.SpinUntil(() => TryDequeue(out s)); | ||
return s; | ||
} | ||
|
||
public static void ClearInputLines() => readLines.Clear(); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
DataInterfaceConsole/Types/Exceptions/DataInterfaceClosedException.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System; | ||
using System.Threading; | ||
|
||
namespace DataInterfaceConsole.Types.Exceptions | ||
{ | ||
|
||
[Serializable] | ||
public class DataInterfaceClosedException : Exception | ||
{ | ||
public DataInterfaceClosedException() { } | ||
public DataInterfaceClosedException(string message) : base(message) { } | ||
public DataInterfaceClosedException(string message, Exception inner) : base(message, inner) { } | ||
protected DataInterfaceClosedException( | ||
System.Runtime.Serialization.SerializationInfo info, | ||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using DataInterfaceConsole.Types; | ||
using DataInterfaceConsole.Types.Exceptions; | ||
using FiveDChessDataInterface; | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace DataInterfaceConsole | ||
{ | ||
static class Util | ||
{ | ||
public static string ConsoleReadLineWhile(Func<bool> doRead) | ||
{ | ||
while (doRead.Invoke()) | ||
{ | ||
if (ConsoleNonBlocking.TryDequeue(out string res)) | ||
return res; | ||
Thread.Sleep(150); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
public static string ConsoleReadLineWhileDiValid(DataInterface di) => ConsoleReadLineWhile(() => di?.IsValid() == true); | ||
|
||
/// <summary> | ||
/// Reads a line from the console, blocking. Aborts if the specified <see cref="DataInterface"/> instance becomes invalid. | ||
/// </summary> | ||
/// <param name="di">The <see cref="DataInterface"/> instance to monitor.</param> | ||
/// <returns>The string that was read from the console input.</returns> | ||
/// <exception cref="DataInterfaceClosedException">if the datainterface instance becomes invalid while reading.</exception> | ||
public static string ConsoleReadLineThrowIfDiInvalid(DataInterface di) | ||
{ | ||
var res = ConsoleReadLineWhileDiValid(di); | ||
if (res == null) | ||
throw new DataInterfaceClosedException("Reading the console was interrupted because the datainterface instance became invalid!"); | ||
|
||
return res; | ||
} | ||
|
||
private static readonly object cwlock = new object(); | ||
public static void WriteColored(string s, ConsoleColor c) | ||
{ | ||
lock (cwlock) | ||
{ | ||
var oldc = Console.ForegroundColor; | ||
Console.ForegroundColor = c; | ||
Console.WriteLine(s); | ||
Console.ForegroundColor = oldc; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.