Compare commits
42 Commits
5ea288ee86
...
6cbe54ff73
Author | SHA1 | Date | |
---|---|---|---|
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 |
@ -35,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;
|
||||||
}
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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) {
|
||||||
|
@ -28,6 +28,14 @@ public class TransactionParserOptions {
|
|||||||
/// Whether we should ignore things done for the fleet carrier faction.
|
/// Whether we should ignore things done for the fleet carrier faction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IgnoreFleetCarrierFaction { get; set; } = true;
|
public bool IgnoreFleetCarrierFaction { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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>
|
||||||
|
public bool FilterDoubleRedeemVouchers { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TransactionList : List<Transaction> {
|
public class TransactionList : List<Transaction> {
|
||||||
@ -422,63 +430,6 @@ internal class MissionFailedParser : ITransactionParserPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
transactions.Add(new Vouchers(entry) {
|
|
||||||
System = context.CurrentSystem,
|
|
||||||
Station = context.CurrentStation,
|
|
||||||
Faction = relevantFaction,
|
|
||||||
ControllingFaction = context.ControllingFaction,
|
|
||||||
IsLegacy = context.IsLegacy,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class SellMicroResourcesParser : ITransactionParserPart {
|
internal class SellMicroResourcesParser : ITransactionParserPart {
|
||||||
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
public void Parse(Entry e, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
||||||
SellMicroResourcesEntry? entry = e as SellMicroResourcesEntry;
|
SellMicroResourcesEntry? entry = e as SellMicroResourcesEntry;
|
||||||
@ -651,15 +602,6 @@ internal class DropshipDeployParser : ITransactionParserPart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class CommanderParser : ITransactionParserPart {
|
|
||||||
public void Parse(Entry entry, TransactionParserContext context, TransactionParserOptions options, TransactionList transactions) {
|
|
||||||
// A commander entry happens when you log out, and log back in again
|
|
||||||
// for example when switching from Open, to Solo or PG.
|
|
||||||
context.DiscernCombatZone(transactions, entry);
|
|
||||||
context.ResetCombatZone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TransactionParser {
|
public class TransactionParser {
|
||||||
private static Dictionary<string, ITransactionParserPart> ParserParts { get; } = new()
|
private static Dictionary<string, ITransactionParserPart> ParserParts { get; } = new()
|
||||||
{
|
{
|
||||||
@ -718,6 +660,11 @@ public class TransactionParser {
|
|||||||
return Parse(entries, defaultOptions);
|
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) {
|
public List<Transaction>? Parse(IEnumerable<Entry> entries, TransactionParserOptions options) {
|
||||||
TransactionList transactions = new();
|
TransactionList transactions = new();
|
||||||
TransactionParserContext context = new();
|
TransactionParserContext context = new();
|
||||||
@ -735,6 +682,9 @@ public class TransactionParser {
|
|||||||
transactionParserPart.Parse(entry, context, options, transactions);
|
transactionParserPart.Parse(entry, context, options, transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy out list of commanders seen
|
||||||
|
Commanders = context.Commanders;
|
||||||
|
|
||||||
return transactions.ToList();
|
return transactions.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
namespace EDPlayerJournal.BGS;
|
namespace EDPlayerJournal.BGS;
|
||||||
|
|
||||||
internal class TransactionParserContext {
|
internal class TransactionParserContext {
|
||||||
|
/// <summary>
|
||||||
|
/// List of commander names seen in the logs. May be empty.
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Commanders { get; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name of the current system the player is in.
|
/// Name of the current system the player is in.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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>();
|
||||||
|
|
||||||
|
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}]}
|
@ -1,12 +1,47 @@
|
|||||||
# EliteBGS changelog
|
# EliteBGS changelog
|
||||||
|
|
||||||
# 0.3.7 on 29.01.2024
|
## 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
|
* Fix wrong locations of BGS action if you remain on your carrier while its
|
||||||
jumping to a new system.
|
jumping to a new system.
|
||||||
* Identify a capital ship in a high CZ by its music.
|
* Identify a capital ship in a high CZ by its music.
|
||||||
|
|
||||||
# 0.3.6 on 25.10.2023
|
## 0.3.6 on 25.10.2023
|
||||||
|
|
||||||
* U17 introduced invalid JSON into the player journal. EliteBGS can now skip over
|
* 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
|
those and keep processing. This way players won't have to delete lines in their
|
@ -111,10 +111,6 @@ public class DiscordLogGenerator {
|
|||||||
|
|
||||||
string summary = GenerateSummary(objective);
|
string summary = GenerateSummary(objective);
|
||||||
|
|
||||||
log.AppendFormat("**Log Generated:** {0} by {1}\n",
|
|
||||||
DateTime.Now.ToString("dd/MM/yyyy"),
|
|
||||||
GetToolVersion()
|
|
||||||
);
|
|
||||||
var earliest = GetDateOfEarliestEntry(objective);
|
var earliest = GetDateOfEarliestEntry(objective);
|
||||||
var latest = GetDateOfLatestEntry(objective);
|
var latest = GetDateOfLatestEntry(objective);
|
||||||
if (earliest != null && latest != null) {
|
if (earliest != null && latest != null) {
|
||||||
@ -125,7 +121,7 @@ public class DiscordLogGenerator {
|
|||||||
}
|
}
|
||||||
log.AppendFormat("**Target:** {0}\n", location);
|
log.AppendFormat("**Target:** {0}\n", location);
|
||||||
if (!string.IsNullOrEmpty(summary)) {
|
if (!string.IsNullOrEmpty(summary)) {
|
||||||
log.AppendFormat("**Summary**: {0}\n", summary);
|
log.AppendFormat("**Summary:** {0}\n", summary);
|
||||||
}
|
}
|
||||||
if (legacycount > 0) {
|
if (legacycount > 0) {
|
||||||
log.AppendFormat("**Warning:** Some actions were performed on ED Legacy\n");
|
log.AppendFormat("**Warning:** Some actions were performed on ED Legacy\n");
|
||||||
@ -149,6 +145,16 @@ public class DiscordLogGenerator {
|
|||||||
return 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();
|
||||||
|
|
||||||
@ -164,6 +170,7 @@ public class DiscordLogGenerator {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.AppendFormat("{0}", BotHeader());
|
||||||
log.AppendFormat("{0}", GenerateHeader());
|
log.AppendFormat("{0}", GenerateHeader());
|
||||||
|
|
||||||
foreach (Objective objective in objectives) {
|
foreach (Objective objective in objectives) {
|
||||||
@ -191,4 +198,65 @@ public class DiscordLogGenerator {
|
|||||||
|
|
||||||
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,7 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<Version>0.3.7</Version>
|
<Version>0.4.3</Version>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
@ -18,12 +18,15 @@
|
|||||||
<Copyright>Copyright 2019 by Florian Stinglmayr</Copyright>
|
<Copyright>Copyright 2019 by Florian Stinglmayr</Copyright>
|
||||||
<RepositoryUrl>https://codeberg.org/nola/EDBGS</RepositoryUrl>
|
<RepositoryUrl>https://codeberg.org/nola/EDBGS</RepositoryUrl>
|
||||||
<PackageTags>ED;Elite Dangerous;BGS</PackageTags>
|
<PackageTags>ED;Elite Dangerous;BGS</PackageTags>
|
||||||
<PackageProjectUrl>https://bgs.n0la.org</PackageProjectUrl>
|
<PackageProjectUrl>https://salusinvicta.org/bgstool/</PackageProjectUrl>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<Description>Elite: Dangerous BGS logging and reporting tool
|
<Description>Elite: Dangerous BGS logging and reporting tool
|
||||||
</Description>
|
</Description>
|
||||||
<PackageIcon>logo_v5.png</PackageIcon>
|
<PackageIcon>logo_v5.png</PackageIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="main-page.png" />
|
||||||
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="main-page.png">
|
<Resource Include="main-page.png">
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
@ -37,15 +40,10 @@
|
|||||||
<Pack>True</Pack>
|
<Pack>True</Pack>
|
||||||
<PackagePath>\</PackagePath>
|
<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>
|
||||||
@ -55,12 +53,12 @@
|
|||||||
<Resource Include="Salus.ico" />
|
<Resource Include="Salus.ico" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MahApps.Metro" Version="2.4.9" />
|
<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="Microsoft.Windows.Compatibility" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Windows.Compatibility" Version="8.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
<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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,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;
|
||||||
}
|
}
|
||||||
|
@ -5,75 +5,57 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:EliteBGS"
|
xmlns:local="clr-namespace:EliteBGS"
|
||||||
xmlns:Util="clr-namespace:EliteBGS.Util" d:DataContext="{d:DesignInstance Type=Util:AppConfig}" x:Name="window" x:Class="EliteBGS.MainWindow"
|
xmlns:Util="clr-namespace:EliteBGS.Util"
|
||||||
|
d:DataContext="{d:DesignInstance Type=Util:AppConfig}"
|
||||||
|
x:Name="window"
|
||||||
|
x:Class="EliteBGS.MainWindow"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Elite: Dangerous BGS Helper" Height="520" Width="950" Icon="Salus.ico" Closing="window_Closing">
|
Title="Elite: Dangerous BGS Helper" Height="620" Width="950" Icon="Salus.ico" Closing="window_Closing"
|
||||||
|
>
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
|
<local:MinusFortyFiveConverter x:Key="MinusFortyFiveConverter" />
|
||||||
<Style x:Key="StretchingTreeViewStyle" TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
|
<Style x:Key="StretchingTreeViewStyle" TargetType="TreeViewItem" BasedOn="{StaticResource {x:Type TreeViewItem}}">
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||||
</Style>
|
</Style>
|
||||||
<local:MinusFortyFiveConverter x:Key="MinusFortyFiveConverter" />
|
|
||||||
</Window.Resources>
|
<local:Report x:Key="ObjectivesBasedOnSystem" />
|
||||||
<mah:MetroWindow.RightWindowCommands>
|
<Util:Config x:Key="Config" />
|
||||||
<mah:WindowCommands ShowSeparators="False">
|
|
||||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,5,0">
|
<DataTemplate DataType="{x:Type Util:DiscordWebhook}">
|
||||||
<Hyperlink x:Name="URL" NavigateUri="https://bgs.n0la.org/" RequestNavigate="URL_RequestNavigate">Homepage</Hyperlink>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,15,0">
|
|
||||||
<Hyperlink x:Name="SRC" NavigateUri="https://codeberg.org/nola/EDBGS" RequestNavigate="URL_RequestNavigate">Source</Hyperlink>
|
|
||||||
</TextBlock>
|
|
||||||
<mah:ToggleSwitch Content="Dark Theme" x:Name="SwitchTheme" IsOn="True" Toggled="SwitchTheme_Toggled"/>
|
|
||||||
</mah:WindowCommands>
|
|
||||||
</mah:MetroWindow.RightWindowCommands>
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<TextBlock Text="Name: " Grid.Column="0" Margin="2,0,0,0"/>
|
||||||
<RowDefinition Height="*"/>
|
<TextBox Text="{Binding Name}" Grid.Column="1"/>
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<TabControl Style="{DynamicResource MahApps.Styles.TabControl.Animated}">
|
<TextBlock Text="Webhook URL: " Grid.Column="2" Margin="2,0,0,0"/>
|
||||||
<TabItem Header="Current Objectives">
|
<TextBox Text="{Binding Webhook}" Grid.Column="3"/>
|
||||||
<Grid>
|
</Grid>
|
||||||
<Grid.RowDefinitions>
|
</DataTemplate>
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
<HierarchicalDataTemplate DataType="{x:Type local:SystemObjectives}" ItemsSource="{Binding Path=Objectives}">
|
||||||
<RowDefinition/>
|
<Grid
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<ToolBar VerticalAlignment="Top" Grid.Row="0" Width="Auto" Margin="0,0,0,0" Height="Auto" Grid.ColumnSpan="3" HorizontalAlignment="Left">
|
|
||||||
<Button x:Name="ParseJournal" Content="Parse Journal" VerticalAlignment="Center" Click="ParseJournal_Click" HorizontalAlignment="Center"/>
|
|
||||||
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
|
||||||
<Label Content="From (UTC):" VerticalAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Center"/>
|
|
||||||
<mah:DateTimePicker x:Name="startdate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
|
||||||
<Label Content="To (UTC):" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
|
||||||
<mah:DateTimePicker x:Name="enddate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
|
||||||
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
|
||||||
<Button x:Name="ResetTime" Content="Reset Time" Click="ResetTime_Click" />
|
|
||||||
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
|
||||||
<Button x:Name="ManuallyParse" Content="Manually Parse" Click="ManuallyParse_Click" />
|
|
||||||
</ToolBar>
|
|
||||||
<ToolBar Grid.Row="1" HorizontalAlignment="Left" Height="Auto" VerticalAlignment="Top" Width="Auto" Grid.ColumnSpan="3">
|
|
||||||
<Button x:Name="GenerateDiscord" Content="Generate Discord Report" VerticalAlignment="Stretch" Margin="0,0,0,0" VerticalContentAlignment="Center" Click="GenerateDiscord_Click"/>
|
|
||||||
<Separator />
|
|
||||||
<ComboBox x:Name="LogType" VerticalAlignment="Stretch" Margin="0,3,0,3" Width="140" SelectionChanged="LogType_SelectionChanged" />
|
|
||||||
</ToolBar>
|
|
||||||
<TreeView CheckBox.Checked="TreeView_CheckBox_Updated"
|
|
||||||
CheckBox.Unchecked="TreeView_CheckBox_Updated"
|
|
||||||
x:Name="entries" Margin="0,0,0,0"
|
|
||||||
Grid.ColumnSpan="3" Grid.Row="2"
|
|
||||||
KeyUp="entries_KeyUp"
|
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Stretch"
|
Width="{Binding ActualWidth, ElementName=entries, Converter={StaticResource MinusFortyFiveConverter}}"
|
||||||
>
|
>
|
||||||
<TreeView.ItemTemplate>
|
<Grid.ColumnDefinitions>
|
||||||
<HierarchicalDataTemplate DataType="{x:Type local:Objective}" ItemsSource="{Binding UITransactions}" ItemContainerStyle="{StaticResource StretchingTreeViewStyle}">
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,2,0,2">
|
||||||
|
<CheckBox Focusable="False" IsChecked="{Binding IsEnabled}" VerticalAlignment="Center"/>
|
||||||
|
<TextBlock Text="System: " Margin="2,0,0,0"/>
|
||||||
|
<TextBlock Text="{Binding SystemName}" FontWeight="DemiBold"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</HierarchicalDataTemplate>
|
||||||
|
|
||||||
|
<HierarchicalDataTemplate DataType="{x:Type local:Objective}"
|
||||||
|
ItemsSource="{Binding Path=UITransactions}"
|
||||||
|
ItemContainerStyle="{StaticResource StretchingTreeViewStyle}">
|
||||||
<Grid
|
<Grid
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Width="{Binding ActualWidth, ElementName=entries, Converter={StaticResource MinusFortyFiveConverter}}"
|
Width="{Binding ActualWidth, ElementName=entries, Converter={StaticResource MinusFortyFiveConverter}}"
|
||||||
@ -85,10 +67,8 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,2,0,2">
|
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,2,0,2">
|
||||||
<CheckBox Focusable="False" IsChecked="{Binding IsEnabled}" VerticalAlignment="Center"/>
|
<CheckBox Focusable="False" IsChecked="{Binding IsEnabled}" VerticalAlignment="Center"/>
|
||||||
<TextBlock Text="System: " Visibility="{Binding HasSystem}" Margin="2,0,0,0"/>
|
<TextBlock Text="Faction: " Margin="2,0,0,0"/>
|
||||||
<TextBlock Text="{Binding System}" FontWeight="DemiBold" Visibility="{Binding HasSystem}"/>
|
<TextBlock Text="{Binding Faction}" FontWeight="DemiBold"/>
|
||||||
<TextBlock Text="Faction: " Visibility="{Binding HasFaction}" Margin="2,0,0,0"/>
|
|
||||||
<TextBlock Text="{Binding Faction}" FontWeight="DemiBold" Visibility="{Binding HasFaction}"/>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Separator Visibility="Hidden" Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" />
|
<Separator Visibility="Hidden" Grid.Column="1" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" />
|
||||||
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Orientation="Horizontal">
|
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Orientation="Horizontal">
|
||||||
@ -97,8 +77,9 @@
|
|||||||
<Button x:Name="AddCombatZone" Content="Add Combat Zone" Click="AddCombatZone_Click" />
|
<Button x:Name="AddCombatZone" Content="Add Combat Zone" Click="AddCombatZone_Click" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<HierarchicalDataTemplate.ItemTemplate>
|
</HierarchicalDataTemplate>
|
||||||
<HierarchicalDataTemplate>
|
|
||||||
|
<DataTemplate DataType="{x:Type local:UITransaction}">
|
||||||
<!-- This will stretch out the width of the item-->
|
<!-- This will stretch out the width of the item-->
|
||||||
<Grid Initialized="Transaction_Initialized"
|
<Grid Initialized="Transaction_Initialized"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
@ -148,10 +129,76 @@
|
|||||||
<TextBox x:Name="Profit" MinWidth="80" HorizontalContentAlignment="Right" Text="{Binding Profit, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" LostFocus="Profit_LostFocus" KeyUp="Profit_KeyUp"/>
|
<TextBox x:Name="Profit" MinWidth="80" HorizontalContentAlignment="Right" Text="{Binding Profit, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" LostFocus="Profit_LostFocus" KeyUp="Profit_KeyUp"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</HierarchicalDataTemplate>
|
</DataTemplate>
|
||||||
</HierarchicalDataTemplate.ItemTemplate>
|
|
||||||
</HierarchicalDataTemplate>
|
</Window.Resources>
|
||||||
</TreeView.ItemTemplate>
|
<mah:MetroWindow.RightWindowCommands>
|
||||||
|
<mah:WindowCommands ShowSeparators="False">
|
||||||
|
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,5,0">
|
||||||
|
<Hyperlink x:Name="URL" NavigateUri="https://salusinvicta.org/bgstool/" RequestNavigate="URL_RequestNavigate">Homepage</Hyperlink>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="5,0,15,0">
|
||||||
|
<Hyperlink x:Name="SRC" NavigateUri="https://codeberg.org/nola/EDBGS" RequestNavigate="URL_RequestNavigate">Source</Hyperlink>
|
||||||
|
</TextBlock>
|
||||||
|
<mah:ToggleSwitch Content="Dark Theme" x:Name="SwitchTheme" IsOn="True" Toggled="SwitchTheme_Toggled"/>
|
||||||
|
</mah:WindowCommands>
|
||||||
|
</mah:MetroWindow.RightWindowCommands>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TabControl Style="{DynamicResource MahApps.Styles.TabControl.Animated}">
|
||||||
|
<TabItem Header="Current Objectives">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ToolBar VerticalAlignment="Top" Grid.Row="0" Width="Auto" Margin="0,0,0,0" Height="Auto" Grid.ColumnSpan="3" HorizontalAlignment="Left">
|
||||||
|
<Button x:Name="ParseJournal" Content="Parse Journal" VerticalAlignment="Center" Click="ParseJournal_Click" HorizontalAlignment="Center"/>
|
||||||
|
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
||||||
|
<Label Content="From (UTC):" VerticalAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Center"/>
|
||||||
|
<mah:DateTimePicker x:Name="startdate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||||
|
<Label Content="To (UTC):" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||||
|
<mah:DateTimePicker x:Name="enddate" Height="26.2857142857143" VerticalAlignment="Center" HorizontalAlignment="Center"/>
|
||||||
|
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
||||||
|
<Button x:Name="ResetTime" Content="Reset Time" Click="ResetTime_Click" />
|
||||||
|
<Separator Margin="1" VerticalAlignment="Center" MinWidth="1" HorizontalAlignment="Center" MinHeight="22"/>
|
||||||
|
<Button x:Name="ManuallyParse" Content="Manually Parse" Click="ManuallyParse_Click" />
|
||||||
|
</ToolBar>
|
||||||
|
<ToolBar Grid.Row="1" HorizontalAlignment="Left" Height="Auto" VerticalAlignment="Top" Width="Auto" Grid.ColumnSpan="3">
|
||||||
|
<Button x:Name="GenerateDiscord" Content="Generate Discord Report" VerticalAlignment="Stretch" Margin="0,0,0,0" VerticalContentAlignment="Center" Click="GenerateDiscord_Click"/>
|
||||||
|
<Separator />
|
||||||
|
<ComboBox x:Name="LogType" VerticalAlignment="Stretch" Margin="0,3,0,3" Width="140" SelectionChanged="LogType_SelectionChanged" />
|
||||||
|
<Separator />
|
||||||
|
<CheckBox x:Name="SelectAll" Content="Select All" IsChecked="True" Click="SelectAll_Click"/>
|
||||||
|
<Separator />
|
||||||
|
<Label Content="Post log as" VerticalAlignment="Center" Margin="0,3,0,3" />
|
||||||
|
<ComboBox x:Name="Commanders" VerticalAlignment="Stretch" Margin="0,3,0,3" Width="180" />
|
||||||
|
<Label Content="to" VerticalAlignment="Center" Margin="0,3,0,3" />
|
||||||
|
<mah:DropDownButton x:Name="PostToDiscord" Content="Discord" />
|
||||||
|
</ToolBar>
|
||||||
|
<TreeView CheckBox.Checked="TreeView_CheckBox_Updated"
|
||||||
|
CheckBox.Unchecked="TreeView_CheckBox_Updated"
|
||||||
|
x:Name="entries" Margin="0,0,0,0"
|
||||||
|
Grid.ColumnSpan="3"
|
||||||
|
Grid.Row="2"
|
||||||
|
KeyUp="entries_KeyUp"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
ItemsSource="{Binding Source={StaticResource ObjectivesBasedOnSystem}}"
|
||||||
|
>
|
||||||
<TreeView.ItemContainerStyle>
|
<TreeView.ItemContainerStyle>
|
||||||
<Style TargetType="TreeViewItem">
|
<Style TargetType="TreeViewItem">
|
||||||
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
|
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
|
||||||
@ -168,6 +215,7 @@
|
|||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -223,6 +271,35 @@
|
|||||||
<mah:ToggleSwitch x:Name="NoFleetCarrier" Grid.Row="2" Grid.ColumnSpan="2" Content="Ignore transactions done on a Fleet Carrier" Toggled="NoFleetCarrier_Toggled" />
|
<mah:ToggleSwitch x:Name="NoFleetCarrier" Grid.Row="2" Grid.ColumnSpan="2" Content="Ignore transactions done on a Fleet Carrier" Toggled="NoFleetCarrier_Toggled" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
<GroupBox Header="Discord Webhooks" Grid.Row="3" VerticalAlignment="Top" Width="Auto" Grid.ColumnSpan="3" Margin="0,5,0,0">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<DataGrid x:Name="Webhooks"
|
||||||
|
Grid.Row="0"
|
||||||
|
ItemsSource="{Binding Webhooks}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
ScrollViewer.CanContentScroll="True"
|
||||||
|
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||||
|
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||||
|
MaxHeight="100"
|
||||||
|
MinHeight="100"
|
||||||
|
KeyUp="Webhooks_KeyUp"
|
||||||
|
CellEditEnding="Webhooks_CellEditEnding"
|
||||||
|
>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
|
||||||
|
<DataGridTextColumn Header="Webhook URL" Binding="{Binding Webhook}" Width="*"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Left" Margin="5,10,5,0">
|
||||||
|
<Button x:Name="AddWebHook" Content="Add" Click="AddWebHook_Click"/>
|
||||||
|
<Button x:Name="RemoveWebHook" Content="Remove" Click="RemoveWebHook_Click" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Header="Event Log">
|
<TabItem Header="Event Log">
|
||||||
|
@ -32,8 +32,8 @@ public partial class MainWindow : MetroWindow {
|
|||||||
private LoadEntriesWindow loadentries = null;
|
private LoadEntriesWindow loadentries = null;
|
||||||
|
|
||||||
private static readonly List<DiscordLogGenerator> logtypes = new List<DiscordLogGenerator>() {
|
private static readonly List<DiscordLogGenerator> logtypes = new List<DiscordLogGenerator>() {
|
||||||
new NonaDiscordLog(),
|
|
||||||
new GenericDiscordLog(),
|
new GenericDiscordLog(),
|
||||||
|
new NonaDiscordLog(),
|
||||||
new OneLineDiscordLog(),
|
new OneLineDiscordLog(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -46,6 +46,9 @@ public partial class MainWindow : MetroWindow {
|
|||||||
/* ignored */
|
/* ignored */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Webhooks.ItemsSource = Config.Global.Webhooks;
|
||||||
|
RefreshPostMenu();
|
||||||
|
|
||||||
foreach (DiscordLogGenerator type in logtypes) {
|
foreach (DiscordLogGenerator type in logtypes) {
|
||||||
LogType.Items.Add(type);
|
LogType.Items.Add(type);
|
||||||
}
|
}
|
||||||
@ -107,6 +110,10 @@ public partial class MainWindow : MetroWindow {
|
|||||||
//{ "HouseSalus", Color.FromRgb(0xBC, 0x94, 0x39) },
|
//{ "HouseSalus", Color.FromRgb(0xBC, 0x94, 0x39) },
|
||||||
{ "HouseSalus", Color.FromRgb(0xED, 0xDA, 0x70) },
|
{ "HouseSalus", Color.FromRgb(0xED, 0xDA, 0x70) },
|
||||||
{ "NovaNavy", Color.FromRgb(0xA1, 0xA4, 0xDB) },
|
{ "NovaNavy", Color.FromRgb(0xA1, 0xA4, 0xDB) },
|
||||||
|
// Official Red of the Polish Flag
|
||||||
|
{ "PolskaGurom", Color.FromRgb(0xD4, 0x21, 0x3D) },
|
||||||
|
// Official Blue in the Armenian Flag
|
||||||
|
{ "ArmeniaBlue", Color.FromRgb(0x00, 0x33, 0xA0) },
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var colourtheme in colorThemes) {
|
foreach (var colourtheme in colorThemes) {
|
||||||
@ -178,6 +185,11 @@ public partial class MainWindow : MetroWindow {
|
|||||||
|
|
||||||
List<Transaction> transactions = parser.Parse(entries, options);
|
List<Transaction> transactions = parser.Parse(entries, options);
|
||||||
|
|
||||||
|
Commanders.ItemsSource = parser.Commanders;
|
||||||
|
if (Commanders.Items.Count > 0) {
|
||||||
|
Commanders.SelectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Filter the transactions down to the given time frame
|
// Filter the transactions down to the given time frame
|
||||||
transactions = transactions
|
transactions = transactions
|
||||||
.Where(t => t.CompletedAtDateTime >= start && t.CompletedAtDateTime <= end)
|
.Where(t => t.CompletedAtDateTime >= start && t.CompletedAtDateTime <= end)
|
||||||
@ -192,7 +204,7 @@ public partial class MainWindow : MetroWindow {
|
|||||||
transactions.RemoveAll(x => incompletes.Contains(x));
|
transactions.RemoveAll(x => incompletes.Contains(x));
|
||||||
|
|
||||||
report = new Report(transactions);
|
report = new Report(transactions);
|
||||||
this.entries.ItemsSource = report.Objectives;
|
this.entries.ItemsSource = report.SystemObjectives;
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
Log("Something went terribly wrong while parsing the E:D player journal.");
|
Log("Something went terribly wrong while parsing the E:D player journal.");
|
||||||
Log("Please send this to CMDR Hekateh:");
|
Log("Please send this to CMDR Hekateh:");
|
||||||
@ -271,15 +283,27 @@ public partial class MainWindow : MetroWindow {
|
|||||||
object obj = entries.SelectedItem;
|
object obj = entries.SelectedItem;
|
||||||
bool removed = false;
|
bool removed = false;
|
||||||
|
|
||||||
if (obj.GetType() == typeof(Objective)) {
|
if (obj.GetType() == typeof(SystemObjectives)) {
|
||||||
removed = report.Objectives.Remove(obj as Objective);
|
removed = report.SystemObjectives.Remove(obj as SystemObjectives);
|
||||||
} else if (obj.GetType() == typeof(UITransaction) ||
|
} else if (obj.GetType() == typeof(Objective)) {
|
||||||
obj.GetType().IsSubclassOf(typeof(UITransaction))) {
|
report
|
||||||
foreach (Objective parent in report.Objectives) {
|
.SystemObjectives
|
||||||
if (parent.UITransactions.Remove(obj as UITransaction)) {
|
.ForEach(x => {
|
||||||
|
if (x.Objectives.Remove(obj as Objective)) {
|
||||||
removed = true;
|
removed = true;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
} else if (obj.GetType() == typeof(UITransaction) ||
|
||||||
|
obj.GetType().IsSubclassOf(typeof(UITransaction))) {
|
||||||
|
report
|
||||||
|
.SystemObjectives
|
||||||
|
.SelectMany(x =>
|
||||||
|
x.Objectives
|
||||||
|
.Where(x => x.UITransactions.Contains(obj as UITransaction))
|
||||||
|
)
|
||||||
|
.ToList()
|
||||||
|
.ForEach(x => removed = x.UITransactions.Remove(obj as UITransaction))
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (removed) {
|
if (removed) {
|
||||||
@ -557,4 +581,136 @@ public partial class MainWindow : MetroWindow {
|
|||||||
} catch (Exception) {
|
} catch (Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SelectAll_Click(object sender, RoutedEventArgs e) {
|
||||||
|
if (report == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
report.SystemObjectives.ForEach(t => { t.IsEnabled = (bool)SelectAll.IsChecked; });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddWebHook_Click(object sender, RoutedEventArgs e) {
|
||||||
|
Config.Global.Webhooks.Add(new DiscordWebhook {
|
||||||
|
Name = "Discord Server Name",
|
||||||
|
Webhook = "..."
|
||||||
|
});
|
||||||
|
Webhooks.Items.Refresh();
|
||||||
|
RefreshPostMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveWebHook_Click(object sender, RoutedEventArgs e) {
|
||||||
|
if (Webhooks.SelectedItems.Count <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selection = Webhooks.SelectedItems
|
||||||
|
.OfType<DiscordWebhook>()
|
||||||
|
.ToList()
|
||||||
|
;
|
||||||
|
foreach (var item in selection) {
|
||||||
|
Config.Global.Webhooks.Remove(item);
|
||||||
|
}
|
||||||
|
Webhooks.Items.Refresh();
|
||||||
|
RefreshPostMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Webhooks_KeyUp(object sender, KeyEventArgs e) {
|
||||||
|
DataGridCell cell = e.OriginalSource as DataGridCell;
|
||||||
|
/* We also get keypresses from DataGridCells that are currently
|
||||||
|
* editing their content. Filter those out. We don't want to delete
|
||||||
|
* the row when the user presses DEL while editing the cells content
|
||||||
|
*/
|
||||||
|
if (cell == null || cell.IsEditing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e.Key == Key.Delete) {
|
||||||
|
RemoveWebHook_Click(this, new RoutedEventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Webhooks_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) {
|
||||||
|
try {
|
||||||
|
Config.SaveGlobal();
|
||||||
|
} catch (Exception) { }
|
||||||
|
e.Cancel = false;
|
||||||
|
RefreshPostMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshPostMenu() {
|
||||||
|
MenuItem menu;
|
||||||
|
PostToDiscord.Items.Clear();
|
||||||
|
if (Config.Global.Webhooks.Count <= 0) {
|
||||||
|
PostToDiscord.IsEnabled = false;
|
||||||
|
} else {
|
||||||
|
PostToDiscord.IsEnabled = true;
|
||||||
|
foreach (var item in Config.Global.Webhooks) {
|
||||||
|
menu = new MenuItem();
|
||||||
|
menu.Header = item.Name;
|
||||||
|
menu.Click += DiscordWebhook_Click;
|
||||||
|
PostToDiscord.Items.Add(menu);
|
||||||
|
}
|
||||||
|
PostToDiscord.Items.Add(new Separator());
|
||||||
|
|
||||||
|
menu = new MenuItem();
|
||||||
|
menu.Header = "All";
|
||||||
|
menu.Click += PostToAll_Click;
|
||||||
|
PostToDiscord.Items.Add(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PostToDiscordWebhook(IEnumerable<DiscordWebhook> hooks) {
|
||||||
|
if (string.IsNullOrEmpty(DiscordLog.Text)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DiscordLogGenerator discord = LogType.SelectedItem as DiscordLogGenerator;
|
||||||
|
string[] chunks;
|
||||||
|
|
||||||
|
try {
|
||||||
|
chunks = discord.SplitLog(DiscordLog.Text);
|
||||||
|
} catch (Exception) {
|
||||||
|
MessageBox.Show(
|
||||||
|
"The log could not be split into discord appropriate length.\n" +
|
||||||
|
"This happens with the bigger logs formats if you do lots of things in one system.\n" +
|
||||||
|
"Try posting the log in the OneLine format.",
|
||||||
|
"Sorry!", MessageBoxButton.OK, MessageBoxImage.Error
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string commander = "EDBGS";
|
||||||
|
if (Commanders.SelectedIndex >= 0) {
|
||||||
|
commander = Commanders.SelectedItem.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var hook in hooks) {
|
||||||
|
try {
|
||||||
|
foreach (var chunk in chunks) {
|
||||||
|
DiscordPoster.PostToDiscord(hook, chunk, commander);
|
||||||
|
}
|
||||||
|
Log(string.Format("successfully posted to discord webhook `{0}`", hook.Name));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log(string.Format("failed to post to discord webhook `{0}`: {1}",
|
||||||
|
hook.Name, ex.Message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DiscordWebhook_Click(object sender, RoutedEventArgs e) {
|
||||||
|
MenuItem item = sender as MenuItem;
|
||||||
|
if (item == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DiscordWebhook hook = Config.Global.Webhooks
|
||||||
|
.Find(x => string.Compare(x.Name, item.Header.ToString()) == 0)
|
||||||
|
;
|
||||||
|
if (hook == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PostToDiscordWebhook(new DiscordWebhook[] { hook });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PostToAll_Click(object sender, RoutedEventArgs e) {
|
||||||
|
PostToDiscordWebhook(Config.Global.Webhooks);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ public class MinusFortyFiveConverter : IValueConverter {
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public object Convert(
|
public object Convert(
|
||||||
object value, Type targetType, object parameter, CultureInfo culture) {
|
object value, Type targetType, object parameter, CultureInfo culture) {
|
||||||
return (double)value - 80;
|
return (double)value - 110;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
@ -7,6 +7,12 @@ using System.Linq;
|
|||||||
namespace EliteBGS.BGS;
|
namespace EliteBGS.BGS;
|
||||||
|
|
||||||
public class NonaDiscordLog : DiscordLogGenerator {
|
public class NonaDiscordLog : DiscordLogGenerator {
|
||||||
|
protected override string BotHeader() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendFormat(":robot: `Bot-Header:` {0}; {1}\n", GetToolVersion(), this.Name);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
private string FormatDate() {
|
private string FormatDate() {
|
||||||
CultureInfo cultureInfo = CultureInfo.InvariantCulture;
|
CultureInfo cultureInfo = CultureInfo.InvariantCulture;
|
||||||
StringBuilder date = new StringBuilder();
|
StringBuilder date = new StringBuilder();
|
||||||
@ -79,6 +85,14 @@ public class NonaDiscordLog : DiscordLogGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return "Nova Navy Log";
|
return "Nova Navy";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name {
|
||||||
|
get { return "NovaNavy"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string[] SplitLog(string log, int maxcount = 2000) {
|
||||||
|
return SplitLogWithHeader(log, ":clock2: `Date:`", maxcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ public class UITransaction : INotifyPropertyChanged {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class Objective : IComparable<Objective> {
|
public class Objective : IComparable<Objective> {
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; } = true;
|
||||||
|
|
||||||
public List<UITransaction> UITransactions { get; } = new List<UITransaction>();
|
public List<UITransaction> UITransactions { get; } = new List<UITransaction>();
|
||||||
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
using EliteBGS.LogGenerator;
|
using EliteBGS.LogGenerator;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
|
||||||
namespace EliteBGS;
|
namespace EliteBGS;
|
||||||
|
|
||||||
@ -25,6 +28,30 @@ public class OneLineDiscordLog : DiscordLogGenerator {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string[] SplitLog(string log, 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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < lines.Length; i++) {
|
||||||
|
string line = lines[i];
|
||||||
|
if ((chunk.Length + line.Length) > maxcount || i == lines.Length - 1) {
|
||||||
|
chunks.Add(chunk.Trim());
|
||||||
|
chunk = string.Empty;
|
||||||
|
chunk = chunk.Insert(0, BotHeader()).Trim();
|
||||||
|
} else {
|
||||||
|
chunk = chunk + "\n" + line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunks.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
public override string GenerateDiscordLog(Report report) {
|
public override string GenerateDiscordLog(Report report) {
|
||||||
StringBuilder log = new StringBuilder();
|
StringBuilder log = new StringBuilder();
|
||||||
|
|
||||||
@ -40,6 +67,8 @@ public class OneLineDiscordLog : DiscordLogGenerator {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.AppendFormat("{0}", BotHeader());
|
||||||
|
|
||||||
foreach (Objective objective in objectives) {
|
foreach (Objective objective in objectives) {
|
||||||
log.AppendFormat("{0}", GenerateObjectiveHeader(objective));
|
log.AppendFormat("{0}", GenerateObjectiveHeader(objective));
|
||||||
|
|
||||||
@ -60,6 +89,10 @@ public class OneLineDiscordLog : DiscordLogGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return "One Line Report";
|
return "One Line";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Name {
|
||||||
|
get { return "OneLine"; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,5 +49,5 @@ using System.Windows;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.3.7.0")]
|
[assembly: AssemblyVersion("0.4.3.0")]
|
||||||
[assembly: AssemblyFileVersion("0.3.7.0")]
|
[assembly: AssemblyFileVersion("0.4.3.0")]
|
||||||
|
@ -7,7 +7,7 @@ been parsed, you may then generate a BGS report you can copy/paste into Discord.
|
|||||||
|
|
||||||
Source code is available at [https://codeberg.org/nola/edbgs](https://codeberg.org/nola/edbgs).
|
Source code is available at [https://codeberg.org/nola/edbgs](https://codeberg.org/nola/edbgs).
|
||||||
|
|
||||||
Binary downloads can be found here: [https://bgs.n0la.org/](https://bgs.n0la.org/).
|
Binary downloads can be found here: [https://salusinvicta.org/bgstool/](https://salusinvicta.org/bgstool/).
|
||||||
|
|
||||||
## How To
|
## How To
|
||||||
|
|
||||||
|
@ -1,10 +1,38 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
using EDPlayerJournal.BGS;
|
using EDPlayerJournal.BGS;
|
||||||
|
|
||||||
namespace EliteBGS;
|
namespace EliteBGS;
|
||||||
|
|
||||||
|
public class SystemObjectives : INotifyPropertyChanged, IComparable<SystemObjectives> {
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
private bool isenabled = true;
|
||||||
|
|
||||||
|
public bool IsEnabled {
|
||||||
|
get { return isenabled; }
|
||||||
|
set {
|
||||||
|
isenabled = value;
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsEnabled"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsExpanded { get; set; } = false;
|
||||||
|
|
||||||
|
public string SystemName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public List<Objective> Objectives { get; set; } = new();
|
||||||
|
|
||||||
|
public int CompareTo(SystemObjectives other) {
|
||||||
|
if (other == null) return 1;
|
||||||
|
return string.Compare(SystemName, other.SystemName, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class Report {
|
public class Report {
|
||||||
public List<Objective> Objectives { get; set; } = new List<Objective>();
|
public List<SystemObjectives> SystemObjectives { get; set; } = new();
|
||||||
|
|
||||||
public Report() { }
|
public Report() { }
|
||||||
|
|
||||||
@ -12,29 +40,35 @@ public class Report {
|
|||||||
Populate(transactions);
|
Populate(transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Objective> Objectives {
|
||||||
|
get {
|
||||||
|
return SystemObjectives
|
||||||
|
.Where(t => t.IsEnabled)
|
||||||
|
.SelectMany(x => x.Objectives)
|
||||||
|
.ToList()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Populate(List<Transaction> transactions) {
|
private void Populate(List<Transaction> transactions) {
|
||||||
if (transactions == null || transactions.Count == 0) {
|
if (transactions == null || transactions.Count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Transaction t in transactions) {
|
foreach (Transaction t in transactions) {
|
||||||
Objective o;
|
var o = SystemObjectives.Find(x => string.Compare(x.SystemName, t.System) == 0);
|
||||||
if (t.SystemContribution) {
|
|
||||||
o = Objectives.Find(x => x.Matches(t.System));
|
|
||||||
} else {
|
|
||||||
o = Objectives.Find(x => x.Matches(t.System, t.Faction));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (o == null) {
|
if (o == null) {
|
||||||
if (t.SystemContribution) {
|
o = new SystemObjectives() { SystemName = t.System };
|
||||||
o = new Objective() { System = t.System };
|
SystemObjectives.Add(o);
|
||||||
} else {
|
|
||||||
o = new Objective() { Faction = t.Faction, System = t.System };
|
|
||||||
}
|
}
|
||||||
Objectives.Add(o);
|
var objective = o.Objectives.Find(x => x.Matches(t.System, t.Faction));
|
||||||
|
if (objective == null) {
|
||||||
|
objective = new Objective() { Faction = t.Faction, System = t.System };
|
||||||
|
o.Objectives.Add(objective);
|
||||||
|
}
|
||||||
|
objective.UITransactions.Add(new UITransaction(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
o.UITransactions.Add(new UITransaction(t));
|
SystemObjectives.Sort();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace EliteBGS.Util {
|
namespace EliteBGS.Util;
|
||||||
public class AppConfig {
|
|
||||||
|
public class AppConfig {
|
||||||
private static readonly string default_journal_location = "%UserProfile%\\Saved Games\\Frontier Developments\\Elite Dangerous";
|
private static readonly string default_journal_location = "%UserProfile%\\Saved Games\\Frontier Developments\\Elite Dangerous";
|
||||||
private string journal_location = default_journal_location;
|
private string journal_location = default_journal_location;
|
||||||
public string DefaultJournalLocation => default_journal_location;
|
|
||||||
private string colour = "Amber";
|
private string colour = "Amber";
|
||||||
private string theme = "Dark";
|
private string theme = "Dark";
|
||||||
|
|
||||||
|
public static string DefaultJournalLocation => default_journal_location;
|
||||||
|
|
||||||
public string LastUsedDiscordTemplate { get; set; }
|
public string LastUsedDiscordTemplate { get; set; }
|
||||||
|
|
||||||
public string JournalLocation {
|
public string JournalLocation {
|
||||||
@ -63,9 +67,13 @@ namespace EliteBGS.Util {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IgnoreFleetCarrier { get; set; } = true;
|
public bool IgnoreFleetCarrier { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of Webhooks configured
|
||||||
|
/// </summary>
|
||||||
|
public List<DiscordWebhook> Webhooks { get; set; } = new List<DiscordWebhook>();
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string FullTheme {
|
public string FullTheme {
|
||||||
get { return Theme + "." + Colour; }
|
get { return Theme + "." + Colour; }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace EliteBGS.Util {
|
namespace EliteBGS.Util {
|
||||||
public class Config {
|
public class Config {
|
||||||
|
13
EliteBGS/Util/DiscordWebhook.cs
Normal file
13
EliteBGS/Util/DiscordWebhook.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace EliteBGS.Util;
|
||||||
|
|
||||||
|
public class DiscordWebhook {
|
||||||
|
/// <summary>
|
||||||
|
/// Webhook URL
|
||||||
|
/// </summary>
|
||||||
|
public string Webhook { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Human readable name for easier identification
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
BIN
EliteBGS/combatzone.png
Normal file
BIN
EliteBGS/combatzone.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 75 KiB |
Binary file not shown.
Before Width: | Height: | Size: 68 KiB |
@ -26,7 +26,7 @@ You can download the **latest** version **0.3.7** at CodeBerg:
|
|||||||
|
|
||||||
Or alternatively from my server:
|
Or alternatively from my server:
|
||||||
|
|
||||||
* [https://bgs.n0la.org/elitebgs-0.3.6.zip](https://bgs.n0la.org/elitebgs-0.3.7.zip)
|
* [https://bgs.n0la.org/elitebgs-0.3.7.zip](https://bgs.n0la.org/elitebgs-0.3.7.zip)
|
||||||
|
|
||||||
## Old Versions
|
## Old Versions
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 67 KiB |
Binary file not shown.
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 74 KiB |
@ -1,15 +0,0 @@
|
|||||||
site_name: EliteBGS
|
|
||||||
|
|
||||||
markdown_extensions:
|
|
||||||
- pymdownx.snippets:
|
|
||||||
check_paths: true
|
|
||||||
|
|
||||||
theme:
|
|
||||||
name: lumen
|
|
||||||
|
|
||||||
nav:
|
|
||||||
- Overview: 'index.md'
|
|
||||||
- "Detailed Description": 'description.md'
|
|
||||||
- "Combat Zones": 'combatzones.md'
|
|
||||||
- FAQ: 'faq.md'
|
|
||||||
- Changelog: 'CHANGELOG.md'
|
|
@ -3,7 +3,7 @@
|
|||||||
EDBGS is a project containing the EliteBGS BGS application. It also contains the dotnet
|
EDBGS is a project containing the EliteBGS BGS application. It also contains the dotnet
|
||||||
class library EDPlayerJournal, which reads and parses Elite Dangerous player journals.
|
class library EDPlayerJournal, which reads and parses Elite Dangerous player journals.
|
||||||
|
|
||||||
See [https://bgs.n0la.org/](https://bgs.n0la.org) for further details.
|
See [https://salusinvicta.org/bgstool/](https://salusinvicta.org/bgstool/) for further details.
|
||||||
|
|
||||||
The tool helps with creating BGS reports for squadrons that support factions in
|
The tool helps with creating BGS reports for squadrons that support factions in
|
||||||
Elite: Dangerous that can be copy and pasted into a Discord server. It finds all BGS
|
Elite: Dangerous that can be copy and pasted into a Discord server. It finds all BGS
|
||||||
|
Loading…
Reference in New Issue
Block a user