mirror of
https://github.com/9ParsonsB/Pulsar.git
synced 2025-07-01 08:23:42 -04:00
Reorganize all observatory core projects into monorepo (#25)
* chore: move all observatory repos to core * only save journal folder on change, don't constantly re-check during monitoring * chore: monorepo project changes * chore: monorepo migration
This commit is contained in:
20
ObservatoryExplorer/CriteriaLoadException.cs
Normal file
20
ObservatoryExplorer/CriteriaLoadException.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.Explorer
|
||||
{
|
||||
internal class CriteriaLoadException : Exception
|
||||
{
|
||||
public CriteriaLoadException(string message, string script)
|
||||
{
|
||||
Message = message;
|
||||
OriginalScript = script;
|
||||
}
|
||||
|
||||
new public readonly string Message;
|
||||
public readonly string OriginalScript;
|
||||
}
|
||||
}
|
236
ObservatoryExplorer/CustomCriteriaManager.cs
Normal file
236
ObservatoryExplorer/CustomCriteriaManager.cs
Normal file
@ -0,0 +1,236 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using NLua;
|
||||
using System.Linq;
|
||||
|
||||
namespace Observatory.Explorer
|
||||
{
|
||||
internal class CustomCriteriaManager
|
||||
{
|
||||
private Lua LuaState;
|
||||
private List<LuaFunction> CriteriaFunctions;
|
||||
|
||||
public CustomCriteriaManager()
|
||||
{
|
||||
CriteriaFunctions = new();
|
||||
}
|
||||
|
||||
public void RefreshCriteria(string criteriaPath)
|
||||
{
|
||||
LuaState = new();
|
||||
LuaState.State.Encoding = Encoding.UTF8;
|
||||
LuaState.LoadCLRPackage();
|
||||
|
||||
#region Iterators
|
||||
|
||||
//Materials and AtmosphereComposition
|
||||
LuaState.DoString(@"
|
||||
function materials (material_list)
|
||||
local i = 0
|
||||
local count = material_list.Count
|
||||
return function ()
|
||||
i = i + 1
|
||||
if i <= count then
|
||||
return { name = material_list[i - 1].Name, percent = material_list[i - 1].Percent }
|
||||
end
|
||||
end
|
||||
end");
|
||||
|
||||
//Rings
|
||||
LuaState.DoString(@"
|
||||
function rings (ring_list)
|
||||
local i = 0
|
||||
local count = ring_list.Count
|
||||
return function ()
|
||||
i = i + 1
|
||||
if i <= count then
|
||||
local ring = ring_list[i - 1]
|
||||
return { name = ring.Name, ringclass = ring.RingClass, massmt = ring.MassMT, innerrad = ring.InnerRad, outerrad = ring.OuterRad }
|
||||
end
|
||||
end
|
||||
end");
|
||||
|
||||
//Bodies in system
|
||||
LuaState.DoString(@"
|
||||
function bodies (system_list)
|
||||
local i = 0
|
||||
local count = system_list.Count
|
||||
return function ()
|
||||
i = i + 1
|
||||
if i <= count then
|
||||
return system_list[i - 1]
|
||||
end
|
||||
end
|
||||
end");
|
||||
|
||||
//Parent bodies
|
||||
LuaState.DoString(@"
|
||||
function allparents (parent_list)
|
||||
local i = 0
|
||||
local count
|
||||
if parent_list then count = parent_list.Count else count = 0 end
|
||||
return function ()
|
||||
i = i + 1
|
||||
if i <= count then
|
||||
return { parenttype = parent_list[i - 1].ParentType, body = parent_list[i - 1].Body, scan = parent_list[i - 1].Scan }
|
||||
end
|
||||
end
|
||||
end");
|
||||
|
||||
#endregion
|
||||
|
||||
CriteriaFunctions.Clear();
|
||||
var criteria = File.Exists(criteriaPath) ? File.ReadAllLines(criteriaPath) : Array.Empty<string>();
|
||||
StringBuilder script = new();
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < criteria.Length; i++)
|
||||
{
|
||||
if (criteria[i].Trim().StartsWith("::"))
|
||||
{
|
||||
string scriptDescription = criteria[i].Trim().Replace("::", string.Empty);
|
||||
if (scriptDescription.ToLower() == "criteria")
|
||||
{
|
||||
string functionName = $"Criteria{i}";
|
||||
script.AppendLine($"function {functionName} (scan, parents, system, biosignals, geosignals)");
|
||||
i++;
|
||||
do
|
||||
{
|
||||
script.AppendLine(criteria[i]);
|
||||
i++;
|
||||
} while (!criteria[i].Trim().ToLower().StartsWith("::end::"));
|
||||
script.AppendLine("end");
|
||||
|
||||
LuaState.DoString(script.ToString());
|
||||
CriteriaFunctions.Add(LuaState[functionName] as LuaFunction);
|
||||
script.Clear();
|
||||
}
|
||||
else if (scriptDescription.ToLower() == "global")
|
||||
{
|
||||
i++;
|
||||
do
|
||||
{
|
||||
script.AppendLine(criteria[i]);
|
||||
i++;
|
||||
} while (!criteria[i].Trim().ToLower().StartsWith("::end::"));
|
||||
LuaState.DoString(script.ToString());
|
||||
script.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
|
||||
string functionName = $"Criteria{i}";
|
||||
|
||||
script.AppendLine($"function {functionName} (scan, parents, system, biosignals, geosignals)");
|
||||
script.AppendLine($" local result = {criteria[i]}");
|
||||
|
||||
if (criteria.Length > i + 1 && criteria[i + 1].Trim().ToLower() == "::detail::")
|
||||
{
|
||||
i++; i++;
|
||||
script.AppendLine($" local detail = {criteria[i]}");
|
||||
}
|
||||
else
|
||||
{
|
||||
script.AppendLine(" local detail = ''");
|
||||
}
|
||||
|
||||
script.AppendLine($" return result, '{scriptDescription}', detail");
|
||||
script.AppendLine("end");
|
||||
|
||||
LuaState.DoString(script.ToString());
|
||||
CriteriaFunctions.Add(LuaState[functionName] as LuaFunction);
|
||||
script.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string originalScript = script.ToString().Trim();
|
||||
|
||||
originalScript = originalScript.Remove(originalScript.LastIndexOf(Environment.NewLine));
|
||||
originalScript = originalScript[(originalScript.IndexOf(Environment.NewLine) + Environment.NewLine.Length)..];
|
||||
|
||||
throw new CriteriaLoadException(e.Message, originalScript.Replace('\t', ' '));
|
||||
}
|
||||
}
|
||||
|
||||
public List<(string, string)> CheckInterest(Scan scan, Dictionary<ulong, Dictionary<int, Scan>> scanHistory, Dictionary<ulong, Dictionary<int, FSSBodySignals>> signalHistory, ExplorerSettings settings)
|
||||
{
|
||||
List<(string, string)> results = new();
|
||||
|
||||
foreach (var criteriaFunction in CriteriaFunctions)
|
||||
{
|
||||
var scanList = scanHistory[scan.SystemAddress].Values.ToList();
|
||||
|
||||
int bioSignals;
|
||||
int geoSignals;
|
||||
|
||||
if (signalHistory.ContainsKey(scan.SystemAddress) && signalHistory[scan.SystemAddress].ContainsKey(scan.BodyID))
|
||||
{
|
||||
bioSignals = signalHistory[scan.SystemAddress][scan.BodyID].Signals.Where(s => s.Type == "$SAA_SignalType_Biological;").Select(s => s.Count).FirstOrDefault();
|
||||
geoSignals = signalHistory[scan.SystemAddress][scan.BodyID].Signals.Where(s => s.Type == "$SAA_SignalType_Geological;").Select(s => s.Count).FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
bioSignals = 0;
|
||||
geoSignals = 0;
|
||||
}
|
||||
|
||||
|
||||
List<Parent> parents;
|
||||
|
||||
if (scan.Parent != null)
|
||||
{
|
||||
parents = new();
|
||||
foreach (var parent in scan.Parent)
|
||||
{
|
||||
var parentScan = scanList.Where(s => s.BodyID == parent.Body);
|
||||
|
||||
parents.Add(new Parent()
|
||||
{
|
||||
ParentType = parent.ParentType.ToString(),
|
||||
Body = parent.Body,
|
||||
Scan = parentScan.Any() ? parentScan.First() : null
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parents = null;
|
||||
}
|
||||
|
||||
var result = criteriaFunction.Call(scan, parents, scanList, bioSignals, geoSignals);
|
||||
|
||||
try
|
||||
{
|
||||
if (result.Length > 0 && ((bool?)result[0]).GetValueOrDefault(false))
|
||||
{
|
||||
results.Add((result[1].ToString(), result[2].ToString()));
|
||||
}
|
||||
}
|
||||
catch (NLua.Exceptions.LuaScriptException e)
|
||||
{
|
||||
settings.EnableCustomCriteria = false;
|
||||
results.Add((e.Message, scan.Json));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
internal class Parent
|
||||
{
|
||||
public string ParentType;
|
||||
public int Body;
|
||||
public Scan Scan;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
206
ObservatoryExplorer/DefaultCriteria.cs
Normal file
206
ObservatoryExplorer/DefaultCriteria.cs
Normal file
@ -0,0 +1,206 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using Observatory.Framework.Files.ParameterTypes;
|
||||
|
||||
namespace Observatory.Explorer
|
||||
{
|
||||
internal static class DefaultCriteria
|
||||
{
|
||||
public static List<(string Description, string Detail)> CheckInterest(Scan scan, Dictionary<ulong, Dictionary<int, Scan>> scanHistory, Dictionary<ulong, Dictionary<int, FSSBodySignals>> signalHistory, ExplorerSettings settings)
|
||||
{
|
||||
List<(string, string)> results = new();
|
||||
TextInfo textInfo = new CultureInfo("en-US", false).TextInfo;
|
||||
|
||||
bool isRing = scan.BodyName.Contains("Ring");
|
||||
|
||||
#region Landable Checks
|
||||
if (scan.Landable)
|
||||
{
|
||||
if (settings.LandableTerraformable && scan.TerraformState?.Length > 0)
|
||||
{
|
||||
results.Add($"Landable and {scan.TerraformState}");
|
||||
}
|
||||
|
||||
if (settings.LandableRing && scan.Rings?.Count > 0)
|
||||
{
|
||||
results.Add("Ringed Landable Body");
|
||||
}
|
||||
|
||||
if (settings.LandableAtmosphere && scan.Atmosphere.Length > 0)
|
||||
{
|
||||
results.Add("Landable with Atmosphere", textInfo.ToTitleCase(scan.Atmosphere));
|
||||
}
|
||||
|
||||
if (settings.LandableHighG && scan.SurfaceGravity > 29.4)
|
||||
{
|
||||
results.Add("Landable with High Gravity", $"Surface gravity: {scan.SurfaceGravity / 9.81:0.00}g");
|
||||
}
|
||||
|
||||
if (settings.LandableLarge && scan.Radius > 18000000)
|
||||
{
|
||||
results.Add("Landable Large Planet", $"Radius: {scan.Radius / 1000:0}km");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Parent Relative Checks
|
||||
|
||||
if (scan.SystemAddress != 0 && scan.SemiMajorAxis != 0 &&
|
||||
scanHistory[scan.SystemAddress].ContainsKey(scan.Parent[0].Body))
|
||||
{
|
||||
Scan parent = scanHistory[scan.SystemAddress][scan.Parent[0].Body];
|
||||
|
||||
if (settings.CloseOrbit && !isRing && parent.Radius * 3 > scan.SemiMajorAxis)
|
||||
{
|
||||
results.Add("Close Orbit", $"Orbital Radius: {scan.SemiMajorAxis / 1000:N0}km, Parent Radius: {parent.Radius / 1000:N0}km");
|
||||
}
|
||||
|
||||
if (settings.ShepherdMoon && !isRing && parent.Rings?.Last().OuterRad > scan.SemiMajorAxis && !parent.Rings.Last().Name.Contains("Belt"))
|
||||
{
|
||||
results.Add("Shepherd Moon", $"Orbit: {scan.SemiMajorAxis / 1000:N0}km, Ring Radius: {parent.Rings.Last().OuterRad / 1000:N0}km");
|
||||
}
|
||||
|
||||
if (settings.CloseRing && parent.Rings?.Count > 0)
|
||||
{
|
||||
foreach (var ring in parent.Rings)
|
||||
{
|
||||
var separation = Math.Min(Math.Abs(scan.SemiMajorAxis - ring.OuterRad), Math.Abs(ring.InnerRad - scan.SemiMajorAxis));
|
||||
if (separation < scan.Radius * 10)
|
||||
{
|
||||
results.Add("Close Ring Proximity", $"Orbit: {scan.SemiMajorAxis / 1000:N0}km, Radius: {scan.Radius / 1000:N0}km, Distance from ring: {separation / 1000:N0}km");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
if (settings.DiverseLife && signalHistory.ContainsKey(scan.SystemAddress) && signalHistory[scan.SystemAddress].ContainsKey(scan.BodyID))
|
||||
{
|
||||
var bioSignals = signalHistory[scan.SystemAddress][scan.BodyID].Signals.Where(s => s.Type == "$SAA_SignalType_Biological;");
|
||||
|
||||
if (bioSignals.Count() > 0 && bioSignals.First().Count > 7)
|
||||
{
|
||||
results.Add("Diverse Life", $"Biological Signals: {bioSignals.First().Count}");
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.WideRing && scan.Rings?.Count > 0)
|
||||
{
|
||||
foreach (var ring in scan.Rings.Where(r => !r.Name.Contains("Belt")))
|
||||
{
|
||||
var ringWidth = ring.OuterRad - ring.InnerRad;
|
||||
if (ringWidth > scan.Radius * 5)
|
||||
{
|
||||
results.Add("Wide Ring", $"Width: {ringWidth / 299792458:N2}Ls / {ringWidth / 1000:N0}km, Parent Radius: {scan.Radius / 1000:N0}km");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.SmallObject && scan.StarType == null && scan.PlanetClass != null && scan.PlanetClass != "Barycentre" && scan.Radius < 300000)
|
||||
{
|
||||
results.Add("Small Object", $"Radius: {scan.Radius / 1000:N0}km");
|
||||
}
|
||||
|
||||
if (settings.HighEccentricity && scan.Eccentricity > 0.9)
|
||||
{
|
||||
results.Add("Highly Eccentric Orbit", $"Eccentricity: {Math.Round(scan.Eccentricity, 4)}");
|
||||
}
|
||||
|
||||
if (settings.Nested && !isRing && scan.Parent?.Count > 1 && scan.Parent[0].ParentType == ParentType.Planet && scan.Parent[1].ParentType == ParentType.Planet)
|
||||
{
|
||||
results.Add("Nested Moon");
|
||||
}
|
||||
|
||||
if (settings.FastRotation && scan.RotationPeriod != 0 && !scan.TidalLock && Math.Abs(scan.RotationPeriod) < 28800 && !isRing)
|
||||
{
|
||||
results.Add("Non-locked Body with Fast Rotation", $"Period: {scan.RotationPeriod/3600:N1} hours");
|
||||
}
|
||||
|
||||
if (settings.FastOrbit && scan.OrbitalPeriod != 0 && Math.Abs(scan.OrbitalPeriod) < 28800 && !isRing)
|
||||
{
|
||||
results.Add("Fast Orbit", $"Orbital Period: {Math.Abs(scan.OrbitalPeriod / 3600):N1} hours");
|
||||
}
|
||||
|
||||
if (settings.GoodFSDBody && scan.Landable)
|
||||
{
|
||||
List<string> boostMaterials = new()
|
||||
{
|
||||
"Carbon",
|
||||
"Germanium",
|
||||
"Arsenic",
|
||||
"Niobium",
|
||||
"Yttrium",
|
||||
"Polonium"
|
||||
};
|
||||
|
||||
boostMaterials.RemoveMatchedMaterials(scan);
|
||||
|
||||
if (boostMaterials.Count == 1)
|
||||
{
|
||||
results.Add("5 of 6 Premium Boost Materials", $"Missing material: {boostMaterials[0]}");
|
||||
}
|
||||
}
|
||||
|
||||
if ((settings.GreenSystem || settings.GoldSystem) && scan.Materials != null)
|
||||
{
|
||||
List<string> boostMaterials = new()
|
||||
{
|
||||
"Carbon",
|
||||
"Germanium",
|
||||
"Arsenic",
|
||||
"Niobium",
|
||||
"Yttrium",
|
||||
"Polonium"
|
||||
};
|
||||
|
||||
var systemBodies = scanHistory[scan.SystemAddress];
|
||||
|
||||
bool notifyGreen = false;
|
||||
|
||||
foreach (var body in systemBodies.Values)
|
||||
{
|
||||
if (settings.GreenSystem && body.Materials != null)
|
||||
{
|
||||
if (!boostMaterials.RemoveMatchedMaterials(body) && boostMaterials.Count == 0)
|
||||
{
|
||||
//If the list has been emptied but we're still checking more bodies this notification has already fired and we can abort.
|
||||
notifyGreen = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (boostMaterials.Count == 0)
|
||||
notifyGreen = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (notifyGreen)
|
||||
results.Add("All Premium Boost Materials In System");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static bool RemoveMatchedMaterials(this List<string> materials, Scan body)
|
||||
{
|
||||
foreach (var material in body.Materials)
|
||||
{
|
||||
var matchedMaterial = materials.Find(mat => mat.Equals(material.Name, StringComparison.OrdinalIgnoreCase));
|
||||
if (matchedMaterial != null)
|
||||
{
|
||||
materials.Remove(matchedMaterial);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void Add(this List<(string, string)> results, string description, string detail = "")
|
||||
{
|
||||
results.Add((description, detail));
|
||||
}
|
||||
}
|
||||
}
|
251
ObservatoryExplorer/Explorer.cs
Normal file
251
ObservatoryExplorer/Explorer.cs
Normal file
@ -0,0 +1,251 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Observatory.Framework;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using Observatory.Framework.Interfaces;
|
||||
|
||||
namespace Observatory.Explorer
|
||||
{
|
||||
internal class Explorer
|
||||
{
|
||||
private IObservatoryCore ObservatoryCore;
|
||||
private ObservableCollection<object> Results;
|
||||
private ExplorerWorker ExplorerWorker;
|
||||
private Dictionary<ulong, Dictionary<int, Scan>> SystemBodyHistory;
|
||||
private Dictionary<ulong, Dictionary<int, FSSBodySignals>> BodySignalHistory;
|
||||
private Dictionary<ulong, Dictionary<int, ScanBaryCentre>> BarycentreHistory;
|
||||
private CustomCriteriaManager CustomCriteriaManager;
|
||||
private DateTime CriteriaLastModified;
|
||||
|
||||
internal Explorer(ExplorerWorker explorerWorker, IObservatoryCore core, ObservableCollection<object> results)
|
||||
{
|
||||
SystemBodyHistory = new();
|
||||
BodySignalHistory = new();
|
||||
BarycentreHistory = new();
|
||||
ExplorerWorker = explorerWorker;
|
||||
ObservatoryCore = core;
|
||||
Results = results;
|
||||
CustomCriteriaManager = new();
|
||||
CriteriaLastModified = new DateTime(0);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
SystemBodyHistory.Clear();
|
||||
BodySignalHistory.Clear();
|
||||
BarycentreHistory.Clear();
|
||||
}
|
||||
|
||||
public void RecordSignal(FSSBodySignals bodySignals)
|
||||
{
|
||||
if (!BodySignalHistory.ContainsKey(bodySignals.SystemAddress))
|
||||
{
|
||||
BodySignalHistory.Add(bodySignals.SystemAddress, new Dictionary<int, FSSBodySignals>());
|
||||
}
|
||||
|
||||
if (!BodySignalHistory[bodySignals.SystemAddress].ContainsKey(bodySignals.BodyID))
|
||||
{
|
||||
BodySignalHistory[bodySignals.SystemAddress].Add(bodySignals.BodyID, bodySignals);
|
||||
}
|
||||
}
|
||||
|
||||
public void RecordBarycentre(ScanBaryCentre scan)
|
||||
{
|
||||
if (!BarycentreHistory.ContainsKey(scan.SystemAddress))
|
||||
{
|
||||
BarycentreHistory.Add(scan.SystemAddress, new Dictionary<int, ScanBaryCentre>());
|
||||
}
|
||||
|
||||
if (!BarycentreHistory[scan.SystemAddress].ContainsKey(scan.BodyID))
|
||||
{
|
||||
BarycentreHistory[scan.SystemAddress].Add(scan.BodyID, scan);
|
||||
}
|
||||
}
|
||||
|
||||
public Scan ConvertBarycentre(ScanBaryCentre barycentre, Scan childScan)
|
||||
{
|
||||
string childAffix = childScan.BodyName
|
||||
.Replace(childScan.StarSystem, string.Empty);
|
||||
|
||||
char childOrdinal = childAffix.ToCharArray().Last();
|
||||
|
||||
bool lowChild = childScan.BodyID - barycentre.BodyID == 1;
|
||||
|
||||
string baryAffix;
|
||||
|
||||
if (lowChild)
|
||||
{
|
||||
baryAffix = new string(new char[] { childOrdinal, (char)(childOrdinal + 1) });
|
||||
}
|
||||
else
|
||||
{
|
||||
baryAffix = new string(new char[] { (char)(childOrdinal - 1), childOrdinal });
|
||||
}
|
||||
|
||||
baryAffix = childAffix.Replace(childOrdinal.ToString(), baryAffix);
|
||||
|
||||
Scan barycentreScan = new()
|
||||
{
|
||||
Timestamp = barycentre.Timestamp,
|
||||
BodyName = barycentre.StarSystem + baryAffix,
|
||||
Parents = childScan.Parents.RemoveAt(0),
|
||||
PlanetClass = "Barycentre",
|
||||
StarSystem = barycentre.StarSystem,
|
||||
SystemAddress = barycentre.SystemAddress,
|
||||
BodyID = barycentre.BodyID,
|
||||
SemiMajorAxis = barycentre.SemiMajorAxis,
|
||||
Eccentricity = barycentre.Eccentricity,
|
||||
OrbitalInclination = barycentre.OrbitalInclination,
|
||||
Periapsis = barycentre.Periapsis,
|
||||
OrbitalPeriod = barycentre.OrbitalPeriod,
|
||||
AscendingNode = barycentre.AscendingNode,
|
||||
MeanAnomaly = barycentre.MeanAnomaly,
|
||||
Json = barycentre.Json
|
||||
};
|
||||
|
||||
return barycentreScan;
|
||||
}
|
||||
|
||||
public void ProcessScan(Scan scanEvent, bool readAll)
|
||||
{
|
||||
if (!readAll)
|
||||
{
|
||||
string criteriaFilePath = ((ExplorerSettings)ExplorerWorker.Settings).CustomCriteriaFile;
|
||||
|
||||
if (File.Exists(criteriaFilePath))
|
||||
{
|
||||
DateTime fileModified = new FileInfo(criteriaFilePath).LastWriteTime;
|
||||
|
||||
if (fileModified != CriteriaLastModified)
|
||||
{
|
||||
try
|
||||
{
|
||||
CustomCriteriaManager.RefreshCriteria(criteriaFilePath);
|
||||
}
|
||||
catch (CriteriaLoadException e)
|
||||
{
|
||||
var exceptionResult = new ExplorerUIResults()
|
||||
{
|
||||
BodyName = "Custom Criteria Processing Error",
|
||||
Time = DateTime.Now.ToString("G"),
|
||||
Description = e.Message,
|
||||
Details = e.OriginalScript
|
||||
};
|
||||
ObservatoryCore.AddGridItem(ExplorerWorker, exceptionResult);
|
||||
((ExplorerSettings)ExplorerWorker.Settings).EnableCustomCriteria = false;
|
||||
}
|
||||
|
||||
CriteriaLastModified = fileModified;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dictionary<int, Scan> systemBodies;
|
||||
if (SystemBodyHistory.ContainsKey(scanEvent.SystemAddress))
|
||||
{
|
||||
systemBodies = SystemBodyHistory[scanEvent.SystemAddress];
|
||||
if (systemBodies.ContainsKey(scanEvent.BodyID))
|
||||
{
|
||||
if (scanEvent.SystemAddress != 0)
|
||||
{
|
||||
//We've already checked this object.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
systemBodies = new();
|
||||
SystemBodyHistory.Add(scanEvent.SystemAddress, systemBodies);
|
||||
}
|
||||
|
||||
if (SystemBodyHistory.Count > 1000)
|
||||
{
|
||||
foreach (var entry in SystemBodyHistory.Where(entry => entry.Key != scanEvent.SystemAddress).ToList())
|
||||
{
|
||||
SystemBodyHistory.Remove(entry.Key);
|
||||
}
|
||||
SystemBodyHistory.TrimExcess();
|
||||
}
|
||||
|
||||
if (scanEvent.SystemAddress != 0 && !systemBodies.ContainsKey(scanEvent.BodyID))
|
||||
systemBodies.Add(scanEvent.BodyID, scanEvent);
|
||||
|
||||
var results = DefaultCriteria.CheckInterest(scanEvent, SystemBodyHistory, BodySignalHistory, (ExplorerSettings)ExplorerWorker.Settings);
|
||||
|
||||
if (BarycentreHistory.ContainsKey(scanEvent.SystemAddress) && BarycentreHistory[scanEvent.SystemAddress].ContainsKey(scanEvent.Parent[0].Body))
|
||||
{
|
||||
ProcessScan(ConvertBarycentre(BarycentreHistory[scanEvent.SystemAddress][scanEvent.Parent[0].Body], scanEvent), readAll);
|
||||
}
|
||||
|
||||
if (((ExplorerSettings)ExplorerWorker.Settings).EnableCustomCriteria)
|
||||
results.AddRange(CustomCriteriaManager.CheckInterest(scanEvent, SystemBodyHistory, BodySignalHistory, (ExplorerSettings)ExplorerWorker.Settings));
|
||||
|
||||
if (results.Count > 0)
|
||||
{
|
||||
StringBuilder notificationDetail = new();
|
||||
foreach (var result in results)
|
||||
{
|
||||
var scanResult = new ExplorerUIResults()
|
||||
{
|
||||
BodyName = scanEvent.BodyName,
|
||||
Time = scanEvent.TimestampDateTime.ToString("G"),
|
||||
Description = result.Description,
|
||||
Details = result.Detail
|
||||
};
|
||||
ObservatoryCore.AddGridItem(ExplorerWorker, scanResult);
|
||||
notificationDetail.AppendLine(result.Description);
|
||||
}
|
||||
|
||||
string bodyAffix;
|
||||
|
||||
if (scanEvent.StarSystem != null && scanEvent.BodyName.StartsWith(scanEvent.StarSystem))
|
||||
{
|
||||
bodyAffix = scanEvent.BodyName.Replace(scanEvent.StarSystem, string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
bodyAffix = string.Empty;
|
||||
}
|
||||
|
||||
string bodyLabel = scanEvent.PlanetClass == "Barycentre" ? "Barycentre" : "Body";
|
||||
|
||||
string spokenAffix;
|
||||
|
||||
if (bodyAffix.Length > 0)
|
||||
{
|
||||
if (bodyAffix.Contains("Ring"))
|
||||
{
|
||||
int ringIndex = bodyAffix.Length - 6;
|
||||
spokenAffix =
|
||||
"<say-as interpret-as=\"spell-out\">" + bodyAffix.Substring(0, ringIndex) +
|
||||
"</say-as><break strength=\"weak\"/><say-as interpret-as=\"spell-out\">" +
|
||||
bodyAffix.Substring(ringIndex, 1) + "</say-as>" + bodyAffix.Substring(ringIndex + 1, bodyAffix.Length - (ringIndex + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
spokenAffix = "<say-as interpret-as=\"spell-out\">" + bodyAffix + "</say-as>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spokenAffix = string.Empty;
|
||||
}
|
||||
|
||||
NotificationArgs args = new()
|
||||
{
|
||||
Title = bodyLabel + bodyAffix,
|
||||
TitleSsml = $"<speak version=\"1.0\" xmlns=\"\" xml:lang=\"en-US\">{bodyLabel} {spokenAffix}</speak>",
|
||||
Detail = notificationDetail.ToString()
|
||||
};
|
||||
|
||||
ObservatoryCore.SendNotification(args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
96
ObservatoryExplorer/ExplorerSettings.cs
Normal file
96
ObservatoryExplorer/ExplorerSettings.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using Observatory.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.Explorer
|
||||
{
|
||||
public class ExplorerSettings
|
||||
{
|
||||
public ExplorerSettings()
|
||||
{
|
||||
CustomCriteriaFile = $"{Environment.GetFolderPath(Environment.SpecialFolder.Personal)}{System.IO.Path.DirectorySeparatorChar}ObservatoryCriteria.lua";
|
||||
}
|
||||
|
||||
[SettingDisplayName("Landable & Terraformable")]
|
||||
public bool LandableTerraformable { get; set; }
|
||||
|
||||
[SettingDisplayName("Landable w/ Atmosphere")]
|
||||
public bool LandableAtmosphere { get; set; }
|
||||
|
||||
[SettingDisplayName("Landable High-g")]
|
||||
public bool LandableHighG { get; set; }
|
||||
|
||||
[SettingDisplayName("Landable Large")]
|
||||
public bool LandableLarge { get; set; }
|
||||
|
||||
[SettingDisplayName("Close Orbit")]
|
||||
public bool CloseOrbit { get; set; }
|
||||
|
||||
[SettingDisplayName("Shepherd Moon")]
|
||||
public bool ShepherdMoon { get; set; }
|
||||
|
||||
[SettingDisplayName("Wide Ring")]
|
||||
public bool WideRing { get; set; }
|
||||
|
||||
[SettingDisplayName("Close Binary")]
|
||||
public bool CloseBinary { get; set; }
|
||||
|
||||
[SettingDisplayName("Colliding Binary")]
|
||||
public bool CollidingBinary { get; set; }
|
||||
|
||||
[SettingDisplayName("Close Ring Proximity")]
|
||||
public bool CloseRing { get; set; }
|
||||
|
||||
[SettingDisplayName("Codex Discoveries")]
|
||||
public bool Codex { get; set; }
|
||||
|
||||
[SettingDisplayName("Uncommon Secondary Star")]
|
||||
public bool UncommonSecondary { get; set; }
|
||||
|
||||
[SettingDisplayName("Landable w/ Ring")]
|
||||
public bool LandableRing { get; set; }
|
||||
|
||||
[SettingDisplayName("Nested Moon")]
|
||||
public bool Nested { get; set; }
|
||||
|
||||
[SettingDisplayName("Small Object")]
|
||||
public bool SmallObject { get; set; }
|
||||
|
||||
[SettingDisplayName("Fast Rotation")]
|
||||
public bool FastRotation { get; set; }
|
||||
|
||||
[SettingDisplayName("Fast Orbit")]
|
||||
public bool FastOrbit { get; set; }
|
||||
|
||||
[SettingDisplayName("High Eccentricity")]
|
||||
public bool HighEccentricity { get; set; }
|
||||
|
||||
[SettingDisplayName("Diverse Life")]
|
||||
public bool DiverseLife { get; set; }
|
||||
|
||||
[SettingDisplayName("Good FSD Injection")]
|
||||
public bool GoodFSDBody { get; set; }
|
||||
|
||||
[SettingDisplayName("All FSD Mats In System")]
|
||||
public bool GreenSystem { get; set; }
|
||||
|
||||
[SettingDisplayName("All Surface Mats In System")]
|
||||
public bool GoldSystem { get; set; }
|
||||
|
||||
[SettingDisplayName("Multiple Criteria Notification")]
|
||||
public bool MultipleCriteria { get; set; }
|
||||
|
||||
[SettingDisplayName("Enable Custom Criteria")]
|
||||
public bool EnableCustomCriteria { get; set; }
|
||||
|
||||
[SettingDisplayName("Custom Criteria File")]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
public System.IO.FileInfo CustomCriteria {get => new System.IO.FileInfo(CustomCriteriaFile); set => CustomCriteriaFile = value.FullName;}
|
||||
|
||||
[SettingIgnore]
|
||||
public string CustomCriteriaFile { get; set; }
|
||||
}
|
||||
}
|
16
ObservatoryExplorer/ExplorerUIResults.cs
Normal file
16
ObservatoryExplorer/ExplorerUIResults.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.Explorer
|
||||
{
|
||||
public class ExplorerUIResults
|
||||
{
|
||||
public string Time { get; set; }
|
||||
public string BodyName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string Details { get; set; }
|
||||
}
|
||||
}
|
42
ObservatoryExplorer/ObservatoryExplorer.csproj
Normal file
42
ObservatoryExplorer/ObservatoryExplorer.csproj
Normal file
@ -0,0 +1,42 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>ObservatoryKey.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<VersionSuffix>0.1.$([System.DateTime]::UtcNow.DayOfYear.ToString()).$([System.DateTime]::UtcNow.ToString(HHmm))</VersionSuffix>
|
||||
<AssemblyVersion Condition=" '$(VersionSuffix)' == '' ">0.0.0.1</AssemblyVersion>
|
||||
<AssemblyVersion Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</AssemblyVersion>
|
||||
<Version Condition=" '$(VersionSuffix)' == '' ">0.0.1.0</Version>
|
||||
<Version Condition=" '$(VersionSuffix)' != '' ">$(VersionSuffix)</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Condition=" '$(OS)' == 'Windows_NT' " Command="xcopy $(TargetPath) $(SolutionDir)\..\ObservatoryCore\$(OutDir)plugins\ /y" />
|
||||
<Exec Condition=" '$(OS)' == 'Windows_NT' " Command="xcopy $(TargetDir)\NLua.dll $(SolutionDir)\..\ObservatoryCore\$(OutDir)plugins\deps\ /y" />
|
||||
<Exec Condition=" '$(OS)' == 'Windows_NT' " Command="xcopy $(TargetDir)\KeraLua.dll $(SolutionDir)\..\ObservatoryCore\$(OutDir)plugins\deps\ /y" />
|
||||
<Exec Condition=" '$(OS)' == 'Windows_NT' " Command="xcopy $(TargetDir)\runtimes\win-x64\native\lua54.dll $(SolutionDir)\..\ObservatoryCore\$(OutDir)plugins\deps\ /y" />
|
||||
<Exec Condition=" '$(OS)' != 'Windows_NT' " Command="cp $(TargetPath) $(SolutionDir)/../ObservatoryCore/ObservatoryCore/$(OutDir)plugins/ -f" />
|
||||
<Exec Condition=" '$(OS)' != 'Windows_NT' " Command="cp $(TargetDir)/NLua.dll $(SolutionDir)/../ObservatoryCore/ObservatoryCore/$(OutDir)plugins/deps/ -f" />
|
||||
<Exec Condition=" '$(OS)' != 'Windows_NT' " Command="cp $(TargetDir)/KeraLua.dll $(SolutionDir)/../ObservatoryCore/ObservatoryCore/$(OutDir)plugins/deps/ -f" />
|
||||
<Exec Condition=" '$(OS)' != 'Windows_NT' " Command="cp ~/.nuget/packages/keralua/1.2.14/runtimes/linux-x64/native/liblua54.so $(SolutionDir)/../ObservatoryCore/ObservatoryCore/$(OutDir)lua54.so -f" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLua" Version="1.5.9" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="ObservatoryFramework">
|
||||
<HintPath>..\ObservatoryFramework\bin\Release\net5.0\ObservatoryFramework.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
25
ObservatoryExplorer/ObservatoryExplorer.sln
Normal file
25
ObservatoryExplorer/ObservatoryExplorer.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31205.134
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ObservatoryExplorer", "ObservatoryExplorer.csproj", "{E0FCF2A2-BF56-4F4D-836B-92A0E8269192}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E0FCF2A2-BF56-4F4D-836B-92A0E8269192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E0FCF2A2-BF56-4F4D-836B-92A0E8269192}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E0FCF2A2-BF56-4F4D-836B-92A0E8269192}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E0FCF2A2-BF56-4F4D-836B-92A0E8269192}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {196B0F23-25FC-4A58-A7A9-2676C7749FFD}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
113
ObservatoryExplorer/Worker.cs
Normal file
113
ObservatoryExplorer/Worker.cs
Normal file
@ -0,0 +1,113 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Observatory.Framework.Files.Journal;
|
||||
using Observatory.Framework.Interfaces;
|
||||
using Observatory.Framework;
|
||||
|
||||
namespace Observatory.Explorer
|
||||
{
|
||||
public class ExplorerWorker : IObservatoryWorker
|
||||
{
|
||||
public ExplorerWorker()
|
||||
{
|
||||
settings = new()
|
||||
{
|
||||
CloseBinary = true,
|
||||
CloseOrbit = true,
|
||||
CloseRing = true,
|
||||
CollidingBinary = true,
|
||||
FastRotation = true,
|
||||
HighEccentricity = true,
|
||||
LandableAtmosphere = true,
|
||||
LandableHighG = true,
|
||||
LandableLarge = true,
|
||||
LandableRing = true,
|
||||
LandableTerraformable = true,
|
||||
Nested = true,
|
||||
ShepherdMoon = true,
|
||||
SmallObject = true,
|
||||
WideRing = true
|
||||
};
|
||||
resultsGrid = new();
|
||||
}
|
||||
|
||||
private Explorer explorer;
|
||||
private ObservableCollection<object> resultsGrid;
|
||||
private IObservatoryCore Core;
|
||||
|
||||
private bool readAllStarting = false;
|
||||
private bool readAllInProgress = false;
|
||||
|
||||
public string Name => "Observatory Explorer";
|
||||
|
||||
public string ShortName => "Explorer";
|
||||
|
||||
public string Version => typeof(ExplorerWorker).Assembly.GetName().Version.ToString();
|
||||
|
||||
private PluginUI pluginUI;
|
||||
|
||||
public PluginUI PluginUI => pluginUI;
|
||||
|
||||
public void Load(IObservatoryCore observatoryCore)
|
||||
{
|
||||
explorer = new Explorer(this, observatoryCore, resultsGrid);
|
||||
resultsGrid.Add(new ExplorerUIResults());
|
||||
pluginUI = new PluginUI(resultsGrid);
|
||||
Core = observatoryCore;
|
||||
}
|
||||
|
||||
public void JournalEvent<TJournal>(TJournal journal) where TJournal : JournalBase
|
||||
{
|
||||
bool recordProcessed = false;
|
||||
switch (journal)
|
||||
{
|
||||
case Scan scan:
|
||||
explorer.ProcessScan(scan, readAllInProgress);
|
||||
recordProcessed = true;
|
||||
break;
|
||||
case FSSBodySignals signals:
|
||||
explorer.RecordSignal(signals);
|
||||
break;
|
||||
case ScanBaryCentre barycentre:
|
||||
explorer.RecordBarycentre(barycentre);
|
||||
break;
|
||||
case DiscoveryScan discoveryScan:
|
||||
break;
|
||||
case FSSDiscoveryScan discoveryScan:
|
||||
break;
|
||||
case FSSSignalDiscovered signalDiscovered:
|
||||
break;
|
||||
case NavBeaconScan beaconScan:
|
||||
break;
|
||||
case SAAScanComplete scanComplete:
|
||||
break;
|
||||
case SAASignalsFound signalsFound:
|
||||
break;
|
||||
}
|
||||
|
||||
//Set this *after* the first scan processes so that we get the current custom criteria file.
|
||||
if (readAllStarting && recordProcessed)
|
||||
readAllInProgress = true;
|
||||
}
|
||||
|
||||
public void ReadAllStarted()
|
||||
{
|
||||
readAllStarting = true;
|
||||
Core.ClearGrid(this, new ExplorerUIResults());
|
||||
explorer.Clear();
|
||||
}
|
||||
|
||||
public void ReadAllFinished()
|
||||
{
|
||||
readAllStarting = false;
|
||||
readAllInProgress = false;
|
||||
}
|
||||
|
||||
public object Settings
|
||||
{
|
||||
get => settings;
|
||||
set => settings = (ExplorerSettings)value;
|
||||
}
|
||||
|
||||
private ExplorerSettings settings;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user