Compare commits
59 Commits
6f9d3a64ff
...
0.2.6
| Author | SHA1 | Date | |
|---|---|---|---|
| 29dc6e9cba | |||
| aeb16c675b | |||
| 00f94ef939 | |||
| 785efad4c0 | |||
| 3a968a7c55 | |||
| 44d5a2b91c | |||
| 69b6e8b306 | |||
| 3bfe599c11 | |||
| 0b47b7331e | |||
| 2fae724bd2 | |||
| 132d090fd5 | |||
| 9d686bea61 | |||
| 78c2636a40 | |||
| 4549413b00 | |||
| f32f1f7dff | |||
| 86f2356f35 | |||
| 6608f33d8d | |||
| 42987cdb12 | |||
| 4f6376d39b | |||
| 273d151358 | |||
| a9ce5be266 | |||
| 3bd0cc1055 | |||
| 1d1ea3f5ef | |||
| b12ab287b6 | |||
| 9deafa6653 | |||
| efbbaa8abf | |||
| b96e40299d | |||
| 194add4436 | |||
| 02286e19a8 | |||
| b4e6b1b46c | |||
| e9b79a8c7a | |||
| 86d27fb2a3 | |||
| 271b151a72 | |||
| e75e0773fd | |||
| ba9b108e5e | |||
| 93a76bc429 | |||
| 0cb8641056 | |||
| c2082df6f1 | |||
| 65d12cb052 | |||
| 44410e86c8 | |||
| 5c7580a3c0 | |||
| f0692c3936 | |||
| a181a3cdd2 | |||
| 40d93e7c84 | |||
| db192748b0 | |||
| a43ade2f3c | |||
| a6b16fd5b8 | |||
| 99373b47c0 | |||
| f5f85586ec | |||
| ba4936ccb0 | |||
| 44774c5cad | |||
| 8d3d48d846 | |||
| a3b54b1326 | |||
| bf43262a8e | |||
| ef8e71cd8a | |||
| bd0d5cf0b6 | |||
| 365c34bdb0 | |||
| 7fa19c0733 | |||
| ea07c4dbcb |
@@ -9,6 +9,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EDPlayerJournalTests", "EDP
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EliteBGS", "EliteBGS\EliteBGS.csproj", "{14B03115-B9D5-4006-A993-9A5069BB172E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1381D5DE-139E-4FEC-BDC4-A3FDADEAEE5C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace EDPlayerJournal.BGS;
|
||||
using EDPlayerJournal.Entries;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
public class IncompleteTransaction : Transaction {
|
||||
public Transaction? UnderlyingTransaction { get; set; } = null;
|
||||
@@ -6,8 +8,9 @@ public class IncompleteTransaction : Transaction {
|
||||
|
||||
public IncompleteTransaction() { }
|
||||
|
||||
public IncompleteTransaction(Transaction? underlying, string reason) {
|
||||
public IncompleteTransaction(Transaction? underlying, string reason, Entry entry) {
|
||||
UnderlyingTransaction = underlying;
|
||||
Reason = reason;
|
||||
Entries.Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,16 +17,16 @@ public class InfluenceSupport : Transaction {
|
||||
public MissionCompletedEntry? RelevantMission { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Mission accepted entry
|
||||
/// Mission information
|
||||
/// </summary>
|
||||
public MissionAcceptedEntry? AcceptedEntry { get; set; }
|
||||
public Mission? Mission { get; set; }
|
||||
|
||||
public override string CompletedAt {
|
||||
public override DateTime? CompletedAtDateTime {
|
||||
get {
|
||||
if (RelevantMission == null) {
|
||||
return "";
|
||||
return null;
|
||||
}
|
||||
return RelevantMission.Timestamp.ToString("dd.MM.yyyy hh:mm UTC");
|
||||
return RelevantMission.Timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,14 +9,16 @@ public class MissionCompleted : Transaction {
|
||||
|
||||
public MissionAcceptedEntry? AcceptedEntry { get; set; }
|
||||
|
||||
public Mission? Mission { get; set; }
|
||||
|
||||
public MissionCompleted() { }
|
||||
|
||||
public override string CompletedAt {
|
||||
public override DateTime? CompletedAtDateTime {
|
||||
get {
|
||||
if (CompletedEntry == null) {
|
||||
return "";
|
||||
return null;
|
||||
}
|
||||
return CompletedEntry.Timestamp.ToString("dd.MM.yyyy HH:mm UTC");
|
||||
return CompletedEntry.Timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,15 +47,13 @@ public class MissionCompleted : Transaction {
|
||||
/// </summary>
|
||||
public override bool SystemContribution {
|
||||
get {
|
||||
if (AcceptedEntry == null ||
|
||||
AcceptedEntry.Mission == null ||
|
||||
AcceptedEntry.Mission.Name == null) {
|
||||
if (Mission == null || Mission.Name == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the mission starts with the name for thargoid war mission
|
||||
// names, we assume its a system contribution
|
||||
if (AcceptedEntry.Mission.Name.Contains("Mission_TW_")) {
|
||||
if (Mission.Name.Contains("Mission_TW_")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,16 +4,13 @@ using EDPlayerJournal.Entries;
|
||||
namespace EDPlayerJournal.BGS;
|
||||
public class MissionFailed : Transaction {
|
||||
public MissionFailedEntry? Failed { get; set; }
|
||||
public MissionAcceptedEntry? Accepted { get; set; }
|
||||
public Mission? Mission { get; set; }
|
||||
|
||||
public MissionFailed() { }
|
||||
|
||||
public MissionFailed(MissionAcceptedEntry accepted) {
|
||||
if (accepted.Mission == null) {
|
||||
throw new Exception("Mission cannot be null");
|
||||
}
|
||||
Accepted = accepted;
|
||||
Faction = accepted.Mission.Faction;
|
||||
public MissionFailed(MissionFailedEntry failed) {
|
||||
Entries.Add(failed);
|
||||
Failed = failed;
|
||||
}
|
||||
|
||||
public override int CompareTo(Transaction? other) {
|
||||
@@ -39,20 +36,15 @@ public class MissionFailed : Transaction {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int Amount {
|
||||
get { return Entries.Count + 1; }
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (Failed == null || Accepted == null) {
|
||||
if (Failed == null || Mission == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
builder.AppendFormat("{0}x Mission failed: \"{1}\"",
|
||||
Amount,
|
||||
Failed?.Mission?.FriendlyName
|
||||
builder.AppendFormat(" Mission failed: \"{0}\"",
|
||||
Mission?.FriendlyName
|
||||
);
|
||||
|
||||
return builder.ToString();
|
||||
|
||||
@@ -1,666 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using EDPlayerJournal.Entries;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
public class Report {
|
||||
private List<Objective> objectives = new List<Objective>();
|
||||
|
||||
public delegate void OnLogDelegate(string log);
|
||||
|
||||
public event OnLogDelegate? OnLog;
|
||||
|
||||
public List<Objective> Objectives {
|
||||
get { return objectives; }
|
||||
set { objectives = value; }
|
||||
}
|
||||
|
||||
public bool AddObjective(Objective objective) {
|
||||
var found = objectives.Find(x => x.CompareTo(objective) == 0);
|
||||
bool added = false;
|
||||
|
||||
if (found == null) {
|
||||
objectives.Add(objective);
|
||||
added = true;
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
public static bool IsRelevant(Entry e) {
|
||||
return e.Is(Events.CommitCrime) ||
|
||||
e.Is(Events.Docked) ||
|
||||
e.Is(Events.FactionKillBond) ||
|
||||
e.Is(Events.FSDJump) ||
|
||||
e.Is(Events.Location) ||
|
||||
e.Is(Events.MarketBuy) ||
|
||||
e.Is(Events.MarketSell) ||
|
||||
e.Is(Events.MissionAccepted) ||
|
||||
e.Is(Events.MissionFailed) ||
|
||||
e.Is(Events.MultiSellExplorationData) ||
|
||||
e.Is(Events.RedeemVoucher) ||
|
||||
e.Is(Events.SearchAndRescue) ||
|
||||
e.Is(Events.SellExplorationData) ||
|
||||
e.Is(Events.SellMicroResources) ||
|
||||
e.Is(Events.SellOrganicData) ||
|
||||
e.Is(Events.ShipTargeted) ||
|
||||
e.Is(Events.MissionCompleted)
|
||||
;
|
||||
}
|
||||
|
||||
public void Scan(PlayerJournal journal, DateTime start, DateTime end) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
public void Scan(List<Entry> entries) {
|
||||
if (entries.Count <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Entry> relevant = entries
|
||||
.Where(x => IsRelevant(x))
|
||||
.ToList()
|
||||
;
|
||||
|
||||
Dictionary<ulong, MissionAcceptedEntry> acceptedMissions = new Dictionary<ulong, MissionAcceptedEntry>();
|
||||
Dictionary<string, long> buyCost = new Dictionary<string, long>();
|
||||
Dictionary<ulong, string> systems = new Dictionary<ulong, string>();
|
||||
Dictionary<string, string> npcfactions = new Dictionary<string, string>();
|
||||
Dictionary<string, List<Faction>> system_factions = new Dictionary<string, List<Faction>>();
|
||||
|
||||
// A dictionary resolving to a station at which each mission was accepted
|
||||
Dictionary<ulong, string> acceptedStations = new Dictionary<ulong, string>();
|
||||
// A dictionary resolving to a system at which each mission was accepted
|
||||
Dictionary<ulong, ulong> acceptedSystems = new Dictionary<ulong, ulong>();
|
||||
|
||||
string? current_system = null;
|
||||
ulong? current_system_address = null;
|
||||
string? current_station = null;
|
||||
string? controlling_faction = null;
|
||||
|
||||
objectives.ForEach(x => x.Clear());
|
||||
|
||||
foreach (Entry e in relevant) {
|
||||
List<Transaction> results = new List<Transaction>();
|
||||
bool collate = false;
|
||||
|
||||
if (e.Is(Events.Docked)) {
|
||||
DockedEntry? docked = e as DockedEntry;
|
||||
if (docked == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* gleem the current station from this message
|
||||
*/
|
||||
current_station = docked.StationName;
|
||||
current_system = docked.StarSystem;
|
||||
controlling_faction = docked.StationFaction;
|
||||
current_system_address = docked.SystemAddress;
|
||||
|
||||
if (current_system_address != null && current_system != null) {
|
||||
if (!systems.ContainsKey(current_system_address.Value)) {
|
||||
systems.Add(current_system_address.Value, current_system);
|
||||
}
|
||||
}
|
||||
} else if (e.Is(Events.FSDJump)) {
|
||||
/* Gleem current system and controlling faction from this message.
|
||||
*/
|
||||
FSDJumpEntry? fsd = e as FSDJumpEntry;
|
||||
|
||||
if (fsd == null || fsd.StarSystem == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
current_system_address = fsd.SystemAddress;
|
||||
current_system = fsd.StarSystem;
|
||||
controlling_faction = fsd.SystemFaction;
|
||||
|
||||
if (!systems.ContainsKey(fsd.SystemAddress)) {
|
||||
systems.Add(fsd.SystemAddress, fsd.StarSystem);
|
||||
}
|
||||
|
||||
if (!system_factions.ContainsKey(fsd.StarSystem) &&
|
||||
fsd.SystemFactions.Count > 0) {
|
||||
system_factions[fsd.StarSystem] = fsd.SystemFactions;
|
||||
}
|
||||
} else if (e.Is(Events.Location)) {
|
||||
/* Get current system, faction name and station from Location message
|
||||
*/
|
||||
LocationEntry? location = e as LocationEntry;
|
||||
|
||||
if (location == null || location.StarSystem == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
current_system = location.StarSystem;
|
||||
current_system_address = location.SystemAddress;
|
||||
|
||||
if (!systems.ContainsKey(location.SystemAddress)) {
|
||||
systems.Add(location.SystemAddress, location.StarSystem);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(location.SystemFaction)) {
|
||||
controlling_faction = location.SystemFaction;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(location.StationName)) {
|
||||
current_station = location.StationName;
|
||||
}
|
||||
|
||||
if (!system_factions.ContainsKey(location.StarSystem) &&
|
||||
location.SystemFactions.Count > 0) {
|
||||
system_factions[location.StarSystem] = location.SystemFactions;
|
||||
}
|
||||
} else if (e.Is(Events.ShipTargeted)) {
|
||||
ShipTargetedEntry? targeted = e as ShipTargetedEntry;
|
||||
|
||||
if (targeted == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(targeted.PilotNameLocalised) ||
|
||||
string.IsNullOrEmpty(targeted.Faction)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
npcfactions[targeted.PilotNameLocalised] = targeted.Faction;
|
||||
} else if (e.Is(Events.CommitCrime)) {
|
||||
CommitCrimeEntry? crime = e as CommitCrimeEntry;
|
||||
if (crime == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
string? faction = crime.Faction;
|
||||
|
||||
if (faction == null || !crime.IsMurder) {
|
||||
/* we don't care about anything but murder for now */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* use localised victim name if we have it, otherwise use normal name */
|
||||
string? victim = crime.VictimLocalised;
|
||||
if (string.IsNullOrEmpty(victim)) {
|
||||
victim = crime.Victim;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(victim)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!npcfactions.ContainsKey(victim)) {
|
||||
/* The faction in the crime report is the faction that issues the bounty,
|
||||
* and not the faction of the victim.
|
||||
*/
|
||||
OnLog?.Invoke(string.Format(
|
||||
"No faction found for victim \"{0}\", using faction that issued the bounty instead.",
|
||||
victim, crime.Faction
|
||||
));
|
||||
} else {
|
||||
faction = npcfactions[victim];
|
||||
}
|
||||
|
||||
results.Add(new FoulMurder(crime) {
|
||||
System = current_system,
|
||||
Faction = faction,
|
||||
});
|
||||
collate = true;
|
||||
} else if (e.Is(Events.MissionCompleted)) {
|
||||
MissionCompletedEntry? completed = e as MissionCompletedEntry;
|
||||
|
||||
if (completed == null ||
|
||||
completed.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MissionAcceptedEntry? accepted = null;
|
||||
MissionCompleted? main_mission = null;
|
||||
ulong accepted_address;
|
||||
string? accepted_system;
|
||||
|
||||
string? target_faction_name = completed.Mission.TargetFaction;
|
||||
string? source_faction_name = completed.Mission.Faction;
|
||||
|
||||
if (!acceptedMissions.TryGetValue(completed.Mission.MissionID, out accepted)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to find mission acceptance for mission \"{0}\". " +
|
||||
"Please extend range to include the mission acceptance.", completed.Mission.LocalisedName
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedSystems.TryGetValue(completed.Mission.MissionID, out accepted_address)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which system mission \"{0}\" was accepted.", completed.Mission.LocalisedName
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!systems.TryGetValue(accepted_address, out accepted_system)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which system mission \"{0}\" was accepted.", completed.Mission.LocalisedName
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var other in completed.Mission.Influences) {
|
||||
string faction = other.Key;
|
||||
if (string.IsNullOrEmpty(faction)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" has empty faction name in influence block, "+
|
||||
"so this influence support was ignored. " +
|
||||
"Please check the README on why this happens.", completed.Mission.LocalisedName)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now comes the fun part. Sometimes the influence list is empty for a faction.
|
||||
* This happens if the faction in question
|
||||
*/
|
||||
if (other.Value.Count() == 0) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" gave no influence to \"{1}\", so we assume this is because the " +
|
||||
"faction is in a conflict and cannot gain influence right now. " +
|
||||
"If this assessment is wrong, just remove the entry from the objective list.",
|
||||
completed.Mission.LocalisedName, faction
|
||||
));
|
||||
|
||||
if (string.Compare(target_faction_name, faction, true) == 0) {
|
||||
/* here we assume that if the faction in question is the target faction,
|
||||
* that we gave said target faction no influence in the target system, aka
|
||||
* current system
|
||||
*/
|
||||
if (current_system_address == null) {
|
||||
continue;
|
||||
}
|
||||
other.Value.Add(current_system_address.Value, "");
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" gave no influence to \"{1}\". Since \"{1}\" is the target faction " +
|
||||
"of the mission, we assume the influence was gained in \"{2}\". " +
|
||||
"Please remove the entry if this assumption is wrong.",
|
||||
completed.Mission.LocalisedName, faction, current_system
|
||||
));
|
||||
} else if (string.Compare(source_faction_name, faction, true) == 0) {
|
||||
/* source faction of the mission is not getting any influence. This could be because
|
||||
* the source faction is in an election state in its home system and cannot gain any
|
||||
* influence. It may also very well be that the source and target faction are the same
|
||||
* since the faction is present in both target and source system. In which case we add
|
||||
* both and hope for the best.
|
||||
*/
|
||||
other.Value.Add(accepted_address, "");
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" gave no influence to \"{1}\". Since \"{1}\" is the source faction " +
|
||||
"of the mission, we assume the influence was gained in \"{2}\". " +
|
||||
"Please remove the entry if this assumption is wrong.",
|
||||
completed.Mission.LocalisedName, faction, accepted_system
|
||||
));
|
||||
|
||||
/* check if source/target faction are equal, in which case we also need an entry
|
||||
* for the target system. As said factions can be present in two systems, and can
|
||||
* give missions that target each other.
|
||||
*/
|
||||
if (string.Compare(source_faction_name, target_faction_name, true) == 0 &&
|
||||
current_system_address != null) {
|
||||
other.Value.Add(current_system_address.Value, "");
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Mission \"{0}\" gave no influence to \"{1}\". Since \"{1}\" is the source and target faction " +
|
||||
"of the mission, we assume the influence was also gained in target system \"{2}\". " +
|
||||
"Please remove the entry if this assumption is wrong.",
|
||||
completed.Mission.LocalisedName, faction, current_system
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var influences in other.Value) {
|
||||
ulong system_address = influences.Key;
|
||||
string? system;
|
||||
string? accepted_station;
|
||||
|
||||
if (completed.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!systems.TryGetValue(system_address, out system)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unknown system \"{0}\" unable to assign that mission a target.", system_address
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedStations.TryGetValue(completed.Mission.MissionID, out accepted_station)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which station mission \"{0}\" was accepted.", completed.Mission.LocalisedName
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (faction.Equals(source_faction_name) && system_address == accepted_address) {
|
||||
/* This is the influence block for the origin of the mission.
|
||||
*/
|
||||
main_mission = new MissionCompleted() {
|
||||
CompletedEntry = completed,
|
||||
AcceptedEntry = accepted,
|
||||
System = accepted_system,
|
||||
Faction = source_faction_name,
|
||||
SystemAddress = accepted_address,
|
||||
Station = accepted_station,
|
||||
};
|
||||
results.Add(main_mission);
|
||||
} else if (!faction.Equals(source_faction_name) ||
|
||||
(faction.Equals(source_faction_name) && system_address != accepted_address)) {
|
||||
/* This block is for secondary factions (first if), or if the secondary faction
|
||||
* is the same as the mission giver, but in another system (second if).
|
||||
*/
|
||||
results.Add(new InfluenceSupport() {
|
||||
Faction = faction,
|
||||
Influence = influences.Value,
|
||||
System = system,
|
||||
SystemAddress = system_address,
|
||||
RelevantMission = completed
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (e.Is(Events.MissionAccepted)) {
|
||||
MissionAcceptedEntry? accepted = e as MissionAcceptedEntry;
|
||||
|
||||
if (accepted == null ||
|
||||
current_station == null ||
|
||||
current_system_address == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (accepted.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ulong id = accepted.Mission.MissionID;
|
||||
|
||||
if (!acceptedMissions.ContainsKey(id)) {
|
||||
acceptedMissions[id] = accepted;
|
||||
}
|
||||
if (!acceptedStations.ContainsKey(id)) {
|
||||
acceptedStations[id] = current_station;
|
||||
}
|
||||
if (!acceptedSystems.ContainsKey(id)) {
|
||||
acceptedSystems[id] = current_system_address.Value;
|
||||
}
|
||||
} else if (e.Is(Events.MissionFailed)) {
|
||||
MissionFailedEntry? failed = e as MissionFailedEntry;
|
||||
MissionAcceptedEntry? accepted = null;
|
||||
ulong accepted_address = 0;
|
||||
string? accepted_system;
|
||||
string? accepted_station;
|
||||
|
||||
if (failed == null || failed.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedMissions.TryGetValue(failed.Mission.MissionID, out accepted)) {
|
||||
OnLog?.Invoke("A mission failed which wasn't accepted in the given time frame. " +
|
||||
"Please adjust start date to when the mission was accepted to include it in the list.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (accepted.Mission == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedSystems.TryGetValue(failed.Mission.MissionID, out accepted_address)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which system mission \"{0}\" was accepted.", accepted.Mission.Name
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!systems.TryGetValue(accepted_address, out accepted_system)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which system mission \"{0}\" was accepted.", accepted.Mission.Name
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!acceptedStations.TryGetValue(failed.Mission.MissionID, out accepted_station)) {
|
||||
OnLog?.Invoke(string.Format(
|
||||
"Unable to figure out in which station mission \"{0}\" was accepted.", accepted.Mission.Name
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
results.Add(new MissionFailed(accepted) {
|
||||
Failed = failed,
|
||||
System = accepted_system,
|
||||
Station = accepted_station,
|
||||
Faction = accepted.Mission.Faction,
|
||||
SystemAddress = accepted_address,
|
||||
});
|
||||
|
||||
/* Mission failed should be collated if they are in the same system/station
|
||||
*/
|
||||
collate = true;
|
||||
} else if (e.Is(Events.SellExplorationData)) {
|
||||
SellExplorationDataEntry? explo = e as SellExplorationDataEntry;
|
||||
|
||||
if (explo == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.Add(new Cartographics(explo) {
|
||||
System = current_system,
|
||||
Station = current_station,
|
||||
Faction = controlling_faction,
|
||||
});
|
||||
|
||||
/* colate single cartographic selling into one */
|
||||
collate = true;
|
||||
} else if (e.Is(Events.SellOrganicData)) {
|
||||
SellOrganicDataEntry? organic = e as SellOrganicDataEntry;
|
||||
|
||||
if (organic == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* organic data sold to Vista Genomics */
|
||||
results.Add(new OrganicData(organic) {
|
||||
System = current_system,
|
||||
Station = current_station,
|
||||
Faction = controlling_faction,
|
||||
});
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.MultiSellExplorationData)) {
|
||||
MultiSellExplorationDataEntry? explo = e as MultiSellExplorationDataEntry;
|
||||
|
||||
if (explo == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* For multi-sell-exploraton-data only the controlling faction of the station sold to matters.
|
||||
*/
|
||||
results.Add(new Cartographics(explo) {
|
||||
System = current_system,
|
||||
Station = current_station,
|
||||
Faction = controlling_faction
|
||||
});
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.RedeemVoucher)) {
|
||||
RedeemVoucherEntry? voucher = e as RedeemVoucherEntry;
|
||||
List<Faction> current_factions = new List<Faction>();
|
||||
|
||||
if (voucher == null || current_system == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (system_factions.ContainsKey(current_system)) {
|
||||
current_factions = system_factions[current_system];
|
||||
} else {
|
||||
OnLog?.Invoke("There are no current system factions, so turned in vouchers were ignored.");
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (string faction in voucher.Factions) {
|
||||
if (current_factions.Find(x => x.Name == faction) == null) {
|
||||
OnLog?.Invoke(
|
||||
string.Format("Vouchers for \"{0}\" were ignored in \"{1}\" since said " +
|
||||
"faction is not present there.", faction, current_system)
|
||||
);
|
||||
continue; /* faction is not present, so it is ignored */
|
||||
}
|
||||
|
||||
/* Same for selling combat vouchers. Only the current controlling faction matters here.
|
||||
*/
|
||||
results.Add(new Vouchers(voucher) {
|
||||
System = current_system,
|
||||
Station = current_station,
|
||||
Faction = faction,
|
||||
ControllingFaction = controlling_faction,
|
||||
});
|
||||
}
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.SellMicroResources)) {
|
||||
SellMicroResourcesEntry? smr = e as SellMicroResourcesEntry;
|
||||
|
||||
if (smr == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.Add(new SellMicroResources(smr) {
|
||||
Faction = controlling_faction,
|
||||
Station = current_station,
|
||||
System = current_system
|
||||
});
|
||||
} else if (e.Is(Events.MarketBuy)) {
|
||||
MarketBuyEntry? buy = e as MarketBuyEntry;
|
||||
|
||||
if (buy == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(buy.Type) || buy.BuyPrice == 0) {
|
||||
continue;
|
||||
}
|
||||
buyCost[buy.Type] = buy.BuyPrice;
|
||||
|
||||
results.Add(new BuyCargo(buy) {
|
||||
Faction = controlling_faction,
|
||||
Station = current_station,
|
||||
System = current_system,
|
||||
});
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.SearchAndRescue)) {
|
||||
SearchAndRescueEntry? sar = e as SearchAndRescueEntry;
|
||||
|
||||
if (sar == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.Add(new SearchAndRescue(sar) {
|
||||
Faction = controlling_faction,
|
||||
Station = current_station,
|
||||
System = current_system,
|
||||
});
|
||||
|
||||
collate = true;
|
||||
} else if (e.Is(Events.MarketSell)) {
|
||||
MarketSellEntry? sell = e as MarketSellEntry;
|
||||
long profit = 0;
|
||||
|
||||
if (sell == null || sell.Type == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!buyCost.ContainsKey(sell.Type)) {
|
||||
OnLog?.Invoke("Could not find buy order for the given commodity. Please adjust profit manually.");
|
||||
} else {
|
||||
long avg = buyCost[sell.Type];
|
||||
profit = (long)sell.TotalSale - (avg * sell.Count);
|
||||
}
|
||||
|
||||
results.Add(new SellCargo(sell) {
|
||||
Faction = controlling_faction,
|
||||
Station = current_station,
|
||||
System = current_system,
|
||||
Profit = profit
|
||||
});
|
||||
}
|
||||
|
||||
if (results == null || results.Count <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (Transaction entry in results) {
|
||||
/* Find all objectives that generally match.
|
||||
*/
|
||||
var matches = objectives
|
||||
.Where(x => x.Matches(entry) >= 2)
|
||||
.OrderBy(x => x.Matches(entry))
|
||||
;
|
||||
|
||||
Objective? objective = null;
|
||||
if (matches != null && matches.Count() > 0) {
|
||||
/* Then select the one that matches the most.
|
||||
*/
|
||||
objective = matches
|
||||
.OrderBy(x => x.Matches(entry))
|
||||
.Reverse()
|
||||
.First()
|
||||
;
|
||||
} else {
|
||||
/* create a new objective if we don't have one */
|
||||
objective = new Objective() {
|
||||
Station = (entry.Station ?? ""),
|
||||
Faction = (entry.Faction ?? ""),
|
||||
System = (entry.System ?? ""),
|
||||
};
|
||||
objectives.Add(objective);
|
||||
}
|
||||
|
||||
Transaction? existing = null;
|
||||
|
||||
existing = objective.LogEntries.Find(x => {
|
||||
try {
|
||||
return x.CompareTo(entry) == 0;
|
||||
} catch (NotImplementedException) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if (collate && existing != null) {
|
||||
existing.Entries.Add(e);
|
||||
} else if (!collate || existing == null) {
|
||||
objective.LogEntries.Add(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Scan(PlayerJournal journal) {
|
||||
Scan(journal, DateTime.Now, DateTime.Now);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,4 @@
|
||||
using EDPlayerJournal.Entries;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
|
||||
@@ -6,18 +6,29 @@ namespace EDPlayerJournal.BGS;
|
||||
public class Transaction : IComparable<Transaction> {
|
||||
public List<Entry> Entries { get; } = new List<Entry>();
|
||||
|
||||
public virtual string CompletedAt {
|
||||
public string CompletedAt {
|
||||
get {
|
||||
DateTime? datetime = CompletedAtDateTime;
|
||||
if (datetime == null) {
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
return datetime.Value.ToString("dd.MM.yyyy HH:mm UTC");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual DateTime? CompletedAtDateTime {
|
||||
get {
|
||||
var items = Entries
|
||||
.OrderBy(x => x.Timestamp)
|
||||
.ToArray()
|
||||
;
|
||||
if (items == null || items.Length == 0) {
|
||||
return "Unknown";
|
||||
return null;
|
||||
}
|
||||
|
||||
Entry last = items.Last();
|
||||
return last.Timestamp.ToString("dd.MM.yyyy HH:mm UTC");
|
||||
return last.Timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using EDPlayerJournal.Entries;
|
||||
using EDPlayerJournal;
|
||||
using EDPlayerJournal.Entries;
|
||||
|
||||
namespace EDPlayerJournal.BGS;
|
||||
|
||||
@@ -52,7 +53,7 @@ internal class TransactionParserContext {
|
||||
/// <summary>
|
||||
/// A list of accepted missions index by their mission ID
|
||||
/// </summary>
|
||||
public Dictionary<ulong, MissionAcceptedEntry> AcceptedMissions { get; } = new();
|
||||
public Dictionary<ulong, Mission> AcceptedMissions { get; } = new();
|
||||
public Dictionary<ulong, Location> AcceptedMissionLocation { get; } = new();
|
||||
/// <summary>
|
||||
/// A way to lookup a system by its system id
|
||||
@@ -83,17 +84,18 @@ internal class TransactionParserContext {
|
||||
return;
|
||||
}
|
||||
|
||||
if (OnFootKills > 0) {
|
||||
if (OnFootKills > 0 || IsOnFoot == true) {
|
||||
cztype = CombatZones.GroundCombatZone;
|
||||
// High on foot combat zones have enforcers that bring 80k a pop
|
||||
if (highest >= 80000) {
|
||||
if (highest >= 60000) {
|
||||
grade = CombatZones.DifficultyHigh;
|
||||
} else if (highest >= 40000) {
|
||||
} else if (highest >= 30000) {
|
||||
// In medium conflict zones, the enforcers are worth 30k
|
||||
grade = CombatZones.DifficultyMedium;
|
||||
} else {
|
||||
grade = CombatZones.DifficultyLow;
|
||||
}
|
||||
} else if (ShipKills > 0) {
|
||||
} else if (ShipKills > 0 && !IsOnFoot) {
|
||||
// Ship combat zones can be identified by the amount of kills
|
||||
if (ShipKills > 20) {
|
||||
grade = CombatZones.DifficultyHigh;
|
||||
@@ -110,10 +112,7 @@ internal class TransactionParserContext {
|
||||
.Count()
|
||||
;
|
||||
|
||||
if (warzoneNpcs >= 2 && grade != CombatZones.DifficultyHigh) {
|
||||
// Only large combat zones have two NPCs
|
||||
grade = CombatZones.DifficultyHigh;
|
||||
} else if (warzoneNpcs >= 1 && grade == CombatZones.DifficultyLow) {
|
||||
if (warzoneNpcs >= 1 && grade == CombatZones.DifficultyLow) {
|
||||
grade = CombatZones.DifficultyMedium;
|
||||
}
|
||||
}
|
||||
@@ -125,7 +124,7 @@ internal class TransactionParserContext {
|
||||
// Still unknown
|
||||
grade = null;
|
||||
} else {
|
||||
transactions.AddIncomplete(new CombatZone(), "Failed to discern combat zone type");
|
||||
transactions.AddIncomplete(new CombatZone(), "Failed to discern combat zone type", e);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -189,16 +188,24 @@ internal class TransactionParserContext {
|
||||
return SystemFactions[system];
|
||||
}
|
||||
|
||||
public void MissionAccepted(MissionAcceptedEntry accepted) {
|
||||
public void MissionAccepted(MissionAcceptedEntry? entry) {
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MissionAccepted(entry.Mission);
|
||||
}
|
||||
|
||||
public void MissionAccepted(Mission? mission) {
|
||||
if (CurrentSystem == null || CurrentSystemAddress == null) {
|
||||
throw new Exception("Mission accepted without knowing where.");
|
||||
}
|
||||
|
||||
if (accepted.Mission == null) {
|
||||
if (mission == null) {
|
||||
throw new Exception("Mission is null");
|
||||
}
|
||||
|
||||
AcceptedMissions.TryAdd(accepted.Mission.MissionID, accepted);
|
||||
AcceptedMissions.TryAdd(mission.MissionID, mission);
|
||||
|
||||
Location location = new() {
|
||||
StarSystem = CurrentSystem,
|
||||
@@ -206,13 +213,13 @@ internal class TransactionParserContext {
|
||||
Station = (CurrentStation ?? ""),
|
||||
};
|
||||
|
||||
AcceptedMissionLocation.TryAdd(accepted.Mission.MissionID, location);
|
||||
AcceptedMissionLocation.TryAdd(mission.MissionID, location);
|
||||
}
|
||||
}
|
||||
|
||||
public class TransactionList : List<Transaction> {
|
||||
public void AddIncomplete(Transaction underlying, string reason) {
|
||||
Add(new IncompleteTransaction(underlying, reason));
|
||||
public void AddIncomplete(Transaction underlying, string reason, Entry entry) {
|
||||
Add(new IncompleteTransaction(underlying, reason, entry));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,7 +403,7 @@ internal class CommitCrimeParser : TransactionParserPart {
|
||||
if (entry.Faction == null) {
|
||||
transactions.AddIncomplete(
|
||||
new FoulMurder(),
|
||||
"On foot murder victim did not have a faction"
|
||||
"On foot murder victim did not have a faction", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -407,7 +414,7 @@ internal class CommitCrimeParser : TransactionParserPart {
|
||||
if (!context.NPCFaction.ContainsKey(victim)) {
|
||||
transactions.AddIncomplete(
|
||||
new FoulMurder(),
|
||||
"Crime victim was not properly scanned."
|
||||
"Crime victim was not properly scanned.", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -422,6 +429,35 @@ internal class CommitCrimeParser : TransactionParserPart {
|
||||
}
|
||||
}
|
||||
|
||||
internal class MissionsParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
MissionsEntry? missions = entry as MissionsEntry;
|
||||
|
||||
if (missions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.CurrentSystem == null || context.CurrentSystemAddress == null) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
"Could not determine current location on Missions event.",
|
||||
entry
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (Mission mission in missions.Active) {
|
||||
try {
|
||||
context.MissionAccepted(mission);
|
||||
} catch (Exception exception) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
exception.Message,
|
||||
entry
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class MissionAcceptedParser : TransactionParserPart {
|
||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
||||
MissionAcceptedEntry? entry = e as MissionAcceptedEntry;
|
||||
@@ -431,7 +467,8 @@ internal class MissionAcceptedParser : TransactionParserPart {
|
||||
|
||||
if (context.CurrentSystem == null || context.CurrentSystemAddress == null) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
"Could not determine current location on mission acceptance."
|
||||
"Could not determine current location on mission acceptance.",
|
||||
e
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -440,7 +477,8 @@ internal class MissionAcceptedParser : TransactionParserPart {
|
||||
context.MissionAccepted(entry);
|
||||
} catch (Exception exception) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
exception.Message
|
||||
exception.Message,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -453,23 +491,23 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
MissionAcceptedEntry? accepted = null;
|
||||
Mission? mission = null;
|
||||
Location? accepted_location = null;
|
||||
string? target_faction_name = entry.Mission.TargetFaction;
|
||||
string? source_faction_name = entry.Mission.Faction;
|
||||
|
||||
// We did not find when the mission was accepted.
|
||||
if (!context.AcceptedMissions.TryGetValue(entry.Mission.MissionID, out accepted)) {
|
||||
if (!context.AcceptedMissions.TryGetValue(entry.Mission.MissionID, out mission)) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
String.Format("Mission acceptance for mission id {0} was not found",
|
||||
entry.Mission.MissionID));
|
||||
entry.Mission.MissionID), e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.AcceptedMissionLocation.TryGetValue(entry.Mission.MissionID, out accepted_location)) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
String.Format("Location for acceptance for mission id {0} was not found",
|
||||
entry.Mission.MissionID));
|
||||
entry.Mission.MissionID), e);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -517,7 +555,8 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
|
||||
if (!context.SystemsByID.TryGetValue(system_address, out system)) {
|
||||
transactions.AddIncomplete(new MissionCompleted(),
|
||||
string.Format("Unknown system {0}, unable to assign that mission a target", system_address)
|
||||
string.Format("Unknown system {0}, unable to assign that mission a target", system_address),
|
||||
e
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -528,7 +567,7 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
// for the source system. So we make a full mission completed entry.
|
||||
transactions.Add(new MissionCompleted() {
|
||||
CompletedEntry = entry,
|
||||
AcceptedEntry = accepted,
|
||||
Mission = mission,
|
||||
System = accepted_location.StarSystem,
|
||||
Faction = source_faction_name,
|
||||
SystemAddress = accepted_location.SystemAddress,
|
||||
@@ -542,7 +581,7 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
// differs. Sometimes missions go to different systems but to
|
||||
// the same faction.
|
||||
transactions.Add(new InfluenceSupport() {
|
||||
AcceptedEntry = accepted,
|
||||
Mission = mission,
|
||||
Faction = faction,
|
||||
Influence = influences.Value,
|
||||
System = system,
|
||||
@@ -558,7 +597,7 @@ internal class MissionCompletedParser : TransactionParserPart {
|
||||
|
||||
internal class MissionFailedParser : TransactionParserPart {
|
||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
||||
MissionAcceptedEntry? accepted = null;
|
||||
Mission? mission = null;
|
||||
Location? accepted_location = null;
|
||||
string? accepted_system = null;
|
||||
|
||||
@@ -571,31 +610,38 @@ internal class MissionFailedParser : TransactionParserPart {
|
||||
throw new InvalidJournalEntryException("No mission specified in mission failure");
|
||||
}
|
||||
|
||||
if (!context.AcceptedMissions.TryGetValue(entry.Mission.MissionID, out accepted)) {
|
||||
if (!context.AcceptedMissions.TryGetValue(entry.Mission.MissionID, out mission)) {
|
||||
transactions.AddIncomplete(new MissionFailed(),
|
||||
"Mission acceptance was not found"
|
||||
"Mission acceptance was not found", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.AcceptedMissionLocation.TryGetValue(entry.Mission.MissionID, out accepted_location)) {
|
||||
if (!context.AcceptedMissionLocation.TryGetValue(mission.MissionID, out accepted_location)) {
|
||||
transactions.AddIncomplete(new MissionFailed(),
|
||||
"Unable to figure out where failed mission was accepted"
|
||||
"Unable to figure out where failed mission was accepted", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.SystemsByID.TryGetValue(accepted_location.SystemAddress, out accepted_system)) {
|
||||
transactions.AddIncomplete(new MissionFailed(),
|
||||
"Unable to figure out in which system failed mission was accepted"
|
||||
"Unable to figure out in which system failed mission was accepted", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
transactions.Add(new MissionFailed() {
|
||||
Accepted = accepted,
|
||||
Faction = accepted.Mission?.Faction,
|
||||
Failed = entry,
|
||||
if (string.IsNullOrEmpty(mission.Faction)) {
|
||||
transactions.AddIncomplete(new MissionFailed(),
|
||||
"Could not determine for what faction you failed a mission. This happens if the " +
|
||||
"mission acceptance is not within the given time frame.",
|
||||
entry
|
||||
);
|
||||
}
|
||||
|
||||
transactions.Add(new MissionFailed(entry) {
|
||||
Faction = mission?.Faction,
|
||||
Mission = mission,
|
||||
Station = accepted_location.Station,
|
||||
System = accepted_location.StarSystem,
|
||||
SystemAddress = accepted_location.SystemAddress,
|
||||
@@ -661,7 +707,7 @@ internal class RedeemVoucherParser : TransactionParserPart {
|
||||
|
||||
if (context.CurrentSystem == null) {
|
||||
transactions.AddIncomplete(new Vouchers(),
|
||||
"Could not find out where the vouchers were redeemed"
|
||||
"Could not find out where the vouchers were redeemed", e
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -669,7 +715,7 @@ internal class RedeemVoucherParser : TransactionParserPart {
|
||||
List<Faction>? current_factions = context.GetFactions(context.CurrentSystem);
|
||||
if (current_factions == null) {
|
||||
transactions.AddIncomplete(new Vouchers(),
|
||||
"Current system factions are unknown, so vouchers were ineffective");
|
||||
"Current system factions are unknown, so vouchers were ineffective", e);
|
||||
}
|
||||
|
||||
foreach (string faction in entry.Factions) {
|
||||
@@ -690,8 +736,8 @@ internal class RedeemVoucherParser : TransactionParserPart {
|
||||
relevantBond = true;
|
||||
} else {
|
||||
transactions.AddIncomplete(new Vouchers(),
|
||||
string.Format("Vouchers for {0} had no effect in {1} since said " +
|
||||
"faction is not present here", faction, context.CurrentSystem)
|
||||
string.Format("Vouchers for \"{0}\" had no effect in \"{1}\" since said " +
|
||||
"faction is not present there", faction, context.CurrentSystem), e
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -832,6 +878,8 @@ internal class EmbarkDisembarkParser : TransactionParserPart {
|
||||
|
||||
internal class SupercruiseEntryParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
// After a super cruise entry we are no longer on foot.
|
||||
context.IsOnFoot = false;
|
||||
context.DiscernCombatZone(transactions, entry);
|
||||
context.ResetCombatZone();
|
||||
}
|
||||
@@ -892,14 +940,32 @@ internal class DiedParser : TransactionParserPart {
|
||||
}
|
||||
}
|
||||
|
||||
internal class DropshipDeployParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
// On drop ship deploy we are now on foot
|
||||
context.IsOnFoot = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal class CommanderParser : TransactionParserPart {
|
||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions) {
|
||||
// A commander entry happens when you log out, and log back in again
|
||||
// for example when switching from Open, to Solo or PG.
|
||||
context.DiscernCombatZone(transactions, entry);
|
||||
context.ResetCombatZone();
|
||||
}
|
||||
}
|
||||
|
||||
public class TransactionParser {
|
||||
private static Dictionary<string, TransactionParserPart> ParserParts { get; } = new()
|
||||
{
|
||||
{ Events.CapShipBond, new CapShipBondParser() },
|
||||
{ Events.Commander, new CommanderParser() },
|
||||
{ Events.CommitCrime, new CommitCrimeParser() },
|
||||
{ Events.Died, new DiedParser() },
|
||||
{ Events.Disembark, new EmbarkDisembarkParser() },
|
||||
{ Events.Docked, new DockedParser() },
|
||||
{ Events.DropshipDeploy, new DropshipDeployParser() },
|
||||
{ Events.Embark, new EmbarkDisembarkParser() },
|
||||
{ Events.FactionKillBond, new FactionKillBondParser() },
|
||||
{ Events.FileHeader, new FileHeaderParser() },
|
||||
@@ -910,6 +976,7 @@ public class TransactionParser {
|
||||
{ Events.MissionAccepted, new MissionAcceptedParser() },
|
||||
{ Events.MissionCompleted, new MissionCompletedParser() },
|
||||
{ Events.MissionFailed, new MissionFailedParser() },
|
||||
{ Events.Missions, new MissionsParser() },
|
||||
{ Events.MultiSellExplorationData, new MultiSellExplorationDataParser() },
|
||||
{ Events.ReceiveText, new ReceiveTextParser() },
|
||||
{ Events.RedeemVoucher, new RedeemVoucherParser() },
|
||||
|
||||
@@ -13,6 +13,16 @@ public class Vouchers : Transaction {
|
||||
Entries.Add(e);
|
||||
}
|
||||
|
||||
public override bool SystemContribution {
|
||||
get {
|
||||
if (Faction == Factions.PilotsFederation && Type == "Combat Bond") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public long TotalSum {
|
||||
get {
|
||||
if (Faction == null) {
|
||||
@@ -39,9 +49,9 @@ public class Vouchers : Transaction {
|
||||
.First();
|
||||
if (v == null) {
|
||||
return null;
|
||||
} else if (v == "CombatBond") {
|
||||
} else if (v == Bonds.CombatBond) {
|
||||
type = "Combat Bond";
|
||||
} else if (v == "bounty") {
|
||||
} else if (v == Bonds.Bounty) {
|
||||
type = "Bounty";
|
||||
} else {
|
||||
type = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(v);
|
||||
|
||||
13
EDPlayerJournal/Bonds.cs
Normal file
13
EDPlayerJournal/Bonds.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace EDPlayerJournal;
|
||||
|
||||
public class Bonds {
|
||||
/// <summary>
|
||||
/// Internal string name for combat bonds.
|
||||
/// </summary>
|
||||
public static readonly string CombatBond = "CombatBond";
|
||||
|
||||
/// <summary>
|
||||
/// Internal string name for bounties.
|
||||
/// </summary>
|
||||
public static readonly string Bounty = "bounty";
|
||||
}
|
||||
@@ -1,27 +1,27 @@
|
||||
using EDPlayerJournal.BGS;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System;
|
||||
|
||||
namespace EDPlayerJournal;
|
||||
namespace EDPlayerJournal;
|
||||
|
||||
public class EnglishMissionNames {
|
||||
public static Dictionary<string, string> MissionNames { get; } = new Dictionary<string, string>() {
|
||||
{"Chain_FindThePirateLord_name", "Assassination (Pirate Lord) (Chain)"},
|
||||
{"Chain_RegainFooting_name", "Regain Footing (Chain)"},
|
||||
{"Chain_SalvageJustice_name", "Assassination (Legal) (Chain)"},
|
||||
{"Mission_Altruism_Bust_name", "Donate (Bust)" },
|
||||
{"Mission_Altruism_CivilUnrest_name", "Donate (Civil Unrest)" },
|
||||
{"Mission_Altruism_name", "Donate"},
|
||||
{"Mission_Altruism_Outbreak_name", "Donate (Outbreak)" },
|
||||
{"Mission_AltruismCredits_Bust_name", "Donate Credits (Bust)"},
|
||||
{"Mission_AltruismCredits_CivilUnrest_name", "Donate Credits (Civil Unrest)" },
|
||||
{"Mission_AltruismCredits_Famine_name", "Donate Credits (Famine)"},
|
||||
{"Mission_AltruismCredits_name", "Donate Credits"},
|
||||
{"Mission_AltruismCredits_Outbreak_name", "Donate Credits (Outbreak)" },
|
||||
{"Mission_Assassinate_Illegal_BLOPS_name", "Assassination (Illegal)"},
|
||||
{"Mission_Assassinate_Legal_Corporate_name", "Corporate Assassination (Legal)"},
|
||||
{"Mission_Assassinate_Legal_Bust_name", "Assassination (Bust, Legal)" },
|
||||
{"MISSION_assassinate_legal_CivilUnrest_name", "Assassination (Civil Unrest, Legal)" },
|
||||
{"Mission_Assassinate_Legal_Communism_name", "Assassination (Communism, Legal)" },
|
||||
{"Mission_Assassinate_Legal_Corporate_name", "Assassination (Corporate, Legal)"},
|
||||
{"Mission_Assassinate_Legal_War_name", "Assassination (War, Legal)" },
|
||||
{"Mission_Assassinate_name", "Assassination"},
|
||||
{"Mission_Assassinate_Planetary_Expansion_name", "Assassination (Planetary Scan, Expansion)" },
|
||||
{"Mission_Assassinate_Planetary_name", "Assassination (Planetary Scan)"},
|
||||
{"Mission_Collect_Bust_name", "Provide (Bust)"},
|
||||
{"Mission_Collect_CivilLiberty_name", "Provide (Civil Liberty)"},
|
||||
@@ -29,8 +29,10 @@ public class EnglishMissionNames {
|
||||
{"Mission_Collect_Famine_name", "Provide (Famine)"},
|
||||
{"Mission_Collect_Industrial_name", "Provide (Industrial)"},
|
||||
{"Mission_Collect_name", "Provide"},
|
||||
{"Mission_Collect_Outbreak_name", "Provide (Outbreak)" },
|
||||
{"Mission_Collect_RankEmp_name", "Provide (Imperial Navy)"},
|
||||
{"Mission_Collect_Retreat_name", "Provide (Retreat)"},
|
||||
{"Mission_Courier_CivilUnrest_name", "Courier (Divil Unrest)" },
|
||||
{"Mission_Courier_Democracy_name", "Courier (Democracy)"},
|
||||
{"Mission_Courier_Elections_name", "Courier (Elections)"},
|
||||
{"Mission_Courier_Expansion_name", "Courier (Expansion)"},
|
||||
@@ -38,8 +40,10 @@ public class EnglishMissionNames {
|
||||
{"Mission_Courier_Lockdown_name", "Courier (Lockdown)"},
|
||||
{"Mission_Courier_name", "Courier"},
|
||||
{"Mission_Courier_RankEmp_name", "Courier (Imperial Navy)"},
|
||||
{"Mission_Courier_War_name", "Courier (War)" },
|
||||
{"Mission_Delivery_Agriculture_name", "Delivery (Agriculture)"},
|
||||
{"Mission_Delivery_Boom_name", "Delivery (Boom)"},
|
||||
{"Mission_Delivery_CivilUnrest_name", "Delivery (Civil Unrest)"},
|
||||
{"Mission_Delivery_Democracy_name", "Delivery (Democracy)"},
|
||||
{"Mission_Delivery_Investment_name", "Delivery (Investment)"},
|
||||
{"Mission_Delivery_name", "Delivery"},
|
||||
@@ -59,14 +63,19 @@ public class EnglishMissionNames {
|
||||
{"Mission_Massacre_RankEmp_name", "Massacre (Imperial Navy)"},
|
||||
{"Mission_MassacreWing_Legal_Bust_name", "Massacre (Wing) (Bust)"},
|
||||
{"Mission_MassacreWing_name", "Massacre (Wing)"},
|
||||
{"Mission_Mining_name", "Mining" },
|
||||
{"Mission_OnFoot_Assassination_MB_name", "On Foot Assassination"},
|
||||
{"Mission_OnFoot_AssassinationIllegal_MB_name", "On Foot Assassination (Illegal)"},
|
||||
{"Mission_OnFoot_AssassinationIllegal_NCD_MB_name", "On Foot Assassination (Illegal)" },
|
||||
{"Mission_OnFoot_Collect_Contact_MB_name", "On Foot Collect"},
|
||||
{"Mission_OnFoot_Collect_MB_name", "On Foot Collection"},
|
||||
{"Mission_OnFoot_Delivery_Contact_MB_name", "On Foot Delivery (Contact)"},
|
||||
{"Mission_OnFoot_Hack_Upload_Covert_MB_name", "On Foot Hack (Covert Upload)"},
|
||||
{"Mission_OnFoot_Hack_Upload_MB_name", "On Foot Hack (Upload)"},
|
||||
{"Mission_OnFoot_Heist_MB_name", "On Foot Heist" },
|
||||
{"Mission_OnFoot_Heist_POI_MB_name", "On Foot Heist (POI)"},
|
||||
{"Mission_OnFoot_Massacre_MB_name", "On Foot Massacre" },
|
||||
{"Mission_OnFoot_MassacreIllegal_MB_name", "On Foot Massacre (Illegal)" },
|
||||
{"Mission_OnFoot_Onslaught_MB_name", "On Foot Onslaught"},
|
||||
{"Mission_OnFoot_Onslaught_Offline_MB_name", "On Foot Onslaught (Offline)"},
|
||||
{"Mission_OnFoot_ProductionHeist_Covert_MB_name", "On Foot Production Heist (Covert)"},
|
||||
@@ -76,13 +85,16 @@ public class EnglishMissionNames {
|
||||
{"Mission_OnFoot_Sabotage_Production_Covert_MB_name", "On Foot Sabotage Production (Covert)"},
|
||||
{"Mission_OnFoot_Salvage_MB_name", "On Foot Salvage"},
|
||||
{"Mission_OnFoot_SalvageIllegal_MB_name", "On Foot Salvage (Illegal)"},
|
||||
{"Mission_PassengerBulk_AIDWORKER_ARRIVING", "Aid Workers Seeking Transport"},
|
||||
{"Mission_OnFoot_Smuggle_Contact_MB_name", "On Foot Smuggling" },
|
||||
{"Mission_PassengerBulk_AIDWORKER_ARRIVING", "Seeking Transport (Aid Workers)"},
|
||||
{"Mission_PassengerBulk_name", "Seeking Transport" },
|
||||
{"Mission_PassengerVIP", "Passenger (VIP)"},
|
||||
{"Mission_PassengerVIP_Criminal_BOOM_name", "Passenger Criminal (VIP) (Boom)"},
|
||||
{"Mission_PassengerVIP_name", "Passenger (VIP)"},
|
||||
{"Mission_PassengerVIP_Scientist_FAMINE_name", "Passenger Scientist (VIP) (Famine)"},
|
||||
{"Mission_PassengerVIP_Tourist_BOOM_name", "Passenger Tourist (VIP) (Boom)"},
|
||||
{"Mission_Rescue_Planet_name", "Planet Rescue"},
|
||||
{"Mission_Rescue_Planet_Expansion_name", "Planet Rescue (Expansion)" },
|
||||
{"MISSION_Salvage_CivilUnrest_name", "Salvage (Civil Unrest)"},
|
||||
{"MISSION_Salvage_Expansion_name", "Salvage (Expansion)"},
|
||||
{"MISSION_Salvage_Illegal_name", "Salvage (Illegal)"},
|
||||
@@ -93,8 +105,15 @@ public class EnglishMissionNames {
|
||||
{"MISSION_Scan_name", "Scan"},
|
||||
{"Mission_Sightseeing_Criminal_FAMINE_name", "Sightseeing (Criminal) (Famine)"},
|
||||
{"Mission_Sightseeing_name", "Sightseeing"},
|
||||
{"Mission_Smuggle_Anarchy_name", "Smuggling (Anarchy)" },
|
||||
{"Mission_TW_Massacre_Basilisk_Plural_name", "Kill Basilisk" },
|
||||
{"Mission_TW_Massacre_Basilisk_Singular_name", "Kill Basilisk" },
|
||||
{"Mission_TW_Massacre_Cyclops_Plural_name", "Kill Cyclops" },
|
||||
{"Mission_TW_Massacre_Cyclops_Singular_name", "Kill Cyclops" },
|
||||
{"Mission_TW_Massacre_Scout_Plural_name", "Kill Scouts (Wing)" },
|
||||
{"Mission_TW_PassengerEvacuation_Burning_name", "Passenger Evacuation (Significant Damage)" },
|
||||
{"Mission_TW_PassengerEvacuation_UnderAttack_name", "Passenger Evacuation (Thargoid Invasion)" },
|
||||
{"Mission_TW_Massacre_Scout_Plural_name", "Kill Scouts (Wing)" }
|
||||
{"Mission_TW_Rescue_UnderAttack_name", "Rescue (Thargoid Attack)" },
|
||||
};
|
||||
|
||||
public static string? Translate(string name) {
|
||||
|
||||
42
EDPlayerJournal/Entries/DropshipDeployEntry.cs
Normal file
42
EDPlayerJournal/Entries/DropshipDeployEntry.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
namespace EDPlayerJournal.Entries;
|
||||
|
||||
public class DropshipDeployEntry : Entry {
|
||||
/// <summary>
|
||||
/// Star system this drop happened in.
|
||||
/// </summary>
|
||||
public string? StarSystem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// System address
|
||||
/// </summary>
|
||||
public ulong? SystemAddress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Planetary body
|
||||
/// </summary>
|
||||
public string? Body { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Body ID
|
||||
/// </summary>
|
||||
public ulong? BodyID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether it happened on station.
|
||||
/// </summary>
|
||||
public bool? OnStation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether it happened on a planet.
|
||||
/// </summary>
|
||||
public bool? OnPlanet { get; set; }
|
||||
|
||||
protected override void Initialise() {
|
||||
StarSystem = JSON.Value<string?>("StarSystem");
|
||||
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||
Body = JSON.Value<string?>("Body");
|
||||
BodyID = JSON.Value<ulong?>("BodyID");
|
||||
OnStation = JSON.Value<bool?>("OnStation");
|
||||
OnPlanet = JSON.Value<bool?>("OnPlanet");
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ public class Entry {
|
||||
{ Events.Died, typeof(DiedEntry) },
|
||||
{ Events.Disembark, typeof(DisembarkEntry) },
|
||||
{ Events.Docked, typeof(DockedEntry) },
|
||||
{ Events.DropshipDeploy, typeof(DropshipDeployEntry) },
|
||||
{ Events.Embark, typeof(EmbarkEntry) },
|
||||
{ Events.FactionKillBond, typeof(FactionKillBondEntry) },
|
||||
{ Events.FileHeader, typeof(FileHeaderEntry) },
|
||||
|
||||
@@ -8,6 +8,7 @@ public class Events {
|
||||
public static readonly string Died = "Died";
|
||||
public static readonly string Disembark = "Disembark";
|
||||
public static readonly string Docked = "Docked";
|
||||
public static readonly string DropshipDeploy = "DropshipDeploy";
|
||||
public static readonly string Embark = "Embark";
|
||||
public static readonly string FactionKillBond = "FactionKillBond";
|
||||
public static readonly string FighterDestroyed = "FighterDestroyed";
|
||||
|
||||
@@ -8,11 +8,17 @@ public class BioData {
|
||||
public string? SpeciesLocalised { get; set; }
|
||||
public long Value { get; set; } = 0;
|
||||
public long Bonus { get; set; } = 0;
|
||||
public long TotalValue => Value + Bonus;
|
||||
|
||||
public long TotalValue {
|
||||
get {
|
||||
return Value + Bonus;
|
||||
}
|
||||
}
|
||||
}
|
||||
public class SellOrganicDataEntry : Entry {
|
||||
public long MarketID { get; set; }
|
||||
public List<BioData> BioData => new List<BioData>();
|
||||
|
||||
public List<BioData> BioData { get; } = new();
|
||||
|
||||
protected override void Initialise() {
|
||||
MarketID = JSON.Value<long?>("MarketID") ?? 0;
|
||||
|
||||
@@ -255,6 +255,18 @@ public class Mission : IComparable<Mission> {
|
||||
/// </summary>
|
||||
public List<MissionFactionEffects> FactionEffects { get; set; } = new List<MissionFactionEffects>();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the name is an on foot mission.
|
||||
/// </summary>
|
||||
public bool IsOnFoot {
|
||||
get {
|
||||
if (string.IsNullOrEmpty(Name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Name.Contains("OnFoot");
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPassengerMission {
|
||||
get {
|
||||
|
||||
@@ -14,13 +14,24 @@ public class Thargoid {
|
||||
public static string ThargoidFaction = Factions.Thargoid;
|
||||
|
||||
public static Dictionary<ulong, ThargoidVessel> VesselPayout { get; } = new() {
|
||||
// Up to date values ever since 14.02
|
||||
{ 65000, ThargoidVessel.Scout },
|
||||
{ 75000, ThargoidVessel.Scout },
|
||||
{ 6500000, ThargoidVessel.Cyclops },
|
||||
{ 20000000, ThargoidVessel.Basilisk },
|
||||
{ 25000000, ThargoidVessel.Orthrus },
|
||||
{ 34000000, ThargoidVessel.Medusa },
|
||||
{ 50000000, ThargoidVessel.Hydra },
|
||||
// These are the old values pre Update 14.02
|
||||
{ 80000, ThargoidVessel.Scout },
|
||||
{ 8000000, ThargoidVessel.Cyclops },
|
||||
{ 24000000, ThargoidVessel.Basilisk },
|
||||
// In Update 14.1 the payout for Orthrus has been rebalanced.
|
||||
{ 30000000, ThargoidVessel.Orthrus },
|
||||
{ 40000000, ThargoidVessel.Medusa },
|
||||
{ 50000000, ThargoidVessel.Orthrus },
|
||||
// This used to be the old payout value for Orthrus, it now conflicts
|
||||
// with Post Update 14.02 Hydra values
|
||||
//{ 50000000, ThargoidVessel.Orthrus },
|
||||
{ 60000000, ThargoidVessel.Hydra },
|
||||
};
|
||||
|
||||
|
||||
28
EDPlayerJournalTests/CombatZoneTest.cs
Normal file
28
EDPlayerJournalTests/CombatZoneTest.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using EDPlayerJournal;
|
||||
using EDPlayerJournal.Entries;
|
||||
using EDPlayerJournal.BGS;
|
||||
|
||||
namespace EDPlayerJournalTests;
|
||||
|
||||
[TestClass]
|
||||
public class CombatZoneTest {
|
||||
[TestMethod]
|
||||
public void DropshipDeployTest() {
|
||||
TransactionParser parser = new();
|
||||
|
||||
List<Entry>? entries = Helper.LoadTestData("dropship-deploy.txt");
|
||||
Assert.IsNotNull(entries);
|
||||
|
||||
List<Transaction>? transactions = parser.Parse(entries);
|
||||
Assert.IsNotNull(transactions);
|
||||
|
||||
Vouchers? vouchers = transactions[0] as Vouchers;
|
||||
Assert.IsNotNull(vouchers);
|
||||
|
||||
CombatZone? combatzone = transactions[1] as CombatZone;
|
||||
Assert.IsNotNull(combatzone);
|
||||
|
||||
Assert.AreEqual(combatzone.Type, CombatZones.GroundCombatZone);
|
||||
Assert.AreEqual(combatzone.Grade, CombatZones.DifficultyHigh);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,9 @@
|
||||
<None Update="double-support.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="dropship-deploy.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="legacy-transaction.txt">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
|
||||
63
EDPlayerJournalTests/dropship-deploy.txt
Normal file
63
EDPlayerJournalTests/dropship-deploy.txt
Normal file
@@ -0,0 +1,63 @@
|
||||
{"timestamp":"2022-12-09T14:23:52Z","event":"Fileheader","part":1,"language":"English/UK","Odyssey":true,"gameversion":"4.0.0.1476","build":"r289925/r0 "}
|
||||
{"timestamp":"2022-12-09T14:33:01Z","event":"Location","DistFromStarLS":774.492896,"Docked":false,"OnFoot":true,"StarSystem":"Kazahua","SystemAddress":2871050905001,"StarPos":[93.28125,-180.25,14.6875],"SystemAllegiance":"Empire","SystemEconomy":"$economy_Industrial;","SystemEconomy_Localised":"Industrial","SystemSecondEconomy":"$economy_Colony;","SystemSecondEconomy_Localised":"Colony","SystemGovernment":"$government_Patronage;","SystemGovernment_Localised":"Patronage","SystemSecurity":"$SYSTEM_SECURITY_low;","SystemSecurity_Localised":"Low Security","Population":17949,"Body":"Kazahua 4 a","BodyID":5,"BodyType":"Planet","Factions":[{"Name":"Kazahua Co","FactionState":"None","Government":"Corporate","Influence":0.049098,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"Kazahua Crimson Ring","FactionState":"None","Government":"Anarchy","Influence":0.01002,"Allegiance":"Independent","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"HIP 10611 Shared","FactionState":"None","Government":"Cooperative","Influence":0.091182,"Allegiance":"Independent","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":2.97},{"Name":"Traditional Yao Tzu Liberty Party","FactionState":"None","Government":"Dictatorship","Influence":0.058116,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":-10.56},{"Name":"Sapii allied","FactionState":"War","Government":"Cooperative","Influence":0.395792,"Allegiance":"Independent","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":-6.0,"ActiveStates":[{"State":"War"}]},{"Name":"Nova Paresa","FactionState":"War","Government":"Patronage","Influence":0.395792,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","SquadronFaction":true,"MyReputation":63.045399,"ActiveStates":[{"State":"War"}]}],"SystemFaction":{"Name":"Nova Paresa","FactionState":"War"},"Conflicts":[{"WarType":"war","Status":"active","Faction1":{"Name":"Sapii allied","Stake":"Barmin Installation","WonDays":0},"Faction2":{"Name":"Nova Paresa","Stake":"Rabinowitz Colony","WonDays":0}}]}
|
||||
{"timestamp":"2022-12-09T14:33:05Z","event":"ReceiveText","From":"Barmin Installation","Message":"$STATION_NoFireZone_entered;","Message_Localised":"No fire zone entered.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:36:52Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol02;","Message_Localised":"Requesting docking clearance, Control.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:39:54Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_StartPatrol01;","Message_Localised":"Patrol craft checking in. Pre-flight checks complete, I'm heading out.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:42:02Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol04;","Message_Localised":"Negative, Tower, I'm bingo on fuel, RTB.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:42:05Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol02;","Message_Localised":"Requesting docking clearance, Control.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:45:23Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_StartPatrol01;","Message_Localised":"Patrol craft checking in. Pre-flight checks complete, I'm heading out.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:45:51Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_StartPatrol04;","Message_Localised":"I'm away, heading to patrol route alpha now.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:46:22Z","event":"RedeemVoucher","Type":"CombatBond","Amount":17406041,"Faction":"Nova Paresa"}
|
||||
{"timestamp":"2022-12-09T14:49:17Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol02;","Message_Localised":"Requesting docking clearance, Control.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:49:43Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_EndPatrol05;","Message_Localised":"Patrol completed, Command, I'm heading home.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:52:32Z","event":"ReceiveText","From":"$ShipName_Police_Independent;","From_Localised":"System Authority Vessel","Message":"$Police_StartPatrol01;","Message_Localised":"Patrol craft checking in. Pre-flight checks complete, I'm heading out.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T14:52:34Z","event":"Embark","SRV":false,"Taxi":true,"Multicrew":false,"StarSystem":"Kazahua","SystemAddress":2871050905001,"Body":"Kazahua 4 a","BodyID":5,"OnStation":false,"OnPlanet":true}
|
||||
{"timestamp":"2022-12-09T14:53:29Z","event":"SupercruiseEntry","Taxi":true,"Multicrew":false,"StarSystem":"Kazahua","SystemAddress":2871050905001}
|
||||
{"timestamp":"2022-12-09T14:58:16Z","event":"DropshipDeploy","StarSystem":"Kazahua","SystemAddress":2871050905001,"Body":"Kazahua 2","BodyID":2,"OnStation":false,"OnPlanet":true}
|
||||
{"timestamp":"2022-12-09T14:59:38Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:00:02Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:00:12Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:00:33Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:00:45Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:01:07Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:01:11Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough06;","Message_Localised":"On patrol. Scanning for hostiles.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:02:12Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:21Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:24Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:32Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:42Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:45Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:02:50Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough09;","Message_Localised":"This is a routine patrol. There's nothing to worry about.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:04:03Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:04:03Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough06;","Message_Localised":"On patrol. Scanning for hostiles.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:04:09Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:04:13Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:04:25Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:05:06Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough06;","Message_Localised":"On patrol. Scanning for hostiles.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:05:10Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough10;","Message_Localised":"System sweep in operation.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:05:19Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough06;","Message_Localised":"On patrol. Scanning for hostiles.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:05:22Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:05:35Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:05:44Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:11Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:22Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough08;","Message_Localised":"Patrol waypoint reached. Scanning.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:06:27Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:27Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:39Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:06:44Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough09;","Message_Localised":"This is a routine patrol. There's nothing to worry about.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:06:50Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:07:03Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:07:11Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:07:15Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:07:26Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:20Z","event":"FactionKillBond","Reward":52500,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:26Z","event":"FactionKillBond","Reward":65358,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:29Z","event":"ReceiveText","From":"$ShipName_Military_Independent;","From_Localised":"System Defence Force","Message":"$Military_Passthrough07;","Message_Localised":"No need to worry, the navy is here.","Channel":"npc"}
|
||||
{"timestamp":"2022-12-09T15:08:33Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:47Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:08:48Z","event":"FactionKillBond","Reward":87362,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:00Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:00Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:08Z","event":"FactionKillBond","Reward":39642,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:20Z","event":"FactionKillBond","Reward":78777,"AwardingFaction":"Nova Paresa","VictimFaction":"Sapii allied"}
|
||||
{"timestamp":"2022-12-09T15:09:46Z","event":"Shutdown"}
|
||||
@@ -2,7 +2,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<Version>0.2.0</Version>
|
||||
<Version>0.2.6</Version>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
@@ -18,6 +18,8 @@
|
||||
<Copyright>Copyright 2019 by Florian Stinglmayr</Copyright>
|
||||
<RepositoryUrl>https://git.aror.org/florian/EDBGS</RepositoryUrl>
|
||||
<PackageTags>ED;Elite Dangerous;BGS</PackageTags>
|
||||
<PackageProjectUrl>https://bgs.n0la.org</PackageProjectUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="main-page.png">
|
||||
@@ -25,6 +27,8 @@
|
||||
</Resource>
|
||||
<None Update="README.md">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<Pack>True</Pack>
|
||||
<PackagePath>\</PackagePath>
|
||||
</None>
|
||||
<None Update="docs\CHANGELOG.md">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
@@ -55,11 +59,12 @@
|
||||
<Resource Include="EliteBGS.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,19 +8,25 @@ namespace EliteBGS.LogGenerator;
|
||||
public class FailedMissionFormat : LogFormatter {
|
||||
public string GenerateLog(Objective objective) {
|
||||
var missions = objective.EnabledOfType<MissionFailed>();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (missions.Count <= 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
foreach (MissionFailed failed in missions) {
|
||||
MissionFailedEntry f = failed.Failed;
|
||||
builder.AppendFormat("Failed {0} mission(s) \"{1}\" targeting {2}\n",
|
||||
failed.Amount,
|
||||
string.IsNullOrEmpty(f.Mission.LocalisedName) ? f.Mission.Name : f.Mission.LocalisedName,
|
||||
failed.Faction
|
||||
);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
var grouping = missions
|
||||
.GroupBy(x => x.Mission.IsOnFoot)
|
||||
;
|
||||
|
||||
foreach (var group in grouping) {
|
||||
int amount = group.Count();
|
||||
|
||||
if (group.Key) {
|
||||
builder.AppendFormat("Failed {0} On Foot Mission(s)\n", amount);
|
||||
} else {
|
||||
builder.AppendFormat("Failed {0} Ship Mission(s)\n", amount);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.ToString().Trim();
|
||||
|
||||
@@ -7,13 +7,16 @@ namespace EliteBGS.LogGenerator;
|
||||
|
||||
public class MissionFormat : LogFormatter {
|
||||
public string GenerateLog(Objective objective) {
|
||||
Dictionary<string, Dictionary<string, int>> collated = new Dictionary<string, Dictionary<string, int>>();
|
||||
Dictionary<string, Dictionary<string, int>> collated = new();
|
||||
Dictionary<string, ulong> passengers = new();
|
||||
StringBuilder output = new StringBuilder();
|
||||
int total_influence = 0;
|
||||
|
||||
var missions = objective.EnabledOfType<MissionCompleted>();
|
||||
var support = objective.EnabledOfType<InfluenceSupport>();
|
||||
|
||||
if (missions == null || missions.Count == 0) {
|
||||
if ((missions == null || missions.Count == 0) &&
|
||||
(support == null || support.Count == 0)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -28,6 +31,15 @@ public class MissionFormat : LogFormatter {
|
||||
++collated[m.MissionName][m.Influence];
|
||||
|
||||
total_influence += m.Influence.Length;
|
||||
|
||||
if (m.AcceptedEntry != null &&
|
||||
m.AcceptedEntry.Mission != null &&
|
||||
m.AcceptedEntry.Mission.IsPassengerMission) {
|
||||
if (!passengers.ContainsKey(m.MissionName)) {
|
||||
passengers[m.MissionName] = 0;
|
||||
}
|
||||
passengers[m.MissionName] += (m.AcceptedEntry.Mission.PassengerCount ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var mission in collated) {
|
||||
@@ -37,10 +49,17 @@ public class MissionFormat : LogFormatter {
|
||||
output.AppendFormat("Inf{0} x{1}, ", influence.Key, influence.Value);
|
||||
}
|
||||
output.Remove(output.Length - 2, 2); // remove last ", "
|
||||
output.Append(")\n\n");
|
||||
output.Append(")");
|
||||
|
||||
if (passengers.ContainsKey(mission.Key)) {
|
||||
output.AppendFormat(" ({0} Passengers)", passengers[mission.Key]);
|
||||
}
|
||||
|
||||
output.Append("\n");
|
||||
}
|
||||
|
||||
var support = objective.EnabledOfType<InfluenceSupport>();
|
||||
output.Append("\n");
|
||||
|
||||
foreach (InfluenceSupport inf in support) {
|
||||
output.Append(inf.ToString());
|
||||
output.Append("\n");
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:abc="http://wpfcontrols.com/"
|
||||
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
|
||||
xmlns:local="clr-namespace:EliteBGS"
|
||||
xmlns:Util="clr-namespace:EliteBGS.Util" d:DataContext="{d:DesignInstance Type=Util:AppConfig}" x:Name="window" x:Class="EliteBGS.MainWindow"
|
||||
mc:Ignorable="d"
|
||||
Title="Elite: Dangerous BGS Helper" Height="520" Width="890" Icon="Salus.ico" Closing="window_Closing">
|
||||
Title="Elite: Dangerous BGS Helper" Height="520" Width="950" Icon="Salus.ico" Closing="window_Closing">
|
||||
<Window.Resources>
|
||||
<Style x:Key="StretchingTreeViewStyle" TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
@@ -27,24 +28,31 @@
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<ToolBar VerticalAlignment="Top" Grid.Row="1" Width="Auto" Margin="0,0,0,0" Height="Auto" Grid.ColumnSpan="3" HorizontalAlignment="Left">
|
||||
<ToolBar VerticalAlignment="Top" Grid.Row="0" 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"/>
|
||||
<Label Content="From:" VerticalAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<DatePicker x:Name="startdate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<Label Content="To:" Height="26.2857142857143" VerticalAlignment="Top"/>
|
||||
<DatePicker x:Name="enddate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<Label Content="From (UTC):" VerticalAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<xctk:DateTimePicker x:Name="startdate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<Label Content="To (UTC):" Height="26.2857142857143" VerticalAlignment="Top"/>
|
||||
<xctk:DateTimePicker x:Name="enddate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
||||
<Button x:Name="ManuallyParse" Content="Manually Parse JSON" Click="ManuallyParse_Click" />
|
||||
<Button x:Name="ResetTime" Content="Reset Time" Click="ResetTime_Click" />
|
||||
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
||||
<Button x:Name="ManuallyParse" Content="Manually Parse" Click="ManuallyParse_Click" />
|
||||
</ToolBar>
|
||||
<ToolBar Grid.Row="1" HorizontalAlignment="Left" Height="36" VerticalAlignment="Top" Width="Auto" Grid.ColumnSpan="3">
|
||||
<Button x:Name="GenerateDiscord" Content="Generate Discord Report" VerticalAlignment="Stretch" Margin="0,0,0,0" VerticalContentAlignment="Center" Click="GenerateDiscord_Click" Height="26"/>
|
||||
<Separator />
|
||||
<ComboBox x:Name="LogType" VerticalAlignment="Stretch" Margin="0,3,0,3" Width="140" SelectionChanged="LogType_SelectionChanged" />
|
||||
</ToolBar>
|
||||
<TreeView CheckBox.Checked="TreeView_CheckBox_Updated"
|
||||
CheckBox.Unchecked="TreeView_CheckBox_Updated"
|
||||
@@ -65,15 +73,17 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,5,0,5">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,2,0,2">
|
||||
<CheckBox Focusable="False" IsChecked="{Binding IsEnabled}" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="System: " Visibility="{Binding HasSystem}" Margin="5,0,0,0"/>
|
||||
<TextBlock Text="System: " Visibility="{Binding HasSystem}" Margin="2,0,0,0"/>
|
||||
<TextBlock Text="{Binding System}" FontWeight="DemiBold" Visibility="{Binding HasSystem}"/>
|
||||
<TextBlock Text="Faction: " Visibility="{Binding HasFaction}" Margin="5,0,0,0"/>
|
||||
<TextBlock Text="Faction: " Visibility="{Binding HasFaction}" Margin="2,0,0,0"/>
|
||||
<TextBlock Text="{Binding Faction}" FontWeight="DemiBold" Visibility="{Binding HasFaction}"/>
|
||||
</StackPanel>
|
||||
<Separator Visibility="Hidden" Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" />
|
||||
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Orientation="Horizontal">
|
||||
<ToggleButton x:Name="ToggleAll" Content="Toggle All" Click="ToggleAll_Click" IsChecked="True" IsThreeState="False"/>
|
||||
<Separator Margin="2,0,2,0" />
|
||||
<Button x:Name="AddCombatZone" Content="Add Combat Zone" Click="AddCombatZone_Click" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
@@ -83,7 +93,7 @@
|
||||
<Grid Initialized="Transaction_Initialized"
|
||||
HorizontalAlignment="Stretch"
|
||||
Width="{Binding ActualWidth, ElementName=entries, Converter={StaticResource MinusFortyFiveConverter}}"
|
||||
Margin="0,5,0,5"
|
||||
Margin="0,2,0,2"
|
||||
>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
@@ -93,7 +103,7 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Center">
|
||||
<CheckBox Focusable="False" IsChecked="{Binding IsEnabled}" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="{Binding CompletedAt}" Margin="5,0,5,0" HorizontalAlignment="Right" TextAlignment="Center"/>
|
||||
<TextBlock Text="{Binding CompletedAt}" Margin="2,0,2,0" HorizontalAlignment="Right" TextAlignment="Center"/>
|
||||
<TextBlock Text="{Binding Name}" FontWeight="DemiBold" TextAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right" x:Name="CombatZone" Visibility="{Binding IsCombatZone}">
|
||||
@@ -136,12 +146,8 @@
|
||||
</Style>
|
||||
</TreeView.ItemContainerStyle>
|
||||
</TreeView>
|
||||
<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="4" Grid.ColumnSpan="3" AcceptsReturn="True" AcceptsTab="True"/>
|
||||
<GridSplitter Background="LightSkyBlue" Grid.Row="3" Height="5" HorizontalAlignment="Stretch" VerticalAlignment="Top" Grid.ColumnSpan="3" ResizeBehavior="PreviousAndNext"/>
|
||||
<TextBox x:Name="DiscordLog" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="4" Height="Auto" TextWrapping="Wrap" FontFamily="Consolas" FontSize="14" Grid.ColumnSpan="3" AcceptsReturn="True" AcceptsTab="True"/>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
<TabItem Header="Settings" HorizontalAlignment="Left" Height="20" VerticalAlignment="Top" Width="53.7142857142857">
|
||||
|
||||
@@ -11,7 +11,9 @@ using EDPlayerJournal.BGS;
|
||||
using EDPlayerJournal.Entries;
|
||||
using EliteBGS.BGS;
|
||||
using EliteBGS.Util;
|
||||
using System.Globalization;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace EliteBGS;
|
||||
|
||||
@@ -56,40 +58,25 @@ public partial class MainWindow : Window {
|
||||
journal = new PlayerJournal(Config.Global.JournalLocation);
|
||||
|
||||
// Set both to now
|
||||
startdate.SelectedDate = DateTime.Now;
|
||||
enddate.SelectedDate = DateTime.Now;
|
||||
InitialiseTime();
|
||||
|
||||
journallocation.Text = Config.Global.JournalLocation;
|
||||
}
|
||||
|
||||
private void InitialiseTime() {
|
||||
DateTime today = DateTime.Today;
|
||||
DateTime tomorrow = today.AddDays(1);
|
||||
|
||||
startdate.CultureInfo = enddate.CultureInfo = CultureInfo.InvariantCulture;
|
||||
|
||||
startdate.Value = today;
|
||||
enddate.Value = tomorrow;
|
||||
}
|
||||
|
||||
private void TreeView_CheckBox_Updated(object sender, RoutedEventArgs args) {
|
||||
GenerateLog();
|
||||
}
|
||||
|
||||
private void HandleEntries(List<Entry> entries) {
|
||||
try {
|
||||
TransactionParser parser = new TransactionParser();
|
||||
List<Transaction> transactions = parser.Parse(entries);
|
||||
|
||||
List<IncompleteTransaction> incompletes = transactions.OfType<IncompleteTransaction>().ToList();
|
||||
// Log incomplete and remove them from the results.
|
||||
foreach (var incomplete in incompletes) {
|
||||
Log(incomplete.Reason);
|
||||
}
|
||||
transactions.RemoveAll(x => incompletes.Contains(x));
|
||||
|
||||
report = new Report(transactions);
|
||||
this.entries.ItemsSource = report.Objectives;
|
||||
} catch (Exception exception) {
|
||||
Log("Something went terribly wrong while parsing the E:D player journal.");
|
||||
Log("Please send this to CMDR Hekateh:");
|
||||
Log(exception.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void Loadentries_EntriesLoaded(List<Entry> lines) {
|
||||
HandleEntries(lines);
|
||||
}
|
||||
|
||||
private void Report_OnLog(string message) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
@@ -105,12 +92,47 @@ public partial class MainWindow : Window {
|
||||
Report_OnLog(message);
|
||||
}
|
||||
|
||||
private void HandleEntries(List<Entry> entries, DateTime start, DateTime end) {
|
||||
try {
|
||||
TransactionParser parser = new TransactionParser();
|
||||
List<Transaction> transactions = parser.Parse(entries);
|
||||
|
||||
// Filter the transactions down to the given time frame
|
||||
transactions = transactions
|
||||
.Where(t => t.CompletedAtDateTime >= start && t.CompletedAtDateTime <= end)
|
||||
.ToList()
|
||||
;
|
||||
|
||||
List<IncompleteTransaction> incompletes = transactions.OfType<IncompleteTransaction>().ToList();
|
||||
// Log incomplete and remove them from the results.
|
||||
foreach (var incomplete in incompletes) {
|
||||
Log(incomplete.Reason);
|
||||
}
|
||||
transactions.RemoveAll(x => incompletes.Contains(x));
|
||||
|
||||
report = new Report(transactions);
|
||||
this.entries.ItemsSource = report.Objectives;
|
||||
} catch (Exception exception) {
|
||||
Log("Something went terribly wrong while parsing the E:D player journal.");
|
||||
Log("Please send this to CMDR Hekateh:");
|
||||
Log(exception.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEntries(List<Entry> entries) {
|
||||
HandleEntries(entries, startdate.Value ?? DateTime.Now, enddate.Value ?? DateTime.Now);
|
||||
}
|
||||
|
||||
private void Loadentries_EntriesLoaded(List<Entry> lines) {
|
||||
HandleEntries(lines);
|
||||
}
|
||||
|
||||
private void ParseJournal_Click(object sender, RoutedEventArgs e) {
|
||||
try {
|
||||
TransactionParser parser = new TransactionParser();
|
||||
|
||||
DateTime start = startdate.SelectedDate ?? DateTime.Now;
|
||||
DateTime end = enddate.SelectedDate ?? DateTime.Now;
|
||||
DateTime start = startdate.Value ?? DateTime.Now;
|
||||
DateTime end = enddate.Value ?? DateTime.Now;
|
||||
|
||||
journal.Open(); // Load all files
|
||||
// Log files only get rotated if you restart the game client. This means that there might
|
||||
@@ -121,21 +143,14 @@ public partial class MainWindow : Window {
|
||||
// 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);
|
||||
DateTime actualend = end.AddDays(1);
|
||||
List<Entry> entries = journal.Files
|
||||
.Where(f => f.NormalisedDateTime >= actualstart && f.NormalisedDateTime <= end)
|
||||
.Where(f => f.NormalisedDateTime >= actualstart && f.NormalisedDateTime <= actualend)
|
||||
.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()
|
||||
;
|
||||
|
||||
HandleEntries(entries);
|
||||
HandleEntries(entries, start, end);
|
||||
GenerateLog();
|
||||
} catch (Exception exception) {
|
||||
Log("Something went terribly wrong while parsing the E:D player journal.");
|
||||
@@ -203,13 +218,17 @@ public partial class MainWindow : Window {
|
||||
journal = new PlayerJournal(Config.Global.JournalLocation);
|
||||
}
|
||||
|
||||
private void AddCombatZone_Click(object sender, RoutedEventArgs e) {
|
||||
private Objective GetObjectiveFromControl(object sender) {
|
||||
System.Windows.Controls.Control control = sender as System.Windows.Controls.Control;
|
||||
if (control == null || control.DataContext == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
Objective objective = control.DataContext as Objective;
|
||||
return control.DataContext as Objective;
|
||||
}
|
||||
|
||||
private void AddCombatZone_Click(object sender, RoutedEventArgs e) {
|
||||
Objective objective = GetObjectiveFromControl(sender);
|
||||
if (objective == null) {
|
||||
return;
|
||||
}
|
||||
@@ -359,4 +378,38 @@ public partial class MainWindow : Window {
|
||||
RefreshView();
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime ResetTimeToZero(DateTime d) {
|
||||
DateTime obj = d;
|
||||
|
||||
obj = obj.AddHours(d.Hour * -1);
|
||||
obj = obj.AddMinutes(d.Minute * -1);
|
||||
obj = obj.AddSeconds(d.Second * -1);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private void ResetTime_Click(object sender, RoutedEventArgs e) {
|
||||
DateTime? d = startdate.Value;
|
||||
if (d != null) {
|
||||
startdate.Value = ResetTimeToZero(d.Value);
|
||||
}
|
||||
|
||||
d = enddate.Value;
|
||||
if (d != null) {
|
||||
enddate.Value = ResetTimeToZero(d.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleAll_Click(object sender, RoutedEventArgs e) {
|
||||
ToggleButton button = sender as ToggleButton;
|
||||
Objective objective = GetObjectiveFromControl(sender);
|
||||
if (objective == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
objective.UITransactions
|
||||
.ForEach(x => x.IsEnabled = (button.IsChecked ?? true))
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,15 @@ public class NonaDiscordLog : DiscordLogGenerator {
|
||||
private string FormatDate() {
|
||||
CultureInfo cultureInfo = CultureInfo.InvariantCulture;
|
||||
StringBuilder date = new StringBuilder();
|
||||
DateTime today = DateTime.Now;
|
||||
DateTime today = DateTime.UtcNow;
|
||||
string suffix;
|
||||
|
||||
if (today.Day == 1 || today.Day == 21 || today.Day == 31) {
|
||||
suffix = "st";
|
||||
} else if (today.Day == 2 || today.Day == 22) {
|
||||
suffix = "nd";
|
||||
} else if (today.Day == 23) {
|
||||
// Shakaka wins the price for finding this "bug"!
|
||||
} else if (today.Day == 3 || today.Day == 23) {
|
||||
suffix = "rd";
|
||||
} else {
|
||||
suffix = "th";
|
||||
|
||||
@@ -6,11 +6,22 @@ using EDPlayerJournal.BGS;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using EDPlayerJournal;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace EliteBGS;
|
||||
|
||||
public class UITransaction {
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
public class UITransaction : INotifyPropertyChanged {
|
||||
private bool isenabled = true;
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public bool IsEnabled {
|
||||
get { return isenabled; }
|
||||
set {
|
||||
isenabled = value;
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsEnabled"));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsExpanded { get; set; } = true;
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace EliteBGS;
|
||||
namespace EliteBGS;
|
||||
|
||||
public class OneLineDiscordLog : DiscordLogGenerator {
|
||||
protected override string GenerateObjectiveHeader(Objective objective) {
|
||||
if (!string.IsNullOrEmpty(objective.Faction)) {
|
||||
return string.Format("{0} for {1}: ", objective.System, objective.Faction);
|
||||
return string.Format("**{0}** for **{1}**: ", objective.System, objective.Faction);
|
||||
} else {
|
||||
return string.Format("{0}: ", objective.System);
|
||||
return string.Format("**{0}**: ", objective.System);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# EliteBGS
|
||||
# EDBGS
|
||||
|
||||
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).
|
||||
Source code is available at [https://codeberg.org/nola/edbgs](https://codeberg.org/nola/edbgs).
|
||||
|
||||
Binary downloads can be found here: [https://bgs.n0la.org/](https://bgs.n0la.org/).
|
||||
|
||||
@@ -24,6 +24,8 @@ transactions. Currently the tool recognises the following transactions:
|
||||
* Selling of micro resources (Odyssey only)
|
||||
* Selling of organic data (Odyssey only)
|
||||
* Vouchers, including bounty vouchers, combat bonds, and settlement vouchers (aka intel packages)
|
||||
* Thargoid kills
|
||||
* Contributions to Thargoid war effort
|
||||
|
||||
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
|
||||
@@ -221,13 +223,11 @@ It would be helpful if you included the JSON player journal. This player journal
|
||||
|
||||
## 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:
|
||||
|
||||
The project also requires `Ookii.Dialogs.WPF` controls, which contains the auto complete text box.
|
||||
|
||||
And of course, `Newtonsoft.Json` as the JSON parser.
|
||||
* `Ookii.Dialogs.WPF`
|
||||
* `Newtonsoft.Json`
|
||||
* `Extended.Wpf.Toolkit`
|
||||
|
||||
## About
|
||||
|
||||
|
||||
@@ -1,5 +1,43 @@
|
||||
# EliteBGS changelog
|
||||
|
||||
## 0.2.6 on 04.02.2023
|
||||
|
||||
* Update Post 14.02 Thargoid bounties
|
||||
* Just summarise failed missions by on-foot and ship, instead of a detailed view
|
||||
* Add some more English mission names
|
||||
* Move code hosting to [CodeBerg](https://codeberg.org/)
|
||||
|
||||
## 0.2.5 on 20.12.2022
|
||||
|
||||
* Repaired mission fails.
|
||||
* Added support for Missions entry.
|
||||
|
||||
## 0.2.4 on 18.12.2022
|
||||
|
||||
* Fixed bug with organic data.
|
||||
* Fixed bug in mission format.
|
||||
* You can now select also a time when filtering transactions.
|
||||
* Added a button to toggle all children on and off at once.
|
||||
* Date in Nova Navy discord log is now UTC.
|
||||
* Added a divider so you can rescale the objectives and the log to a preferred aspect ratio.
|
||||
|
||||
## 0.2.3 on 11.12.2022
|
||||
|
||||
* Fixed detection of medium ground combat zones.
|
||||
* Improve detection of things done near or around a new day. The tool should not properly
|
||||
pick up missions done the previous day, and completed at the selected day.
|
||||
* Add support for ground combat zones when done using Frontier Solutions (DropshipDeploy).
|
||||
* Add more mission names for Thargoid war.
|
||||
* Relogs in an on foot combat zone are now properly detected.
|
||||
|
||||
## 0.2.2 on 07.12.2022
|
||||
|
||||
* Orthrus interceptor payout changed to U14.1 values.
|
||||
* Detection of AX combat zones has been improved.
|
||||
* All thargoid war missions now contribute to the system.
|
||||
* Thargoid combat zones go to "Very High".
|
||||
* Passenger missions show amount of people rescued.
|
||||
|
||||
## 0.2.1 on 03.12.2022
|
||||
|
||||
* Add support for Thargoid combat zones.
|
||||
|
||||
@@ -18,12 +18,6 @@ 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
|
||||
@@ -91,4 +85,3 @@ Sometimes, due to a bug, the bounty vouchers in the journal have no faction info
|
||||
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.
|
||||
|
||||
|
||||
@@ -13,9 +13,16 @@ The tool requires .NET 7.0, you can download it from Microsoft here:
|
||||
|
||||
* [https://dotnet.microsoft.com/en-us/download/dotnet/7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0)
|
||||
|
||||
You can download the **latest** version **0.2.1** here:
|
||||
If you have problems with the installer, you might try running the following in the Windows
|
||||
command line:
|
||||
|
||||
* [https://bgs.n0la.org/elitebgs-0.2.1.zip](https://bgs.n0la.org/elitebgs-0.2.1.zip)
|
||||
```
|
||||
winget install Microsoft.DotNet.DesktopRuntime.7
|
||||
```
|
||||
|
||||
You can download the **latest** version **0.2.5** here:
|
||||
|
||||
* [https://bgs.n0la.org/elitebgs-0.2.5.zip](https://bgs.n0la.org/elitebgs-0.2.5.zip)
|
||||
|
||||
## Old Versions
|
||||
|
||||
@@ -65,7 +72,7 @@ The tool itself is Open Source, licenced unter the GPLv3.
|
||||
|
||||
The source code can be found here:
|
||||
|
||||
* [https://git.aror.org/florian/EDBGS](https://git.aror.org/florian/EDBGS)
|
||||
* [https://codeberg.org/nola/edbgs](https://codeberg.org/nola/edbgs)
|
||||
|
||||
## Contact
|
||||
|
||||
|
||||
11
README.md
Normal file
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# EDBGS
|
||||
|
||||
EDBGS is a project containing the EliteBGS BGS application. It also contains the dotnet
|
||||
class library EDPlayerJournal, which reads and parses Elite Dangerous player journals.
|
||||
|
||||
See [https://bgs.n0la.org/](https://bgs.n0la.org) for further details.
|
||||
|
||||
## Requirements
|
||||
|
||||
This repository depends on dotnet desktop SDK 7, as well as Newtonsoft.JSON, Extended
|
||||
WPF toolkit, and Ookii Dialogs.
|
||||
Reference in New Issue
Block a user