EliteBGS/BGS/Report.cs

324 lines
14 KiB
C#
Raw Normal View History

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) {
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) ||
e.Is(Events.MissionFailed) ||
e.Is(Events.MissionAccepted) ||
2021-07-09 11:03:30 +02:00
e.Is(Events.Docked) ||
e.Is(Events.FSDJump) ||
e.Is(Events.Location) ||
2021-07-09 11:03:30 +02:00
e.Is(Events.MultiSellExplorationData) ||
e.Is(Events.SellExplorationData) ||
2021-07-09 11:03:30 +02:00
e.Is(Events.SellMicroResources) ||
2022-02-07 16:47:00 +01:00
e.Is(Events.SellOrganicData) ||
e.Is(Events.RedeemVoucher) ||
e.Is(Events.FactionKillBond) ||
e.Is(Events.MarketBuy) ||
2022-01-23 17:05:43 +01:00
e.Is(Events.MarketSell) ||
e.Is(Events.CommitCrime)
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
;
2022-01-23 15:52:19 +01:00
Scan(entries.SelectMany(x => x).ToList());
}
2021-07-09 11:03:30 +02:00
2022-01-23 15:52:19 +01:00
public void Scan(List<Entry> entries) {
if (entries.Count <= 0) {
return;
}
2022-01-23 15:52:19 +01:00
List<Entry> relevant = entries.Where(x => IsRelevant(x)).ToList();
Dictionary<int, MissionAcceptedEntry> acceptedMissions = new Dictionary<int, MissionAcceptedEntry>();
Dictionary<string, long> buyCost = new Dictionary<string, long>();
Dictionary<ulong, string> systems = new Dictionary<ulong, string>();
2021-07-09 11:03:30 +02:00
string current_system = null;
ulong current_system_address = 0;
2021-07-09 11:03:30 +02:00
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) {
List<LogEntry> results = new List<LogEntry>();
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;
current_system_address = docked.SystemAddress;
if (!systems.ContainsKey(docked.SystemAddress)) {
systems.Add(docked.SystemAddress, docked.StarSystem);
}
2021-07-09 11:03:30 +02:00
} else if (e.Is(Events.FSDJump)) {
/* Gleem current system and controlling faction from this message.
*/
FSDJumpEntry fsd = e as FSDJumpEntry;
current_system_address = fsd.SystemAddress;
current_system = fsd.StarSystem;
controlling_faction = fsd.SystemFaction;
if (!systems.ContainsKey(fsd.SystemAddress)) {
systems.Add(fsd.SystemAddress, fsd.StarSystem);
}
} 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;
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;
}
2022-01-23 17:05:43 +01:00
} else if (e.Is(Events.CommitCrime)) {
CommitCrimeEntry crime = e as CommitCrimeEntry;
if (!crime.IsMurder) {
/* we don't care about anything but murder for now */
continue;
}
results.Add(new FoulMurder(crime) {
System = current_system,
Faction = crime.Faction,
});
collate = true;
2021-07-09 11:03:30 +02:00
} else if (e.Is(Events.MissionCompleted)) {
var completed = e as MissionCompletedEntry;
results.Add(new MissionCompleted(completed) {
System = current_system,
Station = current_station,
SystemAddress = current_system_address,
});
2021-07-09 11:03:30 +02:00
if (completed.HumanReadableNameWasGenerated) {
/* 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.");
}
2022-01-29 10:48:49 +01:00
foreach (var other in completed.Influences) {
string faction = other.Key;
if (string.IsNullOrEmpty(faction)) {
continue;
}
foreach (var influences in other.Value) {
ulong system_address = influences.Key;
if (!faction.Equals(results[0].Faction) ||
(faction.Equals(results[0].Faction) && system_address != current_system_address)) {
string system = systems.TryGetValue(system_address, out string sys) ? sys : "";
results.Add(new InfluenceSupport() {
Faction = faction,
Influence = influences.Value,
System = system,
SystemAddress = system_address,
RelevantMission = results[0] as MissionCompleted
});
}
}
}
} 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.");
continue;
}
results.Add(new MissionFailed(accepted) { Failed = failed, System = current_system });
if (failed.HumanReadableName == null) {
OnLog?.Invoke("Human readable name for mission \"" +
failed.Name +
"\" was not recognised");
}
/* Mission failed should be collated if they are in the same system/station
*/
collate = true;
} else if (e.Is(Events.SellExplorationData)) {
results.Add(new Cartographics(e as SellExplorationDataEntry) {
System = current_system,
Station = current_station,
Faction = controlling_faction,
});
/* colate single cartographic selling into one */
2022-02-07 16:47:00 +01:00
collate = true;
} else if (e.Is(Events.SellOrganicData)) {
/* organic data sold to Vista Genomics */
results.Add(new OrganicData(e as SellOrganicDataEntry) {
System = current_system,
Station = current_station,
Faction = controlling_faction,
});
collate = true;
2021-07-09 11:03:30 +02:00
} else if (e.Is(Events.MultiSellExplorationData)) {
/* For multi-sell-exploraton-data only the controlling faction of the station sold to matters.
*/
results.Add(new Cartographics(e as MultiSellExplorationDataEntry) {
System = current_system,
Station = current_station,
Faction = controlling_faction
});
collate = true;
2021-07-09 11:03:30 +02:00
} else if (e.Is(Events.RedeemVoucher)) {
/* Same for selling combat vouchers. Only the current controlling faction matters here.
*/
results.Add(new Vouchers(e as RedeemVoucherEntry) {
System = current_system,
Station = current_station,
Faction = (e as RedeemVoucherEntry).Factions.FirstOrDefault() ?? "",
ControllingFaction = controlling_faction,
});
collate = true;
2021-07-09 11:03:30 +02:00
} else if (e.Is(Events.SellMicroResources)) {
results.Add(new SellMicroResources(e as SellMicroResourcesEntry) {
Faction = controlling_faction,
Station = current_station,
System = current_system
});
} else if (e.Is(Events.MarketBuy)) {
MarketBuyEntry buy = e as MarketBuyEntry;
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.MarketSell)) {
MarketSellEntry sell = e as MarketSellEntry;
long profit = 0;
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(e as MarketSellEntry) {
Faction = controlling_faction,
Station = current_station,
System = current_system,
Profit = profit
});
2021-07-09 11:03:30 +02:00
}
if (results == null || results.Count <= 0) {
2021-07-09 11:03:30 +02:00
continue;
}
foreach (LogEntry entry in results) {
/* Find all objectives that generally match.
*/
var matches = objectives
2022-01-29 16:18:28 +01:00
.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);
2021-11-10 21:24:39 +01:00
}
2021-09-30 13:32:31 +02:00
LogEntry 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);
}
2021-07-09 11:03:30 +02:00
}
}
}
public void Scan(PlayerJournal journal) {
Scan(journal, DateTime.Now, DateTime.Now);
}
}
}