99import requests
1010import sys
1111import threading
12- try :
13- # Python 2
14- from urllib2 import quote
15- import Tkinter as tk
16- except ModuleNotFoundError :
17- # Python 3
18- from urllib .parse import quote
19- import tkinter as tk
12+ from urllib .parse import quote
13+ import tkinter as tk
2014
2115from ttkHyperlinkLabel import HyperlinkLabel
2216import myNotebook as nb
2923
3024VERSION = '1.20'
3125
32- SETTING_DEFAULT = 0x0002 # Earth-like
26+ SETTING_DEFAULT = 0x0002 # Earth-like
3327SETTING_EDSM = 0x1000
3428SETTING_NONE = 0xffff
3529
3630WORLDS = [
37- # Type Black-body temp range EDSM description
38- ('Metal-Rich' , 0 , 1103.0 , 'Metal-rich body' ),
39- ('Earth-Like' , 278.0 , 227.0 , 'Earth-like world' ),
40- ('Water' , 307.0 , 156.0 , 'Water world' ),
41- ('Ammonia' , 193.0 , 117.0 , 'Ammonia world' ),
42- ('Class II Giant' , 250.0 , 150.0 , 'Class II gas giant' ),
43- ('Terraformable' , 315.0 , 223.0 , 'terraformable' ),
31+ # Type Black-body temp range EDSM description
32+ ('Metal-Rich' , 0 , 1103.0 , 'Metal-rich body' ),
33+ ('Earth-Like' , 278.0 , 227.0 , 'Earth-like world' ),
34+ ('Water' , 307.0 , 156.0 , 'Water world' ),
35+ ('Ammonia' , 193.0 , 117.0 , 'Ammonia world' ),
36+ ('Class II Giant' , 250.0 , 150.0 , 'Class II gas giant' ),
37+ ('Terraformable' , 318.0 , 223.0 , 'terraformable' ),
38+ ('Organic' , 500.0 , 200.0 , 'Organic POI' ),
4439]
4540
46- LS = 300000000.0 # 1 ls in m (approx)
41+ LS = 300000000.0 # 1 ls in m (approx)
4742
48- this = sys .modules [__name__ ] # For holding module globals
43+ this = sys .modules [__name__ ] # For holding module globals
4944this .frame = None
5045this .worlds = []
5146this .scanned_worlds = {'system' : None , 'bodies' : {}}
5651this .settings = None
5752this .edsm_setting = None
5853
54+ this .istar = 0
55+ this .stars = defaultdict (list )
56+ this .bodies = defaultdict (list )
57+
5958
6059def plugin_start3 (plugin_dir ):
6160 return plugin_start ()
6261
62+
6363def plugin_start ():
6464 # App isn't initialised at this point so can't do anything interesting
6565 return 'HabZone'
6666
67+
6768def plugin_app (parent ):
6869 # Create and display widgets
6970 this .frame = tk .Frame (parent )
70- this .frame .columnconfigure (3 , weight = 1 )
71- this .frame .bind ('<<HabZoneData>>' , edsm_data ) # callback when EDSM data received
71+ this .frame .columnconfigure (6 , weight = 1 )
72+ this .frame .bind ('<<HabZoneData>>' , edsm_data ) # callback when EDSM data received
73+ this .starused_label = tk .Label (this .frame , text = 'Star used: [0]' )
74+ this .starused = HyperlinkLabel (this .frame )
75+ this .starused_next = HyperlinkLabel (this .frame )
76+ this .starused_next ['text' ] = '>'
77+ this .starused_next ['url' ] = '>'
78+ this .starused_next .bind ("<Button-1>" , next_star )
79+ this .starused_prev = HyperlinkLabel (this .frame )
80+ this .starused_prev ['text' ] = '<'
81+ this .starused_prev ['url' ] = '<'
82+ this .starused_prev .bind ("<Button-1>" , prev_star )
7283 for (name , high , low , subType ) in WORLDS :
7384 this .worlds .append ((tk .Label (this .frame , text = name + ':' ),
74- HyperlinkLabel (this .frame , wraplength = 100 ), # edsm
75- tk .Label (this .frame ), # near
76- tk .Label (this .frame ), # dash
77- tk .Label (this .frame ), # far
78- tk .Label (this .frame ), # ls
85+ HyperlinkLabel (this .frame , wraplength = 100 ), # edsm
86+ tk .Label (this .frame ), # near
87+ tk .Label (this .frame ), # dash
88+ tk .Label (this .frame ), # far
89+ tk .Label (this .frame ), # ls
7990 ))
80- this .spacer = tk .Frame (this .frame ) # Main frame can't be empty or it doesn't resize
91+ this .spacer = tk .Frame (this .frame ) # Main frame can't be empty or it doesn't resize
8192 update_visibility ()
8293 return this .frame
8394
95+
8496def plugin_prefs (parent , cmdr , is_beta ):
8597 frame = nb .Frame (parent )
8698 nb .Label (frame , text = 'Display:' ).grid (row = 0 , padx = 10 , pady = (10 ,0 ), sticky = tk .W )
@@ -102,6 +114,7 @@ def plugin_prefs(parent, cmdr, is_beta):
102114
103115 return frame
104116
117+
105118def prefs_changed (cmdr , is_beta ):
106119 row = 1
107120 setting = 0
@@ -117,67 +130,66 @@ def prefs_changed(cmdr, is_beta):
117130
118131
119132def journal_entry (cmdr , is_beta , system , station , entry , state ):
120-
133+ if not this .scanned_worlds .get ('system' ):
134+ this .scanned_worlds ['system' ] = system
121135 if entry ['event' ] == 'Scan' :
122- try :
123- if not float (entry ['DistanceFromArrivalLS' ]): # Only calculate for arrival star
124- r = float (entry ['Radius' ])
125- t = float (entry ['SurfaceTemperature' ])
126- for i in range (len (WORLDS )):
127- (name , high , low , subType ) = WORLDS [i ]
128- (label , edsm , near , dash , far , ls ) = this .worlds [i ]
129- far_dist = int (0.5 + dfort (r , t , low ))
130- radius = int (0.5 + r / LS )
131- if far_dist <= radius :
132- near ['text' ] = ''
133- dash ['text' ] = u'×'
134- far ['text' ] = ''
135- ls ['text' ] = ''
136- else :
137- if not high :
138- near ['text' ] = Locale .stringFromNumber (radius )
139- else :
140- near ['text' ] = Locale .stringFromNumber (int (0.5 + dfort (r , t , high )))
141- dash ['text' ] = '-'
142- far ['text' ] = Locale .stringFromNumber (far_dist )
143- ls ['text' ] = 'ls'
144- if entry .get ('TerraformState' , False ) or (entry .get ('PlanetClass' , False )):
145- mapped = entry .get ('WasMapped' )
146- # TODO: Clean up repetitive code - perhaps integrate Journal types into WORLDS constant?
147- body_type = None
148- if entry .get ('TerraformState' ) == 'Terraformable' :
149- body_type = 'terraformable'
150- elif entry .get ('PlanetClass' ) == 'Earthlike body' :
151- body_type = 'Earth-like world'
152- elif entry .get ('PlanetClass' ) == 'Water world' :
153- body_type = 'Water world'
154- elif entry .get ('PlanetClass' ) == 'Ammonia world' :
155- body_type = 'Ammonia world'
156- elif entry .get ('PlanetClass' ) == 'Metal rich body' :
157- body_type = 'Metal-rich body'
158- elif entry .get ('PlanetClass' ) == 'Sudarsky class II gas giant' :
159- body_type = 'Class II gas giant'
160- if body_type :
161- data = this .scanned_worlds ['bodies' ].get (entry .get ('BodyName' ), {})
162- data .update ({'type' : body_type , 'was_mapped' : mapped })
163- this .scanned_worlds ['bodies' ][entry .get ('BodyName' )] = data
164- list_bodies (system )
165- except (RuntimeError , TypeError ) as err :
166- for (label , edsm , near , dash , far , ls ) in this .worlds :
167- near ['text' ] = ''
168- dash ['text' ] = ''
169- far ['text' ] = ''
170- ls ['text' ] = '?'
171- edsm ['test' ] = err
172-
173- elif entry ['event' ] == 'FSDJump' :
136+ if 'StarType' in entry :
137+ r = float (entry ['Radius' ])
138+ t = float (entry ['SurfaceTemperature' ])
139+ if not entry ['BodyName' ] in this .stars ['name' ]:
140+ this .stars ['name' ].append (entry ['BodyName' ])
141+ this .stars ['surfaceTemperature' ].append (t )
142+ this .stars ['solarRadius' ].append (r )
143+ this .starused_label ['text' ] = 'Star used: [' + str (this .istar + 1 )+ '/' + str (len (this .stars ['name' ]))+ ']'
144+ updateValues (r ,t ,entry ['BodyName' ])
145+
146+ if 'PlanetClass' in entry :
147+ for i in range (len (WORLDS )):
148+ (name , high , low , subType ) = WORLDS [i ]
149+ (label , edsm , near , dash , far , ls ) = this .worlds [i ]
150+ if entry ['PlanetClass' ][0 :5 ] == subType [0 :5 ]:
151+ if not entry ['BodyName' ] in this .bodies [subType ]:
152+ this .bodies [subType ].append (entry ['BodyName' ])
153+ edsm ['text' ] = ' ' .join ([x [len (this .systemName ):].replace (' ' , '' ) if x .startswith (this .systemName ) else x for x in this .bodies [subType ]])
154+ edsm ['url' ] = len (this .bodies [subType ]) == 1 and 'https://www.edsm.net/show-system?systemName=%s&bodyName=%s' % (quote (this .systemName ), quote (this .bodies [subType ][0 ]))
155+
156+ if entry .get ('TerraformState' , False ) or (entry .get ('PlanetClass' , False )):
157+ mapped = entry .get ('WasMapped' )
158+ # TODO: Clean up repetitive code - perhaps integrate Journal types into WORLDS constant?
159+ body_type = None
160+ if entry .get ('TerraformState' ) == 'Terraformable' :
161+ body_type = 'terraformable'
162+ elif entry .get ('PlanetClass' ) == 'Earthlike body' :
163+ body_type = 'Earth-like world'
164+ elif entry .get ('PlanetClass' ) == 'Water world' :
165+ body_type = 'Water world'
166+ elif entry .get ('PlanetClass' ) == 'Ammonia world' :
167+ body_type = 'Ammonia world'
168+ elif entry .get ('PlanetClass' ) == 'Metal rich body' :
169+ body_type = 'Metal-rich body'
170+ elif entry .get ('PlanetClass' ) == 'Sudarsky class II gas giant' :
171+ body_type = 'Class II gas giant'
172+ if body_type :
173+ data = this .scanned_worlds ['bodies' ].get (entry .get ('BodyName' ), {})
174+ data .update ({'type' : body_type , 'was_mapped' : mapped })
175+ this .scanned_worlds ['bodies' ][entry .get ('BodyName' )] = data
176+ list_bodies (system )
177+
178+ if entry ['event' ] in ['Location' , 'FSDJump' , 'StartUp' ]:
179+ this .istar = 0
180+ this .stars = defaultdict (list )
181+ this .bodies = defaultdict (list )
182+ this .starused_label ['text' ] = 'Star used: [0]'
183+ this .starused ['text' ] = ''
184+ this .starused ['url' ] = ''
174185 for (label , edsm , near , dash , far , ls ) in this .worlds :
175186 edsm ['text' ] = ''
176187 edsm ['url' ] = ''
177188 near ['text' ] = ''
178189 dash ['text' ] = ''
179190 far ['text' ] = ''
180191 ls ['text' ] = ''
192+ this .systemName = entry ['StarSystem' ]
181193 this .scanned_worlds ['system' ] = entry ['StarSystem' ]
182194 this .scanned_worlds ['bodies' ].clear ()
183195
@@ -188,13 +200,29 @@ def journal_entry(cmdr, is_beta, system, station, entry, state):
188200 this .scanned_worlds ['bodies' ][name ].update ({'mapped' : True })
189201 list_bodies (system )
190202
191- if entry ['event' ] in ['Location' , 'FSDJump' ] and get_setting () & SETTING_EDSM :
192- thread = threading .Thread (target = edsm_worker , name = 'EDSM worker' , args = (entry [ 'StarSystem' ] ,))
203+ if entry ['event' ] in ['Location' , 'FSDJump' , 'StartUp' ] and get_setting () & SETTING_EDSM :
204+ thread = threading .Thread (target = edsm_worker , name = 'EDSM worker' , args = (this . systemName ,))
193205 thread .daemon = True
194206 thread .start ()
195207
196208
197209def cmdr_data (data , is_beta ):
210+
211+ this .istar = 0
212+ this .stars = defaultdict (list )
213+ this .bodies = defaultdict (list )
214+ this .starused_label ['text' ] = 'Star used: [0]'
215+ this .starused ['text' ] = ''
216+ this .starused ['url' ] = ''
217+
218+ for (label , edsm , near , dash , far , ls ) in this .worlds :
219+ edsm ['text' ] = ''
220+ edsm ['url' ] = ''
221+ near ['text' ] = ''
222+ dash ['text' ] = ''
223+ far ['text' ] = ''
224+ ls ['text' ] = ''
225+
198226 # Manual Update
199227 if get_setting () & SETTING_EDSM and not data ['commander' ]['docked' ]:
200228 thread = threading .Thread (target = edsm_worker , name = 'EDSM worker' , args = (data ['lastSystem' ]['name' ],))
@@ -208,6 +236,30 @@ def dfort(r, t, target):
208236 return (((r ** 2 ) * (t ** 4 ) / (4 * (target ** 4 ))) ** 0.5 ) / LS
209237
210238
239+ def updateValues (r ,t ,name ):
240+ this .starused ['text' ] = name
241+ this .starused ['url' ] = 'https://www.edsm.net/show-system?systemName=%s&bodyName=%s' % (quote (this .systemName ), quote (name ))
242+ for i in range (len (WORLDS )):
243+ (name , high , low , subType ) = WORLDS [i ]
244+ (label , edsm , near , dash , far , ls ) = this .worlds [i ]
245+ far_dist = int (0.5 + dfort (r , t , low ))
246+ radius = int (0.5 + r / LS )
247+ if far_dist <= radius :
248+ near ['text' ] = ''
249+ dash ['text' ] = u'×'
250+ far ['text' ] = ''
251+ ls ['text' ] = ''
252+ else :
253+ if not high :
254+ near ['text' ] = Locale .stringFromNumber (radius )
255+ else :
256+ near ['text' ] = Locale .stringFromNumber (int (0.5 + dfort (r , t , high )))
257+ dash ['text' ] = '-'
258+ far ['text' ] = Locale .stringFromNumber (far_dist )
259+ ls ['text' ] = 'ls'
260+ return 0
261+
262+
211263def list_bodies (system ):
212264 body_data = {}
213265 for name in this .scanned_worlds ['bodies' ]:
@@ -236,7 +288,7 @@ def edsm_worker(systemName):
236288 try :
237289 r = this .edsm_session .get ('https://www.edsm.net/api-system-v1/bodies?systemName=%s' % quote (systemName ), timeout = 10 )
238290 r .raise_for_status ()
239- this .edsm_data = r .json () or {} # Unknown system represented as empty list
291+ this .edsm_data = r .json () or {} # Unknown system represented as empty list
240292 except :
241293 this .edsm_data = None
242294
@@ -257,6 +309,13 @@ def edsm_data(event):
257309
258310 # Collate
259311 for body in this .edsm_data .get ('bodies' , []):
312+ if body ['type' ] == 'Star' :
313+ if body ['name' ] not in this .stars ['name' ]:
314+ this .stars ['name' ].append (body ['name' ])
315+ this .stars ['surfaceTemperature' ].append (body ['surfaceTemperature' ])
316+ this .stars ['solarRadius' ].append (body ['solarRadius' ]* 695500000 )
317+
318+ this .bodies [body ['subType' ]].append (body ['name' ])
260319 if body .get ('terraformingState' ) == 'Candidate for terraforming' :
261320 data = this .scanned_worlds ['bodies' ].get (body ['name' ], {})
262321 data .update ({'type' : 'terraformable' })
@@ -266,8 +325,12 @@ def edsm_data(event):
266325 data .update ({'type' : body ['subType' ]})
267326 this .scanned_worlds ['bodies' ][body ['name' ]] = data
268327
328+ if len (this .stars ['name' ]) > 0 :
329+ this .starused_label ['text' ] = 'Star used: [' + str (this .istar + 1 )+ '/' + str (len (this .stars ['name' ]))+ ']'
330+ updateValues (this .stars ['solarRadius' ][this .istar ],this .stars ['surfaceTemperature' ][this .istar ],this .stars ['name' ][this .istar ])
331+
269332 # Display
270- systemName = this .edsm_data .get ('name' , '' )
333+ systemName = this .edsm_data .get ('name' , this . scanned_worlds [ 'system' ] )
271334 url = 'https://www.edsm.net/show-system?systemName=%s&bodyName=ALL' % quote (systemName )
272335 for i in range (len (WORLDS )):
273336 (name , high , low , subType ) = WORLDS [i ]
@@ -280,23 +343,28 @@ def edsm_data(event):
280343def get_setting ():
281344 setting = config .getint ('habzone' )
282345 if setting == 0 :
283- return SETTING_DEFAULT # Default to Earth-Like
346+ return SETTING_DEFAULT # Default to Earth-Like
284347 elif setting == SETTING_NONE :
285- return 0 # Explicitly set by the user to display nothing
348+ return 0 # Explicitly set by the user to display nothing
286349 else :
287350 return setting
288351
352+
289353def update_visibility ():
290354 setting = get_setting ()
291355 row = 1
356+ this .starused_label .grid (row = row , column = 0 , sticky = tk .W )
357+ this .starused .grid (row = row , column = 1 , columnspan = 3 , sticky = tk .W )
358+ this .starused_prev .grid (row = row , column = 4 , sticky = tk .E )
359+ this .starused_next .grid (row = row , column = 5 , sticky = tk .E )
292360 for (label , edsm , near , dash , far , ls ) in this .worlds :
293361 if setting & row :
294- label .grid (row = row , column = 0 , sticky = tk .W )
295- edsm .grid (row = row , column = 1 , sticky = tk .W , padx = ( 0 , 10 ) )
296- near .grid (row = row , column = 2 , sticky = tk .E )
297- dash .grid (row = row , column = 3 , sticky = tk .E )
298- far .grid (row = row , column = 4 , sticky = tk .E )
299- ls .grid (row = row , column = 5 , sticky = tk .W )
362+ label .grid (row = row + 1 , column = 0 , sticky = tk .W )
363+ edsm .grid (row = row + 1 , column = 1 , sticky = tk .E )
364+ near .grid (row = row + 1 , column = 2 , sticky = tk .E )
365+ dash .grid (row = row + 1 , column = 3 , sticky = tk .E )
366+ far .grid (row = row + 1 , column = 4 , sticky = tk .E )
367+ ls .grid (row = row + 1 , column = 5 , sticky = tk .E )
300368 else :
301369 label .grid_remove ()
302370 edsm .grid_remove ()
@@ -309,3 +377,17 @@ def update_visibility():
309377 this .spacer .grid_remove ()
310378 else :
311379 this .spacer .grid (row = 0 )
380+
381+ def next_star (event ):
382+ this .istar += 1
383+ if this .istar >= len (this .stars ['name' ]):
384+ this .istar = 0
385+ this .starused_label ['text' ] = 'Star used: [' + str (this .istar + 1 )+ '/' + str (len (this .stars ['name' ]))+ ']'
386+ updateValues (this .stars ['solarRadius' ][this .istar ],this .stars ['surfaceTemperature' ][this .istar ],this .stars ['name' ][this .istar ])
387+
388+ def prev_star (event ):
389+ this .istar -= 1
390+ if this .istar < 0 :
391+ this .istar = len (this .stars ['name' ])- 1
392+ this .starused_label ['text' ] = 'Star used: [' + str (this .istar + 1 )+ '/' + str (len (this .stars ['name' ]))+ ']'
393+ updateValues (this .stars ['solarRadius' ][this .istar ],this .stars ['surfaceTemperature' ][this .istar ],this .stars ['name' ][this .istar ])
0 commit comments