sa/Stars Assistant/Services/FleetManager.cs

184 lines
5.9 KiB
C#

using System;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Reactive;
using System.Reactive.Linq;
using System.Text.RegularExpressions;
using Avalonia.Controls.Platform;
using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using Splat;
using StarsAssistant.Model;
using StarsAssistant.ViewModels;
namespace StarsAssistant.Services;
public class FleetManager : IEnableLogger, IDisposable
{
protected Services.Game Game = Locator.Current.GetService<Services.Game>()!;
/// <summary>
/// SourceList for fleets read from the game files
/// </summary>
private SourceList<Fleet> _fleets = new();
/// <summary>
/// Fleet data summarized by destination, will be chaned to _fleets
/// </summary>
private SourceCache<FleetSummary, string> _fleetSummaries = new(fs => fs.Destination);
/// <summary>
/// Public accessor to the continously updated fleet summaries.
/// </summary>
public IObservableCache<FleetSummary, string> FleetSummaries => _fleetSummaries.AsObservableCache();
/// <summary>
/// Disposal tracking
/// </summary>
private IDisposable _fleetSummariesSubscription;
public FleetManager()
{
CreateFleetSummariesLink();
}
[MemberNotNull(nameof(_fleetSummariesSubscription))]
protected void CreateFleetSummariesLink()
{
_fleetSummariesSubscription = _fleets.Connect()
.Filter(fleet => fleet.TrueDestination != "-- ")
.GroupOn(fleet => fleet.TrueDestination)
.Log(this, $"{DateTime.Now.ToLongTimeString()} fleetWatcher", grp => $"{grp.TotalChanges} detected")
.Transform(group => new FleetSummary
{
Destination = group.GroupKey,
TotalIronium = group.List.Items.Sum(f => f.Ironium),
TotalBoranium = group.List.Items.Sum(f => f.Boranium),
TotalGermanium = group.List.Items.Sum(f => f.Germanium),
TotalColonists = group.List.Items.Sum(f => f.Colonists)
})
.AddKey(fs => fs.Destination)
.Log(this, "FleetManager _fleetSummaries update", changes =>
$"{changes.Adds} adds, {changes.Updates} updates, {changes.Removes} removes"
)
.PopulateInto(_fleetSummaries)
;
/*
// Demo only
var sourceCache = new SourceCache<FleetSummary, string>(fs => fs.Destination);
var tmp = fleetSummaries
.AddKey(fs => fs.Destination)
.PopulateInto(sourceCache);
_fleetSummaries
.ObserveOn(RxApp.MainThreadScheduler)
.Bind(out summaries)
.DisposeMany()
.Subscribe();
d1 = summaries
.Subscribe(Observer.Create<FleetSummary>(f =>
{
this.Log().Debug($"FleetSummary observed: {f}");
}
));
d2 = _fleetSummaries
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(x =>
{
var lst = x.ToList();
foreach (var f in lst)
{
this.Log().Debug($"Reason {f.Reason}, Type {f.Type}: {f.Item.Current}");
}
}
);
*/
}
/// <summary>
/// Load the fleet records from the database and push them into our source cache.
/// If the data has been freshly imported, call PostProcessImportedData first.
/// </summary>
public void InitFromDatabase()
{
using var db = Locator.Current.GetService<StarsDatabase>()!;
var allFleets = db.Fleet.ToList();
_fleets.Edit(innerCache =>
{
innerCache.Clear();
innerCache.Add(allFleets);
}
);
}
/// <summary>
/// Helper to fill up missing data from the original import. Tries to deduce
/// missing properties using heuristics.
/// </summary>
public static void PostProcessImportedData()
{
using var db = Locator.Current.GetService<StarsDatabase>()!;
// Check for all cases where we're targeting another fleet instead of
// a planet. Update the DB accordingly.
var playerFleets = from flt in db.Fleet
where flt.OwnerFileId == Game.Player.PlayerFileId
select flt;
Regex shipPattern = new ($@"^{Regex.Escape(Game.Player.Name)} (?<ShipType>.+) #\d+$");
foreach (Fleet flt in playerFleets)
{
if (flt.Destination != "-- ")
{
var trueDest = db.Fleet
.FirstOrDefault(f => f.FleetName == $"{Game.Player.Name} {flt.Destination}"
&& f.Planet != String.Empty);
flt.TrueDestination = trueDest?.Planet ?? flt.Destination;
}
else
{
flt.TrueDestination = flt.Planet;
}
Match m = shipPattern.Match(flt.FleetName);
if (m.Success)
flt.ShipTypeGuess = m.Groups[1].Value;
flt.Colonists *= 100;
db.Update(flt);
}
db.SaveChanges();
}
/// <summary>
/// Handle disposal of all subscriptions and dependencies.
/// </summary>/
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_fleetSummariesSubscription.Dispose();
_fleetSummaries.Dispose();
_fleets.Dispose();
}
}
/// <summary>
/// Boilerplate disposal
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}