Conditions | 45 |
Total Lines | 270 |
Code Lines | 191 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like main_client.runClient() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | # |
||
177 | def runClient(options): |
||
178 | |||
179 | # log initialization |
||
180 | log.message("Starting Outer Space Client", ige.version.versionString) |
||
181 | log.debug("sys.path =", sys.path) |
||
182 | log.debug("os.name =", os.name) |
||
183 | log.debug("sys.platform =", sys.platform) |
||
184 | log.debug("os.getcwd() =", os.getcwd()) |
||
185 | log.debug("sys.frozen =", getattr(sys, "frozen", None)) |
||
186 | |||
187 | # create required directories |
||
188 | if not os.path.exists(options.configDir): |
||
189 | os.makedirs(options.configDir) |
||
190 | log.debug("options.configDir =", options.configDir) |
||
191 | |||
192 | running = 1 |
||
193 | first = True |
||
194 | #while running: |
||
195 | if not first: |
||
196 | reload(osci) |
||
|
|||
197 | # parse configuration |
||
198 | if first: |
||
199 | import osci.gdata as gdata |
||
200 | else: |
||
201 | reload(gdata) |
||
202 | |||
203 | gdata.config = Config(os.path.join(options.configDir, options.configFilename)) |
||
204 | gdata.config.game.server = options.server |
||
205 | |||
206 | setDefaults(gdata, options) |
||
207 | |||
208 | language = gdata.config.client.language |
||
209 | import gettext |
||
210 | log.debug('OSCI', 'Installing translation for:', language) |
||
211 | if language == 'en': |
||
212 | log.debug('OSCI', 'English is native - installing null translations') |
||
213 | tran = gettext.NullTranslations() |
||
214 | else: |
||
215 | try: |
||
216 | tran = gettext.translation('OSPACE', resources.get('translations'), languages = [language]) |
||
217 | except IOError: |
||
218 | log.warning('OSCI', 'Cannot find catalog for', language) |
||
219 | log.message('OSCI', 'Installing null translations') |
||
220 | tran = gettext.NullTranslations() |
||
221 | |||
222 | tran.install(unicode = 1) |
||
223 | |||
224 | |||
225 | #initialize pygame and prepare screen |
||
226 | if (gdata.config.defaults.sound == "yes") or (gdata.config.defaults.music == "yes"): |
||
227 | pygame.mixer.pre_init(44100, -16, 2, 4096) |
||
228 | |||
229 | os.environ['SDL_VIDEO_ALLOW_SCREENSAVER'] = '1' |
||
230 | os.environ['SDL_DEBUG'] = '1' |
||
231 | pygame.init() |
||
232 | |||
233 | flags = pygame.SWSURFACE |
||
234 | |||
235 | DEFAULT_SCRN_SIZE = (800, 600) |
||
236 | gdata.scrnSize = DEFAULT_SCRN_SIZE |
||
237 | if gdata.config.display.resolution == "FULLSCREEN": |
||
238 | gdata.scrnSize = (0, 0) |
||
239 | flags |= pygame.FULLSCREEN |
||
240 | elif gdata.config.display.resolution is not None: |
||
241 | width, height = gdata.config.display.resolution.split('x') |
||
242 | gdata.scrnSize = (int(width), int(height)) |
||
243 | |||
244 | if gdata.config.display.depth == None: |
||
245 | # guess best depth |
||
246 | bestdepth = pygame.display.mode_ok(gdata.scrnSize, flags) |
||
247 | else: |
||
248 | bestdepth = int(gdata.config.display.depth) |
||
249 | |||
250 | # initialize screen |
||
251 | try: |
||
252 | screen = pygame.display.set_mode(gdata.scrnSize, flags, bestdepth) |
||
253 | # gdata.scrnSize is used everywhere to setup windows |
||
254 | gdata.scrnSize = screen.get_size() |
||
255 | except pygame.error: |
||
256 | # for example if fullscreen is selected with resolution bigger than display |
||
257 | # TODO: as of now, fullscreen has automatic resolution |
||
258 | gdata.scrnSize = DEFAULT_SCRN_SIZE |
||
259 | screen = pygame.display.set_mode(gdata.scrnSize, flags, bestdepth) |
||
260 | gdata.screen = screen |
||
261 | log.debug('OSCI', 'Driver:', pygame.display.get_driver()) |
||
262 | log.debug('OSCI', 'Using depth:', bestdepth) |
||
263 | log.debug('OSCI', 'Display info:', pygame.display.Info()) |
||
264 | |||
265 | pygame.mouse.set_visible(1) |
||
266 | |||
267 | pygame.display.set_caption(_('Outer Space %s') % ige.version.versionString) |
||
268 | |||
269 | # set icon |
||
270 | pygame.display.set_icon(pygame.image.load(resources.get('icon48.png')).convert_alpha()) |
||
271 | |||
272 | # UI stuff |
||
273 | if first: |
||
274 | import pygameui as ui |
||
275 | else: |
||
276 | reload(ui) |
||
277 | |||
278 | setSkinTheme(gdata, ui) |
||
279 | |||
280 | app = ui.Application(update, theme = ui.SkinableTheme) |
||
281 | app.background = defineBackground() |
||
282 | app.draw(gdata.screen) |
||
283 | app.windowSurfaceFlags = pygame.SWSURFACE | pygame.SRCALPHA |
||
284 | gdata.app = app |
||
285 | |||
286 | pygame.event.clear() |
||
287 | |||
288 | # resources |
||
289 | import osci.res |
||
290 | |||
291 | osci.res.initialize() |
||
292 | |||
293 | # load resources |
||
294 | import osci.dialog |
||
295 | dlg = osci.dialog.ProgressDlg(gdata.app) |
||
296 | osci.res.loadResources(dlg) |
||
297 | dlg.hide() |
||
298 | osci.res.prepareUIIcons(ui.SkinableTheme.themeIcons) |
||
299 | |||
300 | |||
301 | while running: |
||
302 | if first: |
||
303 | import osci.client, osci.handler |
||
304 | from igeclient.IClient import IClientException |
||
305 | else: |
||
306 | reload(osci.client) |
||
307 | reload(osci.handler) |
||
308 | osci.client.initialize(gdata.config.game.server, osci.handler, options) |
||
309 | |||
310 | # create initial dialogs |
||
311 | if first: |
||
312 | import osci.dialog |
||
313 | else: |
||
314 | reload(osci.dialog) |
||
315 | gdata.savePassword = gdata.config.game.lastpasswordcrypted != None |
||
316 | |||
317 | if options.login and options.password: |
||
318 | gdata.config.game.lastlogin = options.login |
||
319 | gdata.config.game.lastpassword = options.password |
||
320 | gdata.config.game.lastpasswordcrypted = binascii.b2a_base64(options.password).strip() |
||
321 | gdata.config.game.autologin = 'yes' |
||
322 | gdata.savePassword = 'no' |
||
323 | |||
324 | loginDlg = osci.dialog.LoginDlg(gdata.app) |
||
325 | updateDlg = osci.dialog.UpdateDlg(gdata.app) |
||
326 | |||
327 | # event loop |
||
328 | update() |
||
329 | |||
330 | lastSave = time.clock() |
||
331 | # set counter to -1 to trigger Update dialog (see "if" below) |
||
332 | counter = -1 |
||
333 | needsRefresh = False |
||
334 | session = 1 |
||
335 | first = False |
||
336 | while running and session: |
||
337 | try: |
||
338 | counter += 1 |
||
339 | if counter == 0: |
||
340 | # display initial dialog in the very first cycle |
||
341 | updateDlg.display(caller = loginDlg, options = options) |
||
342 | # process as many events as possible before updating |
||
343 | evt = pygame.event.wait() |
||
344 | evts = pygame.event.get() |
||
345 | evts.insert(0, evt) |
||
346 | |||
347 | forceKeepAlive = False |
||
348 | saveDB = False |
||
349 | |||
350 | for evt in evts: |
||
351 | if evt.type == pygame.QUIT: |
||
352 | running = 0 |
||
353 | break |
||
354 | if evt.type == (ui.USEREVENT) and evt.action == "localExit": |
||
355 | session = False |
||
356 | break |
||
357 | if evt.type == pygame.ACTIVEEVENT: |
||
358 | if evt.gain == 1 and evt.state == 6: |
||
359 | # pygame desktop window focus event |
||
360 | needsRefresh = True |
||
361 | if evt.type == pygame.KEYUP and evt.key == pygame.K_F12: |
||
362 | if not pygame.key.get_mods() & pygame.KMOD_CTRL: |
||
363 | running = 0 |
||
364 | break |
||
365 | if evt.type == pygame.KEYUP and evt.key == pygame.K_F9: |
||
366 | forceKeepAlive = True |
||
367 | evt = gdata.app.processEvent(evt) |
||
368 | |||
369 | if gdata.app.needsUpdate() or needsRefresh: |
||
370 | needsRefresh = False |
||
371 | update() |
||
372 | # keep alive connection |
||
373 | osci.client.keepAlive(forceKeepAlive) |
||
374 | |||
375 | # save DB every 4 hours in case of a computer crash |
||
376 | # using "counter" to limit calls to time.clock() to approximately every 10-15 minutes |
||
377 | if counter > 5000: |
||
378 | # set this to zero so we don't display Update dialog |
||
379 | counter = 0 |
||
380 | if time.clock() - lastSave > 14400: |
||
381 | saveDB = True |
||
382 | if saveDB: |
||
383 | osci.client.saveDB() |
||
384 | lastSave = time.clock(); |
||
385 | |||
386 | except IClientException, e: |
||
387 | osci.client.reinitialize() |
||
388 | gdata.app.setStatus(e.args[0]) |
||
389 | loginDlg.display(message = e.args[0]) |
||
390 | except Exception, e: |
||
391 | log.warning('OSCI', 'Exception in event loop') |
||
392 | if not isinstance(e, SystemExit) and not isinstance(e, KeyboardInterrupt): |
||
393 | log.debug("Processing exception") |
||
394 | # handle exception |
||
395 | import traceback, StringIO |
||
396 | fh = StringIO.StringIO() |
||
397 | exctype, value, tb = sys.exc_info() |
||
398 | funcs = [entry[2] for entry in traceback.extract_tb(tb)] |
||
399 | faultID = "%06d-%03d" % ( |
||
400 | hash("/".join(funcs)) % 1000000, |
||
401 | traceback.extract_tb(tb)[-1][1] % 1000, |
||
402 | ) |
||
403 | del tb |
||
404 | # high level info |
||
405 | print >>fh, "Exception ID:", faultID |
||
406 | print >>fh |
||
407 | print >>fh, "%s: %s" % (exctype, value) |
||
408 | print >>fh |
||
409 | print >>fh, "--- EXCEPTION DATA ---" |
||
410 | # dump exception |
||
411 | traceback.print_exc(file = fh) |
||
412 | excDlg = osci.dialog.ExceptionDlg(gdata.app) |
||
413 | excDlg.display(faultID, fh.getvalue()) |
||
414 | del excDlg # reference to the dialog holds app's intance |
||
415 | fh.close() |
||
416 | del fh |
||
417 | else: |
||
418 | break |
||
419 | |||
420 | # write configuration |
||
421 | log.debug("Saving configuration.") |
||
422 | # Save highlights |
||
423 | hl = "" |
||
424 | for playerID in gdata.playersHighlightColors.keys(): |
||
425 | color = gdata.playersHighlightColors[playerID] |
||
426 | r = hex(color[0]) |
||
427 | g = hex(color[1]) |
||
428 | b = hex(color[2]) |
||
429 | hl = "%s %s:%s,%s,%s" % (hl,playerID,r,g,b) |
||
430 | gdata.config.defaults.colors = hl |
||
431 | # Save objects |
||
432 | of = "" |
||
433 | for keyNum in gdata.objectFocus.keys(): |
||
434 | objid = gdata.objectFocus[keyNum] |
||
435 | of = "%s %s:%s" % (of,keyNum,objid) |
||
436 | gdata.config.defaults.objectkeys = of |
||
437 | # |
||
438 | if gdata.savePassword == False: |
||
439 | gdata.config.game.lastpasswordcrypted = None |
||
440 | gdata.config.save() |
||
441 | |||
442 | # logout |
||
443 | osci.client.logout() |
||
444 | |||
445 | log.debug("Shut down") |
||
446 | return osci.client |
||
447 |