Compare commits

...

36 Commits

Author SHA1 Message Date
25362183c9 update docs for new release 2022-11-09 09:07:34 +01:00
fe9ade5058 update changelog 2022-11-09 09:02:14 +01:00
0e77ea1433 remove old pictures 2022-11-06 16:53:16 +01:00
e2b72e1231 added file 2022-11-06 16:52:18 +01:00
8a6397b399 update readme 2022-11-06 16:52:09 +01:00
6ed3b1fd10 move log just beneath BGS results 2022-11-06 16:23:16 +01:00
19513d50e9 drop station from list, it doesn't matter 2022-11-06 15:41:12 +01:00
03e7fcbc15 allow a choice whether to collate entries 2022-11-05 21:02:51 +01:00
ed26c48f5f updated page with new version info 2022-09-24 10:04:05 +02:00
66e9e9bc4d updated changelog 2022-09-24 10:02:56 +02:00
d93af68a56 no more 23th of September 2022-09-24 09:42:57 +02:00
678ca39b44 add a mkdocs based website 2022-09-17 15:00:24 +02:00
9329c1d17a update changelog 2022-08-24 09:55:11 +02:00
4cac9f74d8 EDDB data has been removed a few versions ago 2022-08-24 09:39:46 +02:00
56b534eba0 update readme to reflect changes in Update 13 2022-08-24 09:35:11 +02:00
3dcfa87ef4 update changelog 2022-07-24 13:34:00 +02:00
22f89928ba fix hour display in UTC timestamp 2022-07-24 13:32:38 +02:00
84385be8a6 add datetime to combat zone wins 2022-07-24 13:32:03 +02:00
1362e53d6b allow adding combat zone wins even if an entry is selected 2022-07-24 13:27:53 +02:00
5405d125d5 upgrade to newest Ookii dialogues 2022-07-24 13:19:47 +02:00
62f9711061 remove autocomplete textbox from project 2022-06-07 19:21:27 +02:00
60949ef475 mark new release 2022-06-07 19:18:48 +02:00
1cde35c234 update changelog 2022-06-07 19:06:33 +02:00
f88047718a remove EDDB use from tool
This never worked right, and it slowed down the tool massively on start up. And now that automatic objective detection works quite well it is no longer really needed.
2022-06-07 19:05:21 +02:00
431c83fc23 fix entries in non-rated files not being picked up
Thanks to CMDR Shakaka
2022-06-07 19:00:38 +02:00
7d7f80c555 update changelog 2022-04-06 17:37:46 +02:00
c336dd6189 update screenshots 2022-04-06 17:36:34 +02:00
551cbe84a9 update changelog and readme 2022-04-06 17:11:03 +02:00
2f4d23d878 add date time of the mission to the overview
This helps with pre- and post-tick evaluations.
2022-04-06 16:59:11 +02:00
773d98a4fb allow exclusion of specific log entries from discord log 2022-04-06 16:33:04 +02:00
d087c1862a fix manual window failing if opened twice thanks to CMDR NeedX 2022-04-06 16:15:03 +02:00
1aeb5a09e0 include bugfix proposed by CMDR NeedX 2022-04-06 16:02:51 +02:00
a39f5fbe4e update changelog 2022-03-15 18:10:22 +01:00
327348ab30 update tool with API changes 2022-03-15 18:08:32 +01:00
41337b8b0b update changelog 2022-02-27 16:20:26 +01:00
8fc177c730 fix new line formatting for discord log 2022-02-27 16:16:20 +01:00
40 changed files with 696 additions and 708 deletions

1
.gitignore vendored
View File

@@ -361,3 +361,4 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
/site

View File

@@ -6,6 +6,13 @@ namespace EliteBGS.BGS {
public string Type { get; set; }
public string Grade { get; set; }
public int Amount { get; set; }
public DateTime Completed { get; set; } = DateTime.UtcNow;
public override string CompletedAt {
get {
return Completed.ToString("dd.MM.yyyy HH:mm UTC");
}
}
public int CompareTo(object obj) {
if (obj.GetType() != typeof(CombatZone)) {

View File

@@ -33,7 +33,7 @@ namespace EliteBGS.BGS {
StringBuilder log = new StringBuilder();
log.AppendFormat("**Date:** {0}\n", DateTime.Now.ToString("dd/MM/yyyy"));
log.AppendFormat("**Location:** {0}\n", objective.ToShortString());
log.AppendFormat("**Location:** {0}\n", objective.ToLocationString());
log.AppendFormat("**Faction:** {0}\n", objective.Faction);
log.AppendLine("");
log.AppendLine("```");
@@ -61,18 +61,19 @@ namespace EliteBGS.BGS {
foreach (Objective objective in objectives) {
StringBuilder objlog = new StringBuilder();
objlog.AppendFormat("{0}\n", GenerateObjectiveHeader(objective));
log.AppendFormat("{0}\n", GenerateObjectiveHeader(objective));
foreach (LogFormatter formatter in formatters) {
string text = formatter.GenerateLog(objective);
text = text.Trim();
if (!string.IsNullOrEmpty(text)) {
objlog.AppendFormat("{0}\n", text.Trim());
objlog.AppendFormat("{0}\n\n", text);
}
}
objlog.AppendFormat("{0}\n", GenerateObjectiveFooter(objective));
log.AppendFormat("{0}\n", objlog.ToString().Trim());
log.AppendFormat("{0}\n", GenerateObjectiveFooter(objective));
}
log.AppendFormat("{0}\n", GenerateFooter());

View File

@@ -11,6 +11,12 @@ namespace EliteBGS.BGS {
public string Influence { get; set; }
public MissionCompletedEntry RelevantMission { get; set; }
public override string CompletedAt {
get {
return RelevantMission.Timestamp.ToString("dd.MM.yyyy hh:mm UTC");
}
}
public override string ToString() {
StringBuilder builder = new StringBuilder();
string missionname;

View File

@@ -9,6 +9,23 @@ namespace EliteBGS.BGS {
public bool IsExpanded { get; set; }
public bool IsEnabled { get; set; } = true;
public virtual string CompletedAt {
get {
var items = Entries
.OrderBy(x => x.Timestamp)
.ToArray()
;
if (items == null || items.Length == 0) {
return "Unknown";
}
Entry last = items.Last();
return last.Timestamp.ToString("dd.MM.yyyy HH:mm UTC");
}
}
/// <summary>
/// Controlling faction of the station this entry was made/turned into.
/// </summary>

View File

@@ -8,6 +8,7 @@ namespace EliteBGS.BGS.LogGenerator {
StringBuilder builder = new StringBuilder();
SellCargo[] sold = objective.LogEntries
.OfType<SellCargo>()
.Where(x => x.IsEnabled)
.ToArray()
;

View File

@@ -4,9 +4,12 @@ using EDJournal;
namespace EliteBGS.BGS.LogGenerator {
public class CartographicsFormat : LogFormatter {
public string GenerateLog(Objective objective) {
var total = objective.LogEntries.OfType<Cartographics>();
var total = objective.LogEntries
.OfType<Cartographics>()
.Where(x => x.IsEnabled)
;
var pages = total.Count();
long sum = total.Sum(x => (x as Cartographics).TotalSum);
long sum = total.Sum(x => x.TotalSum);
if (pages <= 0 || sum <= 0) {
return "";

View File

@@ -5,7 +5,12 @@ using EDJournal;
namespace EliteBGS.BGS.LogGenerator {
public class FailedMissionFormat : LogFormatter {
public string GenerateLog(Objective objective) {
MissionFailed[] missions = objective.LogEntries.OfType<MissionFailed>().ToArray();
MissionFailed[] missions = objective
.LogEntries
.OfType<MissionFailed>()
.Where(x => x.IsEnabled)
.ToArray()
;
StringBuilder builder = new StringBuilder();
if (missions.Length <= 0) {

View File

@@ -8,9 +8,9 @@ namespace EliteBGS.BGS.LogGenerator {
/// per line
/// </summary>
/// <typeparam name="Type">LogEntry subtype to work on</typeparam>
public class GenericFormat<Type> : LogFormatter {
public class GenericFormat<Type> : LogFormatter where Type : LogEntry {
public string GenerateLog(Objective objective) {
IEnumerable<Type> logs = objective.LogEntries.OfType<Type>();
IEnumerable<Type> logs = objective.LogEntries.OfType<Type>().Where(x => x.IsEnabled);
StringBuilder builder = new StringBuilder();
if (logs == null || logs.Count() <= 0) {

View File

@@ -4,7 +4,10 @@ using EDJournal;
namespace EliteBGS.BGS.LogGenerator {
public class MicroResourcesFormat : LogFormatter {
public string GenerateLog(Objective objective) {
var total = objective.LogEntries.OfType<SellMicroResources>();
var total = objective.LogEntries
.OfType<SellMicroResources>()
.Where(x => x.IsEnabled)
;
long sum = total.Sum(x => x.TotalSum);
if (total == null || total.Count() <= 0 || sum <= 0) {

View File

@@ -9,7 +9,10 @@ namespace EliteBGS.BGS.LogGenerator {
StringBuilder output = new StringBuilder();
int total_influence = 0;
var missions = objective.LogEntries.OfType<MissionCompleted>();
var missions = objective.LogEntries
.OfType<MissionCompleted>()
.Where(x => x.IsEnabled)
;
if (missions == null) {
return "";

View File

@@ -1,4 +1,4 @@
namespace EliteBGS.BGS.LogGenerator {
class VistaGenomicsFormat : GenericFormat<VistaGenomicsFormat> {
class VistaGenomicsFormat : GenericFormat<OrganicData> {
}
}

View File

@@ -6,7 +6,10 @@ namespace EliteBGS.BGS.LogGenerator {
public class VoucherFormat : LogFormatter {
public string GenerateLog(Objective objective) {
StringBuilder builder = new StringBuilder();
var missions = objective.LogEntries.OfType<Vouchers>();
var missions = objective.LogEntries
.OfType<Vouchers>()
.Where(x => x.IsEnabled)
;
if (missions == null || missions.Count() <= 0) {
return "";

View File

@@ -15,6 +15,8 @@ namespace EliteBGS.BGS {
suffix = "st";
} else if (today.Day == 2 || today.Day == 22) {
suffix = "nd";
} else if (today.Day == 23) {
suffix = "rd";
} else {
suffix = "th";
}
@@ -31,7 +33,7 @@ namespace EliteBGS.BGS {
protected override string GenerateObjectiveHeader(Objective objective) {
StringBuilder log = new StringBuilder();
log.AppendFormat(":globe_with_meridians: `Location:` {0}\n", objective.ToShortString());
log.AppendFormat(":globe_with_meridians: `Location:` {0}\n", objective.ToLocationString());
log.Append(":clipboard: `Conducted:`\n");
log.Append("```");

View File

@@ -5,37 +5,30 @@ using Newtonsoft.Json;
namespace EliteBGS.BGS {
public class Objective : IComparable<Objective> {
private string system;
private string station;
private string faction;
private List<LogEntry> entries = new List<LogEntry>();
[JsonIgnore]
public bool IsEnabled { get; set; }
[JsonIgnore]
public List<LogEntry> Children {
get => entries;
}
public List<LogEntry> Children { get; } = new List<LogEntry>();
[JsonIgnore]
public string Name => this.ToString();
public string Name {
get { return this.ToString(); }
}
[JsonIgnore]
public bool IsExpanded { get; set; }
[JsonIgnore]
public List<LogEntry> LogEntries {
get => entries;
set => entries = value;
get => Children;
}
public void Clear() {
if (entries == null) {
if (LogEntries == null) {
return;
}
entries.RemoveAll(x => !x.ManuallyAdded);
LogEntries.RemoveAll(x => !x.ManuallyAdded);
}
public bool ManuallyAdded { get; set; }
@@ -49,8 +42,8 @@ namespace EliteBGS.BGS {
}
}
if (e.Faction != null && faction != null) {
if (string.Compare(e.Faction, faction, true) != 0) {
if (e.Faction != null && Faction != null) {
if (string.Compare(e.Faction, Faction, true) != 0) {
/* if we have a faction, and it doesn't match we don't care.
* faction is the most important comparision, so if it doesn't match
* it is not the right objective
@@ -62,18 +55,13 @@ namespace EliteBGS.BGS {
}
/* system and station only add to the match strength though */
if (e.System != null && system != null) {
if (string.Compare(e.System, system, true) == 0) {
if (e.System != null && System != null) {
if (string.Compare(e.System, System, true) == 0) {
++match_count;
}
}
/* if system and faction already match, station is not so important */
if (e.Station != null && station != null) {
if (string.Compare(e.Station, station, true) == 0) {
++match_count;
}
}
/* station does not matter */
return match_count;
}
@@ -86,51 +74,36 @@ namespace EliteBGS.BGS {
public bool IsValid => System != null && Faction != null;
public string System {
get { return system; }
set { system = value; }
}
public string System { get; set; }
public string Station {
get { return station; }
set { station = value; }
}
public string Station { get; set; }
public string Faction {
get { return faction; }
set { faction = value; }
}
public string Faction { get; set; }
public override string ToString() {
StringBuilder str = new StringBuilder();
if (system != null && system.Length > 0) {
str.AppendFormat("System: {0}", system);
if (!string.IsNullOrEmpty(System)) {
str.AppendFormat("System: {0}", System);
}
if (station != null && station.Length > 0) {
if (!string.IsNullOrEmpty(Faction)) {
if (str.Length > 0) {
str.Append(", ");
}
str.AppendFormat("Station: {0}", station);
}
if (faction != null && faction.Length > 0) {
if (str.Length > 0) {
str.Append(", ");
}
str.AppendFormat("Faction: {0}", faction);
str.AppendFormat("Faction: {0}", Faction);
}
return str.ToString();
}
public string ToShortString() {
public string ToLocationString() {
StringBuilder str = new StringBuilder();
if (system != null && system.Length > 0) {
str.AppendFormat("{0}", system);
if (!string.IsNullOrEmpty(System)) {
str.AppendFormat("{0}", System);
}
if (station != null && station.Length > 0) {
if (!string.IsNullOrEmpty(Station)) {
if (str.Length > 0) {
str.Append(", ");
}
str.AppendFormat("{0}", station);
str.AppendFormat("{0}", Station);
}
return str.ToString();
}

View File

@@ -49,15 +49,33 @@ namespace EliteBGS.BGS {
;
}
public void Scan(PlayerJournal journal, DateTime start, DateTime end) {
var entries = from file in journal.Files
where file.NormalisedTimestamp >= start && file.NormalisedTimestamp <= end
select file.Entries
;
Scan(entries.SelectMany(x => x).ToList());
public void Scan(PlayerJournal journal, DateTime start, DateTime end, bool CollateEntries = true) {
/* Log files only get rotated if you restart the game client. This means that there might
* be - say - entries from the 4th of May in the file with a timestamp of 3rd of May. This
* happens if you happen to play a session late into the night.
* At first I tried extracting the first and last line of a file to see the date range, but
* if you have a lot of files this becomes quite slow, and quite the memory hog (as journal
* files have to be read in their entirety to check this). So we assume that you can't play
* three days straight, and keep the code fast.
*/
DateTime actualstart = start.AddDays(-3);
List<Entry> entries = journal.Files
.Where(f => f.NormalisedDateTime >= actualstart && f.NormalisedDateTime <= end)
.SelectMany(e => e.Entries)
.ToList()
;
// Now further sort the list down to entries that are actually within the given datetime
// Note that entry datetimes are not normalised, so we have to sort until end + 1 day
DateTime actualend = end.AddDays(1);
entries = entries
.Where(e => e.Timestamp >= start && e.Timestamp < actualend)
.ToList()
;
Scan(entries, CollateEntries);
}
public void Scan(List<Entry> entries) {
public void Scan(List<Entry> entries, bool CollateEntries = true) {
if (entries.Count <= 0) {
return;
}
@@ -180,7 +198,7 @@ namespace EliteBGS.BGS {
System = current_system,
Faction = faction,
});
collate = true;
collate = CollateEntries;
} else if (e.Is(Events.MissionCompleted)) {
MissionCompletedEntry completed = e as MissionCompletedEntry;
MissionAcceptedEntry accepted = null;
@@ -393,7 +411,7 @@ namespace EliteBGS.BGS {
/* Mission failed should be collated if they are in the same system/station
*/
collate = true;
collate = CollateEntries;
} else if (e.Is(Events.SellExplorationData)) {
results.Add(new Cartographics(e as SellExplorationDataEntry) {
System = current_system,
@@ -402,7 +420,7 @@ namespace EliteBGS.BGS {
});
/* colate single cartographic selling into one */
collate = true;
collate = CollateEntries;
} else if (e.Is(Events.SellOrganicData)) {
/* organic data sold to Vista Genomics */
results.Add(new OrganicData(e as SellOrganicDataEntry) {
@@ -411,7 +429,7 @@ namespace EliteBGS.BGS {
Faction = controlling_faction,
});
collate = true;
collate = CollateEntries;
} else if (e.Is(Events.MultiSellExplorationData)) {
/* For multi-sell-exploraton-data only the controlling faction of the station sold to matters.
*/
@@ -421,7 +439,7 @@ namespace EliteBGS.BGS {
Faction = controlling_faction
});
collate = true;
collate = CollateEntries;
} else if (e.Is(Events.RedeemVoucher)) {
RedeemVoucherEntry voucher = e as RedeemVoucherEntry;
List<Faction> current_factions = new List<Faction>();
@@ -452,7 +470,7 @@ namespace EliteBGS.BGS {
});
}
collate = true;
collate = CollateEntries;
} else if (e.Is(Events.SellMicroResources)) {
results.Add(new SellMicroResources(e as SellMicroResourcesEntry) {
Faction = controlling_faction,
@@ -472,7 +490,7 @@ namespace EliteBGS.BGS {
System = current_system,
});
collate = true;
collate = CollateEntries;
} else if (e.Is(Events.SearchAndRescue)) {
results.Add(new SearchAndRescue(e as SearchAndRescueEntry) {
Faction = controlling_faction,
@@ -480,7 +498,7 @@ namespace EliteBGS.BGS {
System = current_system,
});
collate = true;
collate = CollateEntries;
} else if (e.Is(Events.MarketSell)) {
MarketSellEntry sell = e as MarketSellEntry;
long profit = 0;

View File

@@ -1,180 +0,0 @@
using System;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace EliteBGS.EDDB {
public class API {
private static readonly string EDDB_SYSTEMS_ARCHIVE = "https://eddb.io/archive/v6/systems_populated.json";
private static readonly string EDDB_STATIONS_ARCHIVE = "https://eddb.io/archive/v6/stations.json";
private string cache_folder = null;
private string systems_file = null;
private string stations_file = null;
private string stations_file_short = null;
public delegate void DatabaseAvailableDelegate();
public delegate void DatabaseUpdateProgressDelegate();
public event DatabaseAvailableDelegate SystemsAvailable;
public event DatabaseAvailableDelegate StationsAvailable;
public event DatabaseUpdateProgressDelegate DatabaseUpdateProgress;
public event DatabaseUpdateProgressDelegate DatabaseUpdateFinished;
public string SystemsFile => systems_file;
public string StationsFile => stations_file;
public string StationsFileShort => stations_file_short;
public string Cache {
get => cache_folder;
set => cache_folder = value;
}
public API(string cache_folder) {
Initialise(cache_folder);
}
private void Initialise(string cache_folder) {
this.cache_folder = cache_folder;
systems_file = Path.Combine(this.cache_folder, "systems_populated.json");
stations_file = Path.Combine(this.cache_folder, "stations.json");
stations_file_short = Path.Combine(this.cache_folder, "stations_short.json");
this.StationsAvailable += API_StationsAvailable;
}
private void API_StationsAvailable() {
TranslateStations();
DatabaseUpdateFinished?.Invoke();
}
private void DownloadFile(string url, string file, DatabaseAvailableDelegate notifier) {
WebClient client = new WebClient();
client.DownloadFileCompleted += Client_DownloadFileCompleted;
client.DownloadProgressChanged += Client_DownloadProgressChanged;
client.DownloadFileAsync(new Uri(url), file, notifier);
}
private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
DatabaseUpdateProgress?.Invoke();
}
private void Client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) {
DatabaseAvailableDelegate notifier = e.UserState as DatabaseAvailableDelegate;
notifier?.Invoke();
}
private void TranslateStations() {
if (!HaveStationsFile) {
return;
}
var short_time = File.GetLastWriteTimeUtc(StationsFileShort);
var long_time = File.GetLastWriteTimeUtc(StationsFile);
if (HaveStationsFileShort && long_time <= short_time) {
return;
}
Dictionary<int, List<string>> systems = new Dictionary<int, List<string>>();
using (var str = new StreamReader(StationsFile)) {
using (var reader = new JsonTextReader(str)) {
JArray obj = (JArray)JToken.ReadFrom(reader);
foreach (JObject child in obj.Children<JObject>()) {
int system_id = child.Value<int>("system_id");
string name = child.Value<string>("name");
if (!systems.ContainsKey(system_id)) {
systems.Add(system_id, new List<string>());
}
DatabaseUpdateProgress?.Invoke();
systems[system_id].Add(name);
}
}
}
JObject short_stations = new JObject();
foreach(int ids in systems.Keys) {
JArray station_names = new JArray();
foreach(string system in systems[ids]) {
station_names.Add(system);
}
short_stations.Add(ids.ToString(), station_names);
}
using (var outstr = new StreamWriter(stations_file_short)) {
using (var jwriter = new JsonTextWriter(outstr)) {
short_stations.WriteTo(jwriter);
}
}
}
public void CheckDatabases() {
if (HaveSystemsFile) {
SystemsAvailable?.Invoke();
}
if (HaveStationsFile) {
StationsAvailable?.Invoke();
}
}
public void Download(bool force) {
if (!HaveSystemsFile || force) {
DownloadFile(EDDB_SYSTEMS_ARCHIVE, systems_file, SystemsAvailable);
} else if (HaveSystemsFile) {
SystemsAvailable?.Invoke();
}
if (!HaveStationsFile || force) {
DownloadFile(EDDB_STATIONS_ARCHIVE, stations_file, StationsAvailable);
} else if (HaveStationsFile) {
StationsAvailable?.Invoke();
}
}
public void Download() {
Download(false);
}
public bool HaveSystemsFile {
get { return systems_file != null && File.Exists(systems_file); }
}
public bool HaveStationsFile {
get { return stations_file != null && File.Exists(stations_file); }
}
public bool HaveStationsFileShort {
get { return stations_file_short != null && File.Exists(stations_file_short); }
}
public PopulatedSystems MakePopulatedSystems() {
if (!HaveSystemsFile) {
throw new InvalidOperationException("no local systems file downloaded");
}
return PopulatedSystems.FromFile(SystemsFile);
}
public Stations MakeStations() {
if (!HaveStationsFile) {
throw new InvalidOperationException("no local systems file downloaded");
}
TranslateStations();
return Stations.FromFile(StationsFileShort);
}
}
}

View File

@@ -1,71 +0,0 @@
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json.Linq;
namespace EliteBGS.EDDB {
public class PopulatedSystems {
private string json_file = null;
private JArray root = null;
private string[] system_names = null;
private Dictionary<string, int> to_id;
public static PopulatedSystems FromFile(string file) {
PopulatedSystems pop = new PopulatedSystems();
string content = File.ReadAllText(file);
pop.json_file = file;
pop.root = JArray.Parse(content);
pop.Initialise();
return pop;
}
private void Initialise() {
MakeSystemNames();
to_id = root.ToDictionary(x => x.Value<string>("name"), x => x.Value<int>("id"));
}
public int ToId(string name) {
return to_id.First(x => string.Compare(x.Key, name, true) == 0).Value;
}
private void MakeSystemNames() {
if (root == null) {
throw new InvalidDataException("no JSON loaded");
}
if (system_names != null && system_names.Length > 0) {
return;
}
var names = root.Children<JObject>().Select(x => x.Value<string>("name"));
system_names = names.ToArray();
}
public string[] SystemNames {
get {
MakeSystemNames();
return system_names;
}
}
public string[] SystemNamesByFilter(string filter) {
MakeSystemNames();
var culture = CultureInfo.InvariantCulture;
return system_names.Where(x => culture.CompareInfo.IndexOf(x, filter, CompareOptions.IgnoreCase) > -1)
.ToArray()
;
}
public string JSONFile {
get => json_file;
}
public JArray Root {
get => root;
}
}
}

View File

@@ -1,51 +0,0 @@
using System.Globalization;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Newtonsoft.Json.Linq;
namespace EliteBGS.EDDB {
public class Stations {
private JObject root = null;
private Dictionary<int, List<string>> by_system_id = null;
public JObject JSON => root;
private Stations() {
}
private void Initialise() {
by_system_id = new Dictionary<int, List<string>>();
foreach (var station in root.Properties()) {
int id = int.Parse(station.Name);
var names = root.Value<JArray>(id.ToString()).Values<string>().ToArray();
if (!by_system_id.ContainsKey(id)) {
by_system_id[id] = new List<string>();
}
by_system_id[id].AddRange(names);
}
}
public static Stations FromFile(string filename) {
string alltext = File.ReadAllText(filename);
Stations stations = new Stations {
root = JObject.Parse(alltext),
};
stations.Initialise();
return stations;
}
public string[] StationNamesBySystemId(int systemid, string filter) {
if (!by_system_id.ContainsKey(systemid)) {
return new string[0];
}
return by_system_id[systemid]
.Where(x => CultureInfo.InvariantCulture.CompareInfo.IndexOf(x, filter, CompareOptions.IgnoreCase) > -1)
.ToArray()
;
}
}
}

View File

@@ -41,9 +41,6 @@
<ApplicationIcon>EliteBGS.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="AutoCompleteTextBox, Version=1.1.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\AutoCompleteTextBox.1.1.1\lib\net472\AutoCompleteTextBox.dll</HintPath>
</Reference>
<Reference Include="EDJournal, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\edjournal\bin\Debug\EDJournal.dll</HintPath>
@@ -51,8 +48,8 @@
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Ookii.Dialogs.Wpf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=66aa232afad40158, processorArchitecture=MSIL">
<HintPath>packages\Ookii.Dialogs.Wpf.3.1.0\lib\net45\Ookii.Dialogs.Wpf.dll</HintPath>
<Reference Include="Ookii.Dialogs.Wpf, Version=5.0.0.0, Culture=neutral, PublicKeyToken=66aa232afad40158, processorArchitecture=MSIL">
<HintPath>packages\Ookii.Dialogs.Wpf.5.0.1\lib\net462\Ookii.Dialogs.Wpf.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
@@ -107,8 +104,6 @@
<Compile Include="BGS\SellCargo.cs" />
<Compile Include="BGS\SellMicroResources.cs" />
<Compile Include="BGS\FactionKillBonds.cs" />
<Compile Include="EDDB\PopulatedSystems.cs" />
<Compile Include="EDDB\Stations.cs" />
<Compile Include="LoadEntriesWindow.xaml.cs">
<DependentUpon>LoadEntriesWindow.xaml</DependentUpon>
</Compile>
@@ -117,14 +112,8 @@
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="UI\StationSuggestionProvider.cs" />
<Compile Include="UI\SystemSuggestionProvider.cs" />
<Compile Include="Util\AppConfig.cs" />
<Compile Include="Util\Config.cs" />
<Compile Include="EDDB\API.cs" />
<Compile Include="ProgressDialog.xaml.cs">
<DependentUpon>ProgressDialog.xaml</DependentUpon>
</Compile>
<Compile Include="CombatZoneDialog.xaml.cs">
<DependentUpon>CombatZoneDialog.xaml</DependentUpon>
</Compile>
@@ -155,10 +144,6 @@
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="ProgressDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="CombatZoneDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@@ -186,22 +171,26 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="docs\faq.md" />
<None Include="docs\index.md" />
<None Include="mkdocs.yml" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<None Include="README.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="docs\description.md" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="main-objectives.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Resource Include="main-page.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
<None Include="README.md">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="TestData\Mission-NoInfForSourceOrTarget.txt" />
<None Include="TestData\NoFactionName-AndNoInfluence.txt" />
<None Include="TestData\Mission-Failed.txt" />
@@ -212,19 +201,14 @@
<None Include="TestData\Double-5-Inf.txt" />
<None Include="TestData\SameInfTwice-Log.txt" />
<None Include="TestData\SameInfTwice.txt" />
<None Include="CHANGELOG.md">
<None Include="docs\CHANGELOG.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="main-entries.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="main-report.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Resource Include="docs\main-page.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
</ItemGroup>
<ItemGroup>
<Content Include="LICENCE.txt">
@@ -242,5 +226,6 @@
<ItemGroup>
<Resource Include="EliteBGS.ico" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -22,26 +22,14 @@
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ToolBar VerticalAlignment="Top" Grid.Row="0" Width="Auto" Grid.ColumnSpan="3" Height="Auto" Margin="0,0,0,0" HorizontalAlignment="Left">
<Label Content="System:" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<abc:AutoCompleteTextBox x:Name="system" VerticalAlignment="Center" MinWidth="120" MinHeight="22" KeyDown="Filter_KeyDown"/>
<Label Content="Station:" Height="26.2857142857143" VerticalAlignment="Top"/>
<abc:AutoCompleteTextBox x:Name="station" Margin="0" VerticalAlignment="Center" MinWidth="120" MinHeight="22" KeyDown="Filter_KeyDown" GotFocus="station_GotFocus"/>
<Label Content="Faction:" Height="26.2857142857143" VerticalAlignment="Top"/>
<abc:AutoCompleteTextBox x:Name="faction" Margin="0" VerticalAlignment="Center" MinWidth="120" MinHeight="22" KeyDown="Filter_KeyDown"/>
<Separator Height="26.2857142857143" Margin="0" VerticalAlignment="Top"/>
<Button x:Name="AddFilter" Content="Add Objective" VerticalAlignment="Stretch" Click="AddFilter_Click" Margin="0,0,0,0.286" RenderTransformOrigin="0.5,0.505"/>
<Separator Height="26.2857142857143" Margin="0" VerticalAlignment="Top"/>
<Button x:Name="AddCombatZone" Content="Add Combat Zone Win" VerticalAlignment="Stretch" Margin="0,0,0,0.286" RenderTransformOrigin="0.5,0.505" Click="AddCombatZone_Click"/>
<Separator Height="26.2857142857143" Margin="0" VerticalAlignment="Top"/>
<Button x:Name="AdjustProfit" Content="Adjust Trade Profit" Margin="0" VerticalAlignment="Stretch" Click="AdjustProfit_Click" />
</ToolBar>
<ToolBar VerticalAlignment="Top" Grid.Row="1" Width="Auto" Margin="0,0,0,0" Height="Auto" Grid.ColumnSpan="3" HorizontalAlignment="Left">
<Button x:Name="ParseJournal" Content="Parse Journal" VerticalAlignment="Center" Click="ParseJournal_Click" HorizontalAlignment="Center"/>
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
@@ -50,9 +38,15 @@
<Label Content="To:" Height="26.2857142857143" VerticalAlignment="Top"/>
<DatePicker x:Name="enddate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
<CheckBox x:Name="collate" Margin="1" Content="Collate entries" IsChecked="True" IsThreeState="False"/>
<Separator Height="26.2857142857143" Margin="0" VerticalAlignment="Top"/>
<Button x:Name="AddCombatZone" Content="Add Combat Zone Win" VerticalAlignment="Stretch" Margin="0,0,0,0.286" RenderTransformOrigin="0.5,0.505" Click="AddCombatZone_Click"/>
<Separator Height="26.2857142857143" Margin="0" VerticalAlignment="Top"/>
<Button x:Name="AdjustProfit" Content="Adjust Trade Profit" Margin="0" VerticalAlignment="Stretch" Click="AdjustProfit_Click" />
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
<Button x:Name="ManuallyParse" Content="Manually Parse JSON" Click="ManuallyParse_Click" />
</ToolBar>
<TreeView x:Name="entries" Margin="0,0,0,0" Grid.ColumnSpan="3" Grid.Row="2" KeyUp="entries_KeyUp">
<TreeView CheckBox.Checked="TreeView_CheckBox_Updated" CheckBox.Unchecked="TreeView_CheckBox_Updated" x:Name="entries" Margin="0,0,0,0" Grid.ColumnSpan="3" Grid.Row="2" KeyUp="entries_KeyUp">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type BGS:Objective}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
@@ -61,7 +55,11 @@
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate>
<TextBlock Text="{Binding Name}"/>
<StackPanel Orientation="Horizontal">
<CheckBox Focusable="False" IsChecked="{Binding IsEnabled}" VerticalAlignment="Center"/>
<TextBlock Text="{Binding CompletedAt}" Margin="5,0,5,0" HorizontalAlignment="Right"/>
<TextBlock Text="{Binding Name}" FontWeight="DemiBold"/>
</StackPanel>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
@@ -72,25 +70,12 @@
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Grid>
</TabItem>
<TabItem Header="Discord Report">
<Grid Background="#FFE5E5E5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="53*"/>
<ColumnDefinition Width="385*"/>
<ColumnDefinition Width="438*"/>
</Grid.ColumnDefinitions>
<ToolBar HorizontalAlignment="Left" Height="36" VerticalAlignment="Top" Width="Auto" Grid.ColumnSpan="2">
<ToolBar HorizontalAlignment="Left" Height="36" VerticalAlignment="Top" Width="Auto" Grid.Row="3" Grid.ColumnSpan="2">
<Button x:Name="GenerateDiscord" Content="Generate Discord Report" VerticalAlignment="Center" Margin="0,0,0,4.857" Click="GenerateDiscord_Click" Height="26"/>
<Separator />
<ComboBox x:Name="LogType" Height="36" Margin="0" VerticalAlignment="Center" Width="140" SelectionChanged="LogType_SelectionChanged" />
</ToolBar>
<TextBox x:Name="DiscordLog" Height="Auto" TextWrapping="Wrap" FontFamily="Consolas" FontSize="14" Grid.Row="1" Grid.ColumnSpan="3" AcceptsReturn="True" AcceptsTab="True"/>
<TextBox x:Name="DiscordLog" Height="Auto" TextWrapping="Wrap" FontFamily="Consolas" FontSize="14" Grid.Row="4" Grid.ColumnSpan="3" AcceptsReturn="True" AcceptsTab="True"/>
</Grid>
</TabItem>
<TabItem Header="Settings" HorizontalAlignment="Left" Height="20" VerticalAlignment="Top" Width="53.7142857142857">
@@ -120,20 +105,6 @@
<Button x:Name="browsejournallocation" Content="Browse" Grid.Row="1" Grid.Column="1" Margin="0,0,0,0" Width="Auto" VerticalAlignment="Top" HorizontalAlignment="Left" Click="browsejournallocation_Click"/>
</Grid>
</GroupBox>
<GroupBox Header="Online Services" Height="Auto" Margin="0,5,0,0" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" VerticalAlignment="Top">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox x:Name="useeddb" Content="Use eddb station and system data for autocompletion" HorizontalAlignment="Left" Margin="0,10,0,10" VerticalAlignment="Top" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="1" Click="useeddb_Click"/>
<Button x:Name="DownloadData" Content="Download Data" HorizontalAlignment="Center" Grid.Column="1" VerticalAlignment="Center" Width="Auto" Click="DownloadData_Click"/>
</Grid>
</GroupBox>
</Grid>
</TabItem>
<TabItem Header="Event Log" HorizontalAlignment="Left" Height="20" VerticalAlignment="Top">

View File

@@ -9,8 +9,6 @@ using Ookii.Dialogs.Wpf;
using EDJournal;
using EliteBGS.BGS;
using EliteBGS.Util;
using EliteBGS.UI;
using EliteBGS.EDDB;
namespace EliteBGS {
/// <summary>
@@ -20,16 +18,12 @@ namespace EliteBGS {
private PlayerJournal journal = null;
private Report report = new Report();
private Config config = new Config();
private API api = null;
private PopulatedSystems systems_db = null;
private Stations stations_db = null;
public Config Config => config;
public Report Report => report;
private LoadEntriesWindow loadentries = new LoadEntriesWindow();
private LoadEntriesWindow loadentries = null;
private static readonly List<DiscordLogGenerator> logtypes = new List<DiscordLogGenerator>() {
new NonaDiscordLog(),
@@ -45,8 +39,6 @@ namespace EliteBGS {
/* ignored */
}
loadentries.EntriesLoaded += Loadentries_EntriesLoaded;
report.OnLog += Report_OnLog;
foreach (DiscordLogGenerator type in logtypes) {
@@ -61,14 +53,12 @@ namespace EliteBGS {
LogType.SelectedIndex = 0;
}
api = new API(config.ConfigPath);
journal = new PlayerJournal(config.Global.JournalLocation);
// Set both to now
startdate.SelectedDate = DateTime.Now;
enddate.SelectedDate = DateTime.Now;
journallocation.Text = Config.Global.JournalLocation;
useeddb.IsChecked = Config.Global.UseEDDB;
try {
config.LoadObjectives(Report);
@@ -76,15 +66,10 @@ namespace EliteBGS {
} catch (Exception e) {
Log(e.Message);
}
}
api.SystemsAvailable += Api_SystemsAvailable;
api.StationsAvailable += Api_StationsAvailable;
try {
api.CheckDatabases();
} catch (Exception e) {
Log(e.Message);
}
private void TreeView_CheckBox_Updated(object sender, RoutedEventArgs args) {
GenerateLog();
}
private void Loadentries_EntriesLoaded(List<Entry> lines) {
@@ -98,23 +83,6 @@ namespace EliteBGS {
}
}
private void Api_StationsAvailable() {
try {
stations_db = api.MakeStations();
} catch (Exception e) {
Log(e.Message);
}
}
private void Api_SystemsAvailable() {
try {
systems_db = api.MakePopulatedSystems();
system.Provider = new SystemSuggestionProvider(systems_db);
} catch (Exception e) {
Log(e.Message);
}
}
private void Report_OnLog(string message) {
StringBuilder builder = new StringBuilder();
@@ -139,18 +107,20 @@ namespace EliteBGS {
foreach (Objective obj in report.Objectives) {
entries.Items.Add(obj);
obj.IsExpanded = obj.ManuallyAdded;
obj.IsEnabled = obj.ManuallyAdded;
obj.IsExpanded = obj.ManuallyAdded || obj.IsExpanded;
obj.IsEnabled = obj.ManuallyAdded || obj.IsEnabled;
}
}
private void ParseJournal_Click(object sender, RoutedEventArgs e) {
try {
bool collate = (this.collate.IsChecked ?? true);
journal.Open(); // Load all files
var start = startdate.SelectedDate ?? DateTime.Now;
var end = enddate.SelectedDate ?? DateTime.Now;
report.Scan(journal, start, end);
report.Scan(journal, start, end, collate);
RefreshObjectives();
GenerateLog();
} catch (Exception exception) {
Log("Something went terribly wrong while parsing the E:D player journal.");
Log("Please send this to CMDR Hekateh:");
@@ -158,29 +128,7 @@ namespace EliteBGS {
}
}
private void AddObjective() {
Objective objective = new Objective {
System = system.Text,
Faction = faction.Text,
Station = station.Text,
ManuallyAdded = true,
};
if (!objective.IsValid) {
return;
}
if (report.AddObjective(objective)) {
RefreshObjectives();
config.SaveObjectives(Report);
}
}
private void AddFilter_Click(object sender, RoutedEventArgs e) {
AddObjective();
}
private void GenerateDiscord_Click(object sender, RoutedEventArgs e) {
private void GenerateLog() {
try {
DiscordLogGenerator discord = LogType.SelectedItem as DiscordLogGenerator;
string report = discord.GenerateDiscordLog(Report);
@@ -193,6 +141,10 @@ namespace EliteBGS {
}
}
private void GenerateDiscord_Click(object sender, RoutedEventArgs e) {
GenerateLog();
}
private void RemoveCurrentObjective() {
if (entries.SelectedItem == null) {
return;
@@ -214,7 +166,7 @@ namespace EliteBGS {
if (removed) {
RefreshObjectives();
config.SaveObjectives(Report);
GenerateLog();
}
}
@@ -236,57 +188,43 @@ namespace EliteBGS {
journal = new PlayerJournal(config.Global.JournalLocation);
}
private void useeddb_Click(object sender, RoutedEventArgs e) {
Config.Global.UseEDDB = (bool)useeddb.IsChecked;
}
/// <summary>
/// Gets the currently selected objective, even if a log entry in said objective
/// is selected instead. If nothing is selected, returns null.
/// </summary>
/// <returns></returns>
private Objective GetSelectedObjective() {
var obj = entries.SelectedItem;
private void Filter_KeyDown(object sender, KeyEventArgs e) {
if (e.Key == Key.Enter) {
AddObjective();
}
}
private void station_GotFocus(object sender, RoutedEventArgs e) {
try {
if (stations_db == null || systems_db == null) {
return;
}
var sys = system.Text;
if (sys == null || sys.Length <= 0) {
return;
}
int system_id = systems_db.ToId(sys);
station.Provider = new StationSuggestionProvider(stations_db, system_id);
} catch (Exception exc) {
Log(exc.ToString());
}
}
private void DownloadData_Click(object sender, RoutedEventArgs e) {
if (!Config.Global.UseEDDB) {
return;
if (obj == null) {
return null;
}
ProgressDialog dialog = new ProgressDialog(api);
dialog.StartDownload();
dialog.ShowDialog();
if (obj.GetType() == typeof(Objective)) {
return obj as Objective;
}
// Some form of entry perhaps?
if (obj.GetType().IsSubclassOf(typeof(LogEntry))) {
LogEntry entry = obj as LogEntry;
Objective objective = entries.Items
.OfType<Objective>()
.First(x => x.LogEntries.Contains(entry))
;
return objective;
}
return null;
}
private void AddCombatZone_Click(object sender, RoutedEventArgs e) {
if (entries.SelectedItem == null) {
Objective objective = GetSelectedObjective();
if (objective == null) {
return;
}
var obj = entries.SelectedItem;
if (obj.GetType() != typeof(Objective)) {
return;
}
Objective objective = obj as Objective;
CombatZoneDialog dialog = new CombatZoneDialog() { Owner = this };
if (!(dialog.ShowDialog() ?? false)) {
@@ -306,6 +244,7 @@ namespace EliteBGS {
objective.LogEntries.Add(zone);
RefreshObjectives();
GenerateLog();
}
private void AdjustProfit_Click(object sender, RoutedEventArgs e) {
@@ -325,6 +264,7 @@ namespace EliteBGS {
if (int.TryParse(adjust.Profit.Text, out int newprofit)) {
sell.Profit = newprofit;
RefreshObjectives();
GenerateLog();
}
}
@@ -335,14 +275,28 @@ namespace EliteBGS {
string template = LogType.SelectedItem.ToString();
config.Global.LastUsedDiscordTemplate = template;
GenerateLog();
}
private void ManuallyParse_Click(object sender, RoutedEventArgs e) {
if (loadentries != null) {
loadentries.Show();
return;
}
loadentries = new LoadEntriesWindow();
loadentries.Closed += Loadentries_Closed;
loadentries.EntriesLoaded += Loadentries_EntriesLoaded;
loadentries.Show();
}
private void Loadentries_Closed(object sender, EventArgs e) {
loadentries = null;
}
private void window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
loadentries.Close();
loadentries?.Close();
loadentries = null;
}
}
}

View File

@@ -1,21 +0,0 @@
<Window x:Class="EliteBGS.ProgressDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:EliteBGS"
mc:Ignorable="d"
Title="Progress" Height="100" Width="450" Icon="EliteBGS.ico">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Content="Downloading EDDB databases might take a while, please be patient." Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Top"/>
<ProgressBar x:Name="progress" Height="25" Margin="10,10" Grid.Row="1" Grid.Column="0" VerticalAlignment="Top" Width="Auto" IsIndeterminate="True"/>
</Grid>
</Window>

View File

@@ -1,30 +0,0 @@
using System.Windows;
using EliteBGS.EDDB;
namespace EliteBGS {
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class ProgressDialog : Window {
private readonly API api = null;
public ProgressDialog(API api) {
InitializeComponent();
this.api = api;
this.api.DatabaseUpdateFinished += Api_DatabaseUpdateFinished;
this.api.DatabaseUpdateProgress += Api_DatabaseUpdateProgress;
}
private void Api_DatabaseUpdateProgress() {
progress.Value = (progress.Value + 1) % 100;
}
private void Api_DatabaseUpdateFinished() {
Close();
}
public void StartDownload() {
api.Download(true);
}
}
}

View File

@@ -51,5 +51,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.1.0.0")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyVersion("0.1.1.0")]
[assembly: AssemblyFileVersion("0.1.1.0")]

View File

@@ -11,17 +11,8 @@ Binary downloads can be found here: [https://bgs.n0la.org/](https://bgs.n0la.org
## How To
![Main Window Objectives](main-objectives.png)
Use the main tab to add objectives to the program. To do this, insert the system name,
faction, and, optionally, a station. Then press "Add Objective". Objectives can be deleted
by selecting them and pressing the "DEL" key. Manually added objectives like this are
enabled by default. You can always enable, and disable an objective by checking the box
next to its name. Disabled objectives are not included in the BGS discord log generation.
Once you have your objectives have been configured, you can press "Parse Journal", which
will check your Elite Dangerous player journal for completed missions. Currently the tool
recognises the following completed tasks:
Press "Parse Journal", which will check your Elite Dangerous player journal for completed
transactions. Currently the tool recognises the following transactions:
* Buying of cargo from stations (new in Update 10)
* Completed missions
@@ -72,19 +63,20 @@ you the bounty. And not the faction of the victim. The tool will look for an eve
scanned your victim, and gleem the victim's faction from that. If you did not scan your victim, then
sadly the tool cannot connect the victim's faction to the victim.
![Main Window with entries](main-entries.png)
![Main Window with entries](main-page.png)
The window will then list all the journal entries it has found, and group them by objectives. You
can remove individual entries (if you think the tool detected something you thought was wrong), by
selecting the entry, and pressing the "DEL" key.
can select which objectives you wish to report, by using the checkmarks.
Once you are satisfied with the result, move to "Discord Report" tab, select a template, and click
"Generate Report".
You can exclude a specific entry within an objective by deselecting the checkbox next to them.
This way said entry will not appear in the final log. You can also remove individual entries
(if you think the tool detected something you thought was wrong), by selecting the entry,
and pressing the "DEL" key.
![Generated Report](main-report.png)
Before you copy/paste it into the discord of your squadron, you should check the log. You can of
course edit it, if something is wrong or the tool itself missed something.
Once you are satisfied with the result, the discord report should be displayed below, ready to be
copy and pasted. Before you copy/paste it into the discord of your squadron, you should check the log.
You can of course edit it, if something is wrong or the tool itself missed something. If you want to
regenerate it, just click "Generate Log".
## Known Issues and Bugs
@@ -122,12 +114,9 @@ Please upvote the issue to get it fixed. Until then, you have to add combat zone
### On-Foot NPC givers
Also missions accepted from NPCs in Odyssey concourses do not get a player journal entry. This is
also an ommission from FDev:
* [https://issues.frontierstore.net/issue-detail/43586](https://issues.frontierstore.net/issue-detail/43586)
Until this is fixed, please edit the resulting BGS log text, and manually add such entries.
Up until update 13 missions accepted from NPCs in Odyssey concourses do not get a player journal entry.
This has been fixed in update 13. Any on foot missions from NPCs accepted before update 13, do not have
an entry in the player journal.
### Failed vs. Abandoned Missions
@@ -220,15 +209,6 @@ decide whether it was because of an election, or not.
Future tool versions should probably take faction states into account in such matters.
## Use EDDB information
EliteBGS can download information from EDDB to auto complete system and station names. You can
enable its use in the "Settings". Once enabled, you must also press "Download", to download and
process the current version of the EDDB database.
Please note that the database is rather large (>200 MB), and processing it takes some time. It is
best if you don't use this feature if you are on a slow or metered internet connection.
## Nothing's Perfect
The tool itself is still a work in progress, and it might miss something. If you think the tool

View File

@@ -1,19 +0,0 @@
using System.Collections;
using AutoCompleteTextBox.Editors;
using EliteBGS.EDDB;
namespace EliteBGS.UI {
public class StationSuggestionProvider : ISuggestionProvider {
private int system_id = 0;
private Stations stations = null;
public StationSuggestionProvider(Stations stations, int system_id) {
this.system_id = system_id;
this.stations = stations;
}
public IEnumerable GetSuggestions(string filter) {
return stations.StationNamesBySystemId(system_id, filter);
}
}
}

View File

@@ -1,23 +0,0 @@
using System;
using System.Collections;
using AutoCompleteTextBox.Editors;
using EliteBGS.EDDB;
namespace EliteBGS.UI {
public class SystemSuggestionProvider : ISuggestionProvider {
private PopulatedSystems systems = null;
public SystemSuggestionProvider(PopulatedSystems systems) {
this.systems = systems;
}
public PopulatedSystems Data {
get => systems;
set => systems = value;
}
public IEnumerable GetSuggestions(string filter) {
return systems.SystemNamesByFilter(filter);
}
}
}

View File

@@ -4,19 +4,10 @@ namespace EliteBGS.Util {
public class AppConfig : INotifyPropertyChanged {
private static readonly string default_journal_location = "%UserProfile%\\Saved Games\\Frontier Developments\\Elite Dangerous";
private string journal_location = default_journal_location;
private bool useeddb = false;
private string lastdiscordlog;
public string DefaultJournalLocation => default_journal_location;
public bool UseEDDB {
get => useeddb;
set {
useeddb = value;
FirePropertyChanged("UseEDDB");
}
}
public string LastUsedDiscordTemplate {
get => lastdiscordlog;
set {

View File

@@ -1,5 +1,56 @@
# EliteBGS changelog
## 0.1.7 on 09.11.2022
* Fixed a bug related to total amount of credits gained by turning in organic data.
* Changed UI to have report, and objectives on the same page.
* Report now automatically updates when objectives and entries are selected, deselected or removed.
* Removed manual adding of objectives.
## 0.1.6 on 24.09.2022
* Fixed datetime format.
## 0.1.5 on 24.08.2022
* Added some mission names.
* Updated README regarding Update 13.
## 0.1.4 on 24.07.2022
* Fixed hour display with entires (now in 24 hour format).
* Allow adding combat zones regardless of whether an objective is selected, or an
entry. If an entry is selected simply use its objective instead.
* Add timestamp to combat zone wins.
## 0.1.3 on 07.06.2022
* Fixed a bug where entries in non-rated journal files were not properly picked up.
* Remove EDDB database usage. This feature could block the tool if it failed to convert
the JSON to something more usable, downloads took forever, and the tool itself could
run out of memory loading and converting JSON from EDDB. With automatic objective
detection this tool is no longer really needed.
## 0.1.2 on 06.04.2022
* If you remove an item the tree items stay collapsed/expanded. (thanks CMDR NeedX).
* Fixed a bug where the program would crash if you opened the manual log entry
window twice (thanks CMDR NeedX).
* Fixed a bug regarding organic data not being properly recognised in logs.
* Date and time when the entry has been added to the overview.
* The actual entry is now semi-bold to distinguish it from the date time.
* You can now select which item should appear in the final log, and which shouldn't.
## 0.1.1 on 15.03.2022
* Update tool to work with the new journal filenames introduced in Update 11.
## 0.1.0 on 27.02.2022
* Final release without beta in front of it.
* Several new mission names for the XML.
* A few small fixes towards the Discord log formatting.
## 0.1.0-beta14 on 26.02.2022
* Missions that give out no influence whatsoever apparently exist. Here the strategy

232
docs/description.md Normal file
View File

@@ -0,0 +1,232 @@
# EliteBGS
This tool is meant to help people contributing to the BGS effort to create BGS reports.
The tool allows you to configure BGS objectives, and will then parse your player journal
for tasks you completed relating to that BGS objective. Once the JSON player journal has
been parsed, you may then generate a BGS report you can copy/paste into Discord.
Source code is available [here](https://git.aror.org/florian/elitebgs).
Binary downloads can be found here: [https://bgs.n0la.org/](https://bgs.n0la.org/).
## How To
Press "Parse Journal", which will check your Elite Dangerous player journal for completed
missions. Currently the tool recognises the following completed tasks:
* Buying of cargo from stations (new in Update 10)
* Completed missions
* Failed missions
* Murders
* Search and Rescue contributions
* Selling cartography data
* Selling of cargo to stations
* Selling of micro resources (Odyssey only)
* Selling of organic data (Odyssey only)
* Vouchers, including bounty vouchers, combat bonds, and settlement vouchers (aka intel packages)
Vouchers help the faction that is listed for them. If said faction is not present in the
current system, then there is no BGS impact. So the tool looks for all system factions, and
makes sure that your vouchers actually have a BGS impact, otherwise it won't list them.
Selling cargo attempts to discern the profit and/or loss, which is helpful to gauge BGS
impact. But the player journal does not tell the amount of profit in the sell message.
So the tool looks for a buy a message related to the same commodity, and calculates loss
and/or profit from that. If the buy of the commodity is not within the time and date range,
or some other shenanigans happen that the tool does not yet support, the profit/loss could
be wrong. You can use the "Adjust Trade Profit" button to manually adjust the trade profit,
or you could simply edit the discord log manually.
Please note that cartography data, and micro resources only help the controlling faction
of a station. The tool is clever enough to exclude these if the station you turn them in at, is not
controlled by the faction you specified in the objective.
Some missions may show up having zero influence for the given faction. This happens if you do
missions for a faction which is currently in an election state. You do not gain influence for
the faction so the influence reads as zero. But you contribute towards the election, so the
missions are selected anyway.
There is no entry in the journal if you win a combat zone. So you have to add those manually. Select
an objective for which you wish to log a combat zone. The faction in the objective, must be the
faction you fought for in the combat zone. Then click "Add Combat Zone Win". Select type,
either "On Foot" for Odyssey, or "Ship" for regular ones. Then select the grade (low, medium or
high), and how many you won. Then press "Accept". Select "Cancel" to abort. You can of course remove
the combat zone entries by selecting them, and pressing "DEL".
If you deliberately fail a mission (to log negative INF towards a faction), the tool cannot detect
it, if the day you accepted the mission is outside of the given date range. It needs the journal
entry where you accept the mission to connect the mission to a faction, system and station. The tool
will warn you if this happens, with a message in the error log in the fourth tab.
When committing murder, the journal entry contains the faction information of the faction that gave
you the bounty. And not the faction of the victim. The tool will look for an event in which you
scanned your victim, and gleem the victim's faction from that. If you did not scan your victim, then
sadly the tool cannot connect the victim's faction to the victim.
![Main Window with entries](main-page.png)
The window will then list all the journal entries it has found, and group them by objectives. You
can select which objectives you wish to report, by using the checkmarks.
You can exclude a specific entry within an objective by deselecting the checkbox next to them.
This way said entry will not appear in the final log. You can also remove individual entries
(if you think the tool detected something you thought was wrong), by selecting the entry,
and pressing the "DEL" key.
Once you are satisfied with the result, you can copy and paste the final report to the discord
server of your choice. Before you copy/paste it into the discord of your squadron, you should
check the log. You can of course also edit it, either if something is wrong because the tool
missed something, or you just wish to add a note the report itself.
If you wish to regenerate the discord log, simply click "Generate Log".
## Known Issues and Bugs
### Settlement Vouchers
Settlement vouchers (aka Intel Packages) help every faction aligned with the given superpower.
So if you turn in an Imperial intel package on an imperial station, all factions aligned with
the Empire will gain a bit of INF boost. The tool currently cannot handle that. All intel packages
are displayed instead.
### Bugged bounty vouchers
Sometimes bounty vouchers are not properly recognised. This is a bug in the player journal, where
the faction information is not properly written out in the journal:
```
{
"timestamp":"2021-10-07T14:57:50Z", "event":"RedeemVoucher",
"Type":"bounty", "Amount":20750,
"Factions":[ { "Faction":"", "Amount":500 }, { "Faction":"", "Amount":20250 }]
}
```
Since the tool does not know for which faction these bounties were redeemed for, it cannot assign
it to an objective.
### Combat Zones
The player journal currently does not make an entry when you win or lose a combat zone. This is a
an ommission from FDev:
* [https://issues.frontierstore.net/issue-detail/43509](https://issues.frontierstore.net/issue-detail/43509)
Please upvote the issue to get it fixed. Until then, you have to add combat zone wins manually.
### On-Foot NPC givers
Up until update 13 missions accepted from NPCs in Odyssey concourses do not get a player journal entry.
This has been fixed in update 13. Any on foot missions from NPCs accepted before update 13, do not have
an entry in the player journal.
### Failed vs. Abandoned Missions
The tool also currently cannot differentiate between missions you have abandoned in the transaction
tab before it was completed, and those that you have failed - either delibaretly or by time-out. So
it will find and add them all, and you simply can remove those that you have abandoned manually.
### Influence given to empty/non-existent faction
Sometimes the log will state that it gave positive or negative influence to a faction, but the
faction name is empty:
```
"FactionEffects": [
{
"Faction": "",
"Effects": [
{
"Effect": "$MISSIONUTIL_Interaction_Summary_EP_down;",
"Effect_Localised": "The economic status of $#MinorFaction; has declined in the $#System; system.",
"Trend": "DownBad"
}
],
"Influence": [
{
"SystemAddress": 251012319587,
"Trend": "DownBad",
"Influence": "+"
}
],
"ReputationTrend": "DownBad",
"Reputation": "+"
}
]
```
This happens for example if you do a scan/heist mission from a surface POI, but no one owns said
surface POI. Randomly generated surface POIs sometimes have no owner, and said non-existant owner
then gets the negative influence.
### Mission Completed but no one gains influence
Sometimes missions are completed but no one gains any influence:
```
{
"timestamp": "2022-02-25T21:30:45Z",
"event": "MissionCompleted",
"Faction": "Social LHS 6103 Confederation",
"Name": "Mission_Courier_Elections_name",
"MissionID": 850025233,
"TargetFaction": "Delphin Blue Federal PLC",
"DestinationSystem": "Delphin",
"DestinationStation": "Aristotle Orbital",
"Reward": 122300,
"FactionEffects": [
{
"Faction": "Social LHS 6103 Confederation",
"Effects": [
{
"Effect": "$MISSIONUTIL_Interaction_Summary_EP_up;",
"Effect_Localised": "The economic status of $#MinorFaction; has improved in the $#System; system.",
"Trend": "UpGood"
}
],
"Influence": [],
"ReputationTrend": "UpGood",
"Reputation": "+"
},
{
"Faction": "Delphin Blue Federal PLC",
"Effects": [],
"Influence": [],
"ReputationTrend": "UpGood",
"Reputation": "+"
}
]
}
```
Here the is known that at the time of completion the Confederation was in an Election and could not
have gained any influence regardless. It is unclear whether this also holds true for Delphin Blue
Federal PLC. So to be save, the tool assumes that if no influence was gained for the source faction,
it still has to make an entry for the source system. The same applies for the target faction: if no
influence is gained for the target faction, still add an entry for the target faction in the missions
target system.
Since it is not possible to differentiate between missions that give no influence no matter what, and
no influence gained because of an election, we have to assume it *gave* influence and let the user
decide whether it was because of an election, or not.
Future tool versions should probably take faction states into account in such matters.
## Nothing's Perfect
The tool itself is still a work in progress, and it might miss something. If you think the tool
missed a task you have done, please contact `Hekateh` on the Elite Dangerous community discord.
It would be helpful if you included the JSON player journal. This player journal can be found here:
```
%userprofile%\saved Games\Frontier Developments\Elite Dangerous\
```
## Build Dependencies
Handling of Elite Dangerous player journals have been moved to a separate project called `EDJournal`.
Its source can be found [here](https://git.aror.org/florian/edjournal). This project simply depends
on the binary DLL that `EDJournal` builds.
The project also requires `Ookii.Dialogs.WPF` controls, which contains the auto complete text box.
And of course, `Newtonsoft.Json` as the JSON parser.

94
docs/faq.md Normal file
View File

@@ -0,0 +1,94 @@
## FAQ
Most frequently asked questions:
### Windows complains that it does not wish to run the application, what gives?
The tool contains no viruses, but it is not seen as "trustworthy". You can however
right-click EliteBGS.exe and "Unblock" the application.
### Does this work for console players?
Sorry, no. Console players don't have a player journal per se, and the tool does
not support Frontier Commander API.
### Why won't the tool start anymore?
Open the file explorer, and go to the path `%AppData%`. Once there, delete the
folder called `EliteBGS` to delete the tool's configuration and cache. If it
still doesn't work, contact me directly.
### I pressed 'Download Data' and it is hanging now and won't respond. Help?
Go and delete the `EliteBGS` folder as described above to undo that action.
Also please upgrade to version 0.1.3, where this feature was removed for
exactly this reason.
### Why is it unable to find my player journal?
Usually your player journal lives in the Saved Games folder in your home
directory. If, for some reason, this doesn't match up, you can point the
tool towards your player journal in the third tab.
### Why do some of the objective not show up in the final discord log?
Only objectives with the little checkbox enabled show up there. Those
that the tool generates by itself are not enabled per default.
### Can I delete an objective or an entry?
Click on an objective or entry and press the Delete key.
### I deleted something I didn't want to. What now?
Just press "Parse Journal" again, and the tool will generate all
the entries again.
### What are micro resources?
Odyssey cargo that you sell at the bartender. Just like normal cargo,
they aid the controlling faction of the station where you sold them.
### Why are missions accepted in a concourse or in a settlement from an NPC missing?
Because up until Update 13, they did not show up in player journal. This should
now be fixed.
### Some mission names are weird. What gives?
That's because the tool uses the game generated mission name, if it doesn't
have a clean and nice mission name on file for the certain mission type. The
fourth tab "Event Log" should have an entry about it, so please post those
names into this channel.
### Some missions say they have 0 influence?
That happens for missions that aid an Election. The faction in question does
not gain influence during an election, as influence is locked during conflicts.
But since you are contributing towards the election win of that faction,
the tool picks them anyway.
### Why are some failed missions not showing up?
The time span you specify must include the day where you accepted the mission,
as well as the day where you failed the mission. Otherwise the tool cannot handle
that failed mission.
### The tool complains about missing factions for an NPC I murdered.
The player journal only tells the faction that issued the bounty upon murder, and
not the faction of the NPC killed. The tool has to fetch that from you scanning the
hip. If you didn't fully scan the ship before murdering it, the tool won't know
the faction of the NPC.
### Why does cartography data, and sold cargo show up for the wrong faction, but for the right station/system?
Because they only aid the controlling faction of the station.
### Why are some of my bounty vouchers missing?
Sometimes, due to a bug, the bounty vouchers in the journal have no faction information
associated with them. Here the tool simply cannot associate the vouchers to a faction
or station. If you are sure they aided in BGS, simply add them by editing the Discord
report.

69
docs/index.md Normal file
View File

@@ -0,0 +1,69 @@
# EliteBGS
EliteBGS is a Windows desktop application, that helps you sum up your BGS related actions.
It then creates a report from your actions, so you can post it your Squadron's discord.
## Origins
The tool originated from the [Nova Navy](https://inara.cz/elite/squadron/5058/), which required
BGS contributions to be posted to the Navy's discord, in a very specific format. Writing those
logs manually was a lot of work, so CMDR Hekateh created a tool to automate this process.
## Overview
EliteBGS reads through your player journal for BGS relevant activity, and sorts them into
"categories". These are based upon the star system, station and the faction for which the
action was taken. So for example if you contributed bounty vouchers for Nova Paresa in
Paresa, but also did some missions for Nova Paresa in Adachit, those actions will be
split into two categories.
You can then select which of the two actions goes into the final log.
### What it detects:
* Buying of cargo from stations (BGS relevant since Update 10)
* Completed missions
* Failed missions
* Murders
* Search and Rescue contributions
* Selling cartography data
* Selling of cargo to stations
* Selling of micro resources (Odyssey only)
* Selling of organic data (Odyssey only)
* Vouchers, including bounty vouchers, combat bonds, and settlement vouchers (aka intel packages)
### What it does not detect:
* Combat zone wins, and its objectives
* Megaship scenarios
* On foot missions accepted by NPCs in stations (pre Update 13)
* Murders of NPCs you haven't fully scanned
## Open Source
The tool itself is Open Source, licenced unter the GPLv3.
The source code can be found here:
* [https://git.aror.org/florian/EliteBGS](https://git.aror.org/florian/EliteBGS)
It requires a separate library, called EDJournal, which is also open source:
* [https://git.aror.org/florian/edjournal](https://git.aror.org/florian/edjournal)
## Downloads
The latest version of EliteBGS **0.1.7** is available for download here:
* [https://bgs.n0la.org/elitebgs-0.1.7.zip](https://bgs.n0la.org/elitebgs-0.1.7.zip)
Older versions are available in the archive:
* [https://bgs.n0la.org/archive/](https://bgs.n0la.org/archive/)
## Contact
I can be reached over discord: `nola#2457`
Or by joining either the [Salus Invicta](https://discord.com/invite/FeEtjqBRkg) or the
[Nova Navy](https://discord.gg/WEJeFQw) discord.

BIN
docs/main-page.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

BIN
main-page.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

14
mkdocs.yml Normal file
View File

@@ -0,0 +1,14 @@
site_name: EliteBGS
markdown_extensions:
- pymdownx.snippets:
check_paths: true
theme:
name: lumen
nav:
- Overview: 'index.md'
- "Detailed Description": 'description.md'
- FAQ: 'faq.md'
- Changelog: 'CHANGELOG.md'

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoCompleteTextBox" version="1.1.1" targetFramework="net472" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net472" />
<package id="Ookii.Dialogs.Wpf" version="3.1.0" targetFramework="net472" />
<package id="Ookii.Dialogs.Wpf" version="5.0.1" targetFramework="net472" />
</packages>