@@ -30,20 +30,50 @@ public class Program {
3030 [ DllImport ( "shell32.dll" ) ]
3131 extern static int SHGetKnownFolderPath ( [ MarshalAs ( UnmanagedType . LPStruct ) ] Guid folderId , uint flags , IntPtr token , [ MarshalAs ( UnmanagedType . LPWStr ) ] out string pszPath ) ;
3232
33+ [ DllImport ( "kernel32.dll" , SetLastError = true ) ]
34+ static extern uint GetConsoleProcessList ( uint [ ] processList , uint processCount ) ;
35+ // https://stackoverflow.com/a/50244207
36+ // https://devblogs.microsoft.com/oldnewthing/20160125-00/?p=92922
37+ private static bool ConsoleWillBeDestroyed ( ) {
38+ var processList = new uint [ 1 ] ;
39+ var processCount = GetConsoleProcessList ( processList , 1 ) ;
40+ return processCount == 1 ;
41+ }
42+
3343 public static void Main ( string [ ] args ) {
44+ Console . Title = "Thargoid Combat Statistics" ;
3445 if ( SHGetKnownFolderPath ( SavedGames , 0 , IntPtr . Zero , out string path ) != 0 ) {
3546 throw new DirectoryNotFoundException ( "Saved Games folder not found" ) ;
3647 }
3748 string logs = Path . GetFullPath ( Path . Combine ( path , "Frontier Developments/Elite Dangerous" ) ) ;
3849
39- var counts = Enum . GetValues < ThargoidRewards > ( ) . ToDictionary < ThargoidRewards , ThargoidRewards , uint > ( s => s , s => 0 ) ;
40- int missionRewards = 0 ;
41-
50+ Cache state = new Cache ( ) ;
51+ string cachePath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , System . Reflection . Assembly . GetExecutingAssembly ( ) . GetName ( ) . Name + ".json" ) ;
52+ if ( File . Exists ( cachePath ) ) {
53+ try {
54+ var json = File . ReadAllText ( cachePath ) ;
55+ state = JsonSerializer . Deserialize < Cache > ( json ) ;
56+ }
57+ catch ( UnauthorizedAccessException e ) {
58+ Console . Error . WriteLine ( "Unable to read cache from {0}" , cachePath ) ;
59+ }
60+ }
61+ DateTimeOffset curr = DateTimeOffset . MinValue ;
62+
4263 foreach ( var log in Directory . GetFiles ( logs , "Journal.*.log" ) . OrderBy ( s => s ) ) {
64+ Console . SetCursorPosition ( 0 , Console . CursorTop ) ;
65+
66+ var ts = log . Split ( '.' ) . Skip ( 1 ) . First ( ) ;
67+ // Journal.200619124437.01.log
68+ curr = DateTimeOffset . ParseExact ( ts , "yyMMddHHmmss" , System . Globalization . CultureInfo . InvariantCulture . DateTimeFormat ) ;
69+ if ( curr <= state . Last ) {
70+ Console . Write ( "Skipping " + log ) ;
71+ continue ;
72+ }
73+ Console . Write ( ( "Analysing " + log ) /*.PadRight(Console.BufferWidth - 1)*/ ) ;
74+
4375 var fs = new FileStream ( log , FileMode . Open , FileAccess . Read , FileShare . ReadWrite ) ;
4476 var sr = new StreamReader ( fs ) ;
45- Console . SetCursorPosition ( 0 , Console . CursorTop ) ;
46- Console . Write ( "Analysing " + log ) ;
4777
4878 var lines = sr . ReadToEnd ( ) ;
4979 if ( ! lines . Contains ( "Thargoid" ) ) continue ;
@@ -60,43 +90,92 @@ public static void Main(string[] args) {
6090 if ( ! string . IsNullOrEmpty ( evt . VictimFaction ) && evt . VictimFaction . Contains ( "$faction_Thargoid" ) ) {
6191 //Console.WriteLine("{0} {1} {2} => {3}", evt.Timestamp, evt.VictimFaction, evt.Reward, (ThargoidRewards)evt.Reward);
6292
63- if ( ! Enum . IsDefined ( typeof ( ThargoidRewards ) , evt . Reward ) ) {
64- Console . WriteLine ( "Unknown reward value {0}" , evt . Reward ) ;
93+ if ( ! Map . ContainsKey ( evt . Reward ) ) {
94+ if ( Console . GetCursorPosition ( ) . Left > 0 )
95+ Console . Error . WriteLine ( ) ;
96+ Console . Error . WriteLine ( "Unknown reward value {0}" , evt . Reward ) ;
97+ continue ;
6598 }
66- counts [ ( ThargoidRewards ) evt . Reward ] ++ ;
99+ state . Counts [ Map [ evt . Reward ] ] ++ ;
67100 }
68101 }
69102 else if ( evt . Event == "MissionCompleted" ) {
70103 if ( evt . Name == "Mission_MassacreThargoid_name" ) {
71- missionRewards += evt . Reward ;
104+ state . MissionRewards += evt . Reward ;
72105 }
73106 }
74107 }
75108 }
76109 Console . SetCursorPosition ( 0 , Console . CursorTop ) ;
110+ Console . Write ( new string ( ' ' , Console . BufferWidth - 1 ) ) ;
111+ Console . SetCursorPosition ( 0 , Console . CursorTop ) ;
112+
113+ state . Last = curr /*DateTimeOffset.Now*/ ;
114+ try {
115+ File . WriteAllText ( cachePath , JsonSerializer . Serialize ( state , new JsonSerializerOptions { WriteIndented = true } ) ) ;
116+ }
117+ catch ( UnauthorizedAccessException e ) {
118+ Console . Error . WriteLine ( "Unable to write cache to {0}" , cachePath ) ;
119+ }
120+
77121 Console . WriteLine ( "--------------------------------------------" ) ;
78122 Console . WriteLine ( " THARGOID COMBAT STATS " ) ;
79123 Console . WriteLine ( "--------------------------------------------" ) ;
80- Console . WriteLine ( " Thargoid Scouts killed: {0,4}" , counts [ ThargoidRewards . Scout ] ) ;
81- Console . WriteLine ( " Cyclops Variant Interceptors killed: {0,4}" , counts [ ThargoidRewards . Cyclops ] ) ;
82- Console . WriteLine ( " Basilisk Variant Interceptors killed: {0,4}" , counts [ ThargoidRewards . Basilisk ] ) ;
83- Console . WriteLine ( " Medusa Variant Interceptors killed: {0,4}" , counts [ ThargoidRewards . Medusa ] ) ;
84- Console . WriteLine ( " Hydra Variant Interceptors killed: {0,4}" , counts [ ThargoidRewards . Hydra ] ) ;
124+ Console . WriteLine ( " Thargoid Scouts killed: {0,4}" , state . Counts [ Thargoids . Scout ] ) ;
125+ Console . WriteLine ( " Cyclops Variant Interceptors killed: {0,4}" , state . Counts [ Thargoids . Cyclops ] ) ;
126+ Console . WriteLine ( " Basilisk Variant Interceptors killed: {0,4}" , state . Counts [ Thargoids . Basilisk ] ) ;
127+ Console . WriteLine ( " Medusa Variant Interceptors killed: {0,4}" , state . Counts [ Thargoids . Medusa ] ) ;
128+ Console . WriteLine ( " Hydra Variant Interceptors killed: {0,4}" , state . Counts [ Thargoids . Hydra ] ) ;
85129 Console . WriteLine ( "--------------------------------------------" ) ;
86- Console . WriteLine ( " Total Thargoids killed: {0,4}" , counts . Sum ( s => s . Value ) ) ;
130+ Console . WriteLine ( " Total Thargoids killed: {0,4}" , state . Counts . Sum ( s => s . Value ) ) ;
87131 Console . WriteLine ( ) ;
88- Console . WriteLine ( " Total Thargoid mission payouts: {0,10:n0}" , missionRewards ) ;
132+ Console . WriteLine ( " Total Thargoid mission payouts: {0,11:n0}" , state . MissionRewards ) ;
133+
134+ if ( ConsoleWillBeDestroyed ( ) ) {
135+ Console . WriteLine ( ) ;
136+ Console . WriteLine ( "Press any key to continue . . . " ) ;
137+ Console . ReadKey ( ) ;
138+ }
89139 }
90140
91- enum ThargoidRewards {
92- // Logs still have the pre-Dec 2020 values
93- Scout = 10000 ,
94- Cyclops = 2000000 ,
95- Basilisk = 6000000 ,
96- Medusa = 10000000 ,
97- Hydra = 15000000 ,
141+ public enum Thargoids {
142+ Scout ,
143+ Cyclops ,
144+ Basilisk ,
145+ Medusa ,
146+ Hydra ,
98147 }
99148
149+ public readonly static Dictionary < int , Thargoids > Map = new Dictionary < int , Thargoids > {
150+ // Logs with pre-Dec 2020 values:
151+ { 10000 , Thargoids . Scout } ,
152+ { 2000000 , Thargoids . Cyclops } ,
153+ { 6000000 , Thargoids . Basilisk } ,
154+ { 10000000 , Thargoids . Medusa } ,
155+ { 15000000 , Thargoids . Hydra } ,
156+ // Logs ≈post-Sep 2021:
157+ { 80000 , Thargoids . Scout } ,
158+ { 8000000 , Thargoids . Cyclops } ,
159+ { 24000000 , Thargoids . Basilisk } ,
160+ { 40000000 , Thargoids . Medusa } ,
161+ { 60000000 , Thargoids . Hydra } ,
162+ { 80000000 , Thargoids . Hydra } ,
163+ } ;
164+
165+ public class Cache {
166+ public DateTimeOffset Last { get ; set ; }
167+ public Dictionary < Thargoids , uint > Counts { get ; set ; }
168+ //public uint[] Counts { get; set; }
169+ public int MissionRewards { get ; set ; }
170+
171+ public Cache ( ) {
172+ Last = DateTimeOffset . MinValue ;
173+ Counts = Enum . GetValues < Thargoids > ( ) . ToDictionary < Thargoids , Thargoids , uint > ( s => s , s => 0 ) ;
174+ //Counts = new uint[ (int)Enum.GetValues<Thargoids>().Max() ];
175+ MissionRewards = 0 ;
176+ }
177+ } ;
178+
100179 public class LogEvent {
101180 public DateTime Timestamp { get ; set ; }
102181 public string Event { get ; set ; }
0 commit comments