2021-07-09 11:03:30 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2021-08-25 16:36:57 +02:00
|
|
|
|
using EDJournal;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
|
2021-11-10 21:24:39 +01:00
|
|
|
|
namespace EliteBGS.BGS {
|
2021-07-09 11:03:30 +02:00
|
|
|
|
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) {
|
2021-07-09 11:30:11 +02:00
|
|
|
|
var found = objectives.Find(x => x.CompareTo(objective) == 0);
|
2021-07-09 11:03:30 +02:00
|
|
|
|
bool added = false;
|
|
|
|
|
|
|
|
|
|
if (found == null) {
|
|
|
|
|
objectives.Add(objective);
|
|
|
|
|
added = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return added;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool IsRelevant(Entry e) {
|
|
|
|
|
return e.Is(Events.MissionCompleted) ||
|
2021-11-12 22:23:40 +01:00
|
|
|
|
e.Is(Events.MissionFailed) ||
|
|
|
|
|
e.Is(Events.MissionAccepted) ||
|
2021-07-09 11:03:30 +02:00
|
|
|
|
e.Is(Events.Docked) ||
|
|
|
|
|
e.Is(Events.FSDJump) ||
|
2021-11-15 19:54:04 +01:00
|
|
|
|
e.Is(Events.Location) ||
|
2021-07-09 11:03:30 +02:00
|
|
|
|
e.Is(Events.MultiSellExplorationData) ||
|
|
|
|
|
e.Is(Events.SellMicroResources) ||
|
2021-09-28 13:20:59 +02:00
|
|
|
|
e.Is(Events.RedeemVoucher) ||
|
2021-09-28 14:41:09 +02:00
|
|
|
|
e.Is(Events.FactionKillBond) ||
|
|
|
|
|
e.Is(Events.MarketSell)
|
2021-07-09 11:03:30 +02:00
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Scan(PlayerJournal journal, DateTime start, DateTime end) {
|
|
|
|
|
var entries = from file in journal.Files
|
|
|
|
|
where file.NormalisedTimestamp >= start && file.NormalisedTimestamp <= end
|
|
|
|
|
select file.Entries
|
|
|
|
|
;
|
|
|
|
|
var relevant = from log in entries.SelectMany(array => array)
|
|
|
|
|
where IsRelevant(log)
|
|
|
|
|
select log
|
|
|
|
|
;
|
|
|
|
|
|
2021-11-12 22:23:40 +01:00
|
|
|
|
Dictionary<int, MissionAcceptedEntry> acceptedMissions = new Dictionary<int, MissionAcceptedEntry>();
|
|
|
|
|
|
2021-07-09 11:03:30 +02:00
|
|
|
|
string current_system = null;
|
|
|
|
|
string current_station = null;
|
|
|
|
|
string controlling_faction = null;
|
|
|
|
|
|
2021-09-30 13:28:52 +02:00
|
|
|
|
objectives.ForEach(x => x.Clear());
|
2021-07-09 11:03:30 +02:00
|
|
|
|
|
|
|
|
|
foreach (var e in relevant) {
|
|
|
|
|
LogEntry entry = null;
|
2021-08-04 17:50:46 +02:00
|
|
|
|
bool collate = false;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
|
|
|
|
|
if (e.Is(Events.Docked)) {
|
2021-11-17 21:01:35 +01:00
|
|
|
|
DockedEntry docked = e as DockedEntry;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
/* gleem the current station from this message
|
|
|
|
|
*/
|
2021-11-17 21:01:35 +01:00
|
|
|
|
current_station = docked.StationName;
|
|
|
|
|
current_system = docked.StarSystem;
|
|
|
|
|
controlling_faction = docked.StationFaction;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
} else if (e.Is(Events.FSDJump)) {
|
2021-07-09 11:39:09 +02:00
|
|
|
|
/* Gleem current system and controlling faction from this message.
|
|
|
|
|
*/
|
2021-07-09 11:03:30 +02:00
|
|
|
|
current_system = (e as FSDJumpEntry).StarSystem;
|
|
|
|
|
controlling_faction = (e as FSDJumpEntry).SystemFaction;
|
2021-11-15 19:54:04 +01:00
|
|
|
|
} else if (e.Is(Events.Location)) {
|
|
|
|
|
/* Get current system, faction name and station from Location message
|
|
|
|
|
*/
|
|
|
|
|
LocationEntry location = e as LocationEntry;
|
|
|
|
|
|
|
|
|
|
current_system = location.StarSystem;
|
|
|
|
|
if (!string.IsNullOrEmpty(location.SystemFaction)) {
|
|
|
|
|
controlling_faction = location.SystemFaction;
|
|
|
|
|
}
|
|
|
|
|
if (!string.IsNullOrEmpty(location.StationName)) {
|
|
|
|
|
current_station = location.StationName;
|
|
|
|
|
}
|
2021-07-09 11:03:30 +02:00
|
|
|
|
} else if (e.Is(Events.MissionCompleted)) {
|
|
|
|
|
var completed = e as MissionCompletedEntry;
|
2021-11-17 21:01:35 +01:00
|
|
|
|
entry = new MissionCompleted(completed) {
|
|
|
|
|
System = current_system,
|
|
|
|
|
Station = current_station
|
|
|
|
|
};
|
2021-07-09 11:03:30 +02:00
|
|
|
|
if (completed.HumanReadableNameWasGenerated) {
|
2021-07-09 11:39:09 +02:00
|
|
|
|
/* If the human readable name was generated, we send a log message. Because the
|
|
|
|
|
* generated names all sort of suck, we should have more human readable names in
|
|
|
|
|
* in the lookup dictionary.
|
|
|
|
|
*/
|
2021-07-09 11:03:30 +02:00
|
|
|
|
OnLog?.Invoke("Human readable name for mission \"" +
|
|
|
|
|
completed.Name +
|
|
|
|
|
"\" was generated, please report this.");
|
|
|
|
|
}
|
2021-11-12 22:23:40 +01:00
|
|
|
|
} else if (e.Is(Events.MissionAccepted)) {
|
|
|
|
|
MissionAcceptedEntry accepted = e as MissionAcceptedEntry;
|
|
|
|
|
acceptedMissions[accepted.MissionID] = accepted;
|
|
|
|
|
} else if (e.Is(Events.MissionFailed)) {
|
|
|
|
|
var failed = e as MissionFailedEntry;
|
2022-01-06 16:15:13 +01:00
|
|
|
|
MissionAcceptedEntry accepted = null;
|
|
|
|
|
if (!acceptedMissions.TryGetValue(failed.MissionID, out accepted)) {
|
2022-01-09 13:11:53 +01:00
|
|
|
|
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.");
|
2021-11-12 22:23:40 +01:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
entry = new MissionFailed(accepted) { Failed = failed, System = current_system };
|
|
|
|
|
if (failed.HumanReadableName == null) {
|
|
|
|
|
OnLog?.Invoke("Human readable name for mission \"" +
|
|
|
|
|
failed.Name +
|
|
|
|
|
"\" was not recognised");
|
|
|
|
|
}
|
2022-01-10 18:58:50 +01:00
|
|
|
|
|
|
|
|
|
/* Mission failed should be collated if they are in the same system/station
|
|
|
|
|
*/
|
|
|
|
|
collate = true;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
} else if (e.Is(Events.MultiSellExplorationData)) {
|
2021-07-09 11:39:09 +02:00
|
|
|
|
/* For multi-sell-exploraton-data only the controlling faction of the station sold to matters.
|
|
|
|
|
*/
|
2021-07-09 11:03:30 +02:00
|
|
|
|
entry = new Cartographics(e as MultiSellExplorationDataEntry, current_system, current_station);
|
|
|
|
|
entry.Faction = controlling_faction;
|
|
|
|
|
} else if (e.Is(Events.RedeemVoucher)) {
|
2021-07-09 11:39:09 +02:00
|
|
|
|
/* Same for selling combat vouchers. Only the current controlling faction matters here.
|
|
|
|
|
*/
|
2021-07-09 11:03:30 +02:00
|
|
|
|
entry = new Vouchers();
|
|
|
|
|
entry.Entries.Add(e);
|
|
|
|
|
entry.System = current_system;
|
|
|
|
|
entry.Station = current_station;
|
2021-10-07 20:38:38 +02:00
|
|
|
|
entry.Faction = (e as RedeemVoucherEntry).Factions.FirstOrDefault() ?? "";
|
2021-10-07 09:02:34 +02:00
|
|
|
|
entry.ControllingFaction = controlling_faction;
|
2021-09-28 13:20:59 +02:00
|
|
|
|
|
2021-08-04 17:50:46 +02:00
|
|
|
|
collate = true;
|
2021-07-09 11:03:30 +02:00
|
|
|
|
} else if (e.Is(Events.SellMicroResources)) {
|
2021-10-07 09:02:34 +02:00
|
|
|
|
entry = new SellMicroResources() {
|
|
|
|
|
Faction = controlling_faction,
|
|
|
|
|
Station = current_station,
|
|
|
|
|
System = current_system
|
|
|
|
|
};
|
|
|
|
|
|
2021-09-28 14:41:09 +02:00
|
|
|
|
entry.Entries.Add(e);
|
|
|
|
|
} else if (e.Is(Events.MarketSell)) {
|
|
|
|
|
entry = new SellCargo() {
|
|
|
|
|
Faction = controlling_faction,
|
|
|
|
|
Station = current_station,
|
|
|
|
|
System = current_system
|
|
|
|
|
};
|
|
|
|
|
|
2021-07-09 11:03:30 +02:00
|
|
|
|
entry.Entries.Add(e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (entry == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-09 11:39:09 +02:00
|
|
|
|
/* Find all objectives that generally match.
|
|
|
|
|
*/
|
2021-07-09 11:03:30 +02:00
|
|
|
|
var matches = objectives
|
|
|
|
|
.Where(x => x.Matches(entry) > 0)
|
|
|
|
|
.OrderBy(x => x.Matches(entry))
|
|
|
|
|
;
|
|
|
|
|
|
2021-11-15 19:54:04 +01:00
|
|
|
|
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);
|
2021-08-04 17:50:46 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LogEntry existing = null;
|
|
|
|
|
|
2021-09-30 13:32:31 +02:00
|
|
|
|
existing = objective.LogEntries.Find(x => {
|
2021-11-10 21:24:39 +01:00
|
|
|
|
try {
|
|
|
|
|
return x.CompareTo(entry) == 0;
|
|
|
|
|
} catch (NotImplementedException) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
});
|
2021-09-30 13:32:31 +02:00
|
|
|
|
|
2021-08-04 17:50:46 +02:00
|
|
|
|
if (collate && existing != null) {
|
|
|
|
|
existing.Entries.Add(e);
|
|
|
|
|
} else if (!collate || existing == null) {
|
2021-07-09 11:03:30 +02:00
|
|
|
|
objective.LogEntries.Add(entry);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Scan(PlayerJournal journal) {
|
|
|
|
|
Scan(journal, DateTime.Now, DateTime.Now);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|