Export version fixes (#83)
* Add file association for .eop, prompt for install dir * Handle .eop or .aip file passed as arg. * VS2022 version bump * Filter neutron stars and black holes from fast spinning criteria. * Adjustments for new "high value" check * Refactor herald cache * Fix element order and namespaces for voice moods. * Add explicit .Stop() between audio player calls. * Use nullsafe member access instead of skipping * Don't queue up a title that's already queued. * Improve body ordinal handling for explorer speech titles. * Escape strings being inserted into xml * Handle flip-flopping JSON type * Converter for flip-flopping property type * Use the converter * Escape characters *before* we wrap it in xml. * Give Eahlstan his clear button. :D * Exclude all stars from fast rotation check. * Close outstanding popup notifications on exit. * TO DONE * [Herald] Suppress duplicate notification titles for spoken notifications If you have notifications from multiple plugins producing notifications with the same title in quick succession (ie. "Body A 1 e" from both Explorer and BioInsights), the title on successive notifications will not be spoken again to save the breath of our friendly Azure speakers. * Doc update * Remove unintended member hiding * Fix export errors when exporting BioInsights data, cleanup Discovered a couple issues with exporting BioInsights data resulting from using two different types of objects in the data grid; improved error handling as well. Also cleaned up some old-style read all code. * Add read-all on launch setting * Updated framework xml * Improve high-value body description text Co-authored-by: Fred Kuipers <mr.fredk@gmail.com>
This commit is contained in:
parent
921f3867fa
commit
8de34a141c
31 changed files with 483 additions and 204 deletions
|
|
@ -19,6 +19,7 @@ AppPublisherURL={#MyAppURL}
|
|||
AppSupportURL={#MyAppURL}
|
||||
AppUpdatesURL={#MyAppURL}
|
||||
DefaultDirName={autopf}\{#MyAppName}
|
||||
DisableDirPage=false
|
||||
DefaultGroupName={#MyAppName}
|
||||
AllowNoIcons=yes
|
||||
LicenseFile=C:\Users\Xjph\Source\Repos\MIT.txt
|
||||
|
|
@ -32,6 +33,7 @@ Compression=lzma
|
|||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
ChangesAssociations=yes
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
|
@ -77,6 +79,13 @@ Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: de
|
|||
[Run]
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
||||
|
||||
[Registry]
|
||||
Root: HKA; Subkey: "Software\Classes\.eop\OpenWithProgids"; ValueType: string; ValueName: "ObservatoryPlugin.eop"; ValueData: ""; Flags: uninsdeletevalue
|
||||
Root: HKA; Subkey: "Software\Classes\ObservatoryPlugin.eop"; ValueType: string; ValueName: ""; ValueData: "Elite Observatory Plugin"; Flags: uninsdeletekey
|
||||
Root: HKA; Subkey: "Software\Classes\ObservatoryPlugin.eop\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"
|
||||
Root: HKA; Subkey: "Software\Classes\ObservatoryPlugin.eop\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
|
||||
Root: HKA; Subkey: "Software\Classes\Applications\{#MyAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".eop"; ValueData: ""
|
||||
|
||||
[Code]
|
||||
|
||||
type
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ namespace Observatory.NativeNotification
|
|||
{
|
||||
public class NativePopup
|
||||
{
|
||||
// TODO: This needs to be cleaned up when the app is closed.
|
||||
private Dictionary<Guid, NotificationView> notifications;
|
||||
|
||||
public NativePopup()
|
||||
|
|
@ -67,5 +66,13 @@ namespace Observatory.NativeNotification
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void CloseAll()
|
||||
{
|
||||
foreach (var notification in notifications)
|
||||
{
|
||||
notification.Value?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,15 @@ namespace Observatory
|
|||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length > 0 && System.IO.File.Exists(args[0]))
|
||||
{
|
||||
var fileInfo = new System.IO.FileInfo(args[0]);
|
||||
if (fileInfo.Extension == ".eop" || fileInfo.Extension == ".zip")
|
||||
System.IO.File.Copy(
|
||||
fileInfo.FullName,
|
||||
$"{AppDomain.CurrentDomain.BaseDirectory}{System.IO.Path.DirectorySeparatorChar}plugins{System.IO.Path.DirectorySeparatorChar}{fileInfo.Name}");
|
||||
}
|
||||
|
||||
string version = System.Reflection.Assembly.GetEntryAssembly().GetName().Version.ToString();
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -170,5 +170,10 @@ namespace Observatory.PluginManagement
|
|||
return folderLocation;
|
||||
}
|
||||
}
|
||||
|
||||
internal void Shutdown()
|
||||
{
|
||||
NativePopup.CloseAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ namespace Observatory.PluginManagement
|
|||
public readonly List<DataTable> pluginTables;
|
||||
public readonly List<(IObservatoryWorker plugin, PluginStatus signed)> workerPlugins;
|
||||
public readonly List<(IObservatoryNotifier plugin, PluginStatus signed)> notifyPlugins;
|
||||
private readonly PluginCore core;
|
||||
|
||||
private PluginManager()
|
||||
{
|
||||
|
|
@ -48,7 +49,7 @@ namespace Observatory.PluginManagement
|
|||
logMonitor.StatusUpdate += pluginHandler.OnStatusUpdate;
|
||||
logMonitor.LogMonitorStateChanged += pluginHandler.OnLogMonitorStateChanged;
|
||||
|
||||
var core = new PluginCore();
|
||||
core = new PluginCore();
|
||||
|
||||
List<IObservatoryPlugin> errorPlugins = new();
|
||||
|
||||
|
|
@ -346,6 +347,11 @@ namespace Observatory.PluginManagement
|
|||
return err;
|
||||
}
|
||||
|
||||
internal void Shutdown()
|
||||
{
|
||||
core.Shutdown();
|
||||
}
|
||||
|
||||
private static void LoadPlaceholderPlugin(string dllPath, PluginStatus pluginStatus, List<(IObservatoryNotifier plugin, PluginStatus signed)> notifiers)
|
||||
{
|
||||
PlaceholderPlugin placeholder = new(new FileInfo(dllPath).Name);
|
||||
|
|
|
|||
12
ObservatoryCore/Properties/Core.Designer.cs
generated
12
ObservatoryCore/Properties/Core.Designer.cs
generated
|
|
@ -262,5 +262,17 @@ namespace Observatory.Properties {
|
|||
this["ExportFolder"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool StartReadAll {
|
||||
get {
|
||||
return ((bool)(this["StartReadAll"]));
|
||||
}
|
||||
set {
|
||||
this["StartReadAll"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,5 +62,8 @@
|
|||
<Setting Name="ExportFolder" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="StartReadAll" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
|
|
@ -21,6 +21,11 @@ namespace Observatory.UI
|
|||
{
|
||||
DataContext = new MainWindowViewModel(pluginManager)
|
||||
};
|
||||
|
||||
desktop.MainWindow.Closing += (o, e) =>
|
||||
{
|
||||
pluginManager.Shutdown();
|
||||
};
|
||||
}
|
||||
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
|
|
|
|||
|
|
@ -1,10 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Observatory.UI.Models
|
||||
namespace Observatory.UI.Models
|
||||
{
|
||||
public class NotificationModel
|
||||
{
|
||||
|
|
|
|||
|
|
@ -58,19 +58,16 @@ namespace Observatory.UI.ViewModels
|
|||
tabs.Add(new CoreModel() { Name = "Core", UI = new BasicUIViewModel(new ObservableCollection<object>()) { UIType = Framework.PluginUI.UIType.Core } });
|
||||
|
||||
if (Properties.Core.Default.StartMonitor)
|
||||
{
|
||||
ToggleMonitor();
|
||||
}
|
||||
|
||||
if (Properties.Core.Default.StartReadAll)
|
||||
ReadAll();
|
||||
|
||||
}
|
||||
|
||||
public void ReadAll()
|
||||
{
|
||||
// TODO(fredjk_gh): remove.
|
||||
SetWorkerReadAllState(true);
|
||||
LogMonitor.GetInstance.ReadAllJournals();
|
||||
// TODO(fredjk_gh): remove.
|
||||
SetWorkerReadAllState(false);
|
||||
}
|
||||
|
||||
public void ToggleMonitor()
|
||||
|
|
@ -84,12 +81,7 @@ namespace Observatory.UI.ViewModels
|
|||
}
|
||||
else
|
||||
{
|
||||
// HACK: Find a better way of suppressing notifications when pre-reading.
|
||||
// TODO(fredjk_gh): remove.
|
||||
SetWorkerReadAllState(true);
|
||||
logMonitor.Start();
|
||||
// TODO(fredjk_gh): remove.
|
||||
SetWorkerReadAllState(false);
|
||||
ToggleButtonText = "Stop Monitor";
|
||||
}
|
||||
}
|
||||
|
|
@ -117,100 +109,129 @@ namespace Observatory.UI.ViewModels
|
|||
|
||||
public async void ExportGrid()
|
||||
{
|
||||
var exportFolder = Properties.Core.Default.ExportFolder;
|
||||
|
||||
if (string.IsNullOrEmpty(exportFolder))
|
||||
try
|
||||
{
|
||||
exportFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
}
|
||||
var exportFolder = Properties.Core.Default.ExportFolder;
|
||||
|
||||
OpenFolderDialog openFolderDialog = new()
|
||||
{
|
||||
Directory = exportFolder
|
||||
};
|
||||
|
||||
var application = (IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current.ApplicationLifetime;
|
||||
|
||||
var selectedFolder = await openFolderDialog.ShowAsync(application.MainWindow);
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFolder))
|
||||
{
|
||||
Properties.Core.Default.ExportFolder = selectedFolder;
|
||||
Properties.Core.Default.Save();
|
||||
exportFolder = selectedFolder;
|
||||
|
||||
foreach (var tab in tabs.Where(t => t.Name != "Core"))
|
||||
if (string.IsNullOrEmpty(exportFolder))
|
||||
{
|
||||
var ui = (BasicUIViewModel)tab.UI;
|
||||
List<object> selectedData;
|
||||
bool specificallySelected = ui.SelectedItems?.Count > 1;
|
||||
exportFolder = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
}
|
||||
|
||||
if (specificallySelected)
|
||||
OpenFolderDialog openFolderDialog = new()
|
||||
{
|
||||
Directory = exportFolder
|
||||
};
|
||||
|
||||
var application = (IClassicDesktopStyleApplicationLifetime)Avalonia.Application.Current.ApplicationLifetime;
|
||||
|
||||
var selectedFolder = await openFolderDialog.ShowAsync(application.MainWindow);
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFolder))
|
||||
{
|
||||
Properties.Core.Default.ExportFolder = selectedFolder;
|
||||
Properties.Core.Default.Save();
|
||||
exportFolder = selectedFolder;
|
||||
|
||||
foreach (var tab in tabs.Where(t => t.Name != "Core"))
|
||||
{
|
||||
selectedData = new();
|
||||
var ui = (BasicUIViewModel)tab.UI;
|
||||
List<object> selectedData;
|
||||
bool specificallySelected = ui.SelectedItems?.Count > 1;
|
||||
|
||||
foreach (var item in ui.SelectedItems)
|
||||
selectedData.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedData = ui.BasicUIGrid.ToList();
|
||||
}
|
||||
|
||||
var columns = selectedData[0].GetType().GetProperties();
|
||||
Dictionary<string, int> colSize = new();
|
||||
Dictionary<string, List<string>> colContent = new();
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
colSize.Add(column.Name, 0);
|
||||
colContent.Add(column.Name, new());
|
||||
}
|
||||
|
||||
var lineType = selectedData[0].GetType();
|
||||
|
||||
foreach (var line in selectedData)
|
||||
{
|
||||
foreach (var column in colContent)
|
||||
if (specificallySelected)
|
||||
{
|
||||
var cellValue = lineType.GetProperty(column.Key).GetValue(line)?.ToString() ?? string.Empty;
|
||||
column.Value.Add(cellValue);
|
||||
if (colSize[column.Key] < cellValue.Length)
|
||||
colSize[column.Key] = cellValue.Length;
|
||||
selectedData = new();
|
||||
|
||||
foreach (var item in ui.SelectedItems)
|
||||
selectedData.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
System.Text.StringBuilder exportData = new();
|
||||
|
||||
|
||||
foreach (var colTitle in colContent.Keys)
|
||||
{
|
||||
if (colSize[colTitle] < colTitle.Length)
|
||||
colSize[colTitle] = colTitle.Length;
|
||||
|
||||
exportData.Append(colTitle.PadRight(colSize[colTitle]) + " ");
|
||||
}
|
||||
exportData.AppendLine();
|
||||
|
||||
for (int i = 0; i < colContent.First().Value.Count; i++)
|
||||
{
|
||||
foreach(var column in colContent)
|
||||
else
|
||||
{
|
||||
if (column.Value[i].Length > 0 && !char.IsNumber(column.Value[i][0]) && column.Value[i].Count(char.IsLetter) / (float)column.Value[i].Length > 0.25)
|
||||
exportData.Append(column.Value[i].PadRight(colSize[column.Key]) + " ");
|
||||
else
|
||||
exportData.Append(column.Value[i].PadLeft(colSize[column.Key]) + " ");
|
||||
selectedData = ui.BasicUIGrid.ToList();
|
||||
}
|
||||
|
||||
var columns = selectedData[0].GetType().GetProperties();
|
||||
Dictionary<string, int> colSize = new();
|
||||
Dictionary<string, List<string>> colContent = new();
|
||||
|
||||
foreach (var column in columns)
|
||||
{
|
||||
colSize.Add(column.Name, 0);
|
||||
colContent.Add(column.Name, new());
|
||||
}
|
||||
|
||||
foreach (var line in selectedData)
|
||||
{
|
||||
var lineType = line.GetType(); // some plugins have different line types, so don't move this out of loop
|
||||
foreach (var column in colContent)
|
||||
{
|
||||
var cellValue = lineType.GetProperty(column.Key)?.GetValue(line)?.ToString() ?? string.Empty;
|
||||
column.Value.Add(cellValue);
|
||||
if (colSize[column.Key] < cellValue.Length)
|
||||
colSize[column.Key] = cellValue.Length;
|
||||
}
|
||||
}
|
||||
|
||||
System.Text.StringBuilder exportData = new();
|
||||
|
||||
|
||||
foreach (var colTitle in colContent.Keys)
|
||||
{
|
||||
if (colSize[colTitle] < colTitle.Length)
|
||||
colSize[colTitle] = colTitle.Length;
|
||||
|
||||
exportData.Append(colTitle.PadRight(colSize[colTitle]) + " ");
|
||||
}
|
||||
exportData.AppendLine();
|
||||
|
||||
for (int i = 0; i < colContent.First().Value.Count; i++)
|
||||
{
|
||||
foreach (var column in colContent)
|
||||
{
|
||||
if (column.Value[i].Length > 0 && !char.IsNumber(column.Value[i][0]) && column.Value[i].Count(char.IsLetter) / (float)column.Value[i].Length > 0.25)
|
||||
exportData.Append(column.Value[i].PadRight(colSize[column.Key]) + " ");
|
||||
else
|
||||
exportData.Append(column.Value[i].PadLeft(colSize[column.Key]) + " ");
|
||||
}
|
||||
exportData.AppendLine();
|
||||
}
|
||||
|
||||
string exportPath = $"{exportFolder}{System.IO.Path.DirectorySeparatorChar}Observatory Export - {DateTime.UtcNow:yyyyMMdd-HHmmss} - {tab.Name}.txt";
|
||||
|
||||
System.IO.File.WriteAllText(exportPath, exportData.ToString());
|
||||
}
|
||||
|
||||
string exportPath = $"{exportFolder}{System.IO.Path.DirectorySeparatorChar}Observatory Export - {DateTime.UtcNow:yyyyMMdd-HHmmss} - {tab.Name}.txt";
|
||||
|
||||
System.IO.File.WriteAllText(exportPath, exportData.ToString());
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ObservatoryCore.LogError(e, "while exporting data");
|
||||
ErrorReporter.ShowErrorPopup("Error encountered!",
|
||||
"An error occurred while exporting; output may be missing or incomplete." + Environment.NewLine +
|
||||
"Please check the error log (found in your Documents folder) for more details and visit our discord to report it.");
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearGrid()
|
||||
{
|
||||
foreach (var tab in tabs.Where(t => t.Name != "Core"))
|
||||
{
|
||||
var ui = (BasicUIViewModel)tab.UI;
|
||||
|
||||
var rowTemplate = ui.BasicUIGrid.First();
|
||||
|
||||
foreach (var property in rowTemplate.GetType().GetProperties())
|
||||
{
|
||||
property.SetValue(rowTemplate, null);
|
||||
}
|
||||
|
||||
ui.BasicUIGrid.Clear();
|
||||
ui.BasicUIGrid.Add(rowTemplate);
|
||||
|
||||
// For some reason UIType's change event will properly
|
||||
// redraw the grid, not BasicUIGrid's.
|
||||
ui.RaisePropertyChanged(nameof(ui.UIType));
|
||||
}
|
||||
}
|
||||
|
||||
public string ToggleButtonText
|
||||
|
|
@ -241,22 +262,6 @@ namespace Observatory.UI.ViewModels
|
|||
get { return tabs; }
|
||||
}
|
||||
|
||||
// TODO(fredjk_gh): remove.
|
||||
private void SetWorkerReadAllState(bool isReadingAll)
|
||||
{
|
||||
foreach (var worker in workers)
|
||||
{
|
||||
if (isReadingAll)
|
||||
{
|
||||
worker.ReadAllStarted();
|
||||
}
|
||||
else
|
||||
{
|
||||
worker.ReadAllFinished();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CheckUpdate()
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -1,9 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Observatory.Framework;
|
||||
using Observatory.Framework;
|
||||
|
||||
namespace Observatory.UI.ViewModels
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@ namespace Observatory.UI.Views
|
|||
{
|
||||
InitializeComponent();
|
||||
nativePopup = new();
|
||||
|
||||
this.DetachedFromVisualTree += (o, e) =>
|
||||
{
|
||||
nativePopup.CloseAll();
|
||||
};
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
|
|
@ -666,7 +671,7 @@ namespace Observatory.UI.Views
|
|||
|
||||
#endregion
|
||||
|
||||
#region Monitor On Launch
|
||||
#region Actions On Launch
|
||||
|
||||
TextBlock startMonitorLabel = new() { Text = "Start monitor on Observatory launch" };
|
||||
CheckBox startMonitorCheckbox = new() { IsChecked = Properties.Core.Default.StartMonitor, Content = startMonitorLabel };
|
||||
|
|
@ -683,6 +688,21 @@ namespace Observatory.UI.Views
|
|||
Properties.Core.Default.Save();
|
||||
};
|
||||
|
||||
TextBlock startReadAllLabel = new() { Text = "Read All on Observatory launch" };
|
||||
CheckBox startReadAllCheckbox = new() { IsChecked = Properties.Core.Default.StartReadAll, Content = startReadAllLabel };
|
||||
|
||||
startReadAllCheckbox.Checked += (object sender, RoutedEventArgs e) =>
|
||||
{
|
||||
Properties.Core.Default.StartReadAll = true;
|
||||
Properties.Core.Default.Save();
|
||||
};
|
||||
|
||||
startReadAllCheckbox.Unchecked += (object sender, RoutedEventArgs e) =>
|
||||
{
|
||||
Properties.Core.Default.StartReadAll = false;
|
||||
Properties.Core.Default.Save();
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
|
@ -753,6 +773,7 @@ namespace Observatory.UI.Views
|
|||
|
||||
gridManager.AddSetting(primeSystemContexCheckbox);
|
||||
gridManager.AddSetting(startMonitorCheckbox);
|
||||
gridManager.AddSetting(startReadAllCheckbox);
|
||||
gridManager.AddSettingWithLabel(journalPathLabel, journalPath);
|
||||
gridManager.AddSetting(journalBrowse);
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,14 @@
|
|||
Content="Export">
|
||||
Export
|
||||
</Button>
|
||||
<Button
|
||||
Name="clear"
|
||||
Margin="10"
|
||||
FontSize="15"
|
||||
Command="{Binding ClearGrid}"
|
||||
Content="Clear">
|
||||
Clear
|
||||
</Button>
|
||||
<Button
|
||||
Name="ToggleMonitor"
|
||||
Margin="10"
|
||||
|
|
|
|||
|
|
@ -9,18 +9,6 @@ namespace Observatory.Explorer
|
|||
{
|
||||
internal static class DefaultCriteria
|
||||
{
|
||||
private static IList<string> HighValueNonTerraformablePlanetClasses = new string[] {
|
||||
"Earthlike body",
|
||||
"Ammonia world",
|
||||
"Water world",
|
||||
};
|
||||
|
||||
private static IList<string> HighValueTerraformablePlanetClasses = new string[] {
|
||||
"Water world",
|
||||
"High metal content body",
|
||||
"Rocky body",
|
||||
};
|
||||
|
||||
public static List<(string Description, string Detail, bool SystemWide)> CheckInterest(Scan scan, Dictionary<ulong, Dictionary<int, Scan>> scanHistory, Dictionary<ulong, Dictionary<int, FSSBodySignals>> signalHistory, ExplorerSettings settings)
|
||||
{
|
||||
List<(string, string, bool)> results = new();
|
||||
|
|
@ -61,13 +49,25 @@ namespace Observatory.Explorer
|
|||
#region Value Checks
|
||||
if (settings.HighValueMappable)
|
||||
{
|
||||
if (HighValueTerraformablePlanetClasses.Contains(scan.PlanetClass) && scan.TerraformState?.Length > 0)
|
||||
IList<string> HighValueNonTerraformablePlanetClasses = new string[] {
|
||||
"Earthlike body",
|
||||
"Ammonia world",
|
||||
"Water world",
|
||||
};
|
||||
|
||||
if (HighValueNonTerraformablePlanetClasses.Contains(scan.PlanetClass) || scan.TerraformState?.Length > 0)
|
||||
{
|
||||
results.Add("High-Value Mapping", $"{scan.DistanceFromArrivalLS:0}Ls, {scan.PlanetClass} (TF)");
|
||||
}
|
||||
if (HighValueNonTerraformablePlanetClasses.Contains(scan.PlanetClass) && scan.TerraformState?.Length == 0)
|
||||
{
|
||||
results.Add("High-Value Mapping", $"{scan.DistanceFromArrivalLS:0}Ls, {scan.PlanetClass}");
|
||||
var info = new System.Text.StringBuilder();
|
||||
|
||||
if (!scan.WasDiscovered)
|
||||
info.Append("Undiscovered ");
|
||||
else if (!scan.WasMapped)
|
||||
info.Append("Unmapped ");
|
||||
|
||||
if (scan.TerraformState?.Length > 0)
|
||||
info.Append("Terraformable ");
|
||||
|
||||
results.Add("High-Value Body", $"{(info.Length > 1 ? info.ToString() : string.Empty)}{textInfo.ToTitleCase(scan.PlanetClass)}, {scan.DistanceFromArrivalLS:N0}Ls");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
|
@ -143,7 +143,7 @@ namespace Observatory.Explorer
|
|||
results.Add("Nested Moon");
|
||||
}
|
||||
|
||||
if (settings.FastRotation && scan.RotationPeriod != 0 && !scan.TidalLock && Math.Abs(scan.RotationPeriod) < 28800 && !isRing)
|
||||
if (settings.FastRotation && scan.RotationPeriod != 0 && !scan.TidalLock && Math.Abs(scan.RotationPeriod) < 28800 && !isRing && string.IsNullOrEmpty(scan.StarType))
|
||||
{
|
||||
results.Add("Non-locked Body with Fast Rotation", $"Period: {scan.RotationPeriod/3600:N1} hours");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ namespace Observatory.Explorer
|
|||
bodyAffix = string.Empty;
|
||||
}
|
||||
|
||||
string bodyLabel = scanEvent.PlanetClass == "Barycentre" ? "Barycentre" : "Body";
|
||||
string bodyLabel = System.Security.SecurityElement.Escape(scanEvent.PlanetClass == "Barycentre" ? "Barycentre" : "Body");
|
||||
|
||||
string spokenAffix;
|
||||
|
||||
|
|
@ -222,13 +222,13 @@ namespace Observatory.Explorer
|
|||
{
|
||||
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));
|
||||
"<say-as interpret-as=\"spell-out\">" + bodyAffix[..ringIndex]
|
||||
+ "</say-as><break strength=\"weak\"/>" + SplitOrdinalForSsml(bodyAffix.Substring(ringIndex, 1))
|
||||
+ bodyAffix[(ringIndex + 1)..];
|
||||
}
|
||||
else
|
||||
{
|
||||
spokenAffix = "<say-as interpret-as=\"spell-out\">" + bodyAffix + "</say-as>";
|
||||
spokenAffix = SplitOrdinalForSsml(bodyAffix);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -248,5 +248,18 @@ namespace Observatory.Explorer
|
|||
}
|
||||
}
|
||||
|
||||
private static string SplitOrdinalForSsml(string ordinalString)
|
||||
{
|
||||
var ordinalSegments = ordinalString.Split(' ');
|
||||
StringBuilder affix = new();
|
||||
foreach (var ordinalSegment in ordinalSegments)
|
||||
{
|
||||
if (ordinalSegment.All(Char.IsDigit))
|
||||
affix.Append(" " + ordinalSegment);
|
||||
else
|
||||
affix.Append("<say-as interpret-as=\"spell-out\">" + ordinalSegment + "</say-as>");
|
||||
}
|
||||
return affix.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ namespace Observatory.Explorer
|
|||
[SettingDisplayName("All Surface Mats In System")]
|
||||
public bool GoldSystem { get; set; }
|
||||
|
||||
[SettingDisplayName("High-Value Mapping")]
|
||||
[SettingDisplayName("High-Value Body")]
|
||||
public bool HighValueMappable { get; set; }
|
||||
|
||||
[SettingDisplayName("Enable Custom Criteria")]
|
||||
|
|
|
|||
|
|
@ -55,29 +55,81 @@ namespace Observatory.Framework
|
|||
/// </summary>
|
||||
public double YPos = -1.0;
|
||||
/// <summary>
|
||||
/// Specifies the desired renderings of the notification.
|
||||
/// Specifies the desired renderings of the notification. Defaults to <see cref="NotificationRendering.All"/>.
|
||||
/// </summary>
|
||||
public NotificationRendering Rendering = NotificationRendering.All;
|
||||
/// <summary>
|
||||
/// Specifies if some part of the notification should be suppressed. Not supported by all notifiers. Defaults to <see cref="NotificationSuppression.None"/>.
|
||||
/// </summary>
|
||||
public NotificationSuppression Suppression = NotificationSuppression.None;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines constants for suppression of title or detail announcement in a notification.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum NotificationSuppression
|
||||
{
|
||||
/// <summary>
|
||||
/// No suppression.
|
||||
/// </summary>
|
||||
None = 0,
|
||||
/// <summary>
|
||||
/// Suppress title.
|
||||
/// </summary>
|
||||
Title = 1,
|
||||
/// <summary>
|
||||
/// Suppress detail.
|
||||
/// </summary>
|
||||
Detail = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines constants for controlling notification routing to plugins or native notification handlers.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum NotificationRendering
|
||||
{
|
||||
// These need to be multiples of 2 as they're used via masking.
|
||||
/// <summary>
|
||||
/// Send notification to native visual popup notificaiton handler.
|
||||
/// </summary>
|
||||
NativeVisual = 1,
|
||||
/// <summary>
|
||||
/// Send notification to native speech notification handler.
|
||||
/// </summary>
|
||||
NativeVocal = 2,
|
||||
/// <summary>
|
||||
/// Send notification to all installed notifier plugins.
|
||||
/// </summary>
|
||||
PluginNotifier = 4,
|
||||
/// <summary>
|
||||
/// Send notification to all available handlers.
|
||||
/// </summary>
|
||||
All = (NativeVisual | NativeVocal | PluginNotifier)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flags indicating current state of journal monitoring.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum LogMonitorState : uint
|
||||
{
|
||||
// These need to be multiples of 2 as they're used via masking.
|
||||
Idle = 0, // Monitoring is stopped
|
||||
Realtime = 1, // Real-time monitoring is active
|
||||
Batch = 2, // Performing a batch read of history
|
||||
PreRead = 4 // Currently pre-reading current system context (a batch read)
|
||||
/// <summary>
|
||||
/// Monitoring is stopped.
|
||||
/// </summary>
|
||||
Idle = 0,
|
||||
/// <summary>
|
||||
/// Real-time monitoring is active.
|
||||
/// </summary>
|
||||
Realtime = 1,
|
||||
/// <summary>
|
||||
/// Batch read of historical journals is in progress.
|
||||
/// </summary>
|
||||
Batch = 2,
|
||||
/// <summary>
|
||||
/// Batch read of recent journals is in progress to establish current player state.
|
||||
/// </summary>
|
||||
PreRead = 4
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Observatory.Framework.Files.Converters
|
||||
{
|
||||
class MutableStringDoubleConverter : JsonConverter<object>
|
||||
{
|
||||
public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.String)
|
||||
return reader.GetString();
|
||||
else
|
||||
return reader.GetDouble();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,5 @@
|
|||
public class CrewLaunchFighter : CrewMemberJoins
|
||||
{
|
||||
public ulong ID { get; init; }
|
||||
public bool Telepresence { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
namespace Observatory.Framework.Files.Journal
|
||||
{
|
||||
public class CrewMemberQuits : CrewMemberJoins
|
||||
{
|
||||
public bool Telepresence { get; init; }
|
||||
}
|
||||
{ }
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue