| Conditions | 46 |
| 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 |