From 22de16e50561580e15b1872d9d11688e9eaba987 Mon Sep 17 00:00:00 2001
From: Jonathan Harris <jonathan@marginal.org.uk>
Date: Sat, 25 Feb 2017 15:05:49 +0000
Subject: [PATCH] Generate StartUp monitor event on joining live game

---
 EDMarketConnector.py |  8 ++++----
 PLUGINS.md           |  2 +-
 monitor.py           | 28 ++++++++++++++++++++++++----
 3 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/EDMarketConnector.py b/EDMarketConnector.py
index 9479f2e6..26202b29 100755
--- a/EDMarketConnector.py
+++ b/EDMarketConnector.py
@@ -596,7 +596,7 @@ class AppWindow:
                 self.w.update_idletasks()
                 try:
                     # Update system status on startup
-                    if monitor.mode and monitor.system and not entry['event']:
+                    if not entry['event'] and monitor.mode and monitor.system:
                         self.edsm.lookup(monitor.system)
 
                     # Send credits to EDSM on new game (but not on startup - data might be old)
@@ -604,11 +604,11 @@ class AppWindow:
                         self.edsm.setcredits(monitor.credits)
 
                     # Send rank info to EDSM on startup or change
-                    if entry['event'] in [None, 'Progress', 'Promotion']:
+                    if entry['event'] in ['StartUp', 'Progress', 'Promotion'] and monitor.ranks:
                         self.edsm.setranks(monitor.ranks)
 
                     # Send ship info to EDSM on startup or change
-                    if entry['event'] in [None, 'LoadGame', 'ShipyardNew', 'ShipyardSwap']:
+                    if entry['event'] in ['StartUp', 'LoadGame', 'ShipyardNew', 'ShipyardSwap'] and monitor.shipid:
                         self.edsm.setshipid(monitor.shipid)
                         self.edsm.updateship(monitor.shipid, monitor.shiptype, monitor.shippaint and [('paintJob', monitor.shippaint)] or [])
                     elif entry['event'] in ['ShipyardBuy', 'ShipyardSell']:
@@ -632,7 +632,7 @@ class AppWindow:
             self.edsmpoll()
 
             # Companion login - do this after EDSM so any EDSM errors don't mask login errors
-            if entry['event'] in [None, 'NewCommander', 'LoadGame'] and monitor.cmdr and not monitor.is_beta:
+            if entry['event'] in [None, 'StartUp', 'NewCommander', 'LoadGame'] and monitor.cmdr and not monitor.is_beta:
                 if config.get('cmdrs') and monitor.cmdr in config.get('cmdrs'):
                     prefs.make_current(monitor.cmdr)
                     self.login()
diff --git a/PLUGINS.md b/PLUGINS.md
index 68775558..054f4309 100644
--- a/PLUGINS.md
+++ b/PLUGINS.md
@@ -77,7 +77,7 @@ Your events all get called on the main tkinter loop so be sure not to block for
 
 ### Journal Entry
 
-This gets called when EDMC sees a new entry in the game's journal.
+This gets called when EDMC sees a new entry in the game's journal. A special 'StartUp' event is sent when EDMC is started while the game is already running.
 
 ```
 def journal_entry(cmdr, system, station, entry):
diff --git a/monitor.py b/monitor.py
index 53a96944..129f42fc 100644
--- a/monitor.py
+++ b/monitor.py
@@ -8,7 +8,7 @@ from os.path import basename, exists, isdir, isfile, join
 from platform import machine
 import sys
 from sys import platform
-from time import sleep
+from time import gmtime, sleep, strftime
 
 if __debug__:
     from traceback import print_exc
@@ -72,6 +72,14 @@ class EDLogs(FileSystemEventHandler):
         self.thread = None
         self.event_queue = []		# For communicating journal entries back to main thread
 
+        # On startup we might be:
+        # 1) Looking at an old journal file because the game isn't running or the user has exited to the main menu.
+        # 2) Looking at an empty journal (only 'Fileheader') because the user is at the main menu.
+        # 3) In the middle of a 'live' game.
+        # If 1 or 2 a LoadGame event will happen when the game goes live.
+        # If 3 we need to inject a special 'StartUp' event since consumers won't see the LoadGame event.
+        self.live = False
+
         # Context for journal handling
         self.version = None
         self.is_beta = False
@@ -129,8 +137,6 @@ class EDLogs(FileSystemEventHandler):
             print '%s "%s"' % (polling and 'Polling' or 'Monitoring', self.currentdir)
             print 'Start logfile "%s"' % self.logfile
 
-        self.event_queue.append(None)	# Generate null event to signal (re)start
-
         if not self.running():
             self.thread = threading.Thread(target = self.worker, name = 'Journal worker')
             self.thread.daemon = True
@@ -186,6 +192,10 @@ class EDLogs(FileSystemEventHandler):
         else:
             loghandle = None
 
+        if self.live:
+            self.event_queue.append(None)	# Generate null event to update the display (with possibly out-of-date info)
+            self.live = False
+
         # Watchdog thread
         emitter = self.observed and self.observer._emitter_for_watch[self.observed]	# Note: Uses undocumented attribute
 
@@ -226,13 +236,18 @@ class EDLogs(FileSystemEventHandler):
                 return	# Terminate
 
     def parse_entry(self, line):
+        if line is None:
+            return { 'event': None }	# Fake startup event
+
         try:
             entry = json.loads(line, object_pairs_hook=OrderedDict)	# Preserve property order because why not?
             entry['timestamp']	# we expect this to exist
             if entry['event'] == 'Fileheader':
+                self.live = False
                 self.version = entry['gameversion']
                 self.is_beta = 'beta' in entry['gameversion'].lower()
             elif entry['event'] == 'LoadGame':
+                self.live = True
                 self.cmdr = entry['Commander']
                 self.mode = entry.get('GameMode')	# 'Open', 'Solo', 'Group', or None for CQC
                 self.group = entry.get('Group')
@@ -286,13 +301,18 @@ class EDLogs(FileSystemEventHandler):
         except:
             if __debug__:
                 print 'Invalid journal entry "%s"' % repr(line)
+                print_exc()
             return { 'event': None }
 
     def get_entry(self):
         if not self.event_queue:
             return None
         else:
-            return self.parse_entry(self.event_queue.pop(0))
+            entry = self.parse_entry(self.event_queue.pop(0))
+            if not self.live and entry['event'] not in [None, 'Fileheader']:
+                self.live = True
+                self.event_queue.append('{ "timestamp":"%s", "event":"StartUp" }' % strftime('%Y-%m-%dT%H:%M:%SZ', gmtime()))
+            return entry
 
 
 # singleton