move towards auto-import
This commit is contained in:
parent
227d8a11d7
commit
802180a26e
87
Stars Assistant/CSV/PlanetLoader.cs
Normal file
87
Stars Assistant/CSV/PlanetLoader.cs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using CsvHelper.Configuration;
|
||||||
|
using CsvHelper;
|
||||||
|
using System.Globalization;
|
||||||
|
using Splat;
|
||||||
|
|
||||||
|
namespace StarsAssistant.CSV;
|
||||||
|
|
||||||
|
public class PlanetLoader
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reference to the game metadata, retrieved by DI
|
||||||
|
/// </summary>
|
||||||
|
protected Services.Game Game = Locator.Current.GetService<Services.Game>()!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CSV Configuration to use for importing Planet files.
|
||||||
|
/// </summary>
|
||||||
|
protected CsvConfiguration CsvConfig;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Construction
|
||||||
|
/// </summary>
|
||||||
|
public PlanetLoader()
|
||||||
|
{
|
||||||
|
CreateConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the CSV configuration for planets.
|
||||||
|
/// </summary>
|
||||||
|
[MemberNotNull(nameof(CsvConfig))]
|
||||||
|
protected void CreateConfig()
|
||||||
|
{
|
||||||
|
CsvConfig = CsvConfiguration.FromAttributes<Planet>(CultureInfo.InvariantCulture);
|
||||||
|
CsvConfig.Delimiter = "\t";
|
||||||
|
CsvConfig.Escape = '\0';
|
||||||
|
CsvConfig.MissingFieldFound = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Import the planet file for the given Race.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="race">Import File</param>
|
||||||
|
public void ImportForRace(Model.Race race)
|
||||||
|
{
|
||||||
|
using (var db = Locator.Current.GetService<Model.StarsDatabase>()!)
|
||||||
|
using (var reader = new StreamReader(Game.PlanetFileForRace(race), System.Text.Encoding.Latin1))
|
||||||
|
using (var csv = new CsvReader(reader, CsvConfig))
|
||||||
|
{
|
||||||
|
List<CSV.Planet> records = csv.GetRecords<Planet>().ToList();
|
||||||
|
var planetByPlayer = from csvp in records
|
||||||
|
group csvp by csvp.Owner into byOwners
|
||||||
|
select byOwners;
|
||||||
|
|
||||||
|
foreach (var owner in planetByPlayer)
|
||||||
|
{
|
||||||
|
Model.Race? r;
|
||||||
|
if (owner.Key == race.Name)
|
||||||
|
{
|
||||||
|
r = race;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
r = db.Race.Find(owner.Key);
|
||||||
|
if (r == null)
|
||||||
|
{
|
||||||
|
r = new()
|
||||||
|
{
|
||||||
|
Name = owner.Key
|
||||||
|
};
|
||||||
|
db.Add(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Planet csvp in owner)
|
||||||
|
{
|
||||||
|
Model.Planet p = new Model.Planet{ Name = csvp.Name };
|
||||||
|
csvp.UpdateDbPlanet(p);
|
||||||
|
db.Add(p);
|
||||||
|
}
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,4 +35,23 @@ public static class RxExtensions
|
|||||||
return src.Buffer(zeroCrossings);
|
return src.Buffer(zeroCrossings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throttle a FileSystemObserver and eliminate all duplicates.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Curtesy of https://endjin.com/blog/2024/05/observe-file-system-changes-with-rx-dotnet
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="watcher">An observer created with <c>ObserveFileSystem</c></param>
|
||||||
|
/// <param name="inactivitySeconds">Throttling window, defaults to 1 second.</param>
|
||||||
|
/// <param name="scheduler">Scheduler to user for throttling, default is set by <c>Quiescent</c></param>
|
||||||
|
/// <returns>A throttled observer with duplicate elimination.</returns>
|
||||||
|
public static IObservable<IEnumerable<FileSystemEventArgs>> ThrottleAndDistinct (
|
||||||
|
this IObservable<FileSystemEventArgs> watcher,
|
||||||
|
int inactivitySeconds = 1,
|
||||||
|
IScheduler? scheduler = null)
|
||||||
|
{
|
||||||
|
return watcher
|
||||||
|
.Quiescent(TimeSpan.FromSeconds(inactivitySeconds), scheduler)
|
||||||
|
.Select(changes => changes.DistinctBy(x => (x.ChangeType, x.FullPath)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace StarsAssistant.Model;
|
|
||||||
|
|
||||||
public class Game (string gamePath, string baseName)
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The base path in which all game files reside.
|
|
||||||
/// </summary>
|
|
||||||
public string GamePath { get; private set; } = gamePath;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The base name without extensions of your game, inside the GamePath folder.
|
|
||||||
/// All dependant files are resolved using this name.
|
|
||||||
/// </summary>
|
|
||||||
public string BaseName { get; private set; } = baseName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The number of the player, for example identifying the pxx planet file.
|
|
||||||
/// </summary>
|
|
||||||
public int PlayerId { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Combine into the DatabaseName
|
|
||||||
/// </summary>
|
|
||||||
public string DatabaseName => Path.Combine(GamePath, $"{BaseName}.sqlite");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Search for Planet files using this pattern, will give you all pxx files.
|
|
||||||
/// </summary>
|
|
||||||
public string PlanetFileSearchPattern => Path.Combine(GamePath, $"{BaseName}.p*");
|
|
||||||
|
|
||||||
}
|
|
@ -22,6 +22,8 @@ public class Race
|
|||||||
|
|
||||||
public bool PlayerRace { get; set; } = false;
|
public bool PlayerRace { get; set; } = false;
|
||||||
|
|
||||||
|
public int? PlayerFileId { get; set; }
|
||||||
|
|
||||||
public int? ColonistsPerResource { get; set; }
|
public int? ColonistsPerResource { get; set; }
|
||||||
|
|
||||||
public int? GrowthRatePercent { get; set; }
|
public int? GrowthRatePercent { get; set; }
|
||||||
|
@ -37,7 +37,7 @@ public class StarsDatabase(string DbPath) : DbContext
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The record with all game metadata, will only contain a single line at all times.
|
/// The record with all game metadata, will only contain a single line at all times.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DbSet<Game> Game { get; set; }
|
// public DbSet<Game> Game { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
@ -22,10 +22,15 @@ sealed class Program
|
|||||||
{
|
{
|
||||||
ModeDetector.OverrideModeDetector(Splat.ModeDetection.Mode.Run);
|
ModeDetector.OverrideModeDetector(Splat.ModeDetection.Mode.Run);
|
||||||
|
|
||||||
Locator.CurrentMutable.Register(
|
Services.Game g = new()
|
||||||
() => new StarsDatabase("stars.sqlite"),
|
{
|
||||||
typeof(StarsDatabase)
|
BaseName = "GOINGTH",
|
||||||
);
|
GamePath = "/home/torben/goingth/"
|
||||||
|
};
|
||||||
|
|
||||||
|
Locator.CurrentMutable.RegisterConstant(g, typeof(Services.Game));
|
||||||
|
Locator.CurrentMutable.RegisterConstant(new Services.CSVDataLoader(), typeof(Services.CSVDataLoader));
|
||||||
|
Locator.CurrentMutable.Register(() => new StarsDatabase(g.DatabaseFileName), typeof(StarsDatabase));
|
||||||
|
|
||||||
__createTestData();
|
__createTestData();
|
||||||
|
|
||||||
@ -44,6 +49,7 @@ sealed class Program
|
|||||||
|
|
||||||
public static void __createTestData ()
|
public static void __createTestData ()
|
||||||
{
|
{
|
||||||
|
Services.Game game = Locator.Current.GetService<Services.Game>()!;
|
||||||
using var db = Locator.Current.GetService<StarsDatabase>()!;
|
using var db = Locator.Current.GetService<StarsDatabase>()!;
|
||||||
|
|
||||||
db.Database.EnsureDeleted();
|
db.Database.EnsureDeleted();
|
||||||
@ -56,6 +62,7 @@ sealed class Program
|
|||||||
{
|
{
|
||||||
Name = "Atlantis",
|
Name = "Atlantis",
|
||||||
PlayerRace = true,
|
PlayerRace = true,
|
||||||
|
PlayerFileId = 1,
|
||||||
ColonistsPerResource = 1000,
|
ColonistsPerResource = 1000,
|
||||||
GrowthRatePercent = 19,
|
GrowthRatePercent = 19,
|
||||||
PRT = PRT.Other,
|
PRT = PRT.Other,
|
||||||
@ -72,40 +79,8 @@ sealed class Program
|
|||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
Race.Player = r;
|
Race.Player = r;
|
||||||
|
|
||||||
var config = CsvConfiguration.FromAttributes<Planet>(CultureInfo.InvariantCulture);
|
var loader = new CSV.PlanetLoader();
|
||||||
config.Delimiter = "\t";
|
loader.ImportForRace(Race.Player);
|
||||||
config.Escape = '\0';
|
|
||||||
config.MissingFieldFound = null;
|
|
||||||
|
|
||||||
using (var reader = new StreamReader("/home/torben/goingth/GOINGTH.p1", System.Text.Encoding.Latin1))
|
|
||||||
using (var csv = new CsvReader(reader, config))
|
|
||||||
{
|
|
||||||
List<CSV.Planet> records = csv.GetRecords<CSV.Planet>().ToList();
|
|
||||||
var planetByPlayer = from csvp in records
|
|
||||||
group csvp by csvp.Owner into byOwners
|
|
||||||
select byOwners;
|
|
||||||
|
|
||||||
foreach (var owner in planetByPlayer)
|
|
||||||
{
|
|
||||||
if (owner.Key != "Atlantis")
|
|
||||||
{
|
|
||||||
r = new()
|
|
||||||
{
|
|
||||||
Name = owner.Key
|
|
||||||
};
|
|
||||||
db.Add(r);
|
|
||||||
db.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (CSV.Planet csvp in owner)
|
|
||||||
{
|
|
||||||
Planet p = new Planet{ Name = csvp.Name };
|
|
||||||
csvp.UpdateDbPlanet(p);
|
|
||||||
db.Add(p);
|
|
||||||
}
|
|
||||||
db.SaveChanges();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using CsvHelper.Configuration;
|
using System.IO;
|
||||||
using CsvHelper;
|
using System.Reactive.Linq;
|
||||||
using Splat;
|
using Splat;
|
||||||
|
using StarsAssistant.Helpers;
|
||||||
|
|
||||||
namespace StarsAssistant.Services;
|
namespace StarsAssistant.Services;
|
||||||
|
|
||||||
@ -11,10 +12,30 @@ public class CSVDataLoader
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reference to the game metadata, retrieved by DI
|
/// Reference to the game metadata, retrieved by DI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Model.Game game;
|
protected Services.Game Game = Locator.Current.GetService<Services.Game>()!;
|
||||||
|
|
||||||
public CSVDataLoader()
|
public void CSVDataLoader()
|
||||||
{
|
{
|
||||||
game = Locator.Current.GetService<Model.Game>()!;
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartPlanetCSVWatcher()
|
||||||
|
{
|
||||||
|
// TODO: which scheduler for Throttle?
|
||||||
|
var watcher = FsWatcher
|
||||||
|
.ObserveFileSystem(Game.GamePath, new string[] { Game.PlanetFileSearchPattern });
|
||||||
|
.ThrottleAndDistinct(2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
watcher.Subscribe(x =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{DateTime.Now.ToLongTimeString()} got {x.Count()} events:");
|
||||||
|
|
||||||
|
foreach (var fsEvent in x)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{DateTime.Now.ToLongTimeString()} {i++} {fsEvent.FullPath} - {fsEvent.ChangeType}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
33
Stars Assistant/Services/Game.cs
Normal file
33
Stars Assistant/Services/Game.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
namespace StarsAssistant.Services;
|
||||||
|
|
||||||
|
public class Game
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The base path in which all game files reside.
|
||||||
|
/// </summary>
|
||||||
|
public required string GamePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The base name without extensions of your game, inside the GamePath folder.
|
||||||
|
/// All dependant files are resolved using this name.
|
||||||
|
/// </summary>
|
||||||
|
public required string BaseName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Combine into the DatabaseName
|
||||||
|
/// </summary>
|
||||||
|
public string DatabaseFileName => Path.Combine(GamePath, $"{BaseName}.sqlite");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Search for Planet files using this pattern, will give you all pxx files.
|
||||||
|
/// </summary>
|
||||||
|
public string PlanetFileSearchPattern => $"{BaseName}.p*";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the name of a planet file for a given race.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="r">The race to load.</param>
|
||||||
|
/// <returns>Fully qualified file path.</returns>
|
||||||
|
public string PlanetFileForRace (Model.Race r) => Path.Combine(GamePath, $"{BaseName}.p{r.PlayerFileId}");
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user