Compare commits
325 Commits
a49859b079
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4cefc393b5 | |||
| 693d49be14 | |||
| 32dbde2c82 | |||
| 894918b5ba | |||
| 41fca4fa8c | |||
| 2acb63025c | |||
| eaa4bda098 | |||
| 9d8f0c1b9a | |||
| 88b770e5ec | |||
| d9dd2cc524 | |||
| 2905696641 | |||
| aeaa6b5220 | |||
| cdbca10f2d | |||
| 1da6f41ec8 | |||
| 2c6eb9190a | |||
| 8a92cac02a | |||
| 4fe77e6946 | |||
| 912e8b602f | |||
| be3bceb880 | |||
| 6cbe54ff73 | |||
| 6fd5bbc582 | |||
| 262182cfaf | |||
| 007b391dc2 | |||
| 9918c7d559 | |||
| 2bf8d9018d | |||
| 8eaf94f634 | |||
| 20adf93d39 | |||
| fd3e5f61cb | |||
| e617c3852b | |||
| 9f013bed38 | |||
| 916afb2348 | |||
| 6eb892151c | |||
| 6a9e4978aa | |||
| 0203008202 | |||
| 03621721b8 | |||
| ccba55ac35 | |||
| 0708880284 | |||
| 18c3073635 | |||
| c43d2ff1d3 | |||
| a3b7623557 | |||
| 1c2fc1e2e6 | |||
| 53da6b4bc2 | |||
| bc44ceb205 | |||
| 4d3048a37d | |||
| 463598c779 | |||
| bf56f3a2d5 | |||
| 450824733d | |||
| 110f909c6f | |||
| a1099628a0 | |||
| 7e85159fd5 | |||
| 2e8daca61c | |||
| 05b714a607 | |||
| 3b0492c70f | |||
| c20280eb13 | |||
| dd863c326e | |||
| 2012aab7b3 | |||
| abb7954614 | |||
| 0f44a6a9a7 | |||
| 34e0a0c8ba | |||
| b0b82811cc | |||
| 4855d78823 | |||
| 5ea288ee86 | |||
| f3fc99a3f3 | |||
| 2bee03dbc2 | |||
| 16b579688d | |||
| 9994a45d06 | |||
| d6e2280a00 | |||
| 160f4f8370 | |||
| 4400418d30 | |||
| 43037b0a5b | |||
| afc831cf31 | |||
| 4ab54ee576 | |||
| d6842115c5 | |||
| acb60e0a08 | |||
| dac9b7b8c7 | |||
| 3338f573c8 | |||
| 204d6b8914 | |||
| 4c75515a70 | |||
| c43c6f742a | |||
| c7a70598c4 | |||
| cdd7eb33de | |||
| dab39b9a4e | |||
| 20c44d41ca | |||
| 4f339944c6 | |||
| ae4e181e7f | |||
| be59588351 | |||
| 1b2a162ac5 | |||
| f490d4ba4d | |||
| 6b09ec4db3 | |||
| d7a1ac5ef2 | |||
| 3643dda39e | |||
| c7be0ef3f5 | |||
| 6a36458026 | |||
| d7dc9bd904 | |||
| af66983497 | |||
| 3f82e335aa | |||
| 77fcbfbba7 | |||
| a45ca9f5bc | |||
| c9e87958ae | |||
| 12b15bb910 | |||
| bec73931b9 | |||
| b3fca4a63e | |||
| 6a61aa4946 | |||
| b005edc27f | |||
| 8f9f4f3e35 | |||
| 7b4176fce5 | |||
| 434756695a | |||
| a50f0c2313 | |||
| 6dce0116ec | |||
| 79914919e5 | |||
| c23e8627f6 | |||
| 1e36eb3419 | |||
| d49612e7e5 | |||
| b19a576515 | |||
| 9ffca16a78 | |||
| 73a1975964 | |||
| f9f1842cb7 | |||
| 5487cb3d37 | |||
| e11572a565 | |||
| 16ee7047cd | |||
| cedc576b47 | |||
| 58b8ed07c4 | |||
| ef85f51734 | |||
| 00deaf20fc | |||
| 5fe652f98c | |||
| 8cf8d7f529 | |||
| fce534c88f | |||
| 25338c8754 | |||
| 139cbd05f8 | |||
| b0302572f8 | |||
| 87314d0258 | |||
| f4bbd3df2b | |||
| d6acbda55c | |||
| 5c9d9c9153 | |||
| da3a355695 | |||
| 5224dd4555 | |||
| 15fda7692e | |||
| 4cd0c02c67 | |||
| e39dd6ffda | |||
| f666a2c7c5 | |||
| 8574b74494 | |||
| 1255bf9fa5 | |||
| 781bb7a209 | |||
| 24817a02a9 | |||
| d00c8d5c06 | |||
| b588050fb4 | |||
| f9eb0d34f9 | |||
| 2a393809fc | |||
| 7ee734bc33 | |||
| 5799b3ed16 | |||
| a13e8446d2 | |||
| 0665e64459 | |||
| d8ac2a7ee7 | |||
| 1a8c163fc4 | |||
| 7b7fdf0ceb | |||
| bf86ce3fe8 | |||
| bbf3d6c6a4 | |||
| d1c232df9d | |||
| 82281ecf1b | |||
| 7bf2b028c3 | |||
| d2300fa088 | |||
| 32d7bccadc | |||
| 831bf38e78 | |||
| e864db8488 | |||
| 0250878ee7 | |||
| 5120c7991f | |||
| 3c1abe5e8c | |||
| 637b4f85d0 | |||
| 53bf0d22b8 | |||
| 1c0c864e62 | |||
| 52aa2706c0 | |||
| fd10b86c79 | |||
| 2f8d32f57a | |||
| 926150cd18 | |||
| 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 | |||
| 6f9d3a64ff | |||
| abdaca2524 | |||
| 1f673970ee | |||
| 2608aeab6f | |||
| b84d028115 | |||
| 123fa15884 | |||
| 43ae93658f | |||
| 8dea9fd094 | |||
| 8a0d21d039 | |||
| c20bc3d0bf | |||
| cb8698dd42 | |||
| f5f6d538f0 | |||
| eaeaa5e0b4 | |||
| 3df82af239 | |||
| 0e92ee8ab4 | |||
| 72cb379c95 | |||
| 84dfd73283 | |||
| 22d0bedf53 | |||
| 1e73c6b7eb | |||
| 661a4672d9 | |||
| 67966ca27a | |||
| 914aa43d33 | |||
| 8d72808fbf | |||
| ac3d1cd8b9 | |||
| 634ba657b4 | |||
| 6b2bef0d30 | |||
| d6b86d28aa | |||
| bfae0adcae | |||
| 454af4ad8f | |||
| 7f73159bb0 | |||
| 0820998d3e | |||
| f14982f37a | |||
| f0977b774b | |||
| 04a839417e | |||
| 93359321d6 | |||
| 6bbc063c25 | |||
| 6fe6f5e26f | |||
| 9f1065c6ea | |||
| 674757d734 | |||
| 712c416725 | |||
| 91bca70168 | |||
| 800ac73331 | |||
| d79ee5a153 | |||
| f683bc372e | |||
| 12ba6d4d96 | |||
| dd1d7ff091 | |||
| 65fec2cd1e | |||
| bb74d72b13 | |||
| d2aadf9882 | |||
| 6b14909335 | |||
| db67ef21fa | |||
| f3134d36d4 | |||
| 1a53a3ba8d | |||
| c7e2f352f2 | |||
| f7c3a1bb41 | |||
| 2648b1390b | |||
| aad688026e | |||
| a451392e93 | |||
| 10351af7f9 | |||
| 697cbc2bc6 | |||
| 0cc8a1f29a | |||
| 22396c9b22 | |||
| 8d95a42698 | |||
| aa7f0bcd1a | |||
| 6e5f8f504f | |||
| e01d3a869d | |||
| 1da4549e2c | |||
| 0be9791abc | |||
| 027f8a892d | |||
| 32e5898b02 | |||
| 34934c82a6 | |||
| 5a8ea2940c | |||
| a13a708c22 | |||
| fbd5a66156 | |||
| 0be0896e91 | |||
| f8559bbe06 | |||
| 987d9c5f49 | |||
| 24f3897582 | |||
| afa4e0d536 | |||
| 1d8f03200b | |||
| 955a108f2e | |||
| fe28a4d17d | |||
| dc9e654351 | |||
| c2037f28e2 | |||
| e6e0233e6d | |||
| 1a6183ba9d | |||
| 3a5d0a90ef | |||
| 8514331701 | |||
| e8de768d01 | |||
| 61f1b10f29 | |||
| e0e7cb5792 | |||
| 5f9fff3922 |
@@ -9,6 +9,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EDPlayerJournalTests", "EDP
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EliteBGS", "EliteBGS\EliteBGS.csproj", "{14B03115-B9D5-4006-A993-9A5069BB172E}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EliteBGS", "EliteBGS\EliteBGS.csproj", "{14B03115-B9D5-4006-A993-9A5069BB172E}"
|
||||||
EndProject
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|||||||
@@ -16,6 +16,22 @@ the game:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Bounty vouchers show up twice
|
||||||
|
|
||||||
|
Sometimes bounty vouchers are redeemed twice. This happens because FDev writes out two
|
||||||
|
`RedeemVoucher` entries with the same values:
|
||||||
|
|
||||||
|
```
|
||||||
|
{ "timestamp":"2022-11-20T14:30:30Z", "event":"RedeemVoucher", "Type":"bounty", "Amount":3197549,
|
||||||
|
"Factions":[ { "Faction":"Nova Paresa", "Amount":3197549 } ] }
|
||||||
|
{ "timestamp":"2022-11-20T14:30:34Z", "event":"RedeemVoucher", "Type":"bounty", "Amount":4785831,
|
||||||
|
"Factions":[ { "Faction":"", "Amount":723175 }, { "Faction":"Nova Paresa", "Amount":3197549 }, { "Faction":"Prismatic Imperium", "Amount":4062656 } ] }
|
||||||
|
```
|
||||||
|
|
||||||
|
Two separate events (apart by four seconds) containing the same entries twice. This
|
||||||
|
happens when you turn in one bounty manually, and then click the "redeem all" button
|
||||||
|
again, which contains the already turned in vouchers.
|
||||||
|
|
||||||
## Combat zones
|
## Combat zones
|
||||||
|
|
||||||
Combat zones receive no mention within the player journal whatsoever. There is no event
|
Combat zones receive no mention within the player journal whatsoever. There is no event
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using System.Linq;
|
using System.Text;
|
||||||
using System.Text;
|
|
||||||
using EDPlayerJournal.Entries;
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
public class Cartographics : Transaction {
|
public class Cartographics : Transaction {
|
||||||
|
public Cartographics() { }
|
||||||
|
|
||||||
public Cartographics(MultiSellExplorationDataEntry e) {
|
public Cartographics(MultiSellExplorationDataEntry e) {
|
||||||
Entries.Add(e);
|
Entries.Add(e);
|
||||||
}
|
}
|
||||||
@@ -34,10 +35,10 @@ public class Cartographics : Transaction {
|
|||||||
/* add multi sell and normal ones together */
|
/* add multi sell and normal ones together */
|
||||||
long total =
|
long total =
|
||||||
Entries.OfType<MultiSellExplorationDataEntry>()
|
Entries.OfType<MultiSellExplorationDataEntry>()
|
||||||
.Sum(x => x.TotalEarnings)
|
.Sum(x => x.Total)
|
||||||
+
|
+
|
||||||
Entries.OfType<SellExplorationDataEntry>()
|
Entries.OfType<SellExplorationDataEntry>()
|
||||||
.Sum(x => x.TotalEarnings)
|
.Sum(x => x.Total)
|
||||||
;
|
;
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,102 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
public class CombatZone : Transaction {
|
public class CombatZone : Transaction {
|
||||||
public string Type { get; set; } = "";
|
/// <summary>
|
||||||
public string Grade { get; set; } = "";
|
/// Type, either on foot or ship
|
||||||
public int Amount { get; set; } = 0;
|
/// </summary>
|
||||||
public DateTime Completed { get; set; } = DateTime.UtcNow;
|
public string Type { get; set; } = CombatZones.ShipCombatZone;
|
||||||
|
|
||||||
public override string CompletedAt {
|
/// <summary>
|
||||||
|
/// Difficulty type, low, medium or high. Null means unknown.
|
||||||
|
/// </summary>
|
||||||
|
public string? Grade { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether spec ops were won.
|
||||||
|
/// </summary>
|
||||||
|
public bool? SpecOps { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether allied captain objective was won
|
||||||
|
/// </summary>
|
||||||
|
public bool? AlliedCaptain { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether enemy captain objective was won
|
||||||
|
/// </summary>
|
||||||
|
public bool? EnemyCaptain { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the allied correspondent objective was won
|
||||||
|
/// </summary>
|
||||||
|
public bool? AlliedCorrespondent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the enemy correspondent objective was won
|
||||||
|
/// </summary>
|
||||||
|
public bool? EnemyCorrespondent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether cap ship objective was won
|
||||||
|
/// </summary>
|
||||||
|
public bool? CapitalShip { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If we have a combat zone, this might point to the settlement
|
||||||
|
/// in question.
|
||||||
|
/// </summary>
|
||||||
|
public string? Settlement { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many optional objectives were completed?
|
||||||
|
/// </summary>
|
||||||
|
public int OptionalObjectivesCompleted {
|
||||||
get {
|
get {
|
||||||
return Completed.ToString("dd.MM.yyyy HH:mm UTC");
|
if (IsGround) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return new List<bool?>() {
|
||||||
|
SpecOps,
|
||||||
|
AlliedCaptain,
|
||||||
|
EnemyCaptain,
|
||||||
|
AlliedCorrespondent,
|
||||||
|
EnemyCorrespondent,
|
||||||
|
CapitalShip
|
||||||
|
}
|
||||||
|
.Where(x => x != null && x == true)
|
||||||
|
.Count()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if it is an on foot/ground combat zone
|
||||||
|
/// </summary>
|
||||||
|
public bool IsGround {
|
||||||
|
get { return string.Compare(Type, CombatZones.GroundCombatZone) == 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if it is an on foot combat zone
|
||||||
|
/// </summary>
|
||||||
|
public bool IsShip {
|
||||||
|
get { return string.Compare(Type, CombatZones.ShipCombatZone) == 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if it is a thargoid combat zone
|
||||||
|
/// </summary>
|
||||||
|
public bool IsThargoid {
|
||||||
|
get { return string.Compare(Type, CombatZones.AXCombatZone) == 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if it is a power combat zone
|
||||||
|
/// </summary>
|
||||||
|
public bool IsPower {
|
||||||
|
get { return string.Compare(Type, CombatZones.PowerCombatZone) == 0; }
|
||||||
|
}
|
||||||
|
|
||||||
public override int CompareTo(Transaction? obj) {
|
public override int CompareTo(Transaction? obj) {
|
||||||
if (obj == null || obj.GetType() != typeof(CombatZone)) {
|
if (obj == null || obj.GetType() != typeof(CombatZone)) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -36,7 +121,10 @@ public class CombatZone : Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return string.Format("Won {0} x {1} {2} Combat Zone(s) for {3}",
|
if (!string.IsNullOrEmpty(Grade)) {
|
||||||
Amount, Grade, Type, Faction);
|
return string.Format("Won {0} {1} Combat Zone", Grade, Type);
|
||||||
|
} else {
|
||||||
|
return string.Format("Won {0} Combat Zone", Type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
namespace EDPlayerJournal.BGS;
|
using EDPlayerJournal.Entries;
|
||||||
internal class IncompleteTransaction : Transaction {
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
public class IncompleteTransaction : Transaction {
|
||||||
public Transaction? UnderlyingTransaction { get; set; } = null;
|
public Transaction? UnderlyingTransaction { get; set; } = null;
|
||||||
public string Reason { get; set; } = "";
|
public string Reason { get; set; } = "";
|
||||||
|
|
||||||
public IncompleteTransaction() { }
|
public IncompleteTransaction() { }
|
||||||
|
|
||||||
public IncompleteTransaction(Transaction? underlying, string reason) {
|
public IncompleteTransaction(Transaction? underlying, string reason, Entry entry) {
|
||||||
UnderlyingTransaction = underlying;
|
UnderlyingTransaction = underlying;
|
||||||
Reason = reason;
|
Reason = reason;
|
||||||
|
Entries.Add(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,15 +9,24 @@ namespace EDPlayerJournal.BGS;
|
|||||||
/// faction to another. Both sometimes gain influence.
|
/// faction to another. Both sometimes gain influence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class InfluenceSupport : Transaction {
|
public class InfluenceSupport : Transaction {
|
||||||
public string Influence { get; set; } = "";
|
public MissionInfluence? Influence { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Relevant mission completed entry
|
||||||
|
/// </summary>
|
||||||
public MissionCompletedEntry? RelevantMission { get; set; }
|
public MissionCompletedEntry? RelevantMission { get; set; }
|
||||||
|
|
||||||
public override string CompletedAt {
|
/// <summary>
|
||||||
|
/// Mission information
|
||||||
|
/// </summary>
|
||||||
|
public Mission? Mission { get; set; }
|
||||||
|
|
||||||
|
public override DateTime? CompletedAtDateTime {
|
||||||
get {
|
get {
|
||||||
if (RelevantMission == null) {
|
if (RelevantMission == null) {
|
||||||
return "";
|
return null;
|
||||||
}
|
}
|
||||||
return RelevantMission.Timestamp.ToString("dd.MM.yyyy hh:mm UTC");
|
return RelevantMission.Timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +35,7 @@ public class InfluenceSupport : Transaction {
|
|||||||
string? missionname;
|
string? missionname;
|
||||||
|
|
||||||
if (RelevantMission != null && RelevantMission.Mission != null) {
|
if (RelevantMission != null && RelevantMission.Mission != null) {
|
||||||
missionname = RelevantMission.Mission.LocalisedName;
|
missionname = RelevantMission.Mission.FriendlyName;
|
||||||
} else {
|
} else {
|
||||||
missionname = "UNKNOWN MISSION";
|
missionname = "UNKNOWN MISSION";
|
||||||
}
|
}
|
||||||
@@ -37,7 +46,7 @@ public class InfluenceSupport : Transaction {
|
|||||||
|
|
||||||
builder.AppendFormat("Influence gained from \"{0}\": \"{1}\"",
|
builder.AppendFormat("Influence gained from \"{0}\": \"{1}\"",
|
||||||
missionname,
|
missionname,
|
||||||
string.IsNullOrEmpty(Influence) ? "NONE" : Influence
|
Influence == null ? "NONE" : Influence.TrendAdjustedInfluence
|
||||||
);
|
);
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
|
|||||||
32
EDPlayerJournal/BGS/MeritsGained.cs
Normal file
32
EDPlayerJournal/BGS/MeritsGained.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
public class MeritsGained : Transaction {
|
||||||
|
public MeritsGained() { }
|
||||||
|
|
||||||
|
public MeritsGained(Entry entry) {
|
||||||
|
Entries.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of merits gained
|
||||||
|
/// </summary>
|
||||||
|
public long Merits {
|
||||||
|
get {
|
||||||
|
return Entries
|
||||||
|
.OfType<PowerplayMeritsEntry>()
|
||||||
|
.Sum(x => x.MeritsGained)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For what power those merits were gained
|
||||||
|
/// </summary>
|
||||||
|
public string Power { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return string.Format("{0} Merits gained for {1}", Merits, Power);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,54 +1,86 @@
|
|||||||
using System.Text;
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
using EDPlayerJournal.Entries;
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
public class MissionCompleted : Transaction {
|
public class MissionCompleted : Transaction {
|
||||||
|
public MissionCompletedEntry? CompletedEntry { get; set; }
|
||||||
|
|
||||||
|
public MissionAcceptedEntry? AcceptedEntry { get; set; }
|
||||||
|
|
||||||
|
public Mission? Mission { get; set; }
|
||||||
|
|
||||||
public MissionCompleted() { }
|
public MissionCompleted() { }
|
||||||
public MissionCompleted(MissionCompletedEntry e) {
|
|
||||||
Entries.Add(e);
|
public override DateTime? CompletedAtDateTime {
|
||||||
|
get {
|
||||||
|
if (CompletedEntry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return CompletedEntry.Timestamp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string MissionName {
|
public string MissionName {
|
||||||
get {
|
get {
|
||||||
MissionCompletedEntry? c = Entries[0] as MissionCompletedEntry;
|
if (CompletedEntry == null || CompletedEntry.Mission == null) {
|
||||||
if (c == null || c.Mission == null) {
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Mission.FriendlyName;
|
return CompletedEntry.Mission.FriendlyName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Influence {
|
public string Influence {
|
||||||
get {
|
get {
|
||||||
MissionCompletedEntry? e = (Entries[0] as MissionCompletedEntry);
|
if (CompletedEntry == null || Faction == null || CompletedEntry.Mission == null) {
|
||||||
|
|
||||||
if (e == null || Faction == null || e.Mission == null) {
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
return (e.Mission.GetInfluenceForFaction(Faction, SystemAddress) ?? "");
|
return string.Join("",
|
||||||
|
CompletedEntry
|
||||||
|
.Mission
|
||||||
|
.GetInfluenceForFaction(Faction, SystemAddress)
|
||||||
|
.Select(x => x.Influence)
|
||||||
|
.ToArray()
|
||||||
|
)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Rescue missions contribute to the system.
|
||||||
|
/// </summary>
|
||||||
|
public override bool SystemContribution {
|
||||||
|
get {
|
||||||
|
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 (Mission.Name.Contains("Mission_TW_")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
if (Faction == null || Entries.Count <= 0) {
|
if (Faction == null || CompletedEntry == null || CompletedEntry.Mission == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
var entry = Entries[0] as MissionCompletedEntry;
|
var influence = CompletedEntry.Mission.GetInfluenceForFaction(Faction, SystemAddress);
|
||||||
|
|
||||||
if (entry == null || entry.Mission == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
var influence = entry.Mission.GetInfluenceForFaction(Faction, SystemAddress);
|
|
||||||
|
|
||||||
builder.AppendFormat("{0}", MissionName);
|
builder.AppendFormat("{0}", MissionName);
|
||||||
if (influence != "") {
|
if (influence != null && influence.Length > 0) {
|
||||||
builder.AppendFormat(", Influence: {0}", influence);
|
builder.AppendFormat(", Influence: {0}",
|
||||||
|
influence.Select(x => x.InfluenceAmount).Sum()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
|
|||||||
@@ -4,16 +4,28 @@ using EDPlayerJournal.Entries;
|
|||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
public class MissionFailed : Transaction {
|
public class MissionFailed : Transaction {
|
||||||
public MissionFailedEntry? Failed { get; set; }
|
public MissionFailedEntry? Failed { get; set; }
|
||||||
public MissionAcceptedEntry? Accepted { get; set; }
|
public Mission? Mission { get; set; }
|
||||||
|
|
||||||
public MissionFailed() { }
|
public MissionFailed() { }
|
||||||
|
|
||||||
public MissionFailed(MissionAcceptedEntry accepted) {
|
public MissionFailed(MissionFailedEntry failed) {
|
||||||
if (accepted.Mission == null) {
|
Entries.Add(failed);
|
||||||
throw new Exception("Mission cannot be null");
|
Failed = failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the amount of influence generated by failing this mission. The
|
||||||
|
/// system returns no influence for one INF missions, but sadly also for
|
||||||
|
/// when the influence had no affect at all (i.e. during a war).
|
||||||
|
/// </summary>
|
||||||
|
public long InfluenceAmount {
|
||||||
|
get {
|
||||||
|
if (Mission == null || string.IsNullOrEmpty(Mission.Influence)) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return Mission.Influence.Length * -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Accepted = accepted;
|
|
||||||
Faction = accepted.Mission.Faction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int CompareTo(Transaction? other) {
|
public override int CompareTo(Transaction? other) {
|
||||||
@@ -39,20 +51,15 @@ public class MissionFailed : Transaction {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Amount {
|
|
||||||
get { return Entries.Count + 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
StringBuilder builder = new StringBuilder();
|
StringBuilder builder = new StringBuilder();
|
||||||
|
|
||||||
if (Failed == null || Accepted == null) {
|
if (Failed == null || Mission == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AppendFormat("{0}x Mission failed: \"{1}\"",
|
builder.AppendFormat(" Mission failed: \"{0}\"",
|
||||||
Amount,
|
Mission?.FriendlyName
|
||||||
Failed?.Mission?.FriendlyName
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ using EDPlayerJournal.Entries;
|
|||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
public class OrganicData : Transaction {
|
public class OrganicData : Transaction {
|
||||||
|
public OrganicData() { }
|
||||||
|
|
||||||
public OrganicData(SellOrganicDataEntry e) {
|
public OrganicData(SellOrganicDataEntry e) {
|
||||||
Entries.Add(e);
|
Entries.Add(e);
|
||||||
}
|
}
|
||||||
@@ -36,6 +38,8 @@ public class OrganicData : Transaction {
|
|||||||
|
|
||||||
/* Selling organic data only helps the controlling faction, just like
|
/* Selling organic data only helps the controlling faction, just like
|
||||||
* selling cartographic data.
|
* selling cartographic data.
|
||||||
|
*
|
||||||
|
* Right now: Organic data helps no one.
|
||||||
*/
|
*/
|
||||||
public override bool OnlyControllingFaction => true;
|
public override bool OnlyControllingFaction => true;
|
||||||
}
|
}
|
||||||
|
|||||||
15
EDPlayerJournal/BGS/Parsers/ApproachSettlementParser.cs
Normal file
15
EDPlayerJournal/BGS/Parsers/ApproachSettlementParser.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class ApproachSettlementParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
ApproachSettlementEntry? approach = entry as ApproachSettlementEntry;
|
||||||
|
if (approach == null || string.IsNullOrEmpty(approach.Name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Settlement = approach.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
30
EDPlayerJournal/BGS/Parsers/CarrierJumpParser.cs
Normal file
30
EDPlayerJournal/BGS/Parsers/CarrierJumpParser.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class CarrierJumpParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
CarrierJump? jump = entry as CarrierJump;
|
||||||
|
|
||||||
|
if (jump == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jump.Docked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.CurrentSystem = jump.StarSystem;
|
||||||
|
context.CurrentSystemAddress = jump.SystemAddress;
|
||||||
|
|
||||||
|
context.SystemsByID.TryAdd(jump.SystemAddress, jump.StarSystem);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(jump.SystemFaction)) {
|
||||||
|
context.ControllingFaction = jump.SystemFaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jump.SystemFactions != null && jump.SystemFactions.Count > 0) {
|
||||||
|
context.SystemFactions[jump.StarSystem] = jump.SystemFactions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
EDPlayerJournal/BGS/Parsers/CommanderParser.cs
Normal file
17
EDPlayerJournal/BGS/Parsers/CommanderParser.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using EDPlayerJournal.BGS;
|
||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
internal class CommanderParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
CommanderEntry commanderEntry = (CommanderEntry)entry;
|
||||||
|
if (commanderEntry != null && !string.IsNullOrEmpty(commanderEntry.FullName)) {
|
||||||
|
if (!context.Commanders.Contains(commanderEntry.FullName)) {
|
||||||
|
context.Commanders.Add(commanderEntry.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
44
EDPlayerJournal/BGS/Parsers/MarketBuyParser.cs
Normal file
44
EDPlayerJournal/BGS/Parsers/MarketBuyParser.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
internal class MarketBuyParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
MarketBuyEntry? entry = e as MarketBuyEntry;
|
||||||
|
if (entry == null) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
context.BoughtCargo(entry.Type, entry.BuyPrice);
|
||||||
|
|
||||||
|
// We still want the information on buy price for profit,
|
||||||
|
// but if the option is on, we don't care for parsing it
|
||||||
|
// further.
|
||||||
|
// TODO: might be wise to split this parser into two; one for
|
||||||
|
// determining profit, the other for the BGS information
|
||||||
|
if (options.IgnoreMarketBuy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.StationOwner == null) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
new BuyCargo(),
|
||||||
|
"Could not discern the station owner for market buy.",
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if its a fleet carrier faction.
|
||||||
|
if (string.Compare(context.StationOwner, Factions.FleetCarrier, StringComparison.OrdinalIgnoreCase) == 0 &&
|
||||||
|
options.IgnoreFleetCarrierFaction) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transactions.Add(new BuyCargo(entry) {
|
||||||
|
System = context.CurrentSystem,
|
||||||
|
Station = context.CurrentStation,
|
||||||
|
Faction = context.StationOwner,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
45
EDPlayerJournal/BGS/Parsers/MarketSellParser.cs
Normal file
45
EDPlayerJournal/BGS/Parsers/MarketSellParser.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
internal class MarketSellParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
long profit = 0;
|
||||||
|
|
||||||
|
if (context.StationOwner == null) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
new SellCargo(),
|
||||||
|
"Could not discern the station owner market sell.",
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if its a fleet carrier faction.
|
||||||
|
if (string.Compare(context.StationOwner, Factions.FleetCarrier, StringComparison.OrdinalIgnoreCase) == 0 &&
|
||||||
|
options.IgnoreFleetCarrierFaction) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarketSellEntry? entry = e as MarketSellEntry;
|
||||||
|
if (entry == null) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.Type == null) {
|
||||||
|
throw new InvalidJournalEntryException("market sell contains no cargo type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.BuyCost.ContainsKey(entry.Type)) {
|
||||||
|
long avg = context.BuyCost[entry.Type];
|
||||||
|
profit = (long)entry.TotalSale - (avg * entry.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
transactions.Add(new SellCargo(entry) {
|
||||||
|
System = context.CurrentSystem,
|
||||||
|
Station = context.CurrentStation,
|
||||||
|
Faction = context.StationOwner,
|
||||||
|
Profit = profit,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
internal class MultiSellExplorationDataParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
MultiSellExplorationDataEntry? entry = e as MultiSellExplorationDataEntry;
|
||||||
|
if (entry == null) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.StationOwner == null) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
new Cartographics(),
|
||||||
|
"Could not discern the station owner for cartographics sell.",
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if its a fleet carrier faction.
|
||||||
|
if (string.Compare(context.StationOwner, Factions.FleetCarrier, StringComparison.OrdinalIgnoreCase) == 0 &&
|
||||||
|
options.IgnoreFleetCarrierFaction) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transactions.Add(new Cartographics(entry) {
|
||||||
|
System = context.CurrentSystem,
|
||||||
|
Station = context.CurrentStation,
|
||||||
|
Faction = context.StationOwner,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
17
EDPlayerJournal/BGS/Parsers/MusicParser.cs
Normal file
17
EDPlayerJournal/BGS/Parsers/MusicParser.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class MusicParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
MusicEntry? entryMusic = (MusicEntry)entry;
|
||||||
|
|
||||||
|
if (entryMusic == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(entryMusic.MusicTrack, "Combat_CapitalShip") == 0) {
|
||||||
|
context.HaveSeenCapShip = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
EDPlayerJournal/BGS/Parsers/PowerplayMeritsParser.cs
Normal file
31
EDPlayerJournal/BGS/Parsers/PowerplayMeritsParser.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class PowerplayMeritsParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
PowerplayMeritsEntry? e = entry as PowerplayMeritsEntry;
|
||||||
|
if (e == null) {
|
||||||
|
throw new ApplicationException("not a valid PowerplayMerits entry");
|
||||||
|
}
|
||||||
|
|
||||||
|
MeritsGained? transaction = null;
|
||||||
|
|
||||||
|
transaction = transactions
|
||||||
|
.OfType<MeritsGained>()
|
||||||
|
.Where(x => x.System == context.CurrentSystem &&
|
||||||
|
x.Power == e.Power)
|
||||||
|
.FirstOrDefault()
|
||||||
|
;
|
||||||
|
if (transaction == null) {
|
||||||
|
transaction = new MeritsGained(e) {
|
||||||
|
System = context.CurrentSystem,
|
||||||
|
Power = e.Power,
|
||||||
|
Faction = e.Power,
|
||||||
|
};
|
||||||
|
transactions.Add(transaction);
|
||||||
|
} else {
|
||||||
|
transaction.Entries.Add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
84
EDPlayerJournal/BGS/Parsers/RedeemVoucherParser.cs
Normal file
84
EDPlayerJournal/BGS/Parsers/RedeemVoucherParser.cs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class RedeemVoucherParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
RedeemVoucherEntry? entry = e as RedeemVoucherEntry;
|
||||||
|
if (entry == null) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.CurrentSystem == null) {
|
||||||
|
transactions.AddIncomplete(new Vouchers(),
|
||||||
|
"Could not find out where the vouchers were redeemed", e
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string faction in entry.Factions) {
|
||||||
|
bool relevantBond = false;
|
||||||
|
string relevantFaction = faction;
|
||||||
|
|
||||||
|
if (string.Compare(faction, Factions.PilotsFederationVouchers) == 0) {
|
||||||
|
// Target faction is pilots' federation, so we assume thargoid bonks
|
||||||
|
// Also assign this combat bond to the Pilots Federation
|
||||||
|
relevantFaction = Factions.PilotsFederation;
|
||||||
|
relevantBond = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_factions != null && !relevantBond) {
|
||||||
|
// If we have local factions, and it ain't thargoid bonds see if the bonds were
|
||||||
|
// useful in the current system
|
||||||
|
if (current_factions.Find(x => string.Compare(x.Name, faction, true) == 0) != null) {
|
||||||
|
relevantBond = true;
|
||||||
|
} else {
|
||||||
|
transactions.AddIncomplete(new Vouchers(),
|
||||||
|
string.Format("Vouchers for \"{0}\" had no effect in \"{1}\" since said " +
|
||||||
|
"faction is not present there", faction, context.CurrentSystem), e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!relevantBond) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var voucher = new Vouchers(entry) {
|
||||||
|
System = context.CurrentSystem,
|
||||||
|
Station = context.CurrentStation,
|
||||||
|
Faction = relevantFaction,
|
||||||
|
ControllingFaction = context.ControllingFaction,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.FilterDoubleRedeemVouchers) {
|
||||||
|
// To filter out doubly redeemed vouchers, find another redeem voucher
|
||||||
|
// event that happened in the same system, same total sum, and also the
|
||||||
|
// same faction. If there is one, filter this one out.
|
||||||
|
var doubledEntry = transactions
|
||||||
|
.OfType<Vouchers>()
|
||||||
|
.Where(x => x.TotalSum == voucher.TotalSum &&
|
||||||
|
x.System == voucher.System &&
|
||||||
|
x.Faction == voucher.Faction)
|
||||||
|
.ToList()
|
||||||
|
;
|
||||||
|
if (doubledEntry.Count > 0) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
voucher,
|
||||||
|
string.Format("A doubled redeem voucher for {0} valued {1} was detected",
|
||||||
|
voucher.Faction, Credits.FormatMillions(voucher.TotalSum)),
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transactions.Add(voucher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
EDPlayerJournal/BGS/Parsers/SellExplorationDataParser.cs
Normal file
33
EDPlayerJournal/BGS/Parsers/SellExplorationDataParser.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
internal class SellExplorationDataParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
SellExplorationDataEntry? entry = e as SellExplorationDataEntry;
|
||||||
|
if (entry == null) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.StationOwner == null) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
new Cartographics(),
|
||||||
|
"Could not discern the station owner for cartographics sell.",
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if its a fleet carrier faction.
|
||||||
|
if (string.Compare(context.StationOwner, Factions.FleetCarrier, StringComparison.OrdinalIgnoreCase) == 0 &&
|
||||||
|
options.IgnoreFleetCarrierFaction) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transactions.Add(new Cartographics(entry) {
|
||||||
|
System = context.CurrentSystem,
|
||||||
|
Station = context.CurrentStation,
|
||||||
|
Faction = context.StationOwner,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
38
EDPlayerJournal/BGS/Parsers/SellOrganicDataParser.cs
Normal file
38
EDPlayerJournal/BGS/Parsers/SellOrganicDataParser.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
internal class SellOrganicDataParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
// If exo biology is ignored, simply do nothing
|
||||||
|
if (options.IgnoreExoBiology) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SellOrganicDataEntry? entry = e as SellOrganicDataEntry;
|
||||||
|
if (entry == null) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.StationOwner == null) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
new OrganicData(),
|
||||||
|
"Could not discern the station owner for organic data sell.",
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore if its a fleet carrier faction.
|
||||||
|
if (string.Compare(context.StationOwner, Factions.FleetCarrier, StringComparison.OrdinalIgnoreCase) == 0 &&
|
||||||
|
options.IgnoreFleetCarrierFaction) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
transactions.Add(new OrganicData(entry) {
|
||||||
|
System = context.CurrentSystem,
|
||||||
|
Station = context.CurrentStation,
|
||||||
|
Faction = context.StationOwner,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
65
EDPlayerJournal/BGS/Parsers/ShipTargetedParser.cs
Normal file
65
EDPlayerJournal/BGS/Parsers/ShipTargetedParser.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// With ship targeted we might find out to which faction a given NPC belonged. This is
|
||||||
|
/// useful later when said NPC gets killed or murdered.
|
||||||
|
/// </summary>
|
||||||
|
internal class ShipTargetedParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
ShipTargetedEntry? entry = e as ShipTargetedEntry;
|
||||||
|
if (entry == null) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan happens in stages, and sometimes this information is not known
|
||||||
|
// yet. Do now throw an error, this is expected behaviour.
|
||||||
|
if (!string.IsNullOrEmpty(entry.PilotNameLocalised) &&
|
||||||
|
!string.IsNullOrEmpty(entry.Faction)) {
|
||||||
|
context.NPCFaction.TryAdd(entry.PilotNameLocalised, entry.Faction);
|
||||||
|
}
|
||||||
|
|
||||||
|
string? faction = context.LastRecordedAwardingFaction;
|
||||||
|
|
||||||
|
// We have seen a captain?
|
||||||
|
if (NPCs.IsWarzoneCaptain(entry.PilotName)) {
|
||||||
|
// if we have faction information, we can compare it to figure out
|
||||||
|
// whether it is the enemy or allied faction. but this is not always
|
||||||
|
// possible. In such a case we assume we have seen the enemy captain.
|
||||||
|
if (!string.IsNullOrEmpty(entry.Faction) &&
|
||||||
|
!string.IsNullOrEmpty(faction)) {
|
||||||
|
if (string.Compare(faction, entry.Faction) != 0) {
|
||||||
|
context.HaveSeenEnemyCaptain = true;
|
||||||
|
} else {
|
||||||
|
context.HaveSeenAlliedCaptain = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context.HaveSeenEnemyCaptain = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spec ops?
|
||||||
|
if (NPCs.IsSpecOps(entry.PilotName)) {
|
||||||
|
context.HaveSeenSpecOps = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correspondent?
|
||||||
|
if (NPCs.IsWarzoneCorrespondent(entry.PilotName)) {
|
||||||
|
// if we have faction information, we can compare it to figure out
|
||||||
|
// whether it is the enemy or allied faction. but this is not always
|
||||||
|
// possible. In such a case we assume we have seen the enemy
|
||||||
|
// correspondent.
|
||||||
|
if (!string.IsNullOrEmpty(entry.Faction) &&
|
||||||
|
!string.IsNullOrEmpty(faction)) {
|
||||||
|
if (string.Compare(faction, entry.Faction) != 0) {
|
||||||
|
context.HaveSeenEnemyCorrespondent = true;
|
||||||
|
} else {
|
||||||
|
context.HaveSeenAlliedCorrespondent = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
context.HaveSeenEnemyCorrespondent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS.Parsers;
|
||||||
|
|
||||||
|
internal class SupercruiseDestinationDropParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
SupercruiseDestinationDropEntry? drop = entry as SupercruiseDestinationDropEntry;
|
||||||
|
if (drop == null || drop.Type == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.CurrentInstanceType = drop.Type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,664 +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(completed) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -49,10 +49,11 @@ public class SellCargo : Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (MarketSellEntry sell in sold) {
|
foreach (MarketSellEntry sell in sold) {
|
||||||
builder.AppendFormat("Sold {0} {1} to the {2}",
|
builder.AppendFormat("Sold {0} {1} to the {2} of {3}",
|
||||||
sell.Count,
|
sell.Count,
|
||||||
Cargo,
|
Cargo,
|
||||||
Market
|
Market,
|
||||||
|
Station
|
||||||
);
|
);
|
||||||
|
|
||||||
if (Profit != 0) {
|
if (Profit != 0) {
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
using EDPlayerJournal.Entries;
|
using EDPlayerJournal.Entries;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
@@ -25,10 +20,18 @@ public class ThargoidKill : Transaction {
|
|||||||
get { return (ulong)Entries.OfType<FactionKillBondEntry>().Sum(x => (decimal)x.Reward); }
|
get { return (ulong)Entries.OfType<FactionKillBondEntry>().Sum(x => (decimal)x.Reward); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Kiling thargoids contributes to the system wide effort of
|
||||||
|
/// the thargoid war.
|
||||||
|
/// </summary>
|
||||||
|
public override bool SystemContribution {
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
public ThargoidKill() { }
|
public ThargoidKill() { }
|
||||||
|
|
||||||
public ThargoidKill(FactionKillBondEntry entry) {
|
public ThargoidKill(FactionKillBondEntry entry) {
|
||||||
if (string.Compare(entry.VictimFaction, Thargoid.ThargoidFaction) != 0) {
|
if (!Factions.IsThargoid(entry.VictimFaction)) {
|
||||||
throw new Exception("Not a valid thargoid kill");
|
throw new Exception("Not a valid thargoid kill");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,52 @@
|
|||||||
using EDPlayerJournal.Entries;
|
using EDPlayerJournal.Entries;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
public class Transaction : IComparable<Transaction> {
|
public class Transaction : IComparable<Transaction> {
|
||||||
public List<Entry> Entries { get; } = new List<Entry>();
|
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 {
|
get {
|
||||||
var items = Entries
|
var items = Entries
|
||||||
.OrderBy(x => x.Timestamp)
|
.OrderBy(x => x.Timestamp)
|
||||||
.ToArray()
|
.ToArray()
|
||||||
;
|
;
|
||||||
if (items == null || items.Length == 0) {
|
if (items == null || items.Length == 0) {
|
||||||
return "Unknown";
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry last = items.Last();
|
Entry last = items.Last();
|
||||||
return last.Timestamp.ToString("dd.MM.yyyy HH:mm UTC");
|
return last.Timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the transaction helps the entire system.
|
||||||
|
/// While all transactions are related to one faction, sometimes their
|
||||||
|
/// overall effect on the system as a whole is more important, than to
|
||||||
|
/// their faction. For example, rescuing refugees helps the Thargoid war
|
||||||
|
/// effort in the system as a whole, not just for the faction.
|
||||||
|
/// So this is true for transactions that help the system as a whole.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool SystemContribution { get; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if this transaction was completed in legacy ED
|
||||||
|
/// </summary>
|
||||||
|
public bool IsLegacy { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controlling faction of the station this entry was made/turned into.
|
/// Controlling faction of the station this entry was made/turned into.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,103 +1,62 @@
|
|||||||
using EDPlayerJournal.Entries;
|
using EDPlayerJournal.BGS.Parsers;
|
||||||
using System.Collections.Generic;
|
using EDPlayerJournal.Entries;
|
||||||
using System.Reflection.Metadata.Ecma335;
|
|
||||||
|
|
||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
internal class TransactionParserContext {
|
public class TransactionParserOptions {
|
||||||
public string? CurrentSystem { get; set; }
|
/// <summary>
|
||||||
public ulong? CurrentSystemAddress { get; set; }
|
/// Whether to ignore exo biology. It does not contribute to BGS, so this
|
||||||
public string? CurrentStation { get; set; }
|
/// is true per default.
|
||||||
public string? ControllingFaction { get; set; }
|
/// </summary>
|
||||||
|
public bool IgnoreExoBiology { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of accepted missions index by their mission ID
|
/// Whether to ignore influence support. Usually one only cares about the
|
||||||
|
/// primary faction for the influence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<ulong, MissionAcceptedEntry> AcceptedMissions { get; } = new();
|
public bool IgnoreInfluenceSupport { get; set; } = false;
|
||||||
public Dictionary<ulong, Location> AcceptedMissionLocation { get; } = new();
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A way to lookup a system by its system id
|
/// Whether we ignore power play and merits gained for now. Support for this
|
||||||
|
/// is experimental at the moment, so that is why it ist `true`.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<ulong, string> SystemsByID { get; } = new();
|
public bool IgnorePowerplay { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of factions present in the given star system
|
/// Whether to ignore market buy. Buying from a market gives a small amount
|
||||||
|
/// of INF if it is sold to a high demand market, but generally one buys from
|
||||||
|
/// a market to aid the faction the stuff is being sold to. So allow it to be
|
||||||
|
/// disabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, List<Faction>> SystemFactions { get; } = new();
|
public bool IgnoreMarketBuy { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// To which faction a given named NPC belonged to.
|
/// Whether we should ignore things done for the fleet carrier faction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, string> NPCFaction { get; } = new();
|
public bool IgnoreFleetCarrierFaction { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Buy costs for a given commodity
|
/// Filter out double redeem vouchers that happen when you redeem a specific
|
||||||
|
/// voucher, and then redeem the rest of your vouchers (say from a KWS) in
|
||||||
|
/// bulk. The bulk redeem will also list the first voucher redeem again in
|
||||||
|
/// its bulk list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, long> BuyCost = new();
|
public bool FilterDoubleRedeemVouchers { get; set; } = true;
|
||||||
|
|
||||||
public void BoughtCargo(string? cargo, long? cost) {
|
|
||||||
if (cargo == null || cost == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
BuyCost[cargo] = cost.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Faction>? GetFactions(string? system) {
|
|
||||||
if (system == null || !SystemFactions.ContainsKey(system)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SystemFactions[system];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MissionAccepted(MissionAcceptedEntry accepted) {
|
|
||||||
if (CurrentSystem == null || CurrentSystemAddress == null) {
|
|
||||||
throw new Exception("Mission accepted without knowing where.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accepted.Mission == null) {
|
|
||||||
throw new Exception("Mission is null");
|
|
||||||
}
|
|
||||||
|
|
||||||
AcceptedMissions.TryAdd(accepted.Mission.MissionID, accepted);
|
|
||||||
|
|
||||||
Location location = new() {
|
|
||||||
StarSystem = CurrentSystem,
|
|
||||||
SystemAddress = CurrentSystemAddress.Value,
|
|
||||||
Station = (CurrentStation ?? ""),
|
|
||||||
};
|
|
||||||
|
|
||||||
AcceptedMissionLocation.TryAdd(accepted.Mission.MissionID, location);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TransactionList : List<Transaction> {
|
public class TransactionList : List<Transaction> {
|
||||||
public void AddIncomplete(Transaction underlying, string reason) {
|
public void AddIncomplete(Transaction underlying, string reason, Entry entry) {
|
||||||
Add(new IncompleteTransaction(underlying, reason));
|
Add(new IncompleteTransaction(underlying, reason, entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal interface TransactionParserPart{
|
|
||||||
/// <summary>
|
|
||||||
/// Parse a given entry of the entry type specified when declaring to implement this
|
|
||||||
/// interface. You must add your transaction to the passed list in case you did have
|
|
||||||
/// enough information to parse one or more. You may update the parser context
|
|
||||||
/// with new information in case the entry yielded new information.
|
|
||||||
/// Throw an exception if there was an error or a malformed entry. If you have an
|
|
||||||
/// incomplete entry, i.e. not enough information to complete one, add an
|
|
||||||
/// IncompleteTransaction to the list
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="entry">The entry to parse</param>
|
|
||||||
/// <param name="context">Parsing context that may contain useful information</param>
|
|
||||||
/// <param name="transactions">List of parsed transactions</param>
|
|
||||||
public void Parse(Entry entry, TransactionParserContext context, TransactionList transactions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The location parser only updates the context with useful information, and does not
|
/// The location parser only updates the context with useful information, and does not
|
||||||
/// by itself generate any transactions. Location is the best information gatherer here
|
/// by itself generate any transactions. Location is the best information gatherer here
|
||||||
/// as we are getting controlling faction, system factions, address and station name.
|
/// as we are getting controlling faction, system factions, address and station name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class LocationParser : TransactionParserPart {
|
internal class LocationParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
LocationEntry? entry = e as LocationEntry;
|
LocationEntry? entry = e as LocationEntry;
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -120,15 +79,20 @@ internal class LocationParser : TransactionParserPart {
|
|||||||
context.CurrentStation = entry.StationName;
|
context.CurrentStation = entry.StationName;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.SystemFactions.ContainsKey(entry.StarSystem) &&
|
if (!string.IsNullOrEmpty(entry.StationFaction)) {
|
||||||
entry.SystemFactions != null && entry.SystemFactions.Count > 0) {
|
context.StationOwner = entry.StationFaction;
|
||||||
|
} else {
|
||||||
|
context.StationOwner = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.SystemFactions != null && entry.SystemFactions.Count > 0) {
|
||||||
context.SystemFactions[entry.StarSystem] = entry.SystemFactions;
|
context.SystemFactions[entry.StarSystem] = entry.SystemFactions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class FSDJumpParser : TransactionParserPart {
|
internal class FSDJumpParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
FSDJumpEntry? entry = e as FSDJumpEntry;
|
FSDJumpEntry? entry = e as FSDJumpEntry;
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -138,6 +102,14 @@ internal class FSDJumpParser : TransactionParserPart {
|
|||||||
throw new InvalidJournalEntryException();
|
throw new InvalidJournalEntryException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If you FSD jump straight out of the combat zone into a different system
|
||||||
|
// then the combat zone will be placed in the wrong system otherwise.
|
||||||
|
// This call needs to be *before* changing the current system.
|
||||||
|
context.DiscernCombatZone(transactions, e);
|
||||||
|
context.ResetCombatZone();
|
||||||
|
|
||||||
|
context.LeftInstance();
|
||||||
|
|
||||||
context.CurrentSystem = entry.StarSystem;
|
context.CurrentSystem = entry.StarSystem;
|
||||||
context.CurrentSystemAddress = entry.SystemAddress;
|
context.CurrentSystemAddress = entry.SystemAddress;
|
||||||
|
|
||||||
@@ -147,15 +119,14 @@ internal class FSDJumpParser : TransactionParserPart {
|
|||||||
context.ControllingFaction = entry.SystemFaction;
|
context.ControllingFaction = entry.SystemFaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.SystemFactions.ContainsKey(entry.StarSystem) &&
|
if (entry.SystemFactions != null && entry.SystemFactions.Count > 0) {
|
||||||
entry.SystemFactions != null && entry.SystemFactions.Count > 0) {
|
|
||||||
context.SystemFactions[entry.StarSystem] = entry.SystemFactions;
|
context.SystemFactions[entry.StarSystem] = entry.SystemFactions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DockedParser : TransactionParserPart {
|
internal class DockedParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
DockedEntry? entry = e as DockedEntry;
|
DockedEntry? entry = e as DockedEntry;
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -171,7 +142,7 @@ internal class DockedParser : TransactionParserPart {
|
|||||||
context.SystemsByID.TryAdd(entry.SystemAddress.Value, entry.StarSystem);
|
context.SystemsByID.TryAdd(entry.SystemAddress.Value, entry.StarSystem);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(entry.StationFaction)) {
|
if (!string.IsNullOrEmpty(entry.StationFaction)) {
|
||||||
context.ControllingFaction = entry.StationFaction;
|
context.StationOwner = entry.StationFaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(entry.StationName)) {
|
if (!string.IsNullOrEmpty(entry.StationName)) {
|
||||||
@@ -180,32 +151,12 @@ internal class DockedParser : TransactionParserPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// With ship targeted we might find out to which faction a given NPC belonged. This is
|
|
||||||
/// useful later when said NPC gets killed or murdered.
|
|
||||||
/// </summary>
|
|
||||||
internal class ShipTargetedParser : TransactionParserPart {
|
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
|
||||||
ShipTargetedEntry? entry = e as ShipTargetedEntry;
|
|
||||||
if (entry == null) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scan happens in stages, and sometimes this information is not known
|
|
||||||
// yet. Do now throw an error, this is expected behaviour.
|
|
||||||
if (!string.IsNullOrEmpty(entry.PilotNameLocalised) &&
|
|
||||||
!string.IsNullOrEmpty(entry.Faction)) {
|
|
||||||
context.NPCFaction.TryAdd(entry.PilotNameLocalised, entry.Faction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Commit crime can result in a transaction, especially if the crime committed is
|
/// Commit crime can result in a transaction, especially if the crime committed is
|
||||||
/// murder.
|
/// murder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class CommitCrimeParser : TransactionParserPart {
|
internal class CommitCrimeParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
CommitCrimeEntry? entry = e as CommitCrimeEntry;
|
CommitCrimeEntry? entry = e as CommitCrimeEntry;
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -228,25 +179,69 @@ internal class CommitCrimeParser : TransactionParserPart {
|
|||||||
victim = "Unknown";
|
victim = "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.NPCFaction.ContainsKey(victim)) {
|
string faction;
|
||||||
transactions.AddIncomplete(
|
|
||||||
new FoulMurder(),
|
|
||||||
"Crime victim was not properly scanned."
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
string faction = context.NPCFaction[victim];
|
if (entry.IsCrime(CrimeTypes.OnFootMurder)) {
|
||||||
|
if (entry.Faction == null) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
new FoulMurder(),
|
||||||
|
"On foot murder victim did not have a faction", e
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// On foot murders are different, there the faction is
|
||||||
|
// the faction the NPC belonged too
|
||||||
|
faction = entry.Faction;
|
||||||
|
} else {
|
||||||
|
if (!context.NPCFaction.ContainsKey(victim)) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
new FoulMurder(),
|
||||||
|
"Crime victim was not properly scanned.", e
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
faction = context.NPCFaction[victim];
|
||||||
|
}
|
||||||
|
|
||||||
transactions.Add(new FoulMurder(entry) {
|
transactions.Add(new FoulMurder(entry) {
|
||||||
System = context.CurrentSystem,
|
System = context.CurrentSystem,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
Faction = faction,
|
Faction = faction,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MissionAcceptedParser : TransactionParserPart {
|
internal class MissionsParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, 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 : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
MissionAcceptedEntry? entry = e as MissionAcceptedEntry;
|
MissionAcceptedEntry? entry = e as MissionAcceptedEntry;
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@@ -254,7 +249,8 @@ internal class MissionAcceptedParser : TransactionParserPart {
|
|||||||
|
|
||||||
if (context.CurrentSystem == null || context.CurrentSystemAddress == null) {
|
if (context.CurrentSystem == null || context.CurrentSystemAddress == null) {
|
||||||
transactions.AddIncomplete(new MissionCompleted(),
|
transactions.AddIncomplete(new MissionCompleted(),
|
||||||
"Could not determine current location on mission acceptance."
|
"Could not determine current location on mission acceptance.",
|
||||||
|
e
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -263,36 +259,37 @@ internal class MissionAcceptedParser : TransactionParserPart {
|
|||||||
context.MissionAccepted(entry);
|
context.MissionAccepted(entry);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
transactions.AddIncomplete(new MissionCompleted(),
|
transactions.AddIncomplete(new MissionCompleted(),
|
||||||
exception.Message
|
exception.Message,
|
||||||
|
e
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MissionCompletedParser : TransactionParserPart {
|
internal class MissionCompletedParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
MissionCompletedEntry? entry = e as MissionCompletedEntry;
|
MissionCompletedEntry? entry = e as MissionCompletedEntry;
|
||||||
if (entry == null || entry.Mission == null) {
|
if (entry == null || entry.Mission == null) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
MissionAcceptedEntry? accepted = null;
|
Mission? mission;
|
||||||
Location? accepted_location = null;
|
Location? accepted_location;
|
||||||
string? target_faction_name = entry.Mission.TargetFaction;
|
string? target_faction_name = entry.Mission.TargetFaction;
|
||||||
string? source_faction_name = entry.Mission.Faction;
|
string? source_faction_name = entry.Mission.Faction;
|
||||||
|
|
||||||
// We did not find when the mission was accepted.
|
// 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(),
|
transactions.AddIncomplete(new MissionCompleted(),
|
||||||
String.Format("Mission acceptance for mission id {0} was not found",
|
String.Format("Mission acceptance for mission id {0} was not found",
|
||||||
entry.Mission.MissionID));
|
entry.Mission.MissionID), e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.AcceptedMissionLocation.TryGetValue(entry.Mission.MissionID, out accepted_location)) {
|
if (!context.AcceptedMissionLocation.TryGetValue(entry.Mission.MissionID, out accepted_location)) {
|
||||||
transactions.AddIncomplete(new MissionCompleted(),
|
transactions.AddIncomplete(new MissionCompleted(),
|
||||||
String.Format("Location for acceptance for mission id {0} was not found",
|
String.Format("Location for acceptance for mission id {0} was not found",
|
||||||
entry.Mission.MissionID));
|
entry.Mission.MissionID), e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,20 +312,20 @@ internal class MissionCompletedParser : TransactionParserPart {
|
|||||||
if (context.CurrentSystemAddress == null) {
|
if (context.CurrentSystemAddress == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
other.Value.Add(context.CurrentSystemAddress.Value, "");
|
other.Value.Add(context.CurrentSystemAddress.Value, new MissionInfluence());
|
||||||
// Mission gave no influence to the target faction, so we assume
|
// Mission gave no influence to the target faction, so we assume
|
||||||
// the target faction was in the same system.
|
// the target faction was in the same system.
|
||||||
} else if (string.Compare(source_faction_name, faction, true) == 0) {
|
} else if (string.Compare(source_faction_name, faction, true) == 0) {
|
||||||
// This happens if the source faction is not getting any influence
|
// This happens if the source faction is not getting any influence
|
||||||
// This could be if the source faction is in a conflict, and thus does
|
// This could be if the source faction is in a conflict, and thus does
|
||||||
// not gain any influence at all.
|
// not gain any influence at all.
|
||||||
other.Value.Add(accepted_location.SystemAddress, "");
|
other.Value.Add(accepted_location.SystemAddress, new MissionInfluence());
|
||||||
|
|
||||||
// Just check if the target/source faction are the same, in which case
|
// Just check if the target/source faction are the same, in which case
|
||||||
// we also have to make an additional entry
|
// we also have to make an additional entry
|
||||||
if (string.Compare(source_faction_name, target_faction_name, true) == 0 &&
|
if (string.Compare(source_faction_name, target_faction_name, true) == 0 &&
|
||||||
context.CurrentSystemAddress != null) {
|
context.CurrentSystemAddress != null) {
|
||||||
other.Value.Add(context.CurrentSystemAddress.Value, "");
|
other.Value.Add(context.CurrentSystemAddress.Value, new MissionInfluence());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,7 +337,8 @@ internal class MissionCompletedParser : TransactionParserPart {
|
|||||||
|
|
||||||
if (!context.SystemsByID.TryGetValue(system_address, out system)) {
|
if (!context.SystemsByID.TryGetValue(system_address, out system)) {
|
||||||
transactions.AddIncomplete(new MissionCompleted(),
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -349,24 +347,33 @@ internal class MissionCompletedParser : TransactionParserPart {
|
|||||||
system_address == accepted_location.SystemAddress) {
|
system_address == accepted_location.SystemAddress) {
|
||||||
// Source and target faction are the same, and this is the block
|
// Source and target faction are the same, and this is the block
|
||||||
// for the source system. So we make a full mission completed entry.
|
// for the source system. So we make a full mission completed entry.
|
||||||
transactions.Add(new MissionCompleted(entry) {
|
transactions.Add(new MissionCompleted() {
|
||||||
|
CompletedEntry = entry,
|
||||||
|
Mission = mission,
|
||||||
System = accepted_location.StarSystem,
|
System = accepted_location.StarSystem,
|
||||||
Faction = source_faction_name,
|
Faction = source_faction_name,
|
||||||
SystemAddress = accepted_location.SystemAddress,
|
SystemAddress = accepted_location.SystemAddress,
|
||||||
Station = accepted_location.Station,
|
Station = accepted_location.Station,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
});
|
});
|
||||||
} else if (string.Compare(faction, source_faction_name, true) != 0 ||
|
} else if (string.Compare(faction, source_faction_name, true) != 0 ||
|
||||||
(string.Compare(faction, source_faction_name) == 0 &&
|
(string.Compare(faction, source_faction_name) == 0 &&
|
||||||
system_address != accepted_location.SystemAddress)) {
|
system_address != accepted_location.SystemAddress)) {
|
||||||
|
// Whether we ignore influence support
|
||||||
|
if (options.IgnoreInfluenceSupport) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Source or target faction are different, and/or the system
|
// Source or target faction are different, and/or the system
|
||||||
// differs. Sometimes missions go to different systems but to
|
// differs. Sometimes missions go to different systems but to
|
||||||
// the same faction.
|
// the same faction.
|
||||||
transactions.Add(new InfluenceSupport() {
|
transactions.Add(new InfluenceSupport() {
|
||||||
|
Mission = mission,
|
||||||
Faction = faction,
|
Faction = faction,
|
||||||
Influence = influences.Value,
|
Influence = influences.Value,
|
||||||
System = system,
|
System = system,
|
||||||
SystemAddress = system_address,
|
SystemAddress = system_address,
|
||||||
RelevantMission = entry,
|
RelevantMission = entry,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -374,11 +381,11 @@ internal class MissionCompletedParser : TransactionParserPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MissionFailedParser : TransactionParserPart {
|
internal class MissionFailedParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
MissionAcceptedEntry? accepted = null;
|
Mission? mission;
|
||||||
Location? accepted_location = null;
|
Location? accepted_location;
|
||||||
string? accepted_system = null;
|
string? accepted_system;
|
||||||
|
|
||||||
MissionFailedEntry? entry = e as MissionFailedEntry;
|
MissionFailedEntry? entry = e as MissionFailedEntry;
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
@@ -389,217 +396,244 @@ internal class MissionFailedParser : TransactionParserPart {
|
|||||||
throw new InvalidJournalEntryException("No mission specified in mission failure");
|
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(),
|
transactions.AddIncomplete(new MissionFailed(),
|
||||||
"Mission acceptance was not found"
|
"Mission acceptance was not found", e
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.AcceptedMissionLocation.TryGetValue(entry.Mission.MissionID, out accepted_location)) {
|
if (!context.AcceptedMissionLocation.TryGetValue(mission.MissionID, out accepted_location)) {
|
||||||
transactions.AddIncomplete(new MissionFailed(),
|
transactions.AddIncomplete(new MissionFailed(),
|
||||||
"Unable to figure out where failed mission was accepted"
|
"Unable to figure out where failed mission was accepted", e
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!context.SystemsByID.TryGetValue(accepted_location.SystemAddress, out accepted_system)) {
|
if (!context.SystemsByID.TryGetValue(accepted_location.SystemAddress, out accepted_system)) {
|
||||||
transactions.AddIncomplete(new MissionFailed(),
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transactions.Add(new MissionFailed() {
|
if (string.IsNullOrEmpty(mission.Faction)) {
|
||||||
Accepted = accepted,
|
transactions.AddIncomplete(new MissionFailed(),
|
||||||
Faction = accepted.Mission?.Faction,
|
"Could not determine for what faction you failed a mission. This happens if the " +
|
||||||
Failed = entry,
|
"mission acceptance is not within the given time frame.",
|
||||||
|
entry
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
transactions.Add(new MissionFailed(entry) {
|
||||||
|
Faction = mission?.Faction,
|
||||||
|
Mission = mission,
|
||||||
Station = accepted_location.Station,
|
Station = accepted_location.Station,
|
||||||
System = accepted_location.StarSystem,
|
System = accepted_location.StarSystem,
|
||||||
SystemAddress = accepted_location.SystemAddress,
|
SystemAddress = accepted_location.SystemAddress,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SellExplorationDataParser : TransactionParserPart {
|
internal class SellMicroResourcesParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
SellExplorationDataEntry? entry = e as SellExplorationDataEntry;
|
|
||||||
if (entry == null) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions.Add(new Cartographics(entry) {
|
|
||||||
System = context.CurrentSystem,
|
|
||||||
Station = context.CurrentStation,
|
|
||||||
Faction = context.ControllingFaction,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class SellOrganicDataParser : TransactionParserPart {
|
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
|
||||||
SellOrganicDataEntry? entry = e as SellOrganicDataEntry;
|
|
||||||
if (entry == null) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions.Add(new OrganicData(entry) {
|
|
||||||
System = context.CurrentSystem,
|
|
||||||
Station = context.CurrentStation,
|
|
||||||
Faction = context.ControllingFaction,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class MultiSellExplorationDataParser : TransactionParserPart {
|
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
|
||||||
MultiSellExplorationDataEntry? entry = e as MultiSellExplorationDataEntry;
|
|
||||||
if (entry == null) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions.Add(new Cartographics(entry) {
|
|
||||||
System = context.CurrentSystem,
|
|
||||||
Station = context.CurrentStation,
|
|
||||||
Faction = context.ControllingFaction,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class RedeemVoucherParser : TransactionParserPart {
|
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
|
||||||
RedeemVoucherEntry? entry = e as RedeemVoucherEntry;
|
|
||||||
if (entry == null) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.CurrentSystem == null) {
|
|
||||||
transactions.AddIncomplete(new Vouchers(),
|
|
||||||
"Could not find out where the vouchers were redeemed"
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string faction in entry.Factions) {
|
|
||||||
if (current_factions.Find(x => string.Compare(x.Name, faction, true) == 0) == null) {
|
|
||||||
transactions.AddIncomplete(new Vouchers(),
|
|
||||||
string.Format("Vouchers for {0} were ignored in {1} since said " +
|
|
||||||
"faction is not present here", faction, context.CurrentSystem)
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions.Add(new Vouchers(entry) {
|
|
||||||
System = context.CurrentSystem,
|
|
||||||
Station = context.CurrentStation,
|
|
||||||
Faction = faction,
|
|
||||||
ControllingFaction = context.ControllingFaction,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class SellMicroResourcesParser : TransactionParserPart {
|
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
|
||||||
SellMicroResourcesEntry? entry = e as SellMicroResourcesEntry;
|
SellMicroResourcesEntry? entry = e as SellMicroResourcesEntry;
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.StationOwner == null) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
new SellMicroResources(),
|
||||||
|
"Could not discern the station owner for micro resources sell.",
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
transactions.Add(new SellMicroResources(entry) {
|
transactions.Add(new SellMicroResources(entry) {
|
||||||
System = context.CurrentSystem,
|
System = context.CurrentSystem,
|
||||||
Station = context.CurrentStation,
|
Station = context.CurrentStation,
|
||||||
Faction = context.ControllingFaction,
|
Faction = context.StationOwner,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SearchAndRescueParser : TransactionParserPart {
|
internal class SearchAndRescueParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
SearchAndRescueEntry? entry = e as SearchAndRescueEntry;
|
SearchAndRescueEntry? entry = e as SearchAndRescueEntry;
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.StationOwner == null) {
|
||||||
|
transactions.AddIncomplete(
|
||||||
|
new OrganicData(),
|
||||||
|
"Could not discern the station owner for S&R operations.",
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
transactions.Add(new SearchAndRescue(entry) {
|
transactions.Add(new SearchAndRescue(entry) {
|
||||||
Faction = context.ControllingFaction,
|
|
||||||
Station = context.CurrentStation,
|
|
||||||
System = context.CurrentSystem,
|
System = context.CurrentSystem,
|
||||||
|
Station = context.CurrentStation,
|
||||||
|
Faction = context.StationOwner,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class MarketBuyParser : TransactionParserPart {
|
internal class FactionKillBondParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
MarketBuyEntry? entry = e as MarketBuyEntry;
|
|
||||||
if (entry == null) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
context.BoughtCargo(entry.Type, entry.BuyPrice);
|
|
||||||
|
|
||||||
transactions.Add(new BuyCargo(entry) {
|
|
||||||
Faction = context.ControllingFaction,
|
|
||||||
Station = context.CurrentStation,
|
|
||||||
System = context.CurrentSystem,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class MarketSellParser : TransactionParserPart {
|
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
|
||||||
long profit = 0;
|
|
||||||
|
|
||||||
MarketSellEntry? entry = e as MarketSellEntry;
|
|
||||||
if (entry == null) {
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.Type == null) {
|
|
||||||
throw new InvalidJournalEntryException("market sell contains no cargo type");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.BuyCost.ContainsKey(entry.Type)) {
|
|
||||||
long avg = context.BuyCost[entry.Type];
|
|
||||||
profit = (long)entry.TotalSale - (avg * entry.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
transactions.Add(new SellCargo(entry) {
|
|
||||||
Faction = context.ControllingFaction,
|
|
||||||
Station = context.CurrentStation,
|
|
||||||
System = context.CurrentSystem,
|
|
||||||
Profit = profit,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class FactionKillBondParser : TransactionParserPart {
|
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionList transactions) {
|
|
||||||
FactionKillBondEntry? entry = e as FactionKillBondEntry;
|
FactionKillBondEntry? entry = e as FactionKillBondEntry;
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Compare(entry.VictimFaction, Thargoid.ThargoidFaction) == 0) {
|
if (Factions.IsThargoid(entry.VictimFaction)) {
|
||||||
// Thargoid bonk
|
// Thargoid bonk
|
||||||
transactions.Add(new ThargoidKill(entry));
|
transactions.Add(new ThargoidKill(entry) {
|
||||||
|
System = context.CurrentSystem,
|
||||||
|
Faction = Factions.PilotsFederation,
|
||||||
|
Station = context.CurrentStation,
|
||||||
|
IsLegacy = context.IsLegacy,
|
||||||
|
});
|
||||||
|
|
||||||
|
ThargoidVessel vessel = Thargoid.GetVesselByPayout(entry.Reward);
|
||||||
|
if (vessel != ThargoidVessel.Unknown) {
|
||||||
|
if (vessel == ThargoidVessel.Scout) {
|
||||||
|
++context.ThargoidScoutKills;
|
||||||
|
} else {
|
||||||
|
++context.ThargoidInterceptorKills;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are done
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.RecordCombatBond(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class EmbarkDisembarkParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
if (e.Is(Events.Embark)) {
|
||||||
|
context.IsOnFoot = false;
|
||||||
|
} else if (e.Is(Events.Disembark)) {
|
||||||
|
context.IsOnFoot = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class SupercruiseEntryParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
// After a super cruise entry we are no longer on foot.
|
||||||
|
context.IsOnFoot = false;
|
||||||
|
context.DiscernCombatZone(transactions, entry);
|
||||||
|
context.ResetCombatZone();
|
||||||
|
// Supercruise entry means you left the current local instance
|
||||||
|
context.LeftInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ShutdownParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
context.DiscernCombatZone(transactions, entry);
|
||||||
|
context.ResetCombatZone();
|
||||||
|
// Shutdown (logout) means you left the instance
|
||||||
|
context.LeftInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class CapShipBondParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
if (entry.GetType() != typeof(CapShipBondEntry)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.HaveSeenCapShip = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class FileHeaderParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
FileHeaderEntry? fileheader = entry as FileHeaderEntry;
|
||||||
|
|
||||||
|
if (fileheader == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.IsLegacy = fileheader.IsLegacy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ReceiveTextParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
ReceiveTextEntry? receivetext = entry as ReceiveTextEntry;
|
||||||
|
|
||||||
|
if (receivetext == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(receivetext.Channel, Channels.NPC) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(receivetext.NPCCategory, NPCs.AXMilitary) == 0) {
|
||||||
|
context.HaveSeenAXWarzoneNPC = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class SelfDestructParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
context.SelfDestruct = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DiedParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
// Death only matters in ship. On foot you can just redeploy with the dropship.
|
||||||
|
if (context.IsOnFoot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (context.SelfDestruct != null && context.SelfDestruct == true) {
|
||||||
|
// Some people just suicide to fast track back to stations after a CZ,
|
||||||
|
// especially since combat bonds don't disappear on death. So count the CZ
|
||||||
|
// on self destruct
|
||||||
|
context.DiscernCombatZone(transactions, entry);
|
||||||
|
context.SelfDestruct = null;
|
||||||
|
}
|
||||||
|
context.ResetCombatZone();
|
||||||
|
// Dying also moves you back to another instance
|
||||||
|
context.LeftInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DropshipDeployParser : ITransactionParserPart {
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
|
// On drop ship deploy we are now on foot
|
||||||
|
context.IsOnFoot = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class TransactionParser {
|
public class TransactionParser {
|
||||||
private static Dictionary<string, TransactionParserPart> ParserParts { get; } = new()
|
private static Dictionary<string, ITransactionParserPart> ParserParts { get; } = new()
|
||||||
{
|
{
|
||||||
|
{ Events.ApproachSettlement, new ApproachSettlementParser() },
|
||||||
|
{ Events.CapShipBond, new CapShipBondParser() },
|
||||||
|
{ Events.CarrierJump, new CarrierJumpParser() },
|
||||||
|
{ Events.Commander, new CommanderParser() },
|
||||||
{ Events.CommitCrime, new CommitCrimeParser() },
|
{ Events.CommitCrime, new CommitCrimeParser() },
|
||||||
|
{ Events.Died, new DiedParser() },
|
||||||
|
{ Events.Disembark, new EmbarkDisembarkParser() },
|
||||||
{ Events.Docked, new DockedParser() },
|
{ Events.Docked, new DockedParser() },
|
||||||
|
{ Events.DropshipDeploy, new DropshipDeployParser() },
|
||||||
|
{ Events.Embark, new EmbarkDisembarkParser() },
|
||||||
{ Events.FactionKillBond, new FactionKillBondParser() },
|
{ Events.FactionKillBond, new FactionKillBondParser() },
|
||||||
|
{ Events.FileHeader, new FileHeaderParser() },
|
||||||
{ Events.FSDJump, new FSDJumpParser() },
|
{ Events.FSDJump, new FSDJumpParser() },
|
||||||
{ Events.Location, new LocationParser() },
|
{ Events.Location, new LocationParser() },
|
||||||
{ Events.MarketBuy, new MarketBuyParser() },
|
{ Events.MarketBuy, new MarketBuyParser() },
|
||||||
@@ -607,16 +641,50 @@ public class TransactionParser {
|
|||||||
{ Events.MissionAccepted, new MissionAcceptedParser() },
|
{ Events.MissionAccepted, new MissionAcceptedParser() },
|
||||||
{ Events.MissionCompleted, new MissionCompletedParser() },
|
{ Events.MissionCompleted, new MissionCompletedParser() },
|
||||||
{ Events.MissionFailed, new MissionFailedParser() },
|
{ Events.MissionFailed, new MissionFailedParser() },
|
||||||
|
{ Events.Missions, new MissionsParser() },
|
||||||
{ Events.MultiSellExplorationData, new MultiSellExplorationDataParser() },
|
{ Events.MultiSellExplorationData, new MultiSellExplorationDataParser() },
|
||||||
|
{ Events.Music, new MusicParser() },
|
||||||
|
{ Events.PowerplayMerits, new PowerplayMeritsParser() },
|
||||||
|
{ Events.ReceiveText, new ReceiveTextParser() },
|
||||||
{ Events.RedeemVoucher, new RedeemVoucherParser() },
|
{ Events.RedeemVoucher, new RedeemVoucherParser() },
|
||||||
{ Events.SearchAndRescue, new SearchAndRescueParser() },
|
{ Events.SearchAndRescue, new SearchAndRescueParser() },
|
||||||
|
{ Events.SelfDestruct, new SelfDestructParser() },
|
||||||
{ Events.SellExplorationData, new SellExplorationDataParser() },
|
{ Events.SellExplorationData, new SellExplorationDataParser() },
|
||||||
{ Events.SellMicroResources, new SellMicroResourcesParser() },
|
{ Events.SellMicroResources, new SellMicroResourcesParser() },
|
||||||
{ Events.SellOrganicData, new SellOrganicDataParser() },
|
{ Events.SellOrganicData, new SellOrganicDataParser() },
|
||||||
{ Events.ShipTargeted, new ShipTargetedParser() },
|
{ Events.ShipTargeted, new ShipTargetedParser() },
|
||||||
|
{ Events.Shutdown, new ShutdownParser() },
|
||||||
|
{ Events.SupercruiseDestinationDrop, new SupercruiseDestinationDropParser() },
|
||||||
|
{ Events.SupercruiseEntry, new SupercruiseEntryParser() },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public bool IsRelevant(string entry) {
|
||||||
|
return ParserParts.ContainsKey(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsRelevant(Entry e) {
|
||||||
|
if (e.Event == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return IsRelevant(e.Event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a list of entries with default options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entries"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public List<Transaction>? Parse(IEnumerable<Entry> entries) {
|
public List<Transaction>? Parse(IEnumerable<Entry> entries) {
|
||||||
|
TransactionParserOptions defaultOptions = new();
|
||||||
|
return Parse(entries, defaultOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of commanders seen during parsing.
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Commanders { get; set; } = new();
|
||||||
|
|
||||||
|
public List<Transaction>? Parse(IEnumerable<Entry> entries, TransactionParserOptions options) {
|
||||||
TransactionList transactions = new();
|
TransactionList transactions = new();
|
||||||
TransactionParserContext context = new();
|
TransactionParserContext context = new();
|
||||||
|
|
||||||
@@ -629,10 +697,13 @@ public class TransactionParser {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionParserPart transactionParserPart = ParserParts[entry.Event];
|
ITransactionParserPart transactionParserPart = ParserParts[entry.Event];
|
||||||
transactionParserPart.Parse(entry, context, transactions);
|
transactionParserPart.Parse(entry, context, options, transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy out list of commanders seen
|
||||||
|
Commanders = context.Commanders;
|
||||||
|
|
||||||
return transactions.ToList();
|
return transactions.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
354
EDPlayerJournal/BGS/TransactionParserContext.cs
Normal file
354
EDPlayerJournal/BGS/TransactionParserContext.cs
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
internal class TransactionParserContext {
|
||||||
|
/// <summary>
|
||||||
|
/// List of commander names seen in the logs. May be empty.
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Commanders { get; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the current system the player is in.
|
||||||
|
/// </summary>
|
||||||
|
public string? CurrentSystem { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 64 bit address of the current system.
|
||||||
|
/// </summary>
|
||||||
|
public ulong? CurrentSystemAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controlling faction of the current system.
|
||||||
|
/// </summary>
|
||||||
|
public string? ControllingFaction { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the current station the player is docked at.
|
||||||
|
/// </summary>
|
||||||
|
public string? CurrentStation { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Faction that owns the current station.
|
||||||
|
/// </summary>
|
||||||
|
public string? StationOwner { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the player is currently on foot, or in an SRV/ship.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsOnFoot { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type of the current instance after a SupercruiseDestinationDropEntry.
|
||||||
|
/// This is null if there is no current instance, or the current instance
|
||||||
|
/// is not known.
|
||||||
|
/// </summary>
|
||||||
|
public string? CurrentInstanceType { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Last faction that awarded the player with combat bonds.
|
||||||
|
/// </summary>
|
||||||
|
public string? LastRecordedAwardingFaction { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Highest combat bond seen so far.
|
||||||
|
/// </summary>
|
||||||
|
public ulong? HighestCombatBond { get; set; }
|
||||||
|
|
||||||
|
public bool HaveSeenCapShip { get; set; } = false;
|
||||||
|
public bool HaveSeenAlliedCaptain { get; set; } = false;
|
||||||
|
public bool HaveSeenEnemyCaptain { get; set; } = false;
|
||||||
|
public bool HaveSeenSpecOps { get; set; } = false;
|
||||||
|
public bool HaveSeenAlliedCorrespondent { get; set; } = false;
|
||||||
|
public bool HaveSeenEnemyCorrespondent { get; set; } = false;
|
||||||
|
|
||||||
|
public bool? SelfDestruct { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current Odyssey settlement.
|
||||||
|
/// </summary>
|
||||||
|
public string? Settlement { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current Merits
|
||||||
|
/// </summary>
|
||||||
|
public long? CurrentMerits { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Merits from last login
|
||||||
|
/// </summary>
|
||||||
|
public long? LastMerits { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the current session is legacy
|
||||||
|
/// </summary>
|
||||||
|
public bool IsLegacy { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many on foot kills were done.
|
||||||
|
/// </summary>
|
||||||
|
public ulong OnFootKills { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many ship kills were done.
|
||||||
|
/// </summary>
|
||||||
|
public ulong ShipKills { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Thargoid scouts killed
|
||||||
|
/// </summary>
|
||||||
|
public ulong ThargoidScoutKills { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Thargoid interceptor kills
|
||||||
|
/// </summary>
|
||||||
|
public ulong ThargoidInterceptorKills { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether we have seen an AX warzone NPC talk to us with ReceiveText
|
||||||
|
/// </summary>
|
||||||
|
public bool HaveSeenAXWarzoneNPC { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of accepted missions index by their mission ID
|
||||||
|
/// </summary>
|
||||||
|
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
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<ulong, string> SystemsByID { get; } = new();
|
||||||
|
/// <summary>
|
||||||
|
/// A list of factions present in the given star system
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, List<Faction>> SystemFactions { get; } = new();
|
||||||
|
/// <summary>
|
||||||
|
/// To which faction a given named NPC belonged to.
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, string> NPCFaction { get; } = new();
|
||||||
|
/// <summary>
|
||||||
|
/// Buy costs for a given commodity
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, long> BuyCost = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when the player leaves an instance, either through logout, FSD jump or
|
||||||
|
/// supercruise instance.
|
||||||
|
/// </summary>
|
||||||
|
public void LeftInstance() {
|
||||||
|
CurrentInstanceType = null;
|
||||||
|
Settlement = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HadCombatZone() {
|
||||||
|
if (CurrentInstanceType != null &&
|
||||||
|
Instances.IsInstance(CurrentInstanceType, Instances.PowerWarzoneMedium)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HighestCombatBond == null &&
|
||||||
|
LastRecordedAwardingFaction == null &&
|
||||||
|
HaveSeenAXWarzoneNPC == false &&
|
||||||
|
CurrentInstanceType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DiscernCombatZone(TransactionList transactions, Entry e) {
|
||||||
|
string? grade = CombatZones.DifficultyLow;
|
||||||
|
string cztype;
|
||||||
|
ulong highest = HighestCombatBond ?? 0;
|
||||||
|
string? faction = LastRecordedAwardingFaction;
|
||||||
|
|
||||||
|
if (!HadCombatZone()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OnFootKills > 0 || IsOnFoot == true) {
|
||||||
|
cztype = CombatZones.GroundCombatZone;
|
||||||
|
// High on foot combat zones have enforcers that bring 80k a pop
|
||||||
|
if (highest >= 60000) {
|
||||||
|
grade = CombatZones.DifficultyHigh;
|
||||||
|
} else if (highest >= 30000) {
|
||||||
|
// In medium conflict zones, the enforcers are worth 30k
|
||||||
|
grade = CombatZones.DifficultyMedium;
|
||||||
|
} else {
|
||||||
|
grade = CombatZones.DifficultyLow;
|
||||||
|
}
|
||||||
|
} else if (CurrentInstanceType != null) {
|
||||||
|
if (!Instances.IsWarzone(CurrentInstanceType)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (LastRecordedAwardingFaction == null &&
|
||||||
|
(Instances.IsHumanWarzone(CurrentInstanceType) ||
|
||||||
|
Instances.IsPowerWarzone(CurrentInstanceType))) {
|
||||||
|
transactions.AddIncomplete(new CombatZone(),
|
||||||
|
"Could not discern for whom you fought for, " +
|
||||||
|
"as it seems you haven't killed anyone in the ship combat zone.",
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If we have information about the current instance being a warship use that
|
||||||
|
// information to determine the warzone.
|
||||||
|
if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneLow)) {
|
||||||
|
cztype = CombatZones.ShipCombatZone;
|
||||||
|
grade = CombatZones.DifficultyLow;
|
||||||
|
} else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneMedium)) {
|
||||||
|
cztype = CombatZones.ShipCombatZone;
|
||||||
|
grade = CombatZones.DifficultyMedium;
|
||||||
|
} else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneHigh)) {
|
||||||
|
cztype = CombatZones.ShipCombatZone;
|
||||||
|
grade = CombatZones.DifficultyHigh;
|
||||||
|
} else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidLow)) {
|
||||||
|
cztype = CombatZones.AXCombatZone;
|
||||||
|
grade = CombatZones.DifficultyLow;
|
||||||
|
} else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidMedium)) {
|
||||||
|
cztype = CombatZones.AXCombatZone;
|
||||||
|
grade = CombatZones.DifficultyMedium;
|
||||||
|
} else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidHigh)) {
|
||||||
|
cztype = CombatZones.AXCombatZone;
|
||||||
|
grade = CombatZones.DifficultyHigh;
|
||||||
|
} else if (Instances.IsInstance(CurrentInstanceType, Instances.WarzoneThargoidVeryHigh)) {
|
||||||
|
cztype = CombatZones.AXCombatZone;
|
||||||
|
grade = CombatZones.DifficultyVeryHigh;
|
||||||
|
} else if (Instances.IsInstance(CurrentInstanceType, Instances.PowerWarzoneMedium)) {
|
||||||
|
cztype = CombatZones.PowerCombatZone;
|
||||||
|
grade = CombatZones.DifficultyMedium;
|
||||||
|
} else {
|
||||||
|
transactions.AddIncomplete(new CombatZone(),
|
||||||
|
"Unknown conflict zone difficulty",
|
||||||
|
e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (ShipKills > 0 && !IsOnFoot) {
|
||||||
|
// Ship combat zones can be identified by the amount of kills
|
||||||
|
if (ShipKills > 20) {
|
||||||
|
grade = CombatZones.DifficultyHigh;
|
||||||
|
} else if (ShipKills > 10) {
|
||||||
|
grade = CombatZones.DifficultyMedium;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cap ship, means a high conflict zone
|
||||||
|
if (HaveSeenCapShip) {
|
||||||
|
grade = CombatZones.DifficultyHigh;
|
||||||
|
} else {
|
||||||
|
int warzoneNpcs = new List<bool>() {
|
||||||
|
HaveSeenEnemyCaptain,
|
||||||
|
HaveSeenEnemyCorrespondent,
|
||||||
|
HaveSeenSpecOps
|
||||||
|
}
|
||||||
|
.Where(x => x == true)
|
||||||
|
.Count()
|
||||||
|
;
|
||||||
|
|
||||||
|
if (warzoneNpcs >= 1 && grade == CombatZones.DifficultyLow) {
|
||||||
|
grade = CombatZones.DifficultyMedium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cztype = CombatZones.ShipCombatZone;
|
||||||
|
} else if ((ThargoidScoutKills > 0 && ThargoidInterceptorKills > 0) ||
|
||||||
|
HaveSeenAXWarzoneNPC == true) {
|
||||||
|
// Could be a thargoid combat zones if interceptors and scouts are there
|
||||||
|
cztype = CombatZones.AXCombatZone;
|
||||||
|
// Still unknown
|
||||||
|
grade = null;
|
||||||
|
} else {
|
||||||
|
transactions.AddIncomplete(new CombatZone(), "Failed to discern combat zone type", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CombatZone zone = new CombatZone() {
|
||||||
|
System = CurrentSystem,
|
||||||
|
Faction = faction,
|
||||||
|
IsLegacy = IsLegacy,
|
||||||
|
Settlement = Settlement,
|
||||||
|
Grade = grade,
|
||||||
|
Type = cztype,
|
||||||
|
// Sad truth is, if HaveSeenXXX is false, we just don't know for certain
|
||||||
|
CapitalShip = HaveSeenCapShip ? true : null,
|
||||||
|
SpecOps = HaveSeenSpecOps ? true : null,
|
||||||
|
EnemyCorrespondent = HaveSeenEnemyCorrespondent ? true : null,
|
||||||
|
AlliedCorrespondent = HaveSeenAlliedCorrespondent ? true : null,
|
||||||
|
EnemyCaptain = HaveSeenEnemyCaptain ? true : null,
|
||||||
|
AlliedCaptain = HaveSeenAlliedCaptain ? true : null,
|
||||||
|
};
|
||||||
|
zone.Entries.Add(e);
|
||||||
|
transactions.Add(zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RecordCombatBond(FactionKillBondEntry e) {
|
||||||
|
if (HighestCombatBond == null || e.Reward > HighestCombatBond) {
|
||||||
|
HighestCombatBond = e.Reward;
|
||||||
|
}
|
||||||
|
|
||||||
|
LastRecordedAwardingFaction = e.AwardingFaction;
|
||||||
|
|
||||||
|
if (IsOnFoot) {
|
||||||
|
++OnFootKills;
|
||||||
|
} else {
|
||||||
|
++ShipKills;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetCombatZone() {
|
||||||
|
HighestCombatBond = null;
|
||||||
|
HaveSeenCapShip = false;
|
||||||
|
HaveSeenAlliedCaptain = false;
|
||||||
|
HaveSeenEnemyCaptain = false;
|
||||||
|
HaveSeenAlliedCorrespondent = false;
|
||||||
|
HaveSeenEnemyCorrespondent = false;
|
||||||
|
HaveSeenSpecOps = false;
|
||||||
|
LastRecordedAwardingFaction = null;
|
||||||
|
OnFootKills = 0;
|
||||||
|
ShipKills = 0;
|
||||||
|
ThargoidInterceptorKills = 0;
|
||||||
|
ThargoidScoutKills = 0;
|
||||||
|
HaveSeenAXWarzoneNPC = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void BoughtCargo(string? cargo, long? cost) {
|
||||||
|
if (cargo == null || cost == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BuyCost[cargo] = cost.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Faction>? GetFactions(string? system) {
|
||||||
|
if (system == null || !SystemFactions.ContainsKey(system)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SystemFactions[system];
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (mission == null) {
|
||||||
|
throw new Exception("Mission is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
AcceptedMissions.TryAdd(mission.MissionID, mission);
|
||||||
|
|
||||||
|
Location location = new() {
|
||||||
|
StarSystem = CurrentSystem,
|
||||||
|
SystemAddress = CurrentSystemAddress.Value,
|
||||||
|
Station = (CurrentStation ?? ""),
|
||||||
|
};
|
||||||
|
|
||||||
|
AcceptedMissionLocation.TryAdd(mission.MissionID, location);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
EDPlayerJournal/BGS/TransactionParserPart.cs
Normal file
19
EDPlayerJournal/BGS/TransactionParserPart.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
|
internal interface ITransactionParserPart {
|
||||||
|
/// <summary>
|
||||||
|
/// Parse a given entry of the entry type specified when declaring to implement this
|
||||||
|
/// interface. You must add your transaction to the passed list in case you did have
|
||||||
|
/// enough information to parse one or more. You may update the parser context
|
||||||
|
/// with new information in case the entry yielded new information.
|
||||||
|
/// Throw an exception if there was an error or a malformed entry. If you have an
|
||||||
|
/// incomplete entry, i.e. not enough information to complete one, add an
|
||||||
|
/// IncompleteTransaction to the list
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entry">The entry to parse</param>
|
||||||
|
/// <param name="context">Parsing context that may contain useful information</param>
|
||||||
|
/// <param name="transactions">List of parsed transactions</param>
|
||||||
|
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions);
|
||||||
|
}
|
||||||
@@ -20,8 +20,8 @@ public class Vouchers : Transaction {
|
|||||||
}
|
}
|
||||||
return Entries
|
return Entries
|
||||||
.OfType<RedeemVoucherEntry>()
|
.OfType<RedeemVoucherEntry>()
|
||||||
.Where(x => x.FactionBounties.ContainsKey(Faction))
|
.ToList()
|
||||||
.Sum(x => x.FactionBounties[Faction])
|
.Sum(x => (long)x.GetBountyForFaction(Faction))
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,9 +39,9 @@ public class Vouchers : Transaction {
|
|||||||
.First();
|
.First();
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
return null;
|
return null;
|
||||||
} else if (v == "CombatBond") {
|
} else if (v == Bonds.CombatBond) {
|
||||||
type = "Combat Bond";
|
type = "Combat Bond";
|
||||||
} else if (v == "bounty") {
|
} else if (v == Bonds.Bounty) {
|
||||||
type = "Bounty";
|
type = "Bounty";
|
||||||
} else {
|
} else {
|
||||||
type = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(v);
|
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";
|
||||||
|
}
|
||||||
8
EDPlayerJournal/Channels.cs
Normal file
8
EDPlayerJournal/Channels.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace EDPlayerJournal;
|
||||||
|
|
||||||
|
public class Channels {
|
||||||
|
/// <summary>
|
||||||
|
/// Channel NPCs use to talk to the commander.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string NPC = "npc";
|
||||||
|
}
|
||||||
69
EDPlayerJournal/CombatZones.cs
Normal file
69
EDPlayerJournal/CombatZones.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
namespace EDPlayerJournal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Static strings related to combat zones
|
||||||
|
/// </summary>
|
||||||
|
public class CombatZones {
|
||||||
|
/// <summary>
|
||||||
|
/// Type string for ground combat zone
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string GroundCombatZone = "Ground";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Type string for ship combat zones
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string ShipCombatZone = "Ship";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Power combat zones, new in Ascendancy update.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string PowerCombatZone = "Power";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AX combat zone
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string AXCombatZone = "AX";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Difficulty low
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string DifficultyLow = "Low";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Difficulty medium
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string DifficultyMedium = "Medium";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Difficulty high
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string DifficultyHigh = "High";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Very high difficulty, so far AX combat zone only
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string DifficultyVeryHigh = "Very High";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the given combat zone difficulty as an integer, so it can be sorted.
|
||||||
|
/// 0 = lowest difficulty, 1 = medium and so forth.
|
||||||
|
/// </summary>
|
||||||
|
public static int? DifficultyRank(string? difficulty) {
|
||||||
|
Dictionary<string, int> ranks = new() {
|
||||||
|
{ DifficultyLow, 0 },
|
||||||
|
{ DifficultyMedium, 1 },
|
||||||
|
{ DifficultyHigh, 2 },
|
||||||
|
{ DifficultyVeryHigh, 3 }
|
||||||
|
};
|
||||||
|
|
||||||
|
if (difficulty == null ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ranks.TryGetValue(difficulty, out int rank)) {
|
||||||
|
return rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,4 +34,16 @@ public class Credits {
|
|||||||
|
|
||||||
return string.Format("{0} CR", amount.ToString("N", format));
|
return string.Format("{0} CR", amount.ToString("N", format));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string FormatMillions(long amount) {
|
||||||
|
double millions = (amount / 1000000.0);
|
||||||
|
|
||||||
|
if (amount >= 100000) {
|
||||||
|
return string.Format("{0:0.0}M", millions);
|
||||||
|
} else if (amount >= 10000) {
|
||||||
|
return string.Format("{0:0.00}M", millions);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format("{0}", amount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,28 @@
|
|||||||
using EDPlayerJournal.BGS;
|
namespace EDPlayerJournal;
|
||||||
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;
|
|
||||||
|
|
||||||
public class EnglishMissionNames {
|
public class EnglishMissionNames {
|
||||||
public static Dictionary<string, string> MissionNames { get; } = new Dictionary<string, string>() {
|
public static Dictionary<string, string> MissionNames { get; } = new Dictionary<string, string>() {
|
||||||
{"Chain_FindThePirateLord_name", "Assassination (Pirate Lord) (Chain)"},
|
{"Chain_FindThePirateLord_name", "Assassination (Pirate Lord) (Chain)"},
|
||||||
{"Chain_RegainFooting_name", "Regain Footing (Chain)"},
|
{"Chain_RegainFooting_name", "Regain Footing (Chain)"},
|
||||||
{"Chain_SalvageJustice_name", "Assassination (Legal) (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_name", "Donate"},
|
||||||
|
{"Mission_Altruism_Outbreak_name", "Donate (Outbreak)" },
|
||||||
{"Mission_AltruismCredits_Bust_name", "Donate Credits (Bust)"},
|
{"Mission_AltruismCredits_Bust_name", "Donate Credits (Bust)"},
|
||||||
|
{"Mission_AltruismCredits_CivilUnrest_name", "Donate Credits (Civil Unrest)" },
|
||||||
{"Mission_AltruismCredits_Famine_name", "Donate Credits (Famine)"},
|
{"Mission_AltruismCredits_Famine_name", "Donate Credits (Famine)"},
|
||||||
{"Mission_AltruismCredits_name", "Donate Credits"},
|
{"Mission_AltruismCredits_name", "Donate Credits"},
|
||||||
|
{"Mission_AltruismCredits_Outbreak_name", "Donate Credits (Outbreak)" },
|
||||||
{"Mission_Assassinate_Illegal_BLOPS_name", "Assassination (Illegal)"},
|
{"Mission_Assassinate_Illegal_BLOPS_name", "Assassination (Illegal)"},
|
||||||
{"Mission_Assassinate_Legal_Corporate_name", "Corporate Assassination (Legal)"},
|
{"MISSION_assassinate_Illegal_Planetary_name", "Assassination (Illegal, Planetary)" },
|
||||||
|
{"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_name", "Assassination"},
|
||||||
|
{"Mission_Assassinate_Planetary_Expansion_name", "Assassination (Planetary Scan, Expansion)" },
|
||||||
{"Mission_Assassinate_Planetary_name", "Assassination (Planetary Scan)"},
|
{"Mission_Assassinate_Planetary_name", "Assassination (Planetary Scan)"},
|
||||||
{"Mission_Collect_Bust_name", "Provide (Bust)"},
|
{"Mission_Collect_Bust_name", "Provide (Bust)"},
|
||||||
{"Mission_Collect_CivilLiberty_name", "Provide (Civil Liberty)"},
|
{"Mission_Collect_CivilLiberty_name", "Provide (Civil Liberty)"},
|
||||||
@@ -29,8 +30,10 @@ public class EnglishMissionNames {
|
|||||||
{"Mission_Collect_Famine_name", "Provide (Famine)"},
|
{"Mission_Collect_Famine_name", "Provide (Famine)"},
|
||||||
{"Mission_Collect_Industrial_name", "Provide (Industrial)"},
|
{"Mission_Collect_Industrial_name", "Provide (Industrial)"},
|
||||||
{"Mission_Collect_name", "Provide"},
|
{"Mission_Collect_name", "Provide"},
|
||||||
|
{"Mission_Collect_Outbreak_name", "Provide (Outbreak)" },
|
||||||
{"Mission_Collect_RankEmp_name", "Provide (Imperial Navy)"},
|
{"Mission_Collect_RankEmp_name", "Provide (Imperial Navy)"},
|
||||||
{"Mission_Collect_Retreat_name", "Provide (Retreat)"},
|
{"Mission_Collect_Retreat_name", "Provide (Retreat)"},
|
||||||
|
{"Mission_Courier_CivilUnrest_name", "Courier (Divil Unrest)" },
|
||||||
{"Mission_Courier_Democracy_name", "Courier (Democracy)"},
|
{"Mission_Courier_Democracy_name", "Courier (Democracy)"},
|
||||||
{"Mission_Courier_Elections_name", "Courier (Elections)"},
|
{"Mission_Courier_Elections_name", "Courier (Elections)"},
|
||||||
{"Mission_Courier_Expansion_name", "Courier (Expansion)"},
|
{"Mission_Courier_Expansion_name", "Courier (Expansion)"},
|
||||||
@@ -38,8 +41,10 @@ public class EnglishMissionNames {
|
|||||||
{"Mission_Courier_Lockdown_name", "Courier (Lockdown)"},
|
{"Mission_Courier_Lockdown_name", "Courier (Lockdown)"},
|
||||||
{"Mission_Courier_name", "Courier"},
|
{"Mission_Courier_name", "Courier"},
|
||||||
{"Mission_Courier_RankEmp_name", "Courier (Imperial Navy)"},
|
{"Mission_Courier_RankEmp_name", "Courier (Imperial Navy)"},
|
||||||
|
{"Mission_Courier_War_name", "Courier (War)" },
|
||||||
{"Mission_Delivery_Agriculture_name", "Delivery (Agriculture)"},
|
{"Mission_Delivery_Agriculture_name", "Delivery (Agriculture)"},
|
||||||
{"Mission_Delivery_Boom_name", "Delivery (Boom)"},
|
{"Mission_Delivery_Boom_name", "Delivery (Boom)"},
|
||||||
|
{"Mission_Delivery_CivilUnrest_name", "Delivery (Civil Unrest)"},
|
||||||
{"Mission_Delivery_Democracy_name", "Delivery (Democracy)"},
|
{"Mission_Delivery_Democracy_name", "Delivery (Democracy)"},
|
||||||
{"Mission_Delivery_Investment_name", "Delivery (Investment)"},
|
{"Mission_Delivery_Investment_name", "Delivery (Investment)"},
|
||||||
{"Mission_Delivery_name", "Delivery"},
|
{"Mission_Delivery_name", "Delivery"},
|
||||||
@@ -47,6 +52,10 @@ public class EnglishMissionNames {
|
|||||||
{"Mission_Delivery_Retreat_name", "Delivery (Retreat)"},
|
{"Mission_Delivery_Retreat_name", "Delivery (Retreat)"},
|
||||||
{"Mission_DeliveryWing_name", "Delivery (Wing)"},
|
{"Mission_DeliveryWing_name", "Delivery (Wing)"},
|
||||||
{"Mission_DeliveryWing_War_name", "Delivery (Wing) (War)"},
|
{"Mission_DeliveryWing_War_name", "Delivery (Wing) (War)"},
|
||||||
|
{"Mission_Disable_BLOPS_Expansion_name", "Disable Surface Installation (Expansion) (Black Ops)" },
|
||||||
|
{"MISSION_Disable_BLOPS_name", "Disable Surface Installation (Black Ops)" },
|
||||||
|
{"MISSION_Disable_name", "Disable Surface Installation" },
|
||||||
|
{"MISSION_Hack_name", "Hack Surface Installation" },
|
||||||
{"Mission_Hack_BLOPS_Boom_name", "Hack Surface Installation (Boom)"},
|
{"Mission_Hack_BLOPS_Boom_name", "Hack Surface Installation (Boom)"},
|
||||||
{"Mission_Hack_BLOPS_Elections_name", "Hack Surface Installation (Elections)"},
|
{"Mission_Hack_BLOPS_Elections_name", "Hack Surface Installation (Elections)"},
|
||||||
{"Mission_Hack_BLOPS_Expansion_name", "Hack Surface Installation (Expansion)"},
|
{"Mission_Hack_BLOPS_Expansion_name", "Hack Surface Installation (Expansion)"},
|
||||||
@@ -59,29 +68,46 @@ public class EnglishMissionNames {
|
|||||||
{"Mission_Massacre_RankEmp_name", "Massacre (Imperial Navy)"},
|
{"Mission_Massacre_RankEmp_name", "Massacre (Imperial Navy)"},
|
||||||
{"Mission_MassacreWing_Legal_Bust_name", "Massacre (Wing) (Bust)"},
|
{"Mission_MassacreWing_Legal_Bust_name", "Massacre (Wing) (Bust)"},
|
||||||
{"Mission_MassacreWing_name", "Massacre (Wing)"},
|
{"Mission_MassacreWing_name", "Massacre (Wing)"},
|
||||||
|
{"Mission_Mining_name", "Mining" },
|
||||||
{"Mission_OnFoot_Assassination_MB_name", "On Foot Assassination"},
|
{"Mission_OnFoot_Assassination_MB_name", "On Foot Assassination"},
|
||||||
|
{"Mission_OnFoot_Assassination_Hard_MB_name", "On Foot Assassination (Flight-Risk)" },
|
||||||
|
{"Mission_OnFoot_Assassination_Covert_MB_name", "On Foot Assassination (Covert)" },
|
||||||
{"Mission_OnFoot_AssassinationIllegal_MB_name", "On Foot Assassination (Illegal)"},
|
{"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_Contact_MB_name", "On Foot Collect"},
|
||||||
{"Mission_OnFoot_Collect_MB_name", "On Foot Collection"},
|
{"Mission_OnFoot_Collect_MB_name", "On Foot Collection"},
|
||||||
|
{"Mission_OnFoot_Defence_MacGuffin_MB_StandardCanister_name", "On Foot Cargo Defence" },
|
||||||
{"Mission_OnFoot_Delivery_Contact_MB_name", "On Foot Delivery (Contact)"},
|
{"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_Covert_MB_name", "On Foot Hack (Covert Upload)"},
|
||||||
{"Mission_OnFoot_Hack_Upload_MB_name", "On Foot Hack (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_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_MB_name", "On Foot Onslaught"},
|
||||||
{"Mission_OnFoot_Onslaught_Offline_MB_name", "On Foot Onslaught (Offline)"},
|
{"Mission_OnFoot_Onslaught_Offline_MB_name", "On Foot Onslaught (Offline)"},
|
||||||
{"Mission_OnFoot_ProductionHeist_Covert_MB_name", "On Foot Production Heist (Covert)"},
|
{"Mission_OnFoot_ProductionHeist_Covert_MB_name", "On Foot Production Heist (Covert)"},
|
||||||
{"Mission_OnFoot_ProductionHeist_MB_name", "On Foot Production Heist"},
|
{"Mission_OnFoot_ProductionHeist_MB_name", "On Foot Production Heist"},
|
||||||
{"Mission_OnFoot_Reboot_MB_name", "On Foot Reboot"},
|
{"Mission_OnFoot_Reboot_MB_name", "On Foot Reboot"},
|
||||||
{"Mission_OnFoot_RebootRestore_MB_name", "On Foot Reboot/Restore"},
|
{"Mission_OnFoot_RebootRestore_MB_name", "On Foot Reboot/Restore"},
|
||||||
{"Mission_OnFoot_Sabotage_Production_Covert_MB_name", "On Foot Sabotage Production (Covert)"},
|
{"Mission_OnFoot_Sabotage_Power_MB_name", "On Foot Power Sabotage"},
|
||||||
|
{"Mission_OnFoot_Sabotage_Power_Covert_MB_name", "On Foot Power Sabotage (Covert)"},
|
||||||
|
{"Mission_OnFoot_Sabotage_Production_MB_name", "On Foot Production Sabotage"},
|
||||||
|
{"Mission_OnFoot_Sabotage_Production_Covert_MB_name", "On Foot Production Sabotage (Covert)"},
|
||||||
{"Mission_OnFoot_Salvage_MB_name", "On Foot Salvage"},
|
{"Mission_OnFoot_Salvage_MB_name", "On Foot Salvage"},
|
||||||
{"Mission_OnFoot_SalvageIllegal_MB_name", "On Foot Salvage (Illegal)"},
|
{"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", "Passenger (VIP)"},
|
||||||
{"Mission_PassengerVIP_Criminal_BOOM_name", "Passenger Criminal (VIP) (Boom)"},
|
{"Mission_PassengerVIP_Criminal_BOOM_name", "Passenger Criminal (VIP) (Boom)"},
|
||||||
{"Mission_PassengerVIP_name", "Passenger (VIP)"},
|
{"Mission_PassengerVIP_name", "Passenger (VIP)"},
|
||||||
{"Mission_PassengerVIP_Scientist_FAMINE_name", "Passenger Scientist (VIP) (Famine)"},
|
{"Mission_PassengerVIP_Scientist_FAMINE_name", "Passenger Scientist (VIP) (Famine)"},
|
||||||
{"Mission_PassengerVIP_Tourist_BOOM_name", "Passenger Tourist (VIP) (Boom)"},
|
{"Mission_PassengerVIP_Tourist_BOOM_name", "Passenger Tourist (VIP) (Boom)"},
|
||||||
|
{"Mission_Rescue_Elections_name", "Liberate Hostages (Election)" },
|
||||||
|
{"Mission_Rescue_name", "Liberate Hostages" },
|
||||||
|
{"Mission_Rescue_Planet_Expansion_name", "Planet Rescue (Expansion)" },
|
||||||
|
{"Mission_Rescue_Planet_Retreat_name", "Planet Rescue (Retreat)" },
|
||||||
{"Mission_Rescue_Planet_name", "Planet Rescue"},
|
{"Mission_Rescue_Planet_name", "Planet Rescue"},
|
||||||
{"MISSION_Salvage_CivilUnrest_name", "Salvage (Civil Unrest)"},
|
{"MISSION_Salvage_CivilUnrest_name", "Salvage (Civil Unrest)"},
|
||||||
{"MISSION_Salvage_Expansion_name", "Salvage (Expansion)"},
|
{"MISSION_Salvage_Expansion_name", "Salvage (Expansion)"},
|
||||||
@@ -93,6 +119,22 @@ public class EnglishMissionNames {
|
|||||||
{"MISSION_Scan_name", "Scan"},
|
{"MISSION_Scan_name", "Scan"},
|
||||||
{"Mission_Sightseeing_Criminal_FAMINE_name", "Sightseeing (Criminal) (Famine)"},
|
{"Mission_Sightseeing_Criminal_FAMINE_name", "Sightseeing (Criminal) (Famine)"},
|
||||||
{"Mission_Sightseeing_name", "Sightseeing"},
|
{"Mission_Sightseeing_name", "Sightseeing"},
|
||||||
|
{"Mission_Smuggle_Anarchy_name", "Smuggling (Anarchy)" },
|
||||||
|
{"Mission_TW_Massacre_Basilisk_Plural_name", "Kill Basilisks" },
|
||||||
|
{"Mission_TW_Massacre_Basilisk_Singular_name", "Kill Basilisk" },
|
||||||
|
{"Mission_TW_Massacre_Cyclops_Plural_name", "Kill Cyclops" },
|
||||||
|
{"Mission_TW_Massacre_Cyclops_Singular_name", "Kill Cyclop" },
|
||||||
|
{"Mission_TW_Massacre_Hydra_Plural_name", "Kill Hydras" },
|
||||||
|
{"Mission_TW_Massacre_Hydra_Singular_name", "Kill Hydra" },
|
||||||
|
{"Mission_TW_Massacre_Medusa_Plural_name", "Kill Medusas" },
|
||||||
|
{"Mission_TW_Massacre_Medusa_Singular_name", "Kill Medusa" },
|
||||||
|
{"Mission_TW_Massacre_Scout_Plural_name", "Kill Scouts" },
|
||||||
|
{"Mission_TW_OnFoot_Reboot_Occupied_MB_name", "Reboot Settlement (Thargoid)" },
|
||||||
|
{"Mission_TW_OnFoot_Reboot_NR_name", "Reboot Settlement (Thargoid)" },
|
||||||
|
{"Mission_TW_OnFoot_Reboot_MB_name", "Reboot Settlement (Thargoid)" },
|
||||||
|
{"Mission_TW_PassengerEvacuation_Burning_name", "Passenger Evacuation (Significant Damage)" },
|
||||||
|
{"Mission_TW_PassengerEvacuation_UnderAttack_name", "Passenger Evacuation (Thargoid Invasion)" },
|
||||||
|
{"Mission_TW_Rescue_UnderAttack_name", "Rescue (Thargoid Attack)" },
|
||||||
};
|
};
|
||||||
|
|
||||||
public static string? Translate(string name) {
|
public static string? Translate(string name) {
|
||||||
|
|||||||
48
EDPlayerJournal/Entries/ApproachSettlementEntry.cs
Normal file
48
EDPlayerJournal/Entries/ApproachSettlementEntry.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class ApproachSettlementEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Settlement name
|
||||||
|
/// </summary>
|
||||||
|
public string? Name { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Market ID of the settlement
|
||||||
|
/// </summary>
|
||||||
|
public long? MarketID { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System ID
|
||||||
|
/// </summary>
|
||||||
|
public long? SystemAddress { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body ID
|
||||||
|
/// </summary>
|
||||||
|
public long? BodyID { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the planet
|
||||||
|
/// </summary>
|
||||||
|
public string? BodyName { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Planet latitude
|
||||||
|
/// </summary>
|
||||||
|
public double Latitude { get; set; } = 0.0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Planet longitude
|
||||||
|
/// </summary>
|
||||||
|
public double Longitude { get; set; } = 0.0;
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
Name = JSON.Value<string?>("Name");
|
||||||
|
MarketID = JSON.Value<long?>("MarketID");
|
||||||
|
SystemAddress = JSON.Value<long?>("SystemID");
|
||||||
|
BodyID = JSON.Value<long?>("BodyID");
|
||||||
|
BodyName = JSON.Value<string?>("BodyName");
|
||||||
|
Longitude = JSON.Value<double?>("Longitude") ?? 0.0;
|
||||||
|
Latitude = JSON.Value<double?>("Latitude") ?? 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
EDPlayerJournal/Entries/CapShipBondEntry.cs
Normal file
24
EDPlayerJournal/Entries/CapShipBondEntry.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class CapShipBondEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Reward gained
|
||||||
|
/// </summary>
|
||||||
|
public ulong Reward { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Victim faction, i.e. to whom the cap ship belongs
|
||||||
|
/// </summary>
|
||||||
|
public string? VictimFaction { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Awarding faction.
|
||||||
|
/// </summary>
|
||||||
|
public string? AwardingFaction { get; set; }
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
Reward = JSON.Value<ulong?>("Reward") ?? 0;
|
||||||
|
VictimFaction = JSON.Value<string?>("VictimFaction");
|
||||||
|
AwardingFaction = JSON.Value<string?>("AwardingFaction");
|
||||||
|
}
|
||||||
|
}
|
||||||
44
EDPlayerJournal/Entries/CarrierJump.cs
Normal file
44
EDPlayerJournal/Entries/CarrierJump.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class CarrierJump : Entry {
|
||||||
|
public bool Docked { get; set; } = false;
|
||||||
|
|
||||||
|
public string? StationName { get; set; } = null;
|
||||||
|
|
||||||
|
public string? StationType { get; set; } = null;
|
||||||
|
|
||||||
|
public string? StarSystem { get; set; } = null;
|
||||||
|
|
||||||
|
public ulong SystemAddress { get; set; } = 0;
|
||||||
|
|
||||||
|
public string? SystemFaction { get; set; } = null;
|
||||||
|
|
||||||
|
public List<Faction> SystemFactions { get; set; } = new List<Faction>();
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
Docked = JSON.Value<bool?>("Docked") ?? false;
|
||||||
|
|
||||||
|
StarSystem = JSON.Value<string>("StarSystem");
|
||||||
|
SystemAddress = JSON.Value<ulong?>("SystemAddress") ?? 0;
|
||||||
|
|
||||||
|
StationName = JSON.Value<string?>("StationName");
|
||||||
|
StationType = JSON.Value<string?>("StationType");
|
||||||
|
|
||||||
|
var faction = JSON.Value<JObject>("SystemFaction");
|
||||||
|
if (faction != null) {
|
||||||
|
SystemFaction = faction.Value<string>("Name");
|
||||||
|
}
|
||||||
|
|
||||||
|
var factions = JSON.Value<JArray>("Factions");
|
||||||
|
if (factions != null) {
|
||||||
|
foreach (JObject system_faction in factions) {
|
||||||
|
Faction? f = Faction.FromJSON(system_faction);
|
||||||
|
if (f != null) {
|
||||||
|
SystemFactions.Add(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,4 +8,13 @@ public class CommanderEntry : Entry {
|
|||||||
Name = JSON.Value<string>("Name") ?? "";
|
Name = JSON.Value<string>("Name") ?? "";
|
||||||
FID = JSON.Value<string>("FID") ?? "";
|
FID = JSON.Value<string>("FID") ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string FullName {
|
||||||
|
get {
|
||||||
|
if (string.IsNullOrEmpty(Name)) {
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
return "CMDR " + Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,4 +19,12 @@ public class CommitCrimeEntry : Entry {
|
|||||||
public bool IsMurder {
|
public bool IsMurder {
|
||||||
get { return CrimeType?.CompareTo(CrimeTypes.Murder) == 0 || CrimeType?.CompareTo(CrimeTypes.OnFootMurder) == 0; }
|
get { return CrimeType?.CompareTo(CrimeTypes.Murder) == 0 || CrimeType?.CompareTo(CrimeTypes.OnFootMurder) == 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsCrime(string crimetype) {
|
||||||
|
if (CrimeType == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Compare(CrimeType, crimetype) == 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
66
EDPlayerJournal/Entries/DisembarkEntry.cs
Normal file
66
EDPlayerJournal/Entries/DisembarkEntry.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class DisembarkEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Disembarked into an SRV?
|
||||||
|
/// </summary>
|
||||||
|
public bool SRV { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Taxi?
|
||||||
|
/// </summary>
|
||||||
|
public bool Taxi { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multicrew or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool Multicrew { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Player's ship ID
|
||||||
|
/// </summary>
|
||||||
|
public ulong? ID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Star system
|
||||||
|
/// </summary>
|
||||||
|
public string? StarSystem { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System address
|
||||||
|
/// </summary>
|
||||||
|
public ulong? SystemAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body, name e.g. HIP 6182 B 2 a
|
||||||
|
/// </summary>
|
||||||
|
public string? Body { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body ID
|
||||||
|
/// </summary>
|
||||||
|
public ulong? BodyID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disembarked on a station?
|
||||||
|
/// </summary>
|
||||||
|
public bool OnStation { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disembarked on a planet?
|
||||||
|
/// </summary>
|
||||||
|
public bool OnPlanet { get; set; } = false;
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
SRV = JSON.Value<bool?>("SRV") ?? false;
|
||||||
|
Taxi = JSON.Value<bool?>("Taxi") ?? false;
|
||||||
|
Multicrew = JSON.Value<bool?>("Multicrew") ?? false;
|
||||||
|
ID = JSON.Value<ulong?>("ID");
|
||||||
|
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") ?? false;
|
||||||
|
OnPlanet = JSON.Value<bool?>("OnPlanet") ?? false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,15 +2,36 @@
|
|||||||
|
|
||||||
namespace EDPlayerJournal.Entries;
|
namespace EDPlayerJournal.Entries;
|
||||||
public class DockedEntry : Entry {
|
public class DockedEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the station
|
||||||
|
/// </summary>
|
||||||
public string? StationName { get; set; }
|
public string? StationName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Star system of the station
|
||||||
|
/// </summary>
|
||||||
public string? StarSystem { get; set; }
|
public string? StarSystem { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System address
|
||||||
|
/// </summary>
|
||||||
public ulong? SystemAddress { get; set; }
|
public ulong? SystemAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Faction owning the station.
|
||||||
|
/// </summary>
|
||||||
public string? StationFaction { get; set; }
|
public string? StationFaction { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// State of the station, new in Update 14
|
||||||
|
/// </summary>
|
||||||
|
public string? StationState { get; set; }
|
||||||
|
|
||||||
protected override void Initialise() {
|
protected override void Initialise() {
|
||||||
StationName = JSON.Value<string>("StationName");
|
StationName = JSON.Value<string>("StationName");
|
||||||
StarSystem = JSON.Value<string>("StarSystem");
|
StarSystem = JSON.Value<string>("StarSystem");
|
||||||
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||||
|
StationState = JSON.Value<string>("StationState");
|
||||||
JObject? faction = JSON.Value<JObject>("StationFaction");
|
JObject? faction = JSON.Value<JObject>("StationFaction");
|
||||||
if (faction != null) {
|
if (faction != null) {
|
||||||
StationFaction = faction.Value<string>("Name") ?? "";
|
StationFaction = faction.Value<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");
|
||||||
|
}
|
||||||
|
}
|
||||||
66
EDPlayerJournal/Entries/EmbarkEntry.cs
Normal file
66
EDPlayerJournal/Entries/EmbarkEntry.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class EmbarkEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Disembarked into an SRV?
|
||||||
|
/// </summary>
|
||||||
|
public bool SRV { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Taxi?
|
||||||
|
/// </summary>
|
||||||
|
public bool Taxi { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multicrew or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool Multicrew { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Player's ship ID
|
||||||
|
/// </summary>
|
||||||
|
public ulong? ID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Star system
|
||||||
|
/// </summary>
|
||||||
|
public string? StarSystem { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System address
|
||||||
|
/// </summary>
|
||||||
|
public ulong? SystemAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body, name e.g. HIP 6182 B 2 a
|
||||||
|
/// </summary>
|
||||||
|
public string? Body { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body ID
|
||||||
|
/// </summary>
|
||||||
|
public ulong? BodyID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disembarked on a station?
|
||||||
|
/// </summary>
|
||||||
|
public bool OnStation { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disembarked on a planet?
|
||||||
|
/// </summary>
|
||||||
|
public bool OnPlanet { get; set; } = false;
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
SRV = JSON.Value<bool?>("SRV") ?? false;
|
||||||
|
Taxi = JSON.Value<bool?>("Taxi") ?? false;
|
||||||
|
Multicrew = JSON.Value<bool?>("Multicrew") ?? false;
|
||||||
|
ID = JSON.Value<ulong?>("ID");
|
||||||
|
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") ?? false;
|
||||||
|
OnPlanet = JSON.Value<bool?>("OnPlanet") ?? false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,13 +12,19 @@ namespace EDPlayerJournal.Entries;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Entry {
|
public class Entry {
|
||||||
private static readonly Dictionary<string, Type> classes = new Dictionary<string, Type> {
|
private static readonly Dictionary<string, Type> classes = new Dictionary<string, Type> {
|
||||||
|
{ Events.ApproachSettlement, typeof(ApproachSettlementEntry) },
|
||||||
{ Events.Bounty, typeof(BountyEntry) },
|
{ Events.Bounty, typeof(BountyEntry) },
|
||||||
|
{ Events.CapShipBond, typeof(CapShipBondEntry) },
|
||||||
|
{ Events.CarrierJump, typeof(CarrierJump) },
|
||||||
{ Events.Commander, typeof(CommanderEntry) },
|
{ Events.Commander, typeof(CommanderEntry) },
|
||||||
{ Events.CommitCrime, typeof(CommitCrimeEntry) },
|
{ Events.CommitCrime, typeof(CommitCrimeEntry) },
|
||||||
{ Events.Died, typeof(DiedEntry) },
|
{ Events.Died, typeof(DiedEntry) },
|
||||||
|
{ Events.Disembark, typeof(DisembarkEntry) },
|
||||||
{ Events.Docked, typeof(DockedEntry) },
|
{ Events.Docked, typeof(DockedEntry) },
|
||||||
{ Events.FileHeader, typeof(FileHeaderEntry) },
|
{ Events.DropshipDeploy, typeof(DropshipDeployEntry) },
|
||||||
|
{ Events.Embark, typeof(EmbarkEntry) },
|
||||||
{ Events.FactionKillBond, typeof(FactionKillBondEntry) },
|
{ Events.FactionKillBond, typeof(FactionKillBondEntry) },
|
||||||
|
{ Events.FileHeader, typeof(FileHeaderEntry) },
|
||||||
{ Events.FSDJump, typeof(FSDJumpEntry) },
|
{ Events.FSDJump, typeof(FSDJumpEntry) },
|
||||||
{ Events.HullDamage, typeof(HullDamageEntry) },
|
{ Events.HullDamage, typeof(HullDamageEntry) },
|
||||||
{ Events.LoadGame, typeof(LoadGameEntry) },
|
{ Events.LoadGame, typeof(LoadGameEntry) },
|
||||||
@@ -32,13 +38,24 @@ public class Entry {
|
|||||||
{ Events.MissionRedirected, typeof(MissionRedirectedEntry) },
|
{ Events.MissionRedirected, typeof(MissionRedirectedEntry) },
|
||||||
{ Events.Missions, typeof(MissionsEntry) },
|
{ Events.Missions, typeof(MissionsEntry) },
|
||||||
{ Events.MultiSellExplorationData, typeof(MultiSellExplorationDataEntry) },
|
{ Events.MultiSellExplorationData, typeof(MultiSellExplorationDataEntry) },
|
||||||
|
{ Events.Music, typeof(MusicEntry) },
|
||||||
|
{ Events.Powerplay, typeof(PowerplayEntry) },
|
||||||
|
{ Events.PowerplayCollect, typeof(PowerplayCollectEntry) },
|
||||||
|
{ Events.PowerplayDeliver, typeof(PowerplayDeliverEntry) },
|
||||||
|
{ Events.PowerplayMerits, typeof(PowerplayMeritsEntry) },
|
||||||
|
{ Events.PowerplayRank, typeof(PowerplayRankEntry) },
|
||||||
|
{ Events.ReceiveText, typeof(ReceiveTextEntry) },
|
||||||
{ Events.RedeemVoucher, typeof(RedeemVoucherEntry) },
|
{ Events.RedeemVoucher, typeof(RedeemVoucherEntry) },
|
||||||
{ Events.SearchAndRescue, typeof(SearchAndRescueEntry) },
|
{ Events.SearchAndRescue, typeof(SearchAndRescueEntry) },
|
||||||
|
{ Events.SelfDestruct, typeof(SelfDestructEntry) },
|
||||||
{ Events.SellExplorationData, typeof(SellExplorationDataEntry) },
|
{ Events.SellExplorationData, typeof(SellExplorationDataEntry) },
|
||||||
{ Events.SellMicroResources, typeof(SellMicroResourcesEntry) },
|
{ Events.SellMicroResources, typeof(SellMicroResourcesEntry) },
|
||||||
{ Events.SellOrganicData, typeof(SellOrganicDataEntry) },
|
{ Events.SellOrganicData, typeof(SellOrganicDataEntry) },
|
||||||
{ Events.ShieldState, typeof(ShieldStateEntry) },
|
{ Events.ShieldState, typeof(ShieldStateEntry) },
|
||||||
{ Events.ShipTargeted, typeof(ShipTargetedEntry) },
|
{ Events.ShipTargeted, typeof(ShipTargetedEntry) },
|
||||||
|
{ Events.SupercruiseDestinationDrop, typeof(SupercruiseDestinationDropEntry) },
|
||||||
|
{ Events.SupercruiseEntry, typeof(SupercruiseEntryEntry) },
|
||||||
|
{ Events.SupercruiseExit, typeof(SupercruiseExitEntry) },
|
||||||
{ Events.UnderAttack, typeof(UnderAttackEntry) },
|
{ Events.UnderAttack, typeof(UnderAttackEntry) },
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,7 +72,15 @@ public class Entry {
|
|||||||
public static Entry? Parse(string journalline) {
|
public static Entry? Parse(string journalline) {
|
||||||
using (JsonReader reader = new JsonTextReader(new StringReader(journalline))) {
|
using (JsonReader reader = new JsonTextReader(new StringReader(journalline))) {
|
||||||
reader.DateParseHandling = DateParseHandling.None;
|
reader.DateParseHandling = DateParseHandling.None;
|
||||||
var json = JObject.Load(reader);
|
JObject? json = null;
|
||||||
|
try {
|
||||||
|
json = JObject.Load(reader);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InvalidJournalEntryException(
|
||||||
|
"invalid JSON journal entry: " + journalline,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
if (json == null) {
|
if (json == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -98,7 +123,7 @@ public class Entry {
|
|||||||
this.datetime = json.GetValue("timestamp")?.ToString();
|
this.datetime = json.GetValue("timestamp")?.ToString();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(this.datetime)) {
|
if (!string.IsNullOrEmpty(this.datetime)) {
|
||||||
this.timestamp = DateTime.Parse(this.datetime);
|
this.timestamp = DateTime.Parse(this.datetime, null, System.Globalization.DateTimeStyles.RoundtripKind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
namespace EDPlayerJournal.Entries;
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
public class Events {
|
public class Events {
|
||||||
|
public static readonly string ApproachSettlement = "ApproachSettlement";
|
||||||
public static readonly string Bounty = "Bounty";
|
public static readonly string Bounty = "Bounty";
|
||||||
|
public static readonly string CapShipBond = "CapShipBond";
|
||||||
|
public static readonly string CarrierJump = "CarrierJump";
|
||||||
public static readonly string Commander = "Commander";
|
public static readonly string Commander = "Commander";
|
||||||
public static readonly string CommitCrime = "CommitCrime";
|
public static readonly string CommitCrime = "CommitCrime";
|
||||||
public static readonly string Died = "Died";
|
public static readonly string Died = "Died";
|
||||||
|
public static readonly string Disembark = "Disembark";
|
||||||
public static readonly string Docked = "Docked";
|
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 FactionKillBond = "FactionKillBond";
|
||||||
public static readonly string FighterDestroyed = "FighterDestroyed";
|
public static readonly string FighterDestroyed = "FighterDestroyed";
|
||||||
public static readonly string FileHeader = "Fileheader";
|
public static readonly string FileHeader = "Fileheader";
|
||||||
@@ -22,12 +28,24 @@ public class Events {
|
|||||||
public static readonly string MissionRedirected = "MissionRedirected";
|
public static readonly string MissionRedirected = "MissionRedirected";
|
||||||
public static readonly string Missions = "Missions";
|
public static readonly string Missions = "Missions";
|
||||||
public static readonly string MultiSellExplorationData = "MultiSellExplorationData";
|
public static readonly string MultiSellExplorationData = "MultiSellExplorationData";
|
||||||
|
public static readonly string Music = "Music";
|
||||||
|
public static readonly string Powerplay = "Powerplay";
|
||||||
|
public static readonly string PowerplayCollect = "PowerplayCollect";
|
||||||
|
public static readonly string PowerplayDeliver = "PowerplayDeliver";
|
||||||
|
public static readonly string PowerplayMerits = "PowerplayMerits";
|
||||||
|
public static readonly string PowerplayRank = "PowerplayRank";
|
||||||
|
public static readonly string ReceiveText = "ReceiveText";
|
||||||
public static readonly string RedeemVoucher = "RedeemVoucher";
|
public static readonly string RedeemVoucher = "RedeemVoucher";
|
||||||
public static readonly string SearchAndRescue = "SearchAndRescue";
|
public static readonly string SearchAndRescue = "SearchAndRescue";
|
||||||
|
public static readonly string SelfDestruct = "SelfDestruct";
|
||||||
public static readonly string SellExplorationData = "SellExplorationData";
|
public static readonly string SellExplorationData = "SellExplorationData";
|
||||||
public static readonly string SellMicroResources = "SellMicroResources";
|
public static readonly string SellMicroResources = "SellMicroResources";
|
||||||
public static readonly string SellOrganicData = "SellOrganicData";
|
public static readonly string SellOrganicData = "SellOrganicData";
|
||||||
public static readonly string ShieldState = "ShieldState";
|
public static readonly string ShieldState = "ShieldState";
|
||||||
public static readonly string ShipTargeted = "ShipTargeted";
|
public static readonly string ShipTargeted = "ShipTargeted";
|
||||||
|
public static readonly string Shutdown = "Shutdown";
|
||||||
|
public static readonly string SupercruiseDestinationDrop = "SupercruiseDestinationDrop";
|
||||||
|
public static readonly string SupercruiseEntry = "SupercruiseEntry";
|
||||||
|
public static readonly string SupercruiseExit = "SupercruiseExit";
|
||||||
public static readonly string UnderAttack = "UnderAttack";
|
public static readonly string UnderAttack = "UnderAttack";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,22 @@ public class FileHeaderEntry : Entry {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Build { get; set; }
|
public string? Build { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the version is legacy (3.X)
|
||||||
|
/// <summary>
|
||||||
|
public bool IsLegacy {
|
||||||
|
get {
|
||||||
|
return GameVersion.StartsWith("3.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the version is live (4.x)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsLive {
|
||||||
|
get { return !IsLegacy; }
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Initialise() {
|
protected override void Initialise() {
|
||||||
Part = JSON.Value<ulong?>("part") ?? 1;
|
Part = JSON.Value<ulong?>("part") ?? 1;
|
||||||
Language = JSON.Value<string?>("language") ?? string.Empty;
|
Language = JSON.Value<string?>("language") ?? string.Empty;
|
||||||
|
|||||||
@@ -1,18 +1,47 @@
|
|||||||
using System;
|
using Newtonsoft.Json.Linq;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace EDPlayerJournal.Entries;
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
public class LocationEntry : Entry {
|
public class LocationEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Current star system.
|
||||||
|
/// </summary>
|
||||||
public string? StarSystem { get; set; }
|
public string? StarSystem { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Faction in control of the current star system. Empty for unpopulated
|
||||||
|
/// systems.
|
||||||
|
/// </summary>
|
||||||
public string? SystemFaction { get; set; }
|
public string? SystemFaction { get; set; }
|
||||||
public string? StationName { get; set; }
|
|
||||||
|
/// <summary>
|
||||||
|
/// 64bit system address.
|
||||||
|
/// </summary>
|
||||||
public ulong SystemAddress { get; set; }
|
public ulong SystemAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Station name if docked at a station.
|
||||||
|
/// </summary>
|
||||||
|
public string? StationName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Faction in control of the current station, if docked.
|
||||||
|
/// </summary>
|
||||||
|
public string? StationFaction { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body within the system, might be null.
|
||||||
|
/// </summary>
|
||||||
public string? Body { get; set; }
|
public string? Body { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the player is docked somewhere.
|
||||||
|
/// </summary>
|
||||||
public bool Docked { get; set; }
|
public bool Docked { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Position of the star system.
|
||||||
|
/// </summary>
|
||||||
public long[]? StarPos { get; set; }
|
public long[]? StarPos { get; set; }
|
||||||
|
|
||||||
public List<Faction> SystemFactions { get; set; } = new List<Faction>();
|
public List<Faction> SystemFactions { get; set; } = new List<Faction>();
|
||||||
@@ -30,7 +59,12 @@ public class LocationEntry : Entry {
|
|||||||
|
|
||||||
JObject? systemfaction = JSON.Value<JObject>("SystemFaction");
|
JObject? systemfaction = JSON.Value<JObject>("SystemFaction");
|
||||||
if (systemfaction != null) {
|
if (systemfaction != null) {
|
||||||
SystemFaction = systemfaction.Value<string>("Name") ?? "";
|
SystemFaction = systemfaction.Value<string>("Name");
|
||||||
|
}
|
||||||
|
|
||||||
|
JObject? stationfaction = JSON.Value<JObject>("StationFaction");
|
||||||
|
if (stationfaction != null) {
|
||||||
|
StationFaction = stationfaction.Value<string>("Name");
|
||||||
}
|
}
|
||||||
|
|
||||||
JArray? factions = JSON.Value<JArray>("Factions");
|
JArray? factions = JSON.Value<JArray>("Factions");
|
||||||
|
|||||||
@@ -1,8 +1,23 @@
|
|||||||
namespace EDPlayerJournal.Entries;
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
public class MultiSellExplorationDataEntry : Entry {
|
public class MultiSellExplorationDataEntry : Entry {
|
||||||
protected override void Initialise() {
|
protected override void Initialise() {
|
||||||
TotalEarnings = (JSON.Value<int?>("TotalEarnings") ?? 0);
|
TotalEarnings = JSON.Value<long?>("TotalEarnings") ?? 0;
|
||||||
|
BaseValue = JSON.Value<long?>("BaseValue") ?? 0;
|
||||||
|
Bonus = JSON.Value<long?>("Bonus") ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int TotalEarnings { get; set; } = 0;
|
public long Total {
|
||||||
|
get { return BaseValue + Bonus; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public long BaseValue { get; set; } = 0;
|
||||||
|
|
||||||
|
public long Bonus { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total Earnings are the actual earnings without bonus. So this
|
||||||
|
/// value is BaseValue minus any percent a crew pilot takes.
|
||||||
|
/// </summary>
|
||||||
|
public long TotalEarnings { get; set; } = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
9
EDPlayerJournal/Entries/MusicEntry.cs
Normal file
9
EDPlayerJournal/Entries/MusicEntry.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class MusicEntry : Entry {
|
||||||
|
public string? MusicTrack { get; set; } = null;
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
MusicTrack = JSON.Value<string?>("MusicTrack");
|
||||||
|
}
|
||||||
|
}
|
||||||
7
EDPlayerJournal/Entries/PowerplayCollectEntry.cs
Normal file
7
EDPlayerJournal/Entries/PowerplayCollectEntry.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class PowerplayCollectEntry : Entry {
|
||||||
|
protected override void Initialise() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
7
EDPlayerJournal/Entries/PowerplayDeliverEntry.cs
Normal file
7
EDPlayerJournal/Entries/PowerplayDeliverEntry.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class PowerplayDeliverEntry : Entry {
|
||||||
|
protected override void Initialise() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
32
EDPlayerJournal/Entries/PowerplayEntry.cs
Normal file
32
EDPlayerJournal/Entries/PowerplayEntry.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace EDPlayerJournal.Entries {
|
||||||
|
public class PowerplayEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the power
|
||||||
|
/// </summary>
|
||||||
|
public string Power { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Player rank
|
||||||
|
/// </summary>
|
||||||
|
public int Rank { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current merits of the player
|
||||||
|
/// </summary>
|
||||||
|
public long Merits { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time pledged (in seconds?)
|
||||||
|
/// </summary>
|
||||||
|
public long TimePledged { get; set; } = 0;
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
Power = JSON.Value<string>("Power") ?? string.Empty;
|
||||||
|
Rank = JSON.Value<int?>("Rank") ?? 0;
|
||||||
|
Merits = JSON.Value<long?>("Merits") ?? 0;
|
||||||
|
TimePledged = JSON.Value<long?>("TimePledged") ?? 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
EDPlayerJournal/Entries/PowerplayMeritsEntry.cs
Normal file
15
EDPlayerJournal/Entries/PowerplayMeritsEntry.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class PowerplayMeritsEntry : Entry {
|
||||||
|
protected override void Initialise() {
|
||||||
|
Power = JSON.Value<string?>("Power") ?? string.Empty;
|
||||||
|
MeritsGained = JSON.Value<long?>("MeritsGained") ?? 0;
|
||||||
|
TotalMerits = JSON.Value<long?>("TotalMerits") ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Power { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public long MeritsGained { get; set; } = 0;
|
||||||
|
|
||||||
|
public long TotalMerits { get; set; } = 0;
|
||||||
|
}
|
||||||
7
EDPlayerJournal/Entries/PowerplayRankEntry.cs
Normal file
7
EDPlayerJournal/Entries/PowerplayRankEntry.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class PowerplayRankEntry : Entry {
|
||||||
|
protected override void Initialise() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
77
EDPlayerJournal/Entries/ReceiveTextEntry.cs
Normal file
77
EDPlayerJournal/Entries/ReceiveTextEntry.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class ReceiveTextEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// From whom this message is
|
||||||
|
/// </summary>
|
||||||
|
public string? From { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// The message, if it is just an NPC text, it will be a message ID
|
||||||
|
/// </summary>
|
||||||
|
public string? Message { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Message localised
|
||||||
|
/// </summary>
|
||||||
|
public string? MessageLocalised { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// On what channel this was received.
|
||||||
|
/// </summary>
|
||||||
|
public string? Channel { get; set; }
|
||||||
|
|
||||||
|
public bool HasNPCCategory {
|
||||||
|
get {
|
||||||
|
if (From == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (From.Contains(';') && From.StartsWith("$")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the NPC's category, if it has one.
|
||||||
|
/// </summary>
|
||||||
|
public string? NPCCategory {
|
||||||
|
get {
|
||||||
|
if (!HasNPCCategory || From == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] parts = From.Split(";", StringSplitOptions.TrimEntries);
|
||||||
|
if (parts.Length < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format("{0};", parts[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the NPC's category, if it has one.
|
||||||
|
/// </summary>
|
||||||
|
public string? NPCName {
|
||||||
|
get {
|
||||||
|
if (!HasNPCCategory || From == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] parts = From.Split(";", StringSplitOptions.TrimEntries);
|
||||||
|
if (parts.Length < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
From = JSON.Value<string>("From");
|
||||||
|
Message = JSON.Value<string>("Message");
|
||||||
|
MessageLocalised = JSON.Value<string>("Message_localised");
|
||||||
|
Channel = JSON.Value<string>("Channel");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||||||
namespace EDPlayerJournal.Entries;
|
namespace EDPlayerJournal.Entries;
|
||||||
public class RedeemVoucherEntry : Entry {
|
public class RedeemVoucherEntry : Entry {
|
||||||
protected override void Initialise() {
|
protected override void Initialise() {
|
||||||
Amount = (JSON.Value<int?>("Amount") ?? 0);
|
Amount = (JSON.Value<ulong?>("Amount") ?? 0);
|
||||||
Type = JSON.Value<string>("Type");
|
Type = JSON.Value<string>("Type");
|
||||||
|
|
||||||
/* according to API, there should be a Factions structure */
|
/* according to API, there should be a Factions structure */
|
||||||
@@ -12,7 +12,7 @@ public class RedeemVoucherEntry : Entry {
|
|||||||
if (factions != null) {
|
if (factions != null) {
|
||||||
foreach (JObject faction in factions.Children<JObject>()) {
|
foreach (JObject faction in factions.Children<JObject>()) {
|
||||||
string? faction_name = faction.Value<string>("Faction");
|
string? faction_name = faction.Value<string>("Faction");
|
||||||
long? faction_bounty = faction.Value<long?>("Amount");
|
ulong? faction_bounty = faction.Value<ulong?>("Amount");
|
||||||
if (faction_name == null || faction_name.Length <= 0 || faction_bounty == null) {
|
if (faction_name == null || faction_name.Length <= 0 || faction_bounty == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -35,8 +35,29 @@ public class RedeemVoucherEntry : Entry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Amount { get; set; } = 0;
|
public ulong GetBountyForFaction(string? a) {
|
||||||
|
if (a == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var relevant = FactionBounties.Where(x => EDPlayerJournal.Factions.CompareFactions(x.Key, a) == 0).ToList();
|
||||||
|
if (relevant == null || relevant.Count() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ulong)relevant.Sum(x => (decimal)x.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ulong Amount { get; set; } = 0;
|
||||||
public string? Type { get; set; } = "Bounty";
|
public string? Type { get; set; } = "Bounty";
|
||||||
public List<string> Factions { get; set; } = new List<string>();
|
|
||||||
public Dictionary<string, long> FactionBounties { get; set; } = new Dictionary<string, long>();
|
/// <summary>
|
||||||
|
/// List of factions
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Factions { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bounties awarded by faction
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, ulong> FactionBounties { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|||||||
5
EDPlayerJournal/Entries/SelfDestructEntry.cs
Normal file
5
EDPlayerJournal/Entries/SelfDestructEntry.cs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
namespace EDPlayerJournal.Entries {
|
||||||
|
public class SelfDestructEntry : Entry {
|
||||||
|
// Has no data
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,17 @@ namespace EDPlayerJournal.Entries;
|
|||||||
public class SellExplorationDataEntry : Entry {
|
public class SellExplorationDataEntry : Entry {
|
||||||
public long BaseValue { get; set; }
|
public long BaseValue { get; set; }
|
||||||
public long Bonus { get; set; }
|
public long Bonus { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total Earnings are the actual earnings without bonus. So this
|
||||||
|
/// value is BaseValue minus any percent a crew pilot takes.
|
||||||
|
/// </summary>
|
||||||
public long TotalEarnings { get; set; }
|
public long TotalEarnings { get; set; }
|
||||||
|
|
||||||
|
public long Total {
|
||||||
|
get { return BaseValue + Bonus; }
|
||||||
|
}
|
||||||
|
|
||||||
public List<string> Systems { get; set; } = new List<string>();
|
public List<string> Systems { get; set; } = new List<string>();
|
||||||
public List<string> Discovered { get; set; } = new List<string>();
|
public List<string> Discovered { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,17 @@ public class BioData {
|
|||||||
public string? SpeciesLocalised { get; set; }
|
public string? SpeciesLocalised { get; set; }
|
||||||
public long Value { get; set; } = 0;
|
public long Value { get; set; } = 0;
|
||||||
public long Bonus { 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 class SellOrganicDataEntry : Entry {
|
||||||
public long MarketID { get; set; }
|
public long MarketID { get; set; }
|
||||||
public List<BioData> BioData => new List<BioData>();
|
|
||||||
|
public List<BioData> BioData { get; } = new();
|
||||||
|
|
||||||
protected override void Initialise() {
|
protected override void Initialise() {
|
||||||
MarketID = JSON.Value<long?>("MarketID") ?? 0;
|
MarketID = JSON.Value<long?>("MarketID") ?? 0;
|
||||||
|
|||||||
30
EDPlayerJournal/Entries/SupercruiseDestinationDropEntry.cs
Normal file
30
EDPlayerJournal/Entries/SupercruiseDestinationDropEntry.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class SupercruiseDestinationDropEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Destination type, internal string.
|
||||||
|
/// </summary>
|
||||||
|
public string? Type { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Destination type, localised string.
|
||||||
|
/// </summary>
|
||||||
|
public string? TypeLocalised { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Threat of the destination, if known.
|
||||||
|
/// </summary>
|
||||||
|
public long? Threat { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Market ID if it has one.
|
||||||
|
/// </summary>
|
||||||
|
public ulong? MarketID { get; set; } = null;
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
Type = JSON.Value<string>("Type");
|
||||||
|
TypeLocalised = JSON.Value<string>("Type_Localised");
|
||||||
|
Threat = JSON.Value<long?>("Threat");
|
||||||
|
MarketID = JSON.Value<ulong?>("MarketID");
|
||||||
|
}
|
||||||
|
}
|
||||||
30
EDPlayerJournal/Entries/SupercruiseEntry.cs
Normal file
30
EDPlayerJournal/Entries/SupercruiseEntry.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class SupercruiseEntryEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Taxi?
|
||||||
|
/// </summary>
|
||||||
|
public bool Taxi { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multicrew or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool Multicrew { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Star system
|
||||||
|
/// </summary>
|
||||||
|
public string? StarSystem { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System address
|
||||||
|
/// </summary>
|
||||||
|
public ulong? SystemAddress { get; set; }
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
Taxi = JSON.Value<bool?>("Taxi") ?? false;
|
||||||
|
Multicrew = JSON.Value<bool?>("Multicrew") ?? false;
|
||||||
|
StarSystem = JSON.Value<string?>("StarSystem");
|
||||||
|
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||||
|
}
|
||||||
|
}
|
||||||
48
EDPlayerJournal/Entries/SupercruiseExitEntry.cs
Normal file
48
EDPlayerJournal/Entries/SupercruiseExitEntry.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
namespace EDPlayerJournal.Entries;
|
||||||
|
|
||||||
|
public class SupercruiseExitEntry : Entry {
|
||||||
|
/// <summary>
|
||||||
|
/// Taxi?
|
||||||
|
/// </summary>
|
||||||
|
public bool Taxi { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multicrew or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool Multicrew { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Star system
|
||||||
|
/// </summary>
|
||||||
|
public string? StarSystem { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System address
|
||||||
|
/// </summary>
|
||||||
|
public ulong? SystemAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body, name e.g. HIP 6182 B 2 a
|
||||||
|
/// </summary>
|
||||||
|
public string? Body { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body ID
|
||||||
|
/// </summary>
|
||||||
|
public ulong? BodyID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Body type (star, planet etc.)
|
||||||
|
/// </summary>
|
||||||
|
public string? BodyType { get; set; }
|
||||||
|
|
||||||
|
protected override void Initialise() {
|
||||||
|
Taxi = JSON.Value<bool?>("Taxi") ?? false;
|
||||||
|
Multicrew = JSON.Value<bool?>("Multicrew") ?? false;
|
||||||
|
StarSystem = JSON.Value<string?>("StarSystem");
|
||||||
|
SystemAddress = JSON.Value<ulong?>("SystemAddress");
|
||||||
|
Body = JSON.Value<string?>("Body");
|
||||||
|
BodyType = JSON.Value<string?>("BodyType");
|
||||||
|
BodyID = JSON.Value<ulong?>("BodyID");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,12 +33,83 @@ public class Factions {
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Internal name for the Pilots Federation faction
|
/// Internal name for the Pilots Federation faction
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string PilotsFederation = "$faction_PilotsFederation;";
|
public static string PilotsFederationInternal = "$faction_PilotsFederation;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name used for Pilots Federation in vouchers
|
||||||
|
/// </summary>
|
||||||
|
public static string PilotsFederationVouchers = "PilotsFederation";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Friendly name of the Pilots Federation
|
||||||
|
/// </summary>
|
||||||
|
public static string PilotsFederation = "Pilots' Federation";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Internal name for the Thargoid faction
|
/// Internal name for the Thargoid faction
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Thargoid = "$faction_Thargoid;";
|
public static string ThargoidInternal = "$faction_Thargoid;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Localised name of the Thargoids
|
||||||
|
/// </summary>
|
||||||
|
public static string Thargoid = "Thargoids";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The faction the fleet carriers use.
|
||||||
|
/// </summary>
|
||||||
|
public static string FleetCarrier = "FleetCarrier";
|
||||||
|
|
||||||
|
public static bool IsPilotsFederation(string? name) {
|
||||||
|
if (name == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(name, PilotsFederationInternal) == 0 ||
|
||||||
|
string.Compare(name, PilotsFederationVouchers) == 0 ||
|
||||||
|
string.Compare(name, PilotsFederation) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsThargoid(string? name) {
|
||||||
|
if (name == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(name, ThargoidInternal) == 0 ||
|
||||||
|
string.Compare(name, Thargoid) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two factions names and sees if they are the same faction. Since
|
||||||
|
/// factions can have an internal name, and a public name, this function takes
|
||||||
|
/// these into account.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a"></param>
|
||||||
|
/// <param name="b"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static int CompareFactions(string? a, string? b) {
|
||||||
|
if (a == null || b == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsPilotsFederation(a) && IsPilotsFederation(b)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsThargoid(a) && IsThargoid(b)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Compare(a, b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Faction {
|
public class Faction {
|
||||||
|
|||||||
87
EDPlayerJournal/Instances.cs
Normal file
87
EDPlayerJournal/Instances.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
namespace EDPlayerJournal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information regarding instances you can supercruise into,
|
||||||
|
/// such as combat zones, installations and megaship scenarios.
|
||||||
|
/// </summary>
|
||||||
|
public class Instances {
|
||||||
|
/// <summary>
|
||||||
|
/// Low ship combat zone
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string WarzoneLow = "$Warzone_PointRace_Low";
|
||||||
|
/// <summary>
|
||||||
|
/// Medium ship combat zone
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string WarzoneMedium = "$Warzone_PointRace_Med";
|
||||||
|
/// <summary>
|
||||||
|
/// High ship combat zone.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string WarzoneHigh = "$Warzone_PointRace_High";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Medium power play conflict zone, new in PP 2.0 Ascendancy update
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string PowerWarzoneMedium = "$Warzone_Powerplay_Med";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Low Thargoid combat zone
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string WarzoneThargoidLow = "$Warzone_TG_Low";
|
||||||
|
/// <summary>
|
||||||
|
/// Medium Thargoid combat zone
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string WarzoneThargoidMedium = "$Warzone_TG_Med";
|
||||||
|
/// <summary>
|
||||||
|
/// High Thargoid combat zone
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string WarzoneThargoidHigh = "$Warzone_TG_High";
|
||||||
|
/// <summary>
|
||||||
|
/// Very High Thargoid combat zone
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string WarzoneThargoidVeryHigh = "$Warzone_TG_VeryHigh";
|
||||||
|
|
||||||
|
public static bool IsThargoidWarzone(string type) {
|
||||||
|
return
|
||||||
|
IsInstance(type, WarzoneThargoidLow) ||
|
||||||
|
IsInstance(type, WarzoneThargoidMedium) ||
|
||||||
|
IsInstance(type, WarzoneThargoidHigh) ||
|
||||||
|
IsInstance(type, WarzoneThargoidVeryHigh)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsHumanWarzone(string type) {
|
||||||
|
return
|
||||||
|
IsInstance(type, WarzoneLow) ||
|
||||||
|
IsInstance(type, WarzoneMedium) ||
|
||||||
|
IsInstance(type, WarzoneHigh)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsPowerWarzone(string type) {
|
||||||
|
return
|
||||||
|
IsInstance(type, PowerWarzoneMedium)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsWarzone(string type) {
|
||||||
|
return IsHumanWarzone(type) ||
|
||||||
|
IsThargoidWarzone(type) ||
|
||||||
|
IsPowerWarzone(type)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInstance(string type, string instance) {
|
||||||
|
if (string.IsNullOrEmpty(type) || string.IsNullOrEmpty(instance)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance names are split by a semi colon, with the remainder being
|
||||||
|
// additional info to such as index.
|
||||||
|
string[] parts = type.Split(":");
|
||||||
|
if (!parts[0].StartsWith("$")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Compare(parts[0], instance, true) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
public class InvalidJournalEntryException : Exception {
|
public class InvalidJournalEntryException : Exception {
|
||||||
public InvalidJournalEntryException() { }
|
public InvalidJournalEntryException() { }
|
||||||
public InvalidJournalEntryException(string message) : base(message) { }
|
public InvalidJournalEntryException(string message) : base(message) { }
|
||||||
|
public InvalidJournalEntryException(string message, Exception inner) : base(message, inner) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ public class JournalFile : IComparable<JournalFile>
|
|||||||
private static Regex update11regex = new Regex("Journal\\.([^\\.]+)\\.(\\d+).log");
|
private static Regex update11regex = new Regex("Journal\\.([^\\.]+)\\.(\\d+).log");
|
||||||
private static string iso8601 = "yyyyMMddTHHmmss";
|
private static string iso8601 = "yyyyMMddTHHmmss";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A public list of errors encountered while parsing the journal files
|
||||||
|
/// </summary>
|
||||||
|
public List<Exception> Errors { get; private set; } = new List<Exception>();
|
||||||
|
|
||||||
public static bool VerifyFile(string path) {
|
public static bool VerifyFile(string path) {
|
||||||
string filename = Path.GetFileName(path);
|
string filename = Path.GetFileName(path);
|
||||||
|
|
||||||
@@ -125,14 +130,19 @@ public class JournalFile : IComparable<JournalFile>
|
|||||||
}
|
}
|
||||||
|
|
||||||
entries.Clear();
|
entries.Clear();
|
||||||
foreach(var line in lines) {
|
Errors.Clear();
|
||||||
|
foreach (var line in lines) {
|
||||||
// Skip empty lines
|
// Skip empty lines
|
||||||
if (line.Trim().Length == 0) {
|
if (line.Trim().Length == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Entry? entry = Entry.Parse(line);
|
try {
|
||||||
if (entry != null) {
|
Entry? entry = Entry.Parse(line);
|
||||||
entries.Add(entry);
|
if (entry != null) {
|
||||||
|
entries.Add(entry);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Errors.Add(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,31 @@ public class MissionInfluence {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Influence { get; set; } = string.Empty;
|
public string Influence { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public long InfluenceAmount {
|
||||||
|
get {
|
||||||
|
string trend = TrendAdjustedInfluence;
|
||||||
|
return (long)
|
||||||
|
(trend.Count(x => x == '-') * -1) +
|
||||||
|
trend.Count(x => x == '+')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns how much influence was made, represented in pluses for positive influence,
|
||||||
|
/// and minuses with negative influence. This takes Trend (up, bad etc.) into account.
|
||||||
|
/// </summary>
|
||||||
|
public string TrendAdjustedInfluence {
|
||||||
|
get {
|
||||||
|
if (!string.IsNullOrEmpty(Trend) &&
|
||||||
|
Trend.Contains("bad", StringComparison.OrdinalIgnoreCase)) {
|
||||||
|
return new string('-', Influence.Length);
|
||||||
|
} else {
|
||||||
|
return new string('+', Influence.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static MissionInfluence FromJSON(JObject obj) {
|
public static MissionInfluence FromJSON(JObject obj) {
|
||||||
MissionInfluence missionInfluence = new MissionInfluence();
|
MissionInfluence missionInfluence = new MissionInfluence();
|
||||||
|
|
||||||
@@ -109,6 +134,11 @@ public class MissionFactionEffects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class Mission : IComparable<Mission> {
|
public class Mission : IComparable<Mission> {
|
||||||
|
/// <summary>
|
||||||
|
/// Passenger type for refugees
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string PassengerTypeRefugee = "Refugee";
|
||||||
|
|
||||||
public ulong MissionID { get; set; } = 0;
|
public ulong MissionID { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -250,6 +280,43 @@ public class Mission : IComparable<Mission> {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public List<MissionFactionEffects> FactionEffects { get; set; } = new List<MissionFactionEffects>();
|
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 {
|
||||||
|
if (PassengerCount == null || PassengerCount == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsRescueMission {
|
||||||
|
get {
|
||||||
|
if (!IsPassengerMission) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(PassengerType, PassengerTypeRefugee) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a friendly human-readable name for the mission. If a localised name is available
|
/// Returns a friendly human-readable name for the mission. If a localised name is available
|
||||||
/// it will use that, baring that it will check EnglishMissionNames for a translation, and
|
/// it will use that, baring that it will check EnglishMissionNames for a translation, and
|
||||||
@@ -352,27 +419,29 @@ public class Mission : IComparable<Mission> {
|
|||||||
/// <param name="faction">Faction name in question.</param>
|
/// <param name="faction">Faction name in question.</param>
|
||||||
/// <param name="systemaddr">Star System address</param>
|
/// <param name="systemaddr">Star System address</param>
|
||||||
/// <returns>null if no entry was found, or a string denoting pluses for the amount influence gained.</returns>
|
/// <returns>null if no entry was found, or a string denoting pluses for the amount influence gained.</returns>
|
||||||
public string? GetInfluenceForFaction(string faction, ulong systemaddr) {
|
public MissionInfluence[]? GetInfluenceForFaction(string faction, ulong systemaddr) {
|
||||||
var results = FactionEffects
|
var results = FactionEffects
|
||||||
.Where(x => string.Compare(x.Faction, faction) == 0)
|
.Where(x => string.Compare(x.Faction, faction) == 0)
|
||||||
.SelectMany(x => x.Influences)
|
.SelectMany(x => x.Influences)
|
||||||
.Where(x => (x.SystemAddress != null && x.SystemAddress == systemaddr))
|
.Where(x => (x.SystemAddress != null && x.SystemAddress == systemaddr))
|
||||||
.Select(x => x.Influence)
|
.Select(x => x)
|
||||||
.ToArray()
|
.ToArray()
|
||||||
;
|
;
|
||||||
|
|
||||||
if (results == null || results.Length == 0) {
|
if (results == null || results.Length == 0) {
|
||||||
return null;
|
return new MissionInfluence[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Join("", results);
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A convenient Dictionary containing all influences given out by faction,
|
/// A convenient Dictionary containing all influences given out by faction,
|
||||||
/// then by system address and then by influence handed out.
|
/// then by system address and then by influence handed out. Influence can
|
||||||
|
/// be either a series of "+" for positive influence, or "-" for negative
|
||||||
|
/// influence.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, Dictionary<ulong, string>> Influences {
|
public Dictionary<string, Dictionary<ulong, MissionInfluence>> Influences {
|
||||||
get {
|
get {
|
||||||
return FactionEffects
|
return FactionEffects
|
||||||
.Where(x => x.Faction != null)
|
.Where(x => x.Faction != null)
|
||||||
@@ -380,7 +449,10 @@ public class Mission : IComparable<Mission> {
|
|||||||
x => (x.Faction ?? string.Empty),
|
x => (x.Faction ?? string.Empty),
|
||||||
x => x.Influences
|
x => x.Influences
|
||||||
.Where(x => x.SystemAddress != null)
|
.Where(x => x.SystemAddress != null)
|
||||||
.ToDictionary(x => (x.SystemAddress ?? 0), x => x.Influence)
|
.ToDictionary(
|
||||||
|
x => (x.SystemAddress ?? 0),
|
||||||
|
x => x
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
122
EDPlayerJournal/NPC.cs
Normal file
122
EDPlayerJournal/NPC.cs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
namespace EDPlayerJournal;
|
||||||
|
|
||||||
|
public class NPCs {
|
||||||
|
/// <summary>
|
||||||
|
/// Internal name of Spec Ops Wing Alpha
|
||||||
|
/// </summary>
|
||||||
|
public static string SpecOpsAInternal = "$LUASC_Scenario_Warzone_NPC_SpecOps_A;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal name of Spec Ops Wing Beta
|
||||||
|
/// </summary>
|
||||||
|
public static string SpecOpsBInternal = "$LUASC_Scenario_Warzone_NPC_SpecOps_B;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal name of Spec Ops Wing Gamma
|
||||||
|
/// </summary>
|
||||||
|
public static string SpecOpsGInternal = "$LUASC_Scenario_Warzone_NPC_SpecOps_G;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal name of Spec Ops Wing Delta
|
||||||
|
/// </summary>
|
||||||
|
public static string SpecOpsDInternal = "$LUASC_Scenario_Warzone_NPC_SpecOps_D;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Empire captain
|
||||||
|
/// </summary>
|
||||||
|
public static string EmpireCaptain = "$LUASC_Scenario_Warzone_NPC_WarzoneGeneral_Emp;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Federation captain
|
||||||
|
/// </summary>
|
||||||
|
public static string FederationCaptain = "$LUASC_Scenario_Warzone_NPC_WarzoneGeneral_Fed;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Federation captain
|
||||||
|
/// </summary>
|
||||||
|
public static string IndependentCaptain = "$LUASC_Scenario_Warzone_NPC_WarzoneGeneral_Ind;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Warzone correspondant
|
||||||
|
/// </summary>
|
||||||
|
public static string WarzoneCorrespondent = "$LUASC_Scenario_Warzone_NPC_WarzoneCorrespondent;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AX Military NPC
|
||||||
|
/// </summary>
|
||||||
|
public static string AXMilitary = "$Name_AX_Military;";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the pilotname is either a captain, specops, or correspondent
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pilotname"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool IsWarzoneNPC(string? pilotname) {
|
||||||
|
if (IsWarzoneCaptain(pilotname) ||
|
||||||
|
IsWarzoneCorrespondent(pilotname) ||
|
||||||
|
IsSpecOps(pilotname)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the given pilot name is a warzone correspondent
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool IsWarzoneCorrespondent(string? pilotname) {
|
||||||
|
if (pilotname == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(pilotname, WarzoneCorrespondent) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the given pilot name is a spec ops wing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool IsSpecOps(string? pilotname) {
|
||||||
|
if (pilotname == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(pilotname, SpecOpsAInternal) == 0 ||
|
||||||
|
string.Compare(pilotname, SpecOpsBInternal) == 0 ||
|
||||||
|
string.Compare(pilotname, SpecOpsGInternal) == 0 ||
|
||||||
|
string.Compare(pilotname, SpecOpsDInternal) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if the given pilot name is a warzone captain
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static bool IsWarzoneCaptain(string? pilotname) {
|
||||||
|
if (pilotname == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Compare(pilotname, EmpireCaptain) == 0 ||
|
||||||
|
string.Compare(pilotname, FederationCaptain) == 0 ||
|
||||||
|
string.Compare(pilotname, IndependentCaptain) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NPC {
|
||||||
|
}
|
||||||
@@ -22,6 +22,12 @@ public class PlayerJournal {
|
|||||||
ScanFiles();
|
ScanFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Exception> AllErrors {
|
||||||
|
get {
|
||||||
|
return Files.SelectMany(x => x.Errors).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<JournalFile> Files {
|
public List<JournalFile> Files {
|
||||||
get { return journalfiles; }
|
get { return journalfiles; }
|
||||||
}
|
}
|
||||||
|
|||||||
101
EDPlayerJournal/PowerPlay/Powers.cs
Normal file
101
EDPlayerJournal/PowerPlay/Powers.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
namespace EDPlayerJournal.PowerPlay;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds a list of all available powers in E:D, and helps
|
||||||
|
/// to translate commonly used short-hands and aliases to
|
||||||
|
/// journal approved power names.
|
||||||
|
/// </summary>
|
||||||
|
public class Powers {
|
||||||
|
public static readonly string
|
||||||
|
// Basking
|
||||||
|
ALavignyDuval = "A. Lavigny-Duval",
|
||||||
|
AislingDuval = "Aisling Duval",
|
||||||
|
DentonPatreus = "Denton Patreus",
|
||||||
|
ZeminaTorval = "Zemina Torval",
|
||||||
|
// Feds
|
||||||
|
JeromeArcher = "Jerome Archer",
|
||||||
|
FeliciaWinters = "Felicia Winters",
|
||||||
|
// Alliance
|
||||||
|
EdmunMahon = "Edmund Mahon",
|
||||||
|
NakatoKaine = "Nakato Kaine",
|
||||||
|
// Independents
|
||||||
|
YuriGrom = "Yuri Grom",
|
||||||
|
ArchonDelaine = "Archon Delaine",
|
||||||
|
LiYongRui = "Li Yong-Rui",
|
||||||
|
PranavAntal = "Pranav Antal"
|
||||||
|
;
|
||||||
|
|
||||||
|
public static readonly Dictionary<string, string> aliases = new() {
|
||||||
|
// ALD
|
||||||
|
{ Powers.ALavignyDuval, Powers.ALavignyDuval },
|
||||||
|
{ "ALD", Powers.ALavignyDuval },
|
||||||
|
{ "Arissa", Powers.ALavignyDuval },
|
||||||
|
{ "Emperor", Powers.ALavignyDuval },
|
||||||
|
{ "Kaiser", Powers.ALavignyDuval },
|
||||||
|
// AD
|
||||||
|
{ Powers.AislingDuval, Powers.AislingDuval },
|
||||||
|
{ "AD", Powers.AislingDuval },
|
||||||
|
{ "Aisling", Powers.AislingDuval },
|
||||||
|
// DP
|
||||||
|
{ Powers.DentonPatreus, Powers.DentonPatreus },
|
||||||
|
{ "DP", Powers.DentonPatreus },
|
||||||
|
{ "Denton", Powers.DentonPatreus },
|
||||||
|
// ZT
|
||||||
|
{ Powers.ZeminaTorval, Powers.ZeminaTorval },
|
||||||
|
{ "ZT", Powers.ZeminaTorval },
|
||||||
|
{ "Torval", Powers.ZeminaTorval },
|
||||||
|
// Archer
|
||||||
|
{ Powers.JeromeArcher, Powers.JeromeArcher },
|
||||||
|
{ "JA", Powers.JeromeArcher },
|
||||||
|
{ "Archer", Powers.JeromeArcher },
|
||||||
|
// Winters
|
||||||
|
{ Powers.FeliciaWinters, Powers.FeliciaWinters },
|
||||||
|
{ "FW", Powers.FeliciaWinters },
|
||||||
|
{ "Winters", Powers.FeliciaWinters },
|
||||||
|
// Mahon
|
||||||
|
{ Powers.EdmunMahon, Powers.EdmunMahon },
|
||||||
|
{ "EM", Powers.EdmunMahon },
|
||||||
|
{ "Mahon", Powers.EdmunMahon },
|
||||||
|
// Kaine
|
||||||
|
{ Powers.NakatoKaine, Powers.NakatoKaine },
|
||||||
|
{ "NK", Powers.NakatoKaine },
|
||||||
|
{ "Kaine", Powers.NakatoKaine },
|
||||||
|
// Grom
|
||||||
|
{ Powers.YuriGrom, Powers.YuriGrom },
|
||||||
|
{ "YG", Powers.YuriGrom },
|
||||||
|
{ "Grom", Powers.YuriGrom },
|
||||||
|
// Archon
|
||||||
|
{ Powers.ArchonDelaine, Powers.ArchonDelaine },
|
||||||
|
{ "Archon", Powers.ArchonDelaine },
|
||||||
|
{ "Kumo", Powers.ArchonDelaine },
|
||||||
|
{ "KumoBurger", Powers.ArchonDelaine },
|
||||||
|
// LYR
|
||||||
|
{ Powers.LiYongRui, Powers.LiYongRui },
|
||||||
|
{ "LYR", Powers.LiYongRui },
|
||||||
|
// Pranav
|
||||||
|
{ Powers.PranavAntal, Powers.PranavAntal },
|
||||||
|
{ "PA", Powers.PranavAntal },
|
||||||
|
{ "Pranav", Powers.PranavAntal },
|
||||||
|
};
|
||||||
|
|
||||||
|
public static bool IsValidPower(string power) {
|
||||||
|
try {
|
||||||
|
string p = GetPower(power);
|
||||||
|
return true;
|
||||||
|
} catch (Exception) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPower(string nameOrAlias) {
|
||||||
|
string? val = aliases
|
||||||
|
.Where(x => string.Compare(x.Key, nameOrAlias, StringComparison.InvariantCultureIgnoreCase) == 0)
|
||||||
|
.Select(x => x.Value)
|
||||||
|
.FirstOrDefault()
|
||||||
|
;
|
||||||
|
if (string.IsNullOrEmpty(val)) {
|
||||||
|
throw new ApplicationException($"not a valid power: {nameOrAlias}");
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,43 +1,68 @@
|
|||||||
using System;
|
namespace EDPlayerJournal;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace EDPlayerJournal;
|
|
||||||
|
|
||||||
public enum ThargoidVessel {
|
public enum ThargoidVessel {
|
||||||
Unknown = 0,
|
Unknown = 0,
|
||||||
Scout = 1,
|
Scout = 1,
|
||||||
/// <summary>
|
|
||||||
/// According to AX wiki no longer found ingame
|
|
||||||
/// </summary>
|
|
||||||
Orthrus = 2,
|
Orthrus = 2,
|
||||||
Cyclops = 3,
|
Cyclops = 3,
|
||||||
Basilisk = 4,
|
Basilisk = 4,
|
||||||
Medusa = 5,
|
Medusa = 5,
|
||||||
Hydra = 6,
|
Hydra = 6,
|
||||||
|
// Includes Glaive and Scythe
|
||||||
|
Hunter = 7,
|
||||||
|
/// <summary>
|
||||||
|
/// Thargoid drone
|
||||||
|
/// </summary>
|
||||||
|
Revenant = 8,
|
||||||
|
/// <summary>
|
||||||
|
/// New thargoid drone in U17
|
||||||
|
/// </summary>
|
||||||
|
Banshee = 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Thargoid {
|
public class Thargoid {
|
||||||
public static string ThargoidFaction = Factions.Thargoid;
|
public static string ThargoidFaction = Factions.Thargoid;
|
||||||
|
|
||||||
public static Dictionary<ulong, ThargoidVessel> VesselPayout { get; } = new() {
|
public static Dictionary<ulong, ThargoidVessel> VesselPayout { get; } = new() {
|
||||||
{ 80000, ThargoidVessel.Scout },
|
// Up to date values ever since 14.02
|
||||||
{ 8000000, ThargoidVessel.Cyclops },
|
{ 25000, ThargoidVessel.Revenant },
|
||||||
{ 24000000, ThargoidVessel.Basilisk },
|
{ 65000, ThargoidVessel.Scout },
|
||||||
{ 40000000, ThargoidVessel.Medusa },
|
{ 75000, ThargoidVessel.Scout },
|
||||||
{ 60000000, ThargoidVessel.Hydra },
|
// New in Update 17
|
||||||
|
{ 100000, ThargoidVessel.Banshee },
|
||||||
|
// New in Update 15
|
||||||
|
{ 4500000, ThargoidVessel.Hunter },
|
||||||
|
{ 6500000, ThargoidVessel.Cyclops },
|
||||||
|
{ 20000000, ThargoidVessel.Basilisk },
|
||||||
|
//{ 25000000, ThargoidVessel.Orthrus },
|
||||||
|
{ 34000000, ThargoidVessel.Medusa },
|
||||||
|
// March, 16th 2023 the Orthrus payout was buffed again.
|
||||||
|
{ 40000000, ThargoidVessel.Orthrus },
|
||||||
|
{ 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 },
|
||||||
|
// 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 },
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Dictionary<ThargoidVessel, string?> VesselNames { get; } = new() {
|
public static Dictionary<ThargoidVessel, string?> VesselNames { get; } = new() {
|
||||||
{ ThargoidVessel.Unknown, null },
|
{ ThargoidVessel.Unknown, "(Unknown)" },
|
||||||
{ ThargoidVessel.Scout, "Thargoid Scout" },
|
{ ThargoidVessel.Revenant, "Revenant" },
|
||||||
|
{ ThargoidVessel.Scout, "Scout" },
|
||||||
{ ThargoidVessel.Orthrus, "Orthrus" },
|
{ ThargoidVessel.Orthrus, "Orthrus" },
|
||||||
{ ThargoidVessel.Cyclops, "Cyclops" },
|
{ ThargoidVessel.Cyclops, "Cyclops" },
|
||||||
{ ThargoidVessel.Basilisk, "Basilisk" },
|
{ ThargoidVessel.Basilisk, "Basilisk" },
|
||||||
{ ThargoidVessel.Medusa, "Medusa" },
|
{ ThargoidVessel.Medusa, "Medusa" },
|
||||||
{ ThargoidVessel.Hydra, "Hydra" },
|
{ ThargoidVessel.Hydra, "Hydra" },
|
||||||
|
{ ThargoidVessel.Hunter, "Hunter" },
|
||||||
|
{ ThargoidVessel.Banshee, "Banshee" },
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ThargoidVessel GetVesselByPayout(ulong payout) {
|
public static ThargoidVessel GetVesselByPayout(ulong payout) {
|
||||||
|
|||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
EDPlayerJournalTests/DoubleVouchers.txt
Normal file
2
EDPlayerJournalTests/DoubleVouchers.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{ "timestamp":"2022-11-20T14:30:30Z", "event":"RedeemVoucher", "Type":"bounty", "Amount":3197549, "Factions":[ { "Faction":"Nova Paresa", "Amount":3197549 } ] }
|
||||||
|
{ "timestamp":"2022-11-20T14:30:34Z", "event":"RedeemVoucher", "Type":"bounty", "Amount":4785831, "Factions":[ { "Faction":"", "Amount":723175 }, { "Faction":"Nova Paresa", "Amount":3197549 }, { "Faction":"Prismatic Imperium", "Amount":4062656 } ] }
|
||||||
@@ -26,6 +26,12 @@
|
|||||||
<None Update="double-support.txt">
|
<None Update="double-support.txt">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="dropship-deploy.txt">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="legacy-transaction.txt">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Update="mission-failed.txt">
|
<None Update="mission-failed.txt">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
@@ -44,6 +50,9 @@
|
|||||||
<None Update="SellOrganicData.txt">
|
<None Update="SellOrganicData.txt">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Update="ThargoidBonds.txt">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Update="ThargoidKills.txt">
|
<None Update="ThargoidKills.txt">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ public class FileHeaderTest {
|
|||||||
Assert.AreEqual(header.Language, "English/UK");
|
Assert.AreEqual(header.Language, "English/UK");
|
||||||
Assert.AreEqual(header.Odyssey, true);
|
Assert.AreEqual(header.Odyssey, true);
|
||||||
Assert.AreEqual(header.GameVersion, "4.0.0.1450");
|
Assert.AreEqual(header.GameVersion, "4.0.0.1450");
|
||||||
|
Assert.AreEqual(header.IsLegacy, false);
|
||||||
|
Assert.AreEqual(header.IsLive, true);
|
||||||
// Someone at FDev messed up string building there.
|
// Someone at FDev messed up string building there.
|
||||||
Assert.AreEqual(header.Build, "r286858/r0 ");
|
Assert.AreEqual(header.Build, "r286858/r0 ");
|
||||||
}
|
}
|
||||||
@@ -44,6 +46,8 @@ public class FileHeaderTest {
|
|||||||
Assert.AreEqual(header.Language, """English\UK""");
|
Assert.AreEqual(header.Language, """English\UK""");
|
||||||
Assert.AreEqual(header.Odyssey, false);
|
Assert.AreEqual(header.Odyssey, false);
|
||||||
Assert.AreEqual(header.GameVersion, "3.5.3.400 EDH");
|
Assert.AreEqual(header.GameVersion, "3.5.3.400 EDH");
|
||||||
|
Assert.AreEqual(header.IsLegacy, true);
|
||||||
|
Assert.AreEqual(header.IsLive, false);
|
||||||
// ~73k commits in two years. Not bad.
|
// ~73k commits in two years. Not bad.
|
||||||
Assert.AreEqual(header.Build, "r213094/r0 ");
|
Assert.AreEqual(header.Build, "r213094/r0 ");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ public class MissionTest {
|
|||||||
Assert.IsTrue(e.IsEmptyFaction);
|
Assert.IsTrue(e.IsEmptyFaction);
|
||||||
Assert.AreEqual(e.Faction, string.Empty);
|
Assert.AreEqual(e.Faction, string.Empty);
|
||||||
|
|
||||||
string? influence = m.GetInfluenceForFaction("", 251012319587UL);
|
var influence = m.GetInfluenceForFaction("", 251012319587UL);
|
||||||
Assert.IsNotNull(influence);
|
Assert.IsNotNull(influence);
|
||||||
Assert.AreEqual(influence, "+");
|
Assert.AreEqual(influence[0].Influence, "+");
|
||||||
|
|
||||||
e = m.FactionEffects[1];
|
e = m.FactionEffects[1];
|
||||||
Assert.AreEqual(e.Faction, "Social LHS 6103 Confederation");
|
Assert.AreEqual(e.Faction, "Social LHS 6103 Confederation");
|
||||||
@@ -101,22 +101,25 @@ public class MissionTest {
|
|||||||
|
|
||||||
Assert.AreEqual(effect.Reputation, "++");
|
Assert.AreEqual(effect.Reputation, "++");
|
||||||
|
|
||||||
string? influence;
|
var influence = m.GetInfluenceForFaction("Salus Imperial Society", 1865919973739UL);
|
||||||
|
Assert.IsNotNull(influence);
|
||||||
influence = m.GetInfluenceForFaction("Salus Imperial Society", 1865919973739UL);
|
Assert.IsTrue(influence.Length > 0);
|
||||||
Assert.AreEqual(influence, "++");
|
Assert.AreEqual(influence[0].Influence, "++");
|
||||||
|
|
||||||
influence = m.GetInfluenceForFaction("Salus Imperial Society", 1733186884306UL);
|
influence = m.GetInfluenceForFaction("Salus Imperial Society", 1733186884306UL);
|
||||||
Assert.AreEqual(influence, "++");
|
Assert.IsNotNull(influence);
|
||||||
|
Assert.IsTrue(influence.Length > 0);
|
||||||
|
Assert.AreEqual(influence[0].Influence, "++");
|
||||||
|
|
||||||
influence = m.GetInfluenceForFaction("Saelishi Saxons", 1733186884306UL);
|
influence = m.GetInfluenceForFaction("Saelishi Saxons", 1733186884306UL);
|
||||||
Assert.IsNull(influence);
|
Assert.IsNotNull(influence);
|
||||||
|
Assert.AreEqual(influence.Length, 0);
|
||||||
|
|
||||||
// Only one entry are we only have Salus
|
// Only one entry are we only have Salus
|
||||||
Assert.AreEqual(m.Influences.Count, 1);
|
Assert.AreEqual(m.Influences.Count, 1);
|
||||||
Assert.AreEqual(m.Influences["Salus Imperial Society"].Count, 2);
|
Assert.AreEqual(m.Influences["Salus Imperial Society"].Count, 2);
|
||||||
Assert.AreEqual(m.Influences["Salus Imperial Society"][1865919973739UL], "++");
|
Assert.AreEqual(m.Influences["Salus Imperial Society"][1865919973739UL].Influence, "++");
|
||||||
Assert.AreEqual(m.Influences["Salus Imperial Society"][1733186884306UL], "++");
|
Assert.AreEqual(m.Influences["Salus Imperial Society"][1733186884306UL].Influence, "++");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|||||||
@@ -6,6 +6,35 @@ namespace EDPlayerJournalTests;
|
|||||||
|
|
||||||
[TestClass]
|
[TestClass]
|
||||||
public class TestTransactionParser {
|
public class TestTransactionParser {
|
||||||
|
[TestMethod]
|
||||||
|
public void Legacy() {
|
||||||
|
TransactionParser parser = new();
|
||||||
|
|
||||||
|
// File header, followed by two legacy transactions, followed by another
|
||||||
|
// file header with an Odyssey transaction
|
||||||
|
List<Entry>? entries = Helper.LoadTestData("legacy-transaction.txt");
|
||||||
|
Assert.IsNotNull(entries, "could not load test data");
|
||||||
|
|
||||||
|
if (entries == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = new TransactionParserOptions() {
|
||||||
|
IgnoreInfluenceSupport = false,
|
||||||
|
IgnoreExoBiology = false,
|
||||||
|
IgnoreFleetCarrierFaction = false,
|
||||||
|
IgnoreMarketBuy = false,
|
||||||
|
};
|
||||||
|
List<Transaction>? transactions = parser.Parse(entries, options);
|
||||||
|
Assert.IsNotNull(transactions, "could not parse entries");
|
||||||
|
Assert.AreEqual(transactions.Count, 3);
|
||||||
|
|
||||||
|
Assert.AreEqual(transactions[0].IsLegacy, true);
|
||||||
|
Assert.AreEqual(transactions[1].IsLegacy, true);
|
||||||
|
|
||||||
|
Assert.AreEqual(transactions[2].IsLegacy, false);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void DoubleFiveINF() {
|
public void DoubleFiveINF() {
|
||||||
TransactionParser parser = new();
|
TransactionParser parser = new();
|
||||||
@@ -121,7 +150,14 @@ public class TestTransactionParser {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Transaction>? transactions = parser.Parse(entries);
|
var options = new TransactionParserOptions() {
|
||||||
|
IgnoreInfluenceSupport = false,
|
||||||
|
IgnoreExoBiology = false,
|
||||||
|
IgnoreFleetCarrierFaction = false,
|
||||||
|
IgnoreMarketBuy = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
List<Transaction>? transactions = parser.Parse(entries, options);
|
||||||
Assert.IsNotNull(transactions, "could not parse entries");
|
Assert.IsNotNull(transactions, "could not parse entries");
|
||||||
Assert.AreEqual(transactions.Count, 1);
|
Assert.AreEqual(transactions.Count, 1);
|
||||||
Assert.IsInstanceOfType(transactions[0], typeof(OrganicData), "result is not of type Organic Data");
|
Assert.IsInstanceOfType(transactions[0], typeof(OrganicData), "result is not of type Organic Data");
|
||||||
|
|||||||
3
EDPlayerJournalTests/ThargoidBonds.txt
Normal file
3
EDPlayerJournalTests/ThargoidBonds.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{ "timestamp":"2022-11-25T10:10:43Z", "event":"FSDJump", "Taxi":false, "Multicrew":false, "StarSystem":"Nyalayan", "SystemAddress":1458309042898, "StarPos":[29.71875,-172.71875,-6.46875], "SystemAllegiance":"Independent", "SystemEconomy":"$economy_Agri;", "SystemEconomy_Localised":"Agriculture", "SystemSecondEconomy":"$economy_Refinery;", "SystemSecondEconomy_Localised":"Refinery", "SystemGovernment":"$government_Theocracy;", "SystemGovernment_Localised":"Theocracy", "SystemSecurity":"$SYSTEM_SECURITY_medium;", "SystemSecurity_Localised":"Medium Security", "Population":1920608781, "Body":"Nyalayan A", "BodyID":1, "BodyType":"Star", "JumpDist":7.769, "FuelUsed":0.142448, "FuelLevel":15.857553, "Factions":[ { "Name":"Nyalayan Imperial Society", "FactionState":"Election", "Government":"Patronage", "Influence":0.165138, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":17.496799, "ActiveStates":[ { "State":"Election" } ] }, { "Name":"Reret Emperor's Grace", "FactionState":"War", "Government":"Patronage", "Influence":0.257900, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":100.000000, "ActiveStates":[ { "State":"Expansion" }, { "State":"War" } ] }, { "Name":"Nyalayan Silver Transport Org", "FactionState":"None", "Government":"Corporate", "Influence":0.076453, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":81.875000 }, { "Name":"Nyalayan Power & Co", "FactionState":"None", "Government":"Corporate", "Influence":0.060143, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":23.173201 }, { "Name":"Amanogawa Enlight", "FactionState":"War", "Government":"Theocracy", "Influence":0.257900, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":-1.210600, "ActiveStates":[ { "State":"Expansion" }, { "State":"War" } ] }, { "Name":"Nyalayan Crimson Dragons", "FactionState":"None", "Government":"Anarchy", "Influence":0.017329, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":-13.530000 }, { "Name":"Traditional Nyalayan Front", "FactionState":"Election", "Government":"Dictatorship", "Influence":0.165138, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":64.699997, "ActiveStates":[ { "State":"Election" } ] } ], "SystemFaction":{ "Name":"Amanogawa Enlight", "FactionState":"War" }, "Conflicts":[ { "WarType":"election", "Status":"active", "Faction1":{ "Name":"Nyalayan Imperial Society", "Stake":"Pilcher Port", "WonDays":2 }, "Faction2":{ "Name":"Traditional Nyalayan Front", "Stake":"Lamar Falls", "WonDays":0 } }, { "WarType":"war", "Status":"active", "Faction1":{ "Name":"Reret Emperor's Grace", "Stake":"", "WonDays":1 }, "Faction2":{ "Name":"Amanogawa Enlight", "Stake":"Sutter Ring", "WonDays":2 } } ] }
|
||||||
|
{ "timestamp":"2022-11-25T10:13:32Z", "event":"Docked", "StationName":"Pilcher Port", "StationType":"Orbis", "Taxi":false, "Multicrew":false, "StarSystem":"Nyalayan", "SystemAddress":1458309042898, "MarketID":3222853120, "StationFaction":{ "Name":"Nyalayan Imperial Society", "FactionState":"Election" }, "StationGovernment":"$government_Patronage;", "StationGovernment_Localised":"Patronage", "StationAllegiance":"Empire", "StationServices":[ "dock", "autodock", "commodities", "contacts", "exploration", "missions", "outfitting", "crewlounge", "rearm", "refuel", "repair", "shipyard", "tuning", "engineer", "missionsgenerated", "flightcontroller", "stationoperations", "powerplay", "searchrescue", "stationMenu", "shop", "livery", "socialspace", "bartender", "vistagenomics", "pioneersupplies", "apexinterstellar", "frontlinesolutions" ], "StationEconomy":"$economy_Refinery;", "StationEconomy_Localised":"Refinery", "StationEconomies":[ { "Name":"$economy_Refinery;", "Name_Localised":"Refinery", "Proportion":1.000000 } ], "DistFromStarLS":76.465557, "LandingPads":{ "Small":8, "Medium":11, "Large":6 } }
|
||||||
|
{ "timestamp":"2022-11-25T10:13:53Z", "event":"RedeemVoucher", "Type":"CombatBond", "Amount":24240000, "Faction":"PilotsFederation" }
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
using EDPlayerJournal.BGS;
|
using EDPlayerJournal;
|
||||||
|
using EDPlayerJournal.BGS;
|
||||||
using EDPlayerJournal.Entries;
|
using EDPlayerJournal.Entries;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace EDPlayerJournalTests;
|
namespace EDPlayerJournalTests;
|
||||||
|
|
||||||
@@ -21,13 +17,41 @@ public class ThargoidKills {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Transaction>? transactions = parser.Parse(entries);
|
List<ThargoidKill>? transactions = parser.Parse(entries)?.OfType<ThargoidKill>().ToList();
|
||||||
|
|
||||||
Assert.IsNotNull(transactions, "could not parse entries");
|
Assert.IsNotNull(transactions, "could not parse entries");
|
||||||
Assert.AreEqual(transactions.Count, 4);
|
Assert.AreEqual(transactions.Count, 3);
|
||||||
|
|
||||||
|
// In recent updates the payout was changed, that's why this test reports unknown thargoid vessels
|
||||||
|
// This test makes sure the new parser does not conflict with legacy values
|
||||||
|
//
|
||||||
Assert.IsInstanceOfType(transactions[0], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
Assert.IsInstanceOfType(transactions[0], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
||||||
|
Assert.AreEqual(transactions[0].ThargoidType, EDPlayerJournal.ThargoidVessel.Unknown);
|
||||||
|
|
||||||
Assert.IsInstanceOfType(transactions[1], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
Assert.IsInstanceOfType(transactions[1], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
||||||
|
Assert.AreEqual(transactions[1].ThargoidType, EDPlayerJournal.ThargoidVessel.Unknown);
|
||||||
|
|
||||||
Assert.IsInstanceOfType(transactions[2], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
Assert.IsInstanceOfType(transactions[2], typeof(ThargoidKill), "result is not of type ThargoidKill");
|
||||||
|
Assert.AreEqual(transactions[2].ThargoidType, EDPlayerJournal.ThargoidVessel.Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ThargoidBonds() {
|
||||||
|
TransactionParser parser = new();
|
||||||
|
|
||||||
|
List<Entry>? entries = Helper.LoadTestData("ThargoidBonds.txt");
|
||||||
|
Assert.IsNotNull(entries, "could not load test data");
|
||||||
|
|
||||||
|
if (entries == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Vouchers>? transactions = parser.Parse(entries)?.OfType<Vouchers>().ToList();
|
||||||
|
|
||||||
|
Assert.IsNotNull(transactions, "could not parse entries");
|
||||||
|
Assert.AreEqual(transactions.Count, 1);
|
||||||
|
Assert.AreEqual(Factions.IsPilotsFederation(transactions[0].Faction), true);
|
||||||
|
Assert.AreEqual(transactions[0].TotalSum, 24240000L);
|
||||||
|
Assert.AreEqual(transactions[0].Type, "Combat Bond");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
{ "timestamp":"2022-11-25T09:50:45Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
{ "timestamp":"2022-11-25T09:50:45Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||||
{ "timestamp":"2022-11-25T09:52:28Z", "event":"FactionKillBond", "Reward":24000000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
{ "timestamp":"2022-11-25T09:52:28Z", "event":"FactionKillBond", "Reward":24000000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||||
{ "timestamp":"2022-11-25T09:47:19Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
{ "timestamp":"2022-11-25T09:47:19Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||||
{ "timestamp":"2022-11-25T10:13:53Z", "event":"RedeemVoucher", "Type":"CombatBond", "Amount":24240000, "Faction":"PilotsFederation" }
|
|
||||||
6
EDPlayerJournalTests/ThargoidKillsAndBonds.txt
Normal file
6
EDPlayerJournalTests/ThargoidKillsAndBonds.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{ "timestamp":"2022-11-25T10:10:43Z", "event":"FSDJump", "Taxi":false, "Multicrew":false, "StarSystem":"Nyalayan", "SystemAddress":1458309042898, "StarPos":[29.71875,-172.71875,-6.46875], "SystemAllegiance":"Independent", "SystemEconomy":"$economy_Agri;", "SystemEconomy_Localised":"Agriculture", "SystemSecondEconomy":"$economy_Refinery;", "SystemSecondEconomy_Localised":"Refinery", "SystemGovernment":"$government_Theocracy;", "SystemGovernment_Localised":"Theocracy", "SystemSecurity":"$SYSTEM_SECURITY_medium;", "SystemSecurity_Localised":"Medium Security", "Population":1920608781, "Body":"Nyalayan A", "BodyID":1, "BodyType":"Star", "JumpDist":7.769, "FuelUsed":0.142448, "FuelLevel":15.857553, "Factions":[ { "Name":"Nyalayan Imperial Society", "FactionState":"Election", "Government":"Patronage", "Influence":0.165138, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":17.496799, "ActiveStates":[ { "State":"Election" } ] }, { "Name":"Reret Emperor's Grace", "FactionState":"War", "Government":"Patronage", "Influence":0.257900, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":100.000000, "ActiveStates":[ { "State":"Expansion" }, { "State":"War" } ] }, { "Name":"Nyalayan Silver Transport Org", "FactionState":"None", "Government":"Corporate", "Influence":0.076453, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":81.875000 }, { "Name":"Nyalayan Power & Co", "FactionState":"None", "Government":"Corporate", "Influence":0.060143, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":23.173201 }, { "Name":"Amanogawa Enlight", "FactionState":"War", "Government":"Theocracy", "Influence":0.257900, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":-1.210600, "ActiveStates":[ { "State":"Expansion" }, { "State":"War" } ] }, { "Name":"Nyalayan Crimson Dragons", "FactionState":"None", "Government":"Anarchy", "Influence":0.017329, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":-13.530000 }, { "Name":"Traditional Nyalayan Front", "FactionState":"Election", "Government":"Dictatorship", "Influence":0.165138, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":64.699997, "ActiveStates":[ { "State":"Election" } ] } ], "SystemFaction":{ "Name":"Amanogawa Enlight", "FactionState":"War" }, "Conflicts":[ { "WarType":"election", "Status":"active", "Faction1":{ "Name":"Nyalayan Imperial Society", "Stake":"Pilcher Port", "WonDays":2 }, "Faction2":{ "Name":"Traditional Nyalayan Front", "Stake":"Lamar Falls", "WonDays":0 } }, { "WarType":"war", "Status":"active", "Faction1":{ "Name":"Reret Emperor's Grace", "Stake":"", "WonDays":1 }, "Faction2":{ "Name":"Amanogawa Enlight", "Stake":"Sutter Ring", "WonDays":2 } } ] }
|
||||||
|
{ "timestamp":"2022-11-25T09:50:45Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||||
|
{ "timestamp":"2022-11-25T09:52:28Z", "event":"FactionKillBond", "Reward":24000000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||||
|
{ "timestamp":"2022-11-25T09:47:19Z", "event":"FactionKillBond", "Reward":80000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||||
|
{ "timestamp":"2022-11-25T10:13:32Z", "event":"Docked", "StationName":"Pilcher Port", "StationType":"Orbis", "Taxi":false, "Multicrew":false, "StarSystem":"Nyalayan", "SystemAddress":1458309042898, "MarketID":3222853120, "StationFaction":{ "Name":"Nyalayan Imperial Society", "FactionState":"Election" }, "StationGovernment":"$government_Patronage;", "StationGovernment_Localised":"Patronage", "StationAllegiance":"Empire", "StationServices":[ "dock", "autodock", "commodities", "contacts", "exploration", "missions", "outfitting", "crewlounge", "rearm", "refuel", "repair", "shipyard", "tuning", "engineer", "missionsgenerated", "flightcontroller", "stationoperations", "powerplay", "searchrescue", "stationMenu", "shop", "livery", "socialspace", "bartender", "vistagenomics", "pioneersupplies", "apexinterstellar", "frontlinesolutions" ], "StationEconomy":"$economy_Refinery;", "StationEconomy_Localised":"Refinery", "StationEconomies":[ { "Name":"$economy_Refinery;", "Name_Localised":"Refinery", "Proportion":1.000000 } ], "DistFromStarLS":76.465557, "LandingPads":{ "Small":8, "Medium":11, "Large":6 } }
|
||||||
|
{ "timestamp":"2022-11-25T10:13:53Z", "event":"RedeemVoucher", "Type":"CombatBond", "Amount":24240000, "Faction":"PilotsFederation" }
|
||||||
7
EDPlayerJournalTests/double-vouchers-2.txt
Normal file
7
EDPlayerJournalTests/double-vouchers-2.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{"timestamp":"2024-04-27T13:27:08Z","event":"Fileheader","part":1,"language":"English/UK","Odyssey":true,"gameversion":"4.0.0.1803","build":"r301470/r0 "}
|
||||||
|
{"timestamp":"2024-04-27T13:27:34Z","event":"Commander","FID":"F9183790","Name":"Jeremaya"}
|
||||||
|
{"timestamp":"2024-04-27T15:06:31Z","event":"FSDJump","Taxi":false,"Multicrew":false,"StarSystem":"HIP 3318","SystemAddress":525890177387,"StarPos":[50.21875,-190.6875,37.5],"SystemAllegiance":"Empire","SystemEconomy":"$economy_Refinery;","SystemEconomy_Localised":"Refinery","SystemSecondEconomy":"$economy_Extraction;","SystemSecondEconomy_Localised":"Extraction","SystemGovernment":"$government_Patronage;","SystemGovernment_Localised":"Patronage","SystemSecurity":"$SYSTEM_SECURITY_high;","SystemSecurity_Localised":"High Security","Population":239484,"Body":"HIP 3318 A","BodyID":2,"BodyType":"Star","JumpDist":27.495,"FuelUsed":3.115176,"FuelLevel":13.228082,"Factions":[{"Name":"HIP 3318 Autocracy","FactionState":"None","Government":"Dictatorship","Influence":0.119192,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"Chakho Gold Galactic Limited","FactionState":"None","Government":"Corporate","Influence":0.09798,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"HIP 3318 Interstellar","FactionState":"None","Government":"Corporate","Influence":0.075758,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"HIP 3318 Values Party","FactionState":"None","Government":"Democracy","Influence":0.032323,"Allegiance":"Independent","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"Nationalists of HIP 3318","FactionState":"None","Government":"Dictatorship","Influence":0.035354,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":0.0},{"Name":"Nova Paresa","FactionState":"Boom","Government":"Patronage","Influence":0.434343,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","SquadronFaction":true,"MyReputation":100.0,"PendingStates":[{"State":"Expansion","Trend":0}]},{"Name":"Empire Consulate Ltd","FactionState":"None","Government":"Patronage","Influence":0.20505,"Allegiance":"Empire","Happiness":"$Faction_HappinessBand2;","Happiness_Localised":"Happy","MyReputation":94.474998}],"SystemFaction":{"Name":"Nova Paresa","FactionState":"Boom"}}
|
||||||
|
{"timestamp":"2024-04-27T15:12:23Z","event":"ApproachSettlement","Name":"Koh Biological Installation","MarketID":3803792128,"StationFaction":{"Name":"Nova Paresa","FactionState":"Boom"},"StationGovernment":"$government_Patronage;","StationGovernment_Localised":"Patronage","StationAllegiance":"Empire","StationServices":["dock","autodock","commodities","contacts","exploration","missions","refuel","repair","engineer","missionsgenerated","flightcontroller","stationoperations","searchrescue","stationMenu"],"StationEconomy":"$economy_HighTech;","StationEconomy_Localised":"High Tech","StationEconomies":[{"Name":"$economy_HighTech;","Name_Localised":"High Tech","Proportion":1.0}],"SystemAddress":525890177387,"BodyID":26,"BodyName":"HIP 3318 D 3","Latitude":-0.893061,"Longitude":-62.928345}
|
||||||
|
{"timestamp":"2024-04-27T15:14:08Z","event":"Docked","StationName":"Koh Biological Installation","StationType":"OnFootSettlement","Taxi":false,"Multicrew":false,"StarSystem":"HIP 3318","SystemAddress":525890177387,"MarketID":3803792128,"StationFaction":{"Name":"Nova Paresa","FactionState":"Boom"},"StationGovernment":"$government_Patronage;","StationGovernment_Localised":"Patronage","StationAllegiance":"Empire","StationServices":["dock","autodock","commodities","contacts","exploration","missions","refuel","repair","engineer","missionsgenerated","flightcontroller","stationoperations","searchrescue","stationMenu"],"StationEconomy":"$economy_HighTech;","StationEconomy_Localised":"High Tech","StationEconomies":[{"Name":"$economy_HighTech;","Name_Localised":"High Tech","Proportion":1.0}],"DistFromStarLS":11972.63409,"LandingPads":{"Small":1,"Medium":0,"Large":1}}
|
||||||
|
{"timestamp":"2024-04-27T15:15:10Z","event":"RedeemVoucher","Type":"bounty","Amount":9449329,"Factions":[{"Faction":"Nova Paresa","Amount":9449329}]}
|
||||||
|
{"timestamp":"2024-04-27T15:15:51Z","event":"RedeemVoucher","Type":"bounty","Amount":18780130,"Factions":[{"Faction":"","Amount":224449},{"Faction":"","Amount":730880},{"Faction":"","Amount":1272764},{"Faction":"","Amount":580384},{"Faction":"","Amount":10180261},{"Faction":"","Amount":1413153},{"Faction":"","Amount":1365934},{"Faction":"","Amount":202193},{"Faction":"Nova Paresa","Amount":9449329},{"Faction":"","Amount":104412},{"Faction":"","Amount":2453443},{"Faction":"","Amount":252257}]}
|
||||||
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"}
|
||||||
7
EDPlayerJournalTests/legacy-transaction.txt
Normal file
7
EDPlayerJournalTests/legacy-transaction.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{ "timestamp":"2022-02-06T16:36:53Z", "event":"Fileheader", "part":1, "language":"English/UK", "gameversion":"3.8.0.1102", "build":"r280672/r0 " }
|
||||||
|
{ "timestamp":"2022-02-06T18:10:26Z", "event":"FSDJump", "Taxi":false, "Multicrew":false, "StarSystem":"Akualanu", "SystemAddress":5069805856169, "StarPos":[63.78125,-128.50000,3.00000], "SystemAllegiance":"Empire", "SystemEconomy":"$economy_Tourism;", "SystemEconomy_Localised":"Tourism", "SystemSecondEconomy":"$economy_HighTech;", "SystemSecondEconomy_Localised":"High Tech", "SystemGovernment":"$government_Patronage;", "SystemGovernment_Localised":"Patronage", "SystemSecurity":"$SYSTEM_SECURITY_low;", "SystemSecurity_Localised":"Low Security", "Population":787019, "Body":"Akualanu A", "BodyID":1, "BodyType":"Star", "Powers":[ "A. Lavigny-Duval" ], "PowerplayState":"Exploited", "JumpDist":40.001, "FuelUsed":4.849240, "FuelLevel":22.573641, "Factions":[ { "Name":"Akualanu United & Co", "FactionState":"War", "Government":"Corporate", "Influence":0.158000, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand3;", "Happiness_Localised":"Discontented", "MyReputation":100.000000, "RecoveringStates":[ { "State":"InfrastructureFailure", "Trend":0 } ], "ActiveStates":[ { "State":"Lockdown" }, { "State":"Famine" }, { "State":"War" } ] }, { "Name":"Alacagui Holdings", "FactionState":"War", "Government":"Corporate", "Influence":0.086000, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":55.000000, "RecoveringStates":[ { "State":"PirateAttack", "Trend":0 } ], "ActiveStates":[ { "State":"War" } ] }, { "Name":"Left Party of Akualanu", "FactionState":"War", "Government":"Communism", "Influence":0.086000, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand3;", "Happiness_Localised":"Discontented", "MyReputation":95.899399, "RecoveringStates":[ { "State":"InfrastructureFailure", "Trend":0 } ], "ActiveStates":[ { "State":"Lockdown" }, { "State":"Famine" }, { "State":"War" } ] }, { "Name":"Cartel of Akualanu", "FactionState":"Famine", "Government":"Anarchy", "Influence":0.028000, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand2;", "Happiness_Localised":"Happy", "MyReputation":29.040001, "RecoveringStates":[ { "State":"InfrastructureFailure", "Trend":0 } ], "ActiveStates":[ { "State":"Famine" } ] }, { "Name":"Revolutionary Akualanu Liberals", "FactionState":"Bust", "Government":"Democracy", "Influence":0.085000, "Allegiance":"Independent", "Happiness":"$Faction_HappinessBand3;", "Happiness_Localised":"Discontented", "MyReputation":43.093700, "PendingStates":[ { "State":"Lockdown", "Trend":0 } ], "ActiveStates":[ { "State":"InfrastructureFailure" }, { "State":"Bust" } ] }, { "Name":"Conservatives of Cockaigne", "FactionState":"War", "Government":"Dictatorship", "Influence":0.138000, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand3;", "Happiness_Localised":"Discontented", "MyReputation":70.000000, "ActiveStates":[ { "State":"CivilUnrest" }, { "State":"InfrastructureFailure" }, { "State":"War" } ] }, { "Name":"Nova Paresa", "FactionState":"Investment", "Government":"Patronage", "Influence":0.419000, "Allegiance":"Empire", "Happiness":"$Faction_HappinessBand1;", "Happiness_Localised":"Elated", "SquadronFaction":true, "MyReputation":100.000000, "ActiveStates":[ { "State":"Investment" }, { "State":"CivilLiberty" } ] } ], "SystemFaction":{ "Name":"Nova Paresa", "FactionState":"Investment" }, "Conflicts":[ { "WarType":"war", "Status":"active", "Faction1":{ "Name":"Akualanu United & Co", "Stake":"Konig Institution", "WonDays":0 }, "Faction2":{ "Name":"Conservatives of Cockaigne", "Stake":"", "WonDays":1 } }, { "WarType":"war", "Status":"active", "Faction1":{ "Name":"Alacagui Holdings", "Stake":"Ware Cultivation Facility", "WonDays":2 }, "Faction2":{ "Name":"Left Party of Akualanu", "Stake":"", "WonDays":2 } } ] }
|
||||||
|
{ "timestamp":"2022-02-06T18:13:30Z", "event":"Docked", "StationName":"Hughes Vista", "StationType":"Coriolis", "Taxi":false, "Multicrew":false, "StarSystem":"Akualanu", "SystemAddress":5069805856169, "MarketID":3222969088, "StationFaction":{ "Name":"Nova Paresa", "FactionState":"Investment" }, "StationGovernment":"$government_Patronage;", "StationGovernment_Localised":"Patronage", "StationAllegiance":"Empire", "StationServices":[ "dock", "autodock", "commodities", "contacts", "exploration", "missions", "outfitting", "crewlounge", "rearm", "refuel", "repair", "shipyard", "tuning", "engineer", "missionsgenerated", "facilitator", "flightcontroller", "stationoperations", "powerplay", "searchrescue", "stationMenu", "shop", "livery", "socialspace", "bartender", "vistagenomics", "pioneersupplies", "apexinterstellar", "frontlinesolutions" ], "StationEconomy":"$economy_Tourism;", "StationEconomy_Localised":"Tourism", "StationEconomies":[ { "Name":"$economy_Tourism;", "Name_Localised":"Tourism", "Proportion":1.000000 } ], "DistFromStarLS":78.917615, "LandingPads":{ "Small":13, "Medium":16, "Large":8 } }
|
||||||
|
{ "timestamp":"2022-11-25T09:52:28Z", "event":"FactionKillBond", "Reward":24000000, "AwardingFaction":"$faction_PilotsFederation;", "AwardingFaction_Localised":"Pilots' Federation", "VictimFaction":"$faction_Thargoid;", "VictimFaction_Localised":"Thargoids" }
|
||||||
|
{ "timestamp":"2022-11-21T15:56:08Z", "event":"MarketSell", "MarketID":3222176256, "Type":"silver", "Count":224, "SellPrice":40996, "TotalSale":9183104, "AvgPricePaid":34311 }
|
||||||
|
{ "timestamp":"2022-02-06T16:36:53Z", "event":"Fileheader", "part":1, "language":"English/UK", "Odyssey":true, "gameversion":"4.0.0.1102", "build":"r280672/r0 " }
|
||||||
|
{ "timestamp":"2022-02-06T18:17:44Z", "event":"SellOrganicData", "MarketID":3222969088, "BioData":[ { "Genus":"$Codex_Ent_Stratum_Genus_Name;", "Genus_Localised":"Stratum", "Species":"$Codex_Ent_Stratum_07_Name;", "Species_Localised":"Stratum Tectonicas", "Value":806300, "Bonus":0 }, { "Genus":"$Codex_Ent_Aleoids_Genus_Name;", "Genus_Localised":"Aleoida", "Species":"$Codex_Ent_Aleoids_05_Name;", "Species_Localised":"Aleoida Gravis", "Value":596500, "Bonus":0 } ] }
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<Window x:Class="EliteBGS.AdjustProfitWindow"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:EliteBGS"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="Adjust Trade Profit" Height="130" Width="450">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Label Content="Use this dialog to adjust trade profits" Grid.Row="0" Grid.ColumnSpan="2" />
|
|
||||||
<TextBox x:Name="Profit" Grid.Row="1" Grid.ColumnSpan="2" Margin="10,10,10,10"/>
|
|
||||||
<Button x:Name="Cancel" Content="Cancel" Width="60" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right" Margin="5,0,5,0" IsCancel="true" Click="Cancel_Click"/>
|
|
||||||
<Button x:Name="Accept" Content="Accept" Width="60" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Right" Margin="5,0,5,0" IsDefault="true" Click="Accept_Click" />
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace EliteBGS {
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for AdjustProfitWindow.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class AdjustProfitWindow : Window {
|
|
||||||
public AdjustProfitWindow() {
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Cancel_Click(object sender, RoutedEventArgs e) {
|
|
||||||
DialogResult = false;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Accept_Click(object sender, RoutedEventArgs e) {
|
|
||||||
DialogResult = true;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json",
|
|
||||||
"version": "2.1.0",
|
|
||||||
"runs": [
|
|
||||||
{
|
|
||||||
"tool": {
|
|
||||||
"driver": {
|
|
||||||
"name": "Dependency Analysis",
|
|
||||||
"semanticVersion": "0.4.355802",
|
|
||||||
"informationUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview",
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"id": "UA106",
|
|
||||||
"name": "PackageToBeAdded",
|
|
||||||
"fullDescription": {
|
|
||||||
"text": "Packages that need to be added in order to upgrade the project to chosen TFM"
|
|
||||||
},
|
|
||||||
"helpUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"ruleId": "UA106",
|
|
||||||
"message": {
|
|
||||||
"text": "Package Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers, Version=0.4.355802 needs to be added."
|
|
||||||
},
|
|
||||||
"locations": [
|
|
||||||
{
|
|
||||||
"physicalLocation": {
|
|
||||||
"artifactLocation": {
|
|
||||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
|
||||||
},
|
|
||||||
"region": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ruleId": "UA106",
|
|
||||||
"message": {
|
|
||||||
"text": "Package Microsoft.Windows.Compatibility, Version=7.0.0 needs to be added."
|
|
||||||
},
|
|
||||||
"locations": [
|
|
||||||
{
|
|
||||||
"physicalLocation": {
|
|
||||||
"artifactLocation": {
|
|
||||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
|
||||||
},
|
|
||||||
"region": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"columnKind": "utf16CodeUnits"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tool": {
|
|
||||||
"driver": {
|
|
||||||
"name": "API Upgradability",
|
|
||||||
"semanticVersion": "0.4.355802",
|
|
||||||
"informationUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"results": [],
|
|
||||||
"columnKind": "utf16CodeUnits"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"tool": {
|
|
||||||
"driver": {
|
|
||||||
"name": "Component Analysis",
|
|
||||||
"semanticVersion": "0.4.355802",
|
|
||||||
"informationUri": "https://docs.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview",
|
|
||||||
"rules": [
|
|
||||||
{
|
|
||||||
"id": "UA209",
|
|
||||||
"name": "Microsoft.DotNet.UpgradeAssistant.Extensions.Windows.WinformsDefaultFontUpdater",
|
|
||||||
"fullDescription": {
|
|
||||||
"text": "Default Font API Alert"
|
|
||||||
},
|
|
||||||
"helpUri": "about:blank"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"ruleId": "UA209",
|
|
||||||
"message": {
|
|
||||||
"text": "Default font in Windows Forms has been changed from Microsoft Sans Serif to Seg Segoe UI, in order to change the default font use the API - Application.SetDefaultFont(Font font). For more details see here - https://devblogs.microsoft.com/dotnet/whats-new-in-windows-forms-in-net-6-0-preview-5/#application-wide-default-font."
|
|
||||||
},
|
|
||||||
"locations": [
|
|
||||||
{
|
|
||||||
"physicalLocation": {
|
|
||||||
"artifactLocation": {
|
|
||||||
"uri": "file:///D:/src/EDBGS/EliteBGS/EliteBGS.csproj"
|
|
||||||
},
|
|
||||||
"region": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"columnKind": "utf16CodeUnits"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,14 @@
|
|||||||
xmlns:local="clr-namespace:EliteBGS"
|
xmlns:local="clr-namespace:EliteBGS"
|
||||||
StartupUri="MainWindow.xaml">
|
StartupUri="MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
|
<!-- Theme setting -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Windows;
|
using ControlzEx.Theming;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
namespace EliteBGS {
|
namespace EliteBGS {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
317
EliteBGS/CHANGELOG.md
Normal file
317
EliteBGS/CHANGELOG.md
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
# EliteBGS changelog
|
||||||
|
|
||||||
|
## 0.4.4 on ??.??.202?
|
||||||
|
|
||||||
|
* Add support for Power Conflict Zones
|
||||||
|
* Show no inf as "Zero INF", so the Nova Navy bot can parse it properly
|
||||||
|
* Add support for MeritsGained, but disable it for now, as the player
|
||||||
|
journal is massively lacking in terms of Powerplay 2.0 support.
|
||||||
|
|
||||||
|
## 0.4.3 on 18.09.2024
|
||||||
|
|
||||||
|
* Add possibility to post log reports to Discord webhooks.
|
||||||
|
Logs are automatically split to fit discord length, and you can choose the
|
||||||
|
name of the Commander to post it as. There are some restrictions, so for
|
||||||
|
ultra long logs the one line log format might be necessary.
|
||||||
|
* Fix cartographics data value by igonring `TotalEarnings`. Total earnings
|
||||||
|
is the same as `BaseValue`, except any percentages taken by crew members
|
||||||
|
is deducted. Actual total value is `BaseValue` plus `Bonus`.
|
||||||
|
|
||||||
|
## 0.4.2 on 02.05.2024
|
||||||
|
|
||||||
|
* Add a bot header for all generated logs that shows the tool version, as
|
||||||
|
well as the name of of the log format used. This makes it easier for bots
|
||||||
|
to parse these logs. Since the different formats have become popular, its
|
||||||
|
always good to make it easier for bots to parse the logs.
|
||||||
|
|
||||||
|
## 0.4.1 on 28.04.2024
|
||||||
|
|
||||||
|
* Filter out vouchers that are redeemed twice, due to bulk turn-in. If you
|
||||||
|
redeem a singular voucher for value X, and then redeem the rest of your
|
||||||
|
vouchers - say KWS vouchers - in bulk, the first voucher of value X will
|
||||||
|
appear again in the logs. It appears twice in the logs, but only counts
|
||||||
|
once.
|
||||||
|
* Add the market name to the trading log entries.
|
||||||
|
|
||||||
|
## 0.4.0 on 13.04.2024
|
||||||
|
|
||||||
|
* Change layout of the results into System -> Faction -> Transaction.
|
||||||
|
Many people who contribute *a lot* of things to the BGS have preferred such
|
||||||
|
a layout to find the right things to post to various discord guilds/threads.
|
||||||
|
* Sort all systems in the new overview by name. It just makes them easier to
|
||||||
|
find when there are a lot of entries.
|
||||||
|
* Add a button to deselect/select all buttons.
|
||||||
|
|
||||||
|
## 0.3.7 on 29.01.2024
|
||||||
|
|
||||||
|
* Fix wrong locations of BGS action if you remain on your carrier while its
|
||||||
|
jumping to a new system.
|
||||||
|
* Identify a capital ship in a high CZ by its music.
|
||||||
|
|
||||||
|
## 0.3.6 on 25.10.2023
|
||||||
|
|
||||||
|
* U17 introduced invalid JSON into the player journal. EliteBGS can now skip over
|
||||||
|
those and keep processing. This way players won't have to delete lines in their
|
||||||
|
journals anymore to keep using the tool.
|
||||||
|
* Banshee has been added.
|
||||||
|
|
||||||
|
## 0.3.5 on 11.09.2023
|
||||||
|
|
||||||
|
* Small bounty voucher formats are no longer suppressed.
|
||||||
|
* Glaive has been renamed to "Hunter" since Scythe has the same bounty
|
||||||
|
and they cannot be distinguished.
|
||||||
|
* Mission influence can now also be negative. Failed missions now properly
|
||||||
|
report the amount of negative influence given to a faction.
|
||||||
|
* Mission secondary influences now also support negative influences. This
|
||||||
|
for example happens if you take a mission to murder another faction's
|
||||||
|
civlians, which causes negative INF.
|
||||||
|
|
||||||
|
## 0.3.4 on 18.06.2023
|
||||||
|
|
||||||
|
* Added possibility to specify allied, as well as enemy captain and correspondent.
|
||||||
|
* Added date range, and tool version to standard log format.
|
||||||
|
* Added new English mission names.
|
||||||
|
|
||||||
|
## 0.3.3 on 15.05.2023
|
||||||
|
|
||||||
|
* Added payout for the Thargoid Glaive.
|
||||||
|
* Added payout and support for the Thargoid Revenant.
|
||||||
|
* Added more English mission names.
|
||||||
|
* Ship and AX combat zones can now be detected through a new event, which
|
||||||
|
allows the tool to properly determine the difficulty. Combat zone outcome,
|
||||||
|
additional objectives, or the name of the factions fighting are still guess
|
||||||
|
work however.
|
||||||
|
* Fixed a bug where newly added factions to a system weren't properly
|
||||||
|
recognised. Thanks to Shakaka.
|
||||||
|
* Added option to ignore FleetCarrier actions.
|
||||||
|
* Added an "Open in Explorer" button to journal locations.
|
||||||
|
|
||||||
|
## 0.3.2 on 19.04.2023
|
||||||
|
|
||||||
|
* Orthrus payout has been adapted to 14.02 values.
|
||||||
|
* Old Thargoid payout values have been removed, so very old logs now no
|
||||||
|
longer parse correctly. The old value clashed with new ones, making
|
||||||
|
detection of interceptor kills difficult.
|
||||||
|
* Fixed a problem regarding the proper detection of station owner, and
|
||||||
|
thus for whom the tool attributed market buy and market sell.
|
||||||
|
* Added GUI options to ignore some less important BGS entries.
|
||||||
|
* One line report has changed to show summaries
|
||||||
|
* Summaries have been streamlined:
|
||||||
|
* semi-colons now separate entries
|
||||||
|
* missing BGS actions (like S&R) have received a summary
|
||||||
|
* Trade has been renamed to "Sold" and "Bought"
|
||||||
|
* Sold now shows tons of cargo sold, plus profit if available
|
||||||
|
* Bought shows tons of cargo bought
|
||||||
|
|
||||||
|
## 0.3.1 on 26.02.2023
|
||||||
|
|
||||||
|
* Fixed: AX combat zones caused crashes with the summary.
|
||||||
|
* Fixed: Summaries for thargoid kills didn't render probably.
|
||||||
|
|
||||||
|
## 0.3.0 on 26.02.2023
|
||||||
|
|
||||||
|
* Move to MahApps toolkit, which replaces extended toolkit.
|
||||||
|
* Introduce themes (by MahApps) including dark mode.
|
||||||
|
* Add summary to the two bigger BGS log types.
|
||||||
|
* Remove organic data from BGS tool, as it has been confirmed that
|
||||||
|
it does not contribute to the BGS.
|
||||||
|
* Add a few more English mission names.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
* Make some missions "system related", meaning they are sorted into an objective with just
|
||||||
|
the system name. This makes sense for contributions for towards a system goal, rather than
|
||||||
|
a faction goal - like Thargoid wars.
|
||||||
|
* Fixed a bug about the visibility of war zone side objectives.
|
||||||
|
|
||||||
|
## 0.2.0 on 29.11.2022
|
||||||
|
|
||||||
|
* Moved project to .NET 7.0
|
||||||
|
* Added an experimental combat zone detector. Since there is no dedicated entry in the journal
|
||||||
|
for a combat zone, this code will do a lot of guessing.
|
||||||
|
* Add thargoid kills and thargoid vouchers.
|
||||||
|
* Add a warning if something has been done in E:D Legacy.
|
||||||
|
* Fixed a bug were on foot murders were not properly recognised.
|
||||||
|
* "On Foot" combat zones are now called Ground Combat Zones.
|
||||||
|
* GUI has been reworked, all functions are now near the relevant items.
|
||||||
|
|
||||||
|
## 0.1.7 on 09.11.2022
|
||||||
|
|
||||||
|
* Fixed a bug related to total amount of credits gained by turning in organic data.
|
||||||
|
* Changed UI to have report, and objectives on the same page.
|
||||||
|
* Report now automatically updates when objectives and entries are selected, deselected or removed.
|
||||||
|
* Removed manual adding of objectives.
|
||||||
|
|
||||||
|
## 0.1.6 on 24.09.2022
|
||||||
|
|
||||||
|
* Fixed datetime format.
|
||||||
|
|
||||||
|
## 0.1.5 on 24.08.2022
|
||||||
|
|
||||||
|
* Added some mission names.
|
||||||
|
* Updated README regarding Update 13.
|
||||||
|
|
||||||
|
## 0.1.4 on 24.07.2022
|
||||||
|
|
||||||
|
* Fixed hour display with entires (now in 24 hour format).
|
||||||
|
* Allow adding combat zones regardless of whether an objective is selected, or an
|
||||||
|
entry. If an entry is selected simply use its objective instead.
|
||||||
|
* Add timestamp to combat zone wins.
|
||||||
|
|
||||||
|
## 0.1.3 on 07.06.2022
|
||||||
|
|
||||||
|
* Fixed a bug where entries in non-rated journal files were not properly picked up.
|
||||||
|
* Remove EDDB database usage. This feature could block the tool if it failed to convert
|
||||||
|
the JSON to something more usable, downloads took forever, and the tool itself could
|
||||||
|
run out of memory loading and converting JSON from EDDB. With automatic objective
|
||||||
|
detection this tool is no longer really needed.
|
||||||
|
|
||||||
|
## 0.1.2 on 06.04.2022
|
||||||
|
|
||||||
|
* If you remove an item the tree items stay collapsed/expanded. (thanks CMDR NeedX).
|
||||||
|
* Fixed a bug where the program would crash if you opened the manual log entry
|
||||||
|
window twice (thanks CMDR NeedX).
|
||||||
|
* Fixed a bug regarding organic data not being properly recognised in logs.
|
||||||
|
* Date and time when the entry has been added to the overview.
|
||||||
|
* The actual entry is now semi-bold to distinguish it from the date time.
|
||||||
|
* You can now select which item should appear in the final log, and which shouldn't.
|
||||||
|
|
||||||
|
## 0.1.1 on 15.03.2022
|
||||||
|
|
||||||
|
* Update tool to work with the new journal filenames introduced in Update 11.
|
||||||
|
|
||||||
|
## 0.1.0 on 27.02.2022
|
||||||
|
|
||||||
|
* Final release without beta in front of it.
|
||||||
|
* Several new mission names for the XML.
|
||||||
|
* A few small fixes towards the Discord log formatting.
|
||||||
|
|
||||||
|
## 0.1.0-beta14 on 26.02.2022
|
||||||
|
|
||||||
|
* Missions that give out no influence whatsoever apparently exist. Here the strategy
|
||||||
|
is to add them to the list anyway, and warn the user that this might happen because
|
||||||
|
of conflicts.
|
||||||
|
|
||||||
|
## 0.1.0-beta13 on 24.02.2022
|
||||||
|
|
||||||
|
* Missions that give no influence are now properly shown again. A warning is also
|
||||||
|
displayed on why there is no influence there (spoiler alert: conflicts).
|
||||||
|
* Missions that give influence to an unknown faction are still ignored, but there is
|
||||||
|
now a warning about it.
|
||||||
|
* Added a few new mission names to the XML.
|
||||||
|
|
||||||
|
## 0.1.0-beta12 on 18.02.2022
|
||||||
|
|
||||||
|
* Failed missions now properly show up where they were accepted, instead of where they
|
||||||
|
were failed.
|
||||||
|
|
||||||
|
## 0.1.0-beta11 on 16.02.2022
|
||||||
|
|
||||||
|
* Fixed a bug in which mission influence was assigned to the wrong station, system
|
||||||
|
and faction. But now the log entry for accepting a mission must be within the given
|
||||||
|
range.
|
||||||
|
* Stop complaining about missing objective files.
|
||||||
|
* Add a few more mission names to the XML.
|
||||||
|
|
||||||
|
## 0.1.0-beta10 on 12.02.2022
|
||||||
|
|
||||||
|
* Added search and rescue.
|
||||||
|
* For mourders try to determine the faction of the victim. The CommitCrime event
|
||||||
|
lists the faction that issues the bounty, and not the faction of the victim.
|
||||||
|
* Vouchers are now properly treated. Each individual voucher is assigned a separate
|
||||||
|
objective, if the target faction for said voucher is present in the system.
|
||||||
|
|
||||||
|
## 0.1.0-beta9 on 07.02.2022
|
||||||
|
|
||||||
|
* Added Vista Genomics to the reports.
|
||||||
|
|
||||||
|
## 0.1.0-beta8 on 29.01.2022
|
||||||
|
|
||||||
|
* Fixed a bug where influence was wrongly counted for missions were both the
|
||||||
|
main beneficiary, and the secondary beneficiary are the same faction.
|
||||||
|
* Tightened selection of which entry goes to which objective.
|
||||||
|
|
||||||
|
## 0.1.0-beta7 on 27.01.2022
|
||||||
|
|
||||||
|
* Added murders, since they give negative INF for the target faction.
|
||||||
|
* Cargo is now collated for the NONA discord template.
|
||||||
|
* Empty secondary influences no longer show up.
|
||||||
|
* Market buying is not part of the BGS since Update 10.
|
||||||
|
* Remove decimal point unless absolutely necessary.
|
||||||
|
* Fixed log file template regarding failed missions.
|
||||||
|
* Support missions were the source and target are both the same faction, but in
|
||||||
|
different systems. Here both systems should be listed in the BGS list.
|
||||||
|
|
||||||
|
## 0.1.0-beta6 on 22.01.2022
|
||||||
|
|
||||||
|
* Month names should now always be in English in the NONA log format.
|
||||||
|
* Add influence support (by secondary mission objectives) to the log format.
|
||||||
|
* Remember last used discord log template.
|
||||||
|
* Add support for SellExplorationData journal entry.
|
||||||
|
* Improve credit formatting.
|
||||||
|
|
||||||
|
## 0.1.0-beta5 on 21.01.2022
|
||||||
|
|
||||||
|
* Missions that affect more than one faction now properly show that in the list.
|
||||||
|
* Cargo sold now shows a better name for the commodity (if available in journal).
|
||||||
|
* Added more mission names.
|
||||||
|
* Mission names are now part of an XML file.
|
||||||
|
* Added licence file with GPLv3.
|
||||||
|
|
||||||
|
## 0.1.0-beta4 on 13.01.2022
|
||||||
|
|
||||||
|
* Fixed a bug in date/time selection. It no longer uses the start date as start and end.
|
||||||
|
|
||||||
|
## 0.1.0-beta3 on 12.01.2022
|
||||||
|
|
||||||
|
* Collated failed missions into a single entry with a counter
|
||||||
|
* Added failed missions to Nova Navy log template
|
||||||
|
* Detect trade profit/loss
|
||||||
|
* Allow adjusting trade profit/loss with a new window
|
||||||
|
|
||||||
|
## 0.1.0-beta2 on 09.01.2022
|
||||||
|
|
||||||
|
* Adding combat zones has been repaired
|
||||||
|
|
||||||
|
## 0.1.0-beta1 on 07.01.2022
|
||||||
|
|
||||||
|
* Initial release
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
<Window x:Class="EliteBGS.CombatZoneDialog"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:EliteBGS"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="Add Combat Zone Wins" Height="150" Width="370" Icon="EliteBGS.ico" WindowStartupLocation="CenterOwner">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<GroupBox Header="Add Combat Zone" Grid.Row="0" Grid.Column="0" Width="Auto">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<ComboBox x:Name="type" Grid.Column="0" VerticalAlignment="Top" Width="Auto" IsReadOnly="True" Height="23" Margin="5" SelectedIndex="0">
|
|
||||||
<ComboBoxItem Content="Ship"/>
|
|
||||||
<ComboBoxItem Content="On Foot"/>
|
|
||||||
</ComboBox>
|
|
||||||
<ComboBox x:Name="grade" Grid.Column="1" VerticalAlignment="Top" IsReadOnly="True" Margin="5" Height="23" Width="Auto" SelectedIndex="0">
|
|
||||||
<ComboBoxItem Content="Low"/>
|
|
||||||
<ComboBoxItem Content="Medium"/>
|
|
||||||
<ComboBoxItem Content="High"/>
|
|
||||||
</ComboBox>
|
|
||||||
<TextBox x:Name="amount" Grid.Column="2" Height="23" TextWrapping="Wrap" Text="1" VerticalAlignment="Top" Width="Auto" Margin="5" HorizontalContentAlignment="Right"/>
|
|
||||||
</Grid>
|
|
||||||
</GroupBox>
|
|
||||||
<Grid Grid.Row="1">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Button x:Name="Accept" Content="Accept" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" Width="75" Margin="5" IsDefault="True" Click="Accept_Click"/>
|
|
||||||
<Button x:Name="Cancel" Content="Cancel" HorizontalAlignment="Right" Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" Width="75" Margin="5" IsCancel="True" Click="Cancel_Click"/>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace EliteBGS {
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for CombatZoneDialog.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class CombatZoneDialog : Window {
|
|
||||||
public CombatZoneDialog() {
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Type => (type.SelectedItem as ComboBoxItem).Content.ToString();
|
|
||||||
public string Grade => (grade.SelectedItem as ComboBoxItem).Content.ToString();
|
|
||||||
public int Amount {
|
|
||||||
get {
|
|
||||||
try {
|
|
||||||
return int.Parse(amount.Text);
|
|
||||||
} catch (Exception) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Accept_Click(object sender, RoutedEventArgs e) {
|
|
||||||
DialogResult = true;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Cancel_Click(object sender, RoutedEventArgs e) {
|
|
||||||
DialogResult = false;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,15 +3,16 @@ using System.Linq;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using EliteBGS.LogGenerator;
|
using EliteBGS.LogGenerator;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace EliteBGS;
|
namespace EliteBGS;
|
||||||
|
|
||||||
public class DiscordLogGenerator {
|
public class DiscordLogGenerator {
|
||||||
protected List<LogFormatter> formatters = new List<LogFormatter>() {
|
protected List<LogFormatter> formatters = new List<LogFormatter>() {
|
||||||
new MissionFormat(),
|
new MissionFormat(),
|
||||||
new FailedMissionFormat(),
|
|
||||||
new MurderFormat(),
|
new MurderFormat(),
|
||||||
new VoucherFormat(),
|
new VoucherFormat(),
|
||||||
|
new ThargoidFormatter(),
|
||||||
new CombatZoneFormat(),
|
new CombatZoneFormat(),
|
||||||
new KillBondsFormat(),
|
new KillBondsFormat(),
|
||||||
new CartographicsFormat(),
|
new CartographicsFormat(),
|
||||||
@@ -20,8 +21,69 @@ public class DiscordLogGenerator {
|
|||||||
new CargoSoldFormatter(),
|
new CargoSoldFormatter(),
|
||||||
new VistaGenomicsFormat(),
|
new VistaGenomicsFormat(),
|
||||||
new SearchAndRescueFormat(),
|
new SearchAndRescueFormat(),
|
||||||
|
new MeritsGainedFormat(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected virtual string GetToolVersion() {
|
||||||
|
Version v = Assembly.GetCallingAssembly().GetName().Version;
|
||||||
|
string ver;
|
||||||
|
if (v == null) {
|
||||||
|
ver = "v?.?.?";
|
||||||
|
} else {
|
||||||
|
ver = "v" + v.ToString(3);
|
||||||
|
}
|
||||||
|
return string.Format("EliteBGS {0}", ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual DateTime? GetDateOfEarliestEntry(Objective objective) {
|
||||||
|
var it = objective
|
||||||
|
.Transactions
|
||||||
|
.OrderBy(x => x.CompletedAtDateTime)
|
||||||
|
.FirstOrDefault()
|
||||||
|
;
|
||||||
|
if (it != null) {
|
||||||
|
return it.CompletedAtDateTime;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual DateTime? GetDateOfLatestEntry(Objective objective) {
|
||||||
|
var it = objective
|
||||||
|
.Transactions
|
||||||
|
.OrderByDescending(x => x.CompletedAtDateTime)
|
||||||
|
.FirstOrDefault()
|
||||||
|
;
|
||||||
|
if (it != null) {
|
||||||
|
return it.CompletedAtDateTime;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string GenerateSummary(Objective objective) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (var formatter in formatters) {
|
||||||
|
string summary = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
summary = formatter.GenerateSummary(objective);
|
||||||
|
} catch (NotImplementedException) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(summary)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sb.Length > 0) {
|
||||||
|
sb.Append("; ");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual string GenerateHeader() {
|
protected virtual string GenerateHeader() {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -33,10 +95,38 @@ public class DiscordLogGenerator {
|
|||||||
protected virtual string GenerateObjectiveHeader(Objective objective) {
|
protected virtual string GenerateObjectiveHeader(Objective objective) {
|
||||||
StringBuilder log = new StringBuilder();
|
StringBuilder log = new StringBuilder();
|
||||||
|
|
||||||
log.AppendFormat("**Date:** {0}\n", DateTime.Now.ToString("dd/MM/yyyy"));
|
string location;
|
||||||
log.AppendFormat("**Location:** {0}, {1}\n", objective.System, objective.Faction);
|
|
||||||
log.AppendFormat("**Faction:** {0}\n", objective.Faction);
|
if (!string.IsNullOrEmpty(objective.System) && !string.IsNullOrEmpty(objective.Faction)) {
|
||||||
log.AppendLine("");
|
location = string.Format("{0}, {1}", objective.System, objective.Faction);
|
||||||
|
} else if (!string.IsNullOrEmpty(objective.System)) {
|
||||||
|
location = objective.System;
|
||||||
|
} else {
|
||||||
|
location = "Unknown Location";
|
||||||
|
}
|
||||||
|
|
||||||
|
int legacycount = objective.Transactions
|
||||||
|
.Where(x => x.IsLegacy)
|
||||||
|
.Count()
|
||||||
|
;
|
||||||
|
|
||||||
|
string summary = GenerateSummary(objective);
|
||||||
|
|
||||||
|
var earliest = GetDateOfEarliestEntry(objective);
|
||||||
|
var latest = GetDateOfLatestEntry(objective);
|
||||||
|
if (earliest != null && latest != null) {
|
||||||
|
log.AppendFormat("**Date:** {0} - {1}\n",
|
||||||
|
GetDateOfEarliestEntry(objective),
|
||||||
|
GetDateOfLatestEntry(objective)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
log.AppendFormat("**Target:** {0}\n", location);
|
||||||
|
if (!string.IsNullOrEmpty(summary)) {
|
||||||
|
log.AppendFormat("**Summary:** {0}\n", summary);
|
||||||
|
}
|
||||||
|
if (legacycount > 0) {
|
||||||
|
log.AppendFormat("**Warning:** Some actions were performed on ED Legacy\n");
|
||||||
|
}
|
||||||
log.AppendLine("```");
|
log.AppendLine("```");
|
||||||
|
|
||||||
return log.ToString();
|
return log.ToString();
|
||||||
@@ -46,6 +136,26 @@ public class DiscordLogGenerator {
|
|||||||
return "```\n";
|
return "```\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is called to do final adjustments to the log body of a given objective.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="objective">Objective in question.</param>
|
||||||
|
/// <param name="log">Final log as generated.</param>
|
||||||
|
/// <returns>The transformed log.</returns>
|
||||||
|
protected virtual string TransformFinalLogForObjective(Objective objective, string log) {
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual string Name {
|
||||||
|
get { return "GenericLog"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual string BotHeader() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendFormat("**Bot-Header:** {0}; {1}\n", GetToolVersion(), this.Name);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual string GenerateDiscordLog(Report report) {
|
public virtual string GenerateDiscordLog(Report report) {
|
||||||
StringBuilder log = new StringBuilder();
|
StringBuilder log = new StringBuilder();
|
||||||
|
|
||||||
@@ -61,12 +171,13 @@ public class DiscordLogGenerator {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
log.AppendFormat("{0}\n", GenerateHeader());
|
log.AppendFormat("{0}", BotHeader());
|
||||||
|
log.AppendFormat("{0}", GenerateHeader());
|
||||||
|
|
||||||
foreach (Objective objective in objectives) {
|
foreach (Objective objective in objectives) {
|
||||||
StringBuilder objlog = new StringBuilder();
|
StringBuilder objlog = new StringBuilder();
|
||||||
|
|
||||||
log.AppendFormat("{0}\n", GenerateObjectiveHeader(objective));
|
log.AppendFormat("{0}", GenerateObjectiveHeader(objective));
|
||||||
|
|
||||||
foreach (LogFormatter formatter in formatters) {
|
foreach (LogFormatter formatter in formatters) {
|
||||||
string text = formatter.GenerateLog(objective);
|
string text = formatter.GenerateLog(objective);
|
||||||
@@ -76,13 +187,77 @@ public class DiscordLogGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.AppendFormat("{0}\n", objlog.ToString().Trim());
|
string finallog = objlog.ToString().Trim();
|
||||||
|
finallog = TransformFinalLogForObjective(objective, finallog);
|
||||||
|
|
||||||
log.AppendFormat("{0}\n", GenerateObjectiveFooter(objective));
|
log.AppendFormat("{0}\n", finallog);
|
||||||
|
|
||||||
|
log.AppendFormat("{0}", GenerateObjectiveFooter(objective));
|
||||||
}
|
}
|
||||||
|
|
||||||
log.AppendFormat("{0}\n", GenerateFooter());
|
log.AppendFormat("{0}", GenerateFooter());
|
||||||
|
|
||||||
return log.ToString().Trim();
|
return log.ToString().Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual string[] SplitLog(string log, int maxcount = 2000) {
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string[] SplitLogWithHeader(string log, string header, int maxcount = 2000) {
|
||||||
|
string[] lines = log.Split("\n");
|
||||||
|
List<string> chunks = new();
|
||||||
|
string chunk = string.Empty;
|
||||||
|
|
||||||
|
// Optimisation
|
||||||
|
if (log.Length <= maxcount) {
|
||||||
|
return new string[] { log };
|
||||||
|
}
|
||||||
|
|
||||||
|
// First split the log into its headers
|
||||||
|
// skip first bot header line
|
||||||
|
for (int i = 1; i < lines.Length; i++) {
|
||||||
|
string line = lines[i];
|
||||||
|
|
||||||
|
if (line.StartsWith(header) && !string.IsNullOrEmpty(chunk)) {
|
||||||
|
chunks.Add(chunk.Trim());
|
||||||
|
chunk = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk = chunk + "\n" + line;
|
||||||
|
}
|
||||||
|
|
||||||
|
int curchunk = 0;
|
||||||
|
string botheader = BotHeader().Trim() + "\n";
|
||||||
|
// Leave room for botheader and some leeway
|
||||||
|
int maxlength = (2000 - botheader.Length - 10);
|
||||||
|
|
||||||
|
// Then try to collate chunks
|
||||||
|
for (curchunk = 0; curchunk < chunks.Count; ++curchunk) {
|
||||||
|
int count = chunks[curchunk].Length;
|
||||||
|
while (count < maxlength && (curchunk+1) < chunks.Count) {
|
||||||
|
count += chunks[curchunk + 1].Length + 2;
|
||||||
|
if (count < maxlength) {
|
||||||
|
chunks[curchunk] += "\n";
|
||||||
|
chunks[curchunk] += chunks[curchunk + 1];
|
||||||
|
chunks.RemoveAt(curchunk + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Readd bott headers
|
||||||
|
for (int i = 0; i < chunks.Count; i++) {
|
||||||
|
chunks[i] = chunks[i].Insert(0, botheader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now finally check if any one chunk is bigger than max length
|
||||||
|
for (int i = 0; i < chunks.Count; i++) {
|
||||||
|
if (chunks[i].Length > maxcount) {
|
||||||
|
throw new ApplicationException(
|
||||||
|
string.Format("a chunk turned out bigger than {0}", maxcount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks.ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
32
EliteBGS/DiscordPoster.cs
Normal file
32
EliteBGS/DiscordPoster.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using EliteBGS.Util;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
|
namespace EliteBGS;
|
||||||
|
|
||||||
|
public class DiscordPoster {
|
||||||
|
public static readonly int DiscordLimit = 2000;
|
||||||
|
|
||||||
|
public static void PostToDiscord(DiscordWebhook webhook, string log, string username = "EDBGS") {
|
||||||
|
JsonObject obj = new();
|
||||||
|
obj.Add("content", log);
|
||||||
|
obj.Add("username", username);
|
||||||
|
|
||||||
|
using (var client = new HttpClient()) {
|
||||||
|
var content = new StringContent(obj.ToString(), Encoding.UTF8, "application/json");
|
||||||
|
var response = client.PostAsync(webhook.Webhook, content);
|
||||||
|
if (response == null) {
|
||||||
|
throw new Exception("failed to post content to Discord webhook");
|
||||||
|
}
|
||||||
|
response.Wait();
|
||||||
|
var resp = response.Result;
|
||||||
|
if (!resp.IsSuccessStatusCode) {
|
||||||
|
throw new Exception(string.Format(
|
||||||
|
"failed to post content to webhook {0}: {1} / {2}",
|
||||||
|
webhook.Name, resp.StatusCode, resp.Content.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
|
<Version>0.4.3</Version>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
@@ -11,64 +12,72 @@
|
|||||||
<StartupObject>EliteBGSApplication</StartupObject>
|
<StartupObject>EliteBGSApplication</StartupObject>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ApplicationIcon>EliteBGS.ico</ApplicationIcon>
|
<ApplicationIcon>Salus.ico</ApplicationIcon>
|
||||||
|
<Title>BGS reporting and logging tool for Elite:Dangerous</Title>
|
||||||
|
<Authors>nola</Authors>
|
||||||
|
<Copyright>Copyright 2019 by Florian Stinglmayr</Copyright>
|
||||||
|
<RepositoryUrl>https://codeberg.org/nola/EDBGS</RepositoryUrl>
|
||||||
|
<PackageTags>ED;Elite Dangerous;BGS</PackageTags>
|
||||||
|
<PackageProjectUrl>https://salusinvicta.org/bgstool/</PackageProjectUrl>
|
||||||
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
|
<Description>Elite: Dangerous BGS logging and reporting tool
|
||||||
|
</Description>
|
||||||
|
<PackageIcon>logo_v5.png</PackageIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="EDJournal, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
<None Remove="main-page.png" />
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\edjournal\bin\Debug\EDJournal.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Design" />
|
|
||||||
<Reference Include="System.Security" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="main-page.png">
|
<Resource Include="main-page.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Resource>
|
</Resource>
|
||||||
|
<None Update="logo_v5.png">
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath>\</PackagePath>
|
||||||
|
</None>
|
||||||
<None Update="README.md">
|
<None Update="README.md">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
<Pack>True</Pack>
|
||||||
|
<PackagePath>\</PackagePath>
|
||||||
</None>
|
</None>
|
||||||
<None Update="docs\CHANGELOG.md">
|
<None Update="CHANGELOG.md">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Resource Include="docs\main-page.png">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</Resource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="LICENCE.txt">
|
<Content Include="LICENCE.txt">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="logo_v4.png">
|
<Resource Include="Salus.ico" />
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Resource>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Resource Include="Resources\EliteBGS.ico" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Resource Include="EliteBGS.ico" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
|
||||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
<PackageReference Include="Microsoft.Windows.Compatibility" Version="8.0.4" />
|
||||||
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.355802">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="7.0.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\EDPlayerJournal\EDPlayerJournal.csproj" />
|
<ProjectReference Include="..\EDPlayerJournal\EDPlayerJournal.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="BGS\" />
|
<Compile Update="Resources.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Update="Resources.resx">
|
||||||
|
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Resources\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 200 KiB |
@@ -1,7 +1,18 @@
|
|||||||
namespace EliteBGS;
|
using System.Collections.Generic;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
|
||||||
|
namespace EliteBGS;
|
||||||
|
|
||||||
public class GenericDiscordLog : DiscordLogGenerator {
|
public class GenericDiscordLog : DiscordLogGenerator {
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return "Generic Log";
|
return "Generic";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name {
|
||||||
|
get { return "Generic"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string[] SplitLog(string log, int maxcount = 2000) {
|
||||||
|
return SplitLogWithHeader(log, "**Date:**", maxcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Windows;
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using EDPlayerJournal.Entries;
|
using EDPlayerJournal.Entries;
|
||||||
using EliteBGS.Util;
|
using EliteBGS.Util;
|
||||||
|
using EDPlayerJournal.BGS;
|
||||||
|
|
||||||
namespace EliteBGS;
|
namespace EliteBGS;
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ public partial class LoadEntriesWindow : Window {
|
|||||||
dialog.DefaultExt = ".log";
|
dialog.DefaultExt = ".log";
|
||||||
dialog.Filter = "Log files (*.log)|*.log|All files (*.*)|*";
|
dialog.Filter = "Log files (*.log)|*.log|All files (*.*)|*";
|
||||||
|
|
||||||
var location = config.Global.DefaultJournalLocation;
|
var location = AppConfig.DefaultJournalLocation;
|
||||||
if (Directory.Exists(location)) {
|
if (Directory.Exists(location)) {
|
||||||
dialog.InitialDirectory = location;
|
dialog.InitialDirectory = location;
|
||||||
}
|
}
|
||||||
@@ -85,6 +86,8 @@ public partial class LoadEntriesWindow : Window {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TransactionParser parser = new();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
List<Entry> entries = new List<Entry>();
|
List<Entry> entries = new List<Entry>();
|
||||||
|
|
||||||
@@ -93,7 +96,9 @@ public partial class LoadEntriesWindow : Window {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Entry entry = Entry.Parse(line);
|
Entry entry = Entry.Parse(line);
|
||||||
entries.Add(entry);
|
if (parser.IsRelevant(entry)) {
|
||||||
|
entries.Add(entry);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entries.Count <= 0) {
|
if (entries.Count <= 0) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user