def createNewGalaxy(self, tran, obj, x, y, galaxyName): log.message("Adding new galaxy '%s' to (%d, %d)" % (galaxyName, x, y)) fh, galaxyFileName = tempfile.mkstemp(text=True) log.debug("Generating new galaxy to temporary file", galaxyFileName) strGalaxyID = 'Circle42P' GenerateGalaxy(strGalaxyID, os.fdopen(fh, "w+b")) log.debug("Creating new galaxy") newGalaxyID = self.createGalaxy(tran, obj) log.debug("Created new galaxy", newGalaxyID) newGalaxy = tran.db[newGalaxyID] log.debug("Loading new ", newGalaxyID) self.cmd(newGalaxy).loadFromXML(tran, newGalaxy, galaxyFileName, strGalaxyID, x, y, galaxyName) log.debug("Setup Enviroment", newGalaxyID) self.cmd(newGalaxy).setupEnvironment(tran, newGalaxy) log.debug("Sending Announcement Message", newGalaxyID) #self.cmd(newGalaxy).announceGalaxy(tran,newGalaxy) log.debug("Removing temp file", galaxyFileName) os.remove(galaxyFileName) # TODO: find you what's this code about #message = { # "sender": 'Galaxy %s' % galaxyName, # "senderID": obj.oid, # "forum": "NEWS", # "data": (obj.oid, MSG_GNC_GALAXY_GENERATOR, obj.oid, tran.db[OID_UNIVERSE].turn, (galaxyName, newGalaxy.description)), # "topic": "EVENT", #} log.debug("Galaxy Restarting END")
def isUpdateAvailable(self): """Check if client version matches server version and update client if neccessary""" log.message("Checking for update...") if "oslauncher" in sys.modules: log.message("Application launched from Outer Space Launcher -- will not update") return False updateMode = gdata.config.client.updatemode or "normal" # quit if update is disabled if updateMode == 'never': return False # compare server and client versions log.message("Retrieving server version") try: self.serverVersion = client.cmdProxy.getVersion() except KeyError: # call is not supported on older server versions log.debug("getVersion call not supported") self.reportFailure(_("Server does not support update feature yet. Check for updates manually, please.")) return None log.debug("Comparing server and client versions", self.serverVersion, ige.version.version) matches = True for i in ("major", "minor", "revision", "status"): if ige.version.version[i] != self.serverVersion[i]: matches = False if matches: log.message("Versions match, no need to update") return False log.message("Version do not match, update is needed") return True
def createNewGalaxy(self, tran, obj, x, y, galaxyName): log.message("Adding new galaxy '%s' to (%d, %d)" % (galaxyName, x, y)) fh, galaxyFileName = tempfile.mkstemp(text = True) log.debug("Generating new galaxy to temporary file", galaxyFileName) strGalaxyID = tran.gameMngr.config.server.newgalaxytype GenerateGalaxy(strGalaxyID, os.fdopen(fh, "w+b")) log.debug("Creating new galaxy") newGalaxyID = self.createGalaxy(tran, obj) log.debug("Created new galaxy", newGalaxyID) newGalaxy = tran.db[newGalaxyID] log.debug("Loading new ", newGalaxyID) self.cmd(newGalaxy).loadFromXML(tran, newGalaxy, galaxyFileName, strGalaxyID, x, y, galaxyName) log.debug("Setup Enviroment", newGalaxyID) self.cmd(newGalaxy).setupEnvironment(tran, newGalaxy) log.debug("Sending Announcement Message", newGalaxyID) #self.cmd(newGalaxy).announceGalaxy(tran,newGalaxy) log.debug("Removing temp file", galaxyFileName) os.remove(galaxyFileName) # TODO: find you what's this code about #message = { # "sender": 'Galaxy %s' % galaxyName, # "senderID": obj.oid, # "forum": "NEWS", # "data": (obj.oid, MSG_GNC_GALAXY_GENERATOR, obj.oid, tran.db[OID_UNIVERSE].turn, (galaxyName, newGalaxy.description)), # "topic": "EVENT", #} log.debug("Galaxy Restarting END")
def createNewGalaxy(self, tran, obj, x, y, galaxyName): galaxyType = tran.gameMngr.config.galaxytype if type(galaxyType) != str: # old configuration file log.debug("OLD configuration file detected, using server.newgalaxytype!") galaxyType = tran.gameMngr.config.server.newgalaxytype galaxyName = "Legacy Galaxy" assert galaxyType, "galaxytype must be defined in configuration file" print galaxyName log.message("Adding new galaxy '%s' with type '%s' to (%d, %d)" % (galaxyName, galaxyType, x, y)) fh, galaxyFileName = tempfile.mkstemp(text = True) log.debug("Generating new galaxy to temporary file", galaxyFileName) GenerateGalaxy(galaxyType, os.fdopen(fh, "w+b")) log.debug("Creating new galaxy") newGalaxyID = self.createGalaxy(tran, obj) log.debug("Created new galaxy", newGalaxyID) newGalaxy = tran.db[newGalaxyID] log.debug("Loading new ", newGalaxyID) self.cmd(newGalaxy).loadFromXML(tran, newGalaxy, galaxyFileName, galaxyType, x, y, galaxyName) log.debug("Setup Enviroment", newGalaxyID) self.cmd(newGalaxy).setupEnvironment(tran, newGalaxy) log.debug("Sending Announcement Message", newGalaxyID) #self.cmd(newGalaxy).announceGalaxy(tran,newGalaxy) log.debug("Removing temp file", galaxyFileName) os.remove(galaxyFileName) # TODO: find you what's this code about #message = { # "sender": 'Galaxy %s' % galaxyName, # "senderID": obj.oid, # "forum": "NEWS", # "data": (obj.oid, MSG_GNC_GALAXY_GENERATOR, obj.oid, tran.db[OID_UNIVERSE].turn, (galaxyName, newGalaxy.description)), # "topic": "EVENT", #} log.debug("Galaxy creation END")
def processDir(arg, dirname, names): log.message('Loading XML files from', dirname) names.sort() for filename in names: if os.path.splitext(filename)[1] == '.xml': log.message('Parsing XML file', filename) xml.sax.parse(os.path.join(dirname, filename), TechTreeContentHandler())
def _autoFinishOuterspace(self, tran, obj, galaxy): if tran.gameMngr.config.server.mode != "normal": # check autoend conditions, but only in normal mode # development mode does not end galaxies return for playerID in obj.players: player = tran.db[playerID] if galaxy.oid != player.galaxy: continue if player.type == Const.T_PIRPLAYER: piratePlayer = True activePlayerCount += 1 continue if player.type != Const.T_PLAYER: continue selfName = player.name activePlayerCount += 1 if activePlayerCount <= 1: log.message("AUTO FINISHING GALAXY", galaxy.oid) if activePlayerCount == 0: self.finishGalaxyAutomated(tran, obj, galaxy.oid, ["The galaxy was ended with no active players."]) elif piratePlayer: #if the pirate is still alive, then he must be the winner. self.finishGalaxyAutomated(tran, obj, galaxy.oid, ["The galaxy was automatically ended with the Pirate as a winner!"]) elif selfName: #if there is only one player, selfName must be themselves if it isn't null self.finishGalaxyAutomated(tran, obj, galaxy.oid, ["The galaxy was automatically ended with commander %s as the only remaining player." % selfName])
def restore(self, backupPath): """ Extracts data of the ai players, as well as the ais_list file. """ os.remove(os.path.join(self.configDir, "ais_list")) shutil.rmtree(os.path.join(self.configDir, "ai_data")) log.message("Restoring AI backup %s" % backupPath) tar = tarfile.open(backupPath, "r:bz2") tar.extractall() tar.close() self.lines = {} # parsing the file try: listfile = open(os.path.join(self.configDir, "ais_list"), "r") for row in listfile: line = row.strip().split(" ") if len(line) == 3: self.lines.update({line[0]: tuple([line[1], line[2]])}) elif len(line) == 4: self.lines.update({line[0]: tuple([line[1], line[2], line[3]])}) else: continue listfile.close() except Exception, e: listfile = open(os.path.join(self.configDir, "ais_list"), "a") listfile.close()
def createNewSubscribedGalaxy(self, tran, obj, galaxyName, galaxyType, listOfPlayers): galGen = GalaxyGenerator.GalaxyGenerator() galaxyRadius = galGen.getGalaxyTemplate(galaxyType).radius posX, posY = self.cmd(obj).findSpotForGalaxy(tran, obj, galaxyRadius) log.message("Adding new galaxy '%s' to (%d, %d)" % (galaxyType, posX, posY)) galaxyFileName = galGen.generateGalaxy(galaxyType) log.debug("Creating new galaxy") newGalaxyID = self.createGalaxy(tran, obj) log.debug("Created new galaxy", newGalaxyID) newGalaxy = tran.db[newGalaxyID] log.debug("Loading new ", newGalaxyID) self.cmd(newGalaxy).loadFromXML(tran, newGalaxy, galaxyFileName, galaxyType, posX, posY, galaxyName) log.debug("Setup Enviroment", newGalaxyID) self.cmd(newGalaxy).setupEnvironment(tran, newGalaxy) log.debug("Sending Announcement Message", newGalaxyID) #self.cmd(newGalaxy).announceGalaxy(tran,newGalaxy) log.debug("Removing temp file", galaxyFileName) os.remove(galaxyFileName) for playerLogin in listOfPlayers: tran.gameMngr.createNewSubscribedPlayer(playerLogin, newGalaxyID) if newGalaxy.scenario != Const.SCENARIO_SINGLE: # no point in announcing single scenario - it starts ticking right away self._sendCreationMessage(tran, obj, newGalaxy) log.debug("Galaxy creation END") return newGalaxyID
def enableTime(self, tran, obj, force=False): log.debug('IGalaxy', 'Checking for time...') if not force and not self._isEligibleEnableTime(tran, obj): return if obj.timeEnabled is None: self._firstEnableTime(tran, obj) # ok, enable time log.message('IGalaxy', 'Enabling time for', obj.oid) obj.timeEnabled = True self._trickleTimeToPlayers(tran, obj)
def enableTime(self, tran, obj, force = False): log.debug('IGalaxy', 'Checking for time...') if not force and not self._isEligibleEnableTime(tran, obj): return if obj.timeEnabled is None: self._firstEnableTime(tran, obj) # ok, enable time log.message('IGalaxy', 'Enabling time for', obj.oid) obj.timeEnabled = True self._trickleTimeToPlayers(tran, obj)
def importFromPath(path): import sys oldpath = sys.path try: sys.path = [path] log.debug("Rules import - using path", sys.path) exec "from rules import *" in globals() log.message("Rules import succeeded") finally: sys.path = oldpath
def loadFromXML(self, tran, obj, file, galID, x, y, name): log.message('IGalaxy', 'Parsing XML file...') dom = parse(os.path.join('data', file)) log.message('IGalaxy', 'XML file parsed.') assert dom.documentElement.tagName == 'universe' for node in dom.documentElement.childNodes: if node.nodeType == Node.ELEMENT_NODE and node.tagName == 'galaxy': if node.getAttribute('id') == galID: self.loadDOMNode(tran, obj, node, x, y, name) self.connectWormHoles(tran, obj) return SUCC raise GameException('No such id %s in resource' % galID)
def __init__(self, configuration): self.loadConfigFile(configuration) # inititalization self.initializeSharedMngrs() # initialize games self.games = list() for section in self.config.sections(): if not section.startswith("game"): continue config = self.config[section] log.message("INITIALIZING GAME", config.gameid) self.initializeGame(config)
def performDownload(self, updateDirectory): """Download zip with new version""" log.debug('Downloading new version') self.setProgress('Preparing download...', 0, 1) # setup proxies proxies = {} if gdata.config.proxy.http != None: proxies['http'] = gdata.config.proxy.http log.debug('Using proxies', proxies) # get file try: # open URL opener = urllib.build_opener(urllib.ProxyHandler(proxies)) # it unfortunately is not completely reliable for i in range(1, 5): try: ifh = opener.open(self.url) log.debug("Retrieving URL", ifh.geturl()) # download file total = int(ifh.info()["content-length"]) basename = re.search( '(?<=filename=).*', ifh.info()["content-disposition"]).group(0) break except KeyError: pygame.time.wait(1) if not basename: log.message("URL is not a file") self.reportFailure(_("Error: URL does not point to a file.")) return filename = os.path.join(updateDirectory, basename) log.debug("Downloading file %s of size %d" % (filename, total)) ofh = open(filename, "wb") # download and report progress downloaded = 0 while True: data = ifh.read(100000) if not data: break ofh.write(data) downloaded += len(data) log.debug("Download progress", downloaded, total) self.setProgress("Downloading update...", downloaded, total) ifh.close() ofh.close() return filename except urllib.error.URLError as e: log.warning("Cannot download file") self.reportFailure( _("Cannot finish download: %(s)") % str(e.reason)) return None
def updateDatabaseUnsafe(clearDB=0, force=0): """Update database by fetching data from the server.""" global lastUpdate, nonexistingObj, db # get real turn result = cmdProxy.getIntroInfo(Const.OID_UNIVERSE) if not db: db = IClientDB.IClientDB(result.cid, result.turn, options.configDir, cmdProxy.gameID) if clearDB: db.clear() db.turn = result.turn # if db.turn <= lastUpdate and not force: return log.message('IClient', 'Updating...') lastUpdate = db.turn nonexistingObj.clear() current = 0 max = 1 # compute total objects to be fetched max += 6 # clear map, get messages, ... current += 1 # delete selected objects # reset combatCounters for objID in db.keys(): obj = db[objID] if hasattr(obj, "combatCounter"): obj.combatCounter = 0 if not hasattr(obj, 'type'): del db[objID] elif obj.type == Const.T_FLEET: del db[objID] elif hasattr(obj, 'owner') and obj.owner == db.playerID \ and objID != db.playerID: # delete player's objects del db[objID] else: if hasattr(obj, "scanPwr"): obj.scanPwr = 0 if hasattr(obj, "scannerPwr"): obj.scannerPwr = 0 # update player db[db.playerID] = get(db.playerID) player = db[db.playerID] # update from scanner's map scannerMap = cmdProxy.getScannerMap(db.playerID) for objID in scannerMap: db[objID] = scannerMap[objID] # update player's planets and fleets for obj in cmdProxy.multiGetInfo(1, player.planets[:] + player.fleets[:]): db[obj.oid] = obj # finished log.message('IClient', 'Update finished.')
def updateDatabaseUnsafe(clearDB = 0, force = 0): """Update database by fetching data from the server.""" global lastUpdate, nonexistingObj, db # get real turn result = cmdProxy.getIntroInfo(Const.OID_UNIVERSE) if not db: db = IClientDB.IClientDB(result.cid, result.turn, options.configDir, cmdProxy.gameID) if clearDB: db.clear() db.turn = result.turn # if db.turn <= lastUpdate and not force: return log.message('IClient', 'Updating...') lastUpdate = db.turn nonexistingObj.clear() current = 0 max = 1 # compute total objects to be fetched max += 6 # clear map, get messages, ... current += 1 # delete selected objects # reset combatCounters for objID in db.keys(): obj = db[objID] if hasattr(obj, "combatCounter"): obj.combatCounter = 0 if not hasattr(obj, 'type'): del db[objID] elif obj.type in (Const.T_FLEET, Const.T_ASTEROID): del db[objID] elif hasattr(obj, 'owner') and obj.owner == db.playerID \ and objID != db.playerID: # delete player's objects del db[objID] else: if hasattr(obj, "scanPwr"): obj.scanPwr = 0 if hasattr(obj, "scannerPwr"): obj.scannerPwr = 0 # update player db[db.playerID] = get(db.playerID) player = db[db.playerID] # update from scanner's map scannerMap = cmdProxy.getScannerMap(db.playerID) for objID in scannerMap: db[objID] = scannerMap[objID] # update player's planets and fleets for obj in cmdProxy.multiGetInfo(1, player.planets[:] + player.fleets[:]): db[obj.oid] = obj # finished log.message('IClient', 'Update finished.')
def performDownload(self, updateDirectory): """Download zip with new version""" log.debug('Downloading new version') self.setProgress('Preparing download...', 0, 1) # setup proxies proxies = {} if gdata.config.proxy.http != None: proxies['http'] = gdata.config.proxy.http log.debug('Using proxies', proxies) # get file try: # open URL opener = urllib2.build_opener(urllib2.ProxyHandler(proxies)) # it unfortunately is not completely reliable for i in xrange(1,5): try: ifh = opener.open(self.url) log.debug("Retrieving URL", ifh.geturl()) # download file total = int(ifh.info()["content-length"]) basename = re.search('(?<=filename=).*', ifh.info()["content-disposition"]).group(0) break except KeyError: pygame.time.wait(1) if not basename: log.message("URL is not a file") self.reportFailure(_("Error: URL does not point to a file.")) return filename = os.path.join(updateDirectory, basename) log.debug("Downloading file %s of size %d" % (filename, total) ) ofh = open(filename, "wb") # download and report progress downloaded = 0 while True: data = ifh.read(100000) if not data: break ofh.write(data) downloaded += len(data) log.debug("Download progress", downloaded, total) self.setProgress("Downloading update...", downloaded, total) ifh.close() ofh.close() return filename except urllib2.URLError, e: log.warning("Cannot download file") self.reportFailure(_("Cannot finish download: %(s)") % str(e.reason)) return None
def initRules(path): log.message("Using ruleset", path) # import rules import sys try: importFromPath(path) except ImportError: path = os.path.join("res/rules", os.path.basename(path)) importFromPath(path) # import technologies import Techs global techs, Tech techs, Tech = Techs.initTechnologies(path) global rulesetName, rulesetPath rulesetName = os.path.basename(path) rulesetPath = path
def restore(self, backupPath): """ Extracts data of the ai players, as well as the ais_list file. """ os.remove(os.path.join(self.configDir, self.listname)) shutil.rmtree(os.path.join(self.configDir, 'ai_data', self.gameName)) log.message('Restoring AI backup {0}'.format(backupPath)) tar = tarfile.open(backupPath, 'r:bz2') tar.extractall() tar.close() self.records = [] # parsing the file try: self.records = json.load(open(os.path.join(self.configDir, self.listname), "r"), object_hook=aiRecordDecoder) except Exception, e: listfile = open(os.path.join(self.configDir, self.listname), "a") listfile.close()
def setUpdateAction(self): # check if update URL exists action, self.url = self.serverVersion["clientURLs"].get(sys.platform, self.serverVersion["clientURLs"]["*"]) version = "%(major)s.%(minor)s.%(revision)s%(status)s" % self.serverVersion text = [ _("Server requires client version %s. It is recommended to update your client.") % version, ] if action == "browser": # open webbrowser with given url text.append(_("Do you want to display download page?")) self.win.vConfirm.action = "onLaunchBrowser" elif action == "execute": # download and run binary installer text.append(_("Do you want to download and install new version?")) self.win.vConfirm.action = "onDownloadAndInstall" else: log.message("Unsupported update action", action) self.onCancel(None, None, _("Unsupported update type.")) self.win.vText.text = text
def enableTime(self, tran, obj, force=0, deleteSP=0, enable=1): log.debug('IGalaxy', 'Checking for time...') if not force: if obj.timeEnabled: return canRun = 0 # there must be at least 1/2 positions already assigned #if len(obj.startingPos) <= obj.numOfStartPos / 2 and obj.creationTime < time.time() - 2 * 24 * 3600: # log.debug("Half galaxy populated", len(obj.startingPos), obj.numOfStartPos) # canRun = 1 # at least two days must pass from creation if not obj.startingPos: log.debug("All positions taken, starting galaxy") canRun = 1 if obj.creationTime < time.time() - 2 * 24 * 3600: log.debug("Two days passed", obj.creationTime, time.time() - 2 * 24 * 3600) canRun = 1 if not canRun: return 0 # ok, enable time log.message('IGalaxy', 'Enabling time for', obj.oid) obj.timeEnabled = enable # close galaxy if deleteSP: obj.startingPos = [] # load new galaxy # TODO # enable time for players for systemID in obj.systems: system = tran.db[systemID] for planetID in system.planets: planet = tran.db[planetID] if planet.owner != OID_NONE: player = tran.db[planet.owner] if player.timeEnabled != enable: player.timeEnabled = enable player.lastLogin = time.time() if enable: Utils.sendMessage(tran, player, MSG_ENABLED_TIME, player.oid, None)
def onDownloadAndInstall(self, widget, action, data): """Download and run installer of the new version""" self.setProgress('Preparing download...', 0, 1) # setup proxies proxies = {} if gdata.config.proxy.http != None: proxies['http'] = gdata.config.proxy.http log.debug('Using proxies', proxies) # get file try: # open URL opener = urllib2.build_opener(urllib2.ProxyHandler(proxies)) ifh = opener.open(self.url) log.debug("Retrieving URL", ifh.geturl()) # download file total = int(ifh.info()["Content-Length"]) basename = os.path.basename(ifh.geturl()) if not basename: log.message("URL is not a file") self.reportFailure(_("Error: URL does not point to a file.")) return filename = os.path.join(self.options.configDir, basename) log.debug("Downloading file %s of size %d" % (filename, total) ) ofh = open(filename, "wb") # download and report progress downloaded = 0 while True: data = ifh.read(100000) if not data: break ofh.write(data) downloaded += len(data) log.debug("Download progress", downloaded, total) self.setProgress("Downloading update...", downloaded, total) ifh.close() ofh.close() except urllib2.URLError, e: log.warning("Cannot download file") self.reportFailure(_("Cannot finish download: %(s)") % str(e.reason)) return
def enableTime(self, tran, obj, force = 0, deleteSP = 0, enable = 1): log.debug('IGalaxy', 'Checking for time...') if not force: if obj.timeEnabled: return canRun = 0 # there must be at least 1/2 positions already assigned #if len(obj.startingPos) <= obj.numOfStartPos / 2 and obj.creationTime < time.time() - 2 * 24 * 3600: # log.debug("Half galaxy populated", len(obj.startingPos), obj.numOfStartPos) # canRun = 1 # at least two days must pass from creation if not obj.startingPos: log.debug("All positions taken, starting galaxy") canRun = 1 if obj.creationTime < time.time() - 2 * 24 * 3600: log.debug("Two days passed", obj.creationTime, time.time() - 2 * 24 * 3600) canRun = 1 if not canRun: return 0 # ok, enable time log.message('IGalaxy', 'Enabling time for', obj.oid) obj.timeEnabled = enable # close galaxy if deleteSP: obj.startingPos = [] # load new galaxy # TODO # enable time for players for systemID in obj.systems: system = tran.db[systemID] for planetID in system.planets: planet = tran.db[planetID] if planet.owner != OID_NONE: player = tran.db[planet.owner] if player.timeEnabled != enable: player.timeEnabled = enable player.lastLogin = time.time() if enable: Utils.sendMessage(tran, player, MSG_ENABLED_TIME, player.oid, None)
def initializeGame(self, config): """Initialize game according to configuration file fragment""" gameID = config.gameid # make sure we have required keys defined assert config.galaxytype, "%s.galaxytype MUST be defined" % gameID assert config.name, "%s.name MUST be defined" % gameID # initialize database and objects gameDB = Database(self.config.server.dbdir, "%s_game" % gameID, cache = 15000) msgDB = DatabaseString(self.config.server.dbdir, "%s_msgs" % gameID, cache = 1000) msgMngr = MsgMngr(msgDB) gameMngr = GameMngr(gameID, config, self.clientMngr, msgMngr, gameDB, self.config.server.datadir, config.name) # reset game if Universe does not exist if not gameDB.has_key(OID_UNIVERSE): log.message('Resetting game \'%s\'...' % gameID) gameMngr.reset() # normal operations gameMngr.init() if self.config.server.upgradegames: gameMngr.upgrade() msgMngr.upgrade() gameMngr.start() # keep reference to this game self.games.append(gameMngr)
def createNewSubscribedGalaxy(self, tran, obj, x, y, galaxyName, galaxyType, listOfPlayers): log.message("Adding new galaxy '%s' to (%d, %d)" % (galaxyName, x, y)) fileHandle, galaxyFileName = tempfile.mkstemp(text = True) log.debug("Generating new galaxy to temporary file", galaxyFileName) galGen = GalaxyGenerator.GalaxyGenerator() galGen.generateGalaxy(galaxyType, os.fdopen(fileHandle, "w+b")) log.debug("Creating new galaxy") newGalaxyID = self.createGalaxy(tran, obj) log.debug("Created new galaxy", newGalaxyID) newGalaxy = tran.db[newGalaxyID] log.debug("Loading new ", newGalaxyID) self.cmd(newGalaxy).loadFromXML(tran, newGalaxy, galaxyFileName, galaxyType, x, y, galaxyName) log.debug("Running scripts specific to booked galaxies", newGalaxyID) self.cmd(newGalaxy).bookedInit(tran, newGalaxy) log.debug("Setup Enviroment", newGalaxyID) self.cmd(newGalaxy).setupEnvironment(tran, newGalaxy) log.debug("Sending Announcement Message", newGalaxyID) #self.cmd(newGalaxy).announceGalaxy(tran,newGalaxy) log.debug("Removing temp file", galaxyFileName) os.remove(galaxyFileName) for playerInfo in listOfPlayers: tran.gameMngr.createNewSubscribedPlayer(playerInfo, newGalaxyID) log.debug("Galaxy creation END")
def processDir(arg, dirname, names): if dirname.find(".svn") >= 0: log.message("Skipping directory", dirname) return log.message('Loading XML files from', dirname) names.sort() for filename in names: if os.path.splitext(filename)[1] == '.xml': log.message('Parsing XML file', filename) xml.sax.parse(os.path.join(dirname, filename), TechTreeContentHandler())
def processDir(arg, dirname, names): if dirname.find(".svn") >= 0: log.message("Skipping directory", dirname) return log.message('Loading XML files from', dirname) names.sort() for filename in names: if os.path.splitext(filename)[1] == '.xml': log.message('Parsing XML file', filename) contentHandler = TechTreeContentHandler() contentHandler.setGlobals(techs, Tech) xml.sax.parse(os.path.join(dirname, filename), contentHandler)
def isUpdateAvailable(self): """Check if client version matches server version and update client if neccessary""" log.message("Checking for update...") updateMode = gdata.config.client.updatemode or "normal" # quit if update is disabled if updateMode == 'never': return False # compare server and client versions log.message("Retrieving server version") self.serverVersion = client.cmdProxy.getVersion() log.debug("Comparing server and client versions", self.serverVersion, clientVersion) matches = True for i in ("major", "minor", "revision", "status"): if clientVersion[i] != self.serverVersion[i]: matches = False if matches: log.message("Versions match, no need to update") return False log.message("Version do not match, update is needed") return True
def main(): log.message("Starting IGE - Outer Space Messager Client version", Ver.versionString) log.debug("sys.path =", sys.path) log.debug("os.name =", os.name) # create required directories if not os.path.exists('var'): os.mkdir('var') # parse configuration gdata.config = Config('var/osci.ini') # default configuration if gdata.config.game.server == None: gdata.config.game.server = 'www.ospace.net:9080' # prepare internationalization if gdata.config.client.language == None: gdata.config.client.language = 'en' language = gdata.config.client.language import gettext try: tran = gettext.translation('OSPACE', 'res', languages=[language]) except IOError: log.warning('OSCI', 'Cannot find catalog for', language) log.message('OSCI', 'Installing null translations') tran = gettext.NullTranslations() tran.install(unicode=1) log.message('OSCI', 'Translations installed for %s languaage' % language) # client from igeclient.IClient import IClientException client.initialize(gdata.config.game.server, handler) app = App(False) app.MainLoop() # write configuration log.debug("Saving configuration.") gdata.config.save('var/osci.ini') # logout client.logout() log.debug("Shut down")
def main(): log.message("Starting IGE - Outer Space Messager Client version", Ver.versionString) log.debug("sys.path =", sys.path) log.debug("os.name =", os.name) # create required directories if not os.path.exists('var'): os.mkdir('var') # parse configuration gdata.config = Config('var/osci.ini') # default configuration if gdata.config.game.server == None: gdata.config.game.server = 'www.ospace.net:9080' # prepare internationalization if gdata.config.client.language == None: gdata.config.client.language = 'en' language = gdata.config.client.language import gettext try: tran = gettext.translation('OSPACE', 'res', languages = [language]) except IOError: log.warning('OSCI', 'Cannot find catalog for', language) log.message('OSCI', 'Installing null translations') tran = gettext.NullTranslations() tran.install(unicode = 1) log.message('OSCI', 'Translations installed for %s languaage' % language) # client from igeclient.IClient import IClientException client.initialize(gdata.config.game.server, handler) app = App(False) app.MainLoop() # write configuration log.debug("Saving configuration.") gdata.config.save('var/osci.ini') # logout client.logout() log.debug("Shut down")
def createRSAKeys(): """Load or generate and save RSA keys""" global publicKey, privateKey if os.path.exists("var/private.pem"): log.message("Loading PRIVATE RSA key") privateKey = rsa.PrivateKey.load_pkcs1(open("var/private.pem", "rb").read()) if os.path.exists("var/public.pem"): log.message("Loading PUBLIC RSA key") publicKey = rsa.PublicKey.load_pkcs1(open("var/public.pem", "rb").read()) if privateKey and publicKey: return # no keys, let's generate them log.message("Generating RSA keys, please wait...") publicKey, privateKey = rsa.newkeys(2048) open("var/public.pem", "w").write(publicKey.save_pkcs1()) open("var/private.pem", "w").write(privateKey.save_pkcs1())
def processFINAL2Phase(self, tran, obj, data): # distribute stats to contacts for playerID in obj.players: player = tran.db[playerID] for partyID in player.diplomacyRels: dipl = player.diplomacyRels[partyID] if dipl.contactType > CONTACT_NONE and tran.db.has_key(partyID): dipl.stats = tran.db[partyID].stats else: dipl.stats = None # imperator voting turn = tran.db[OID_UNIVERSE].turn if (turn + 2 * Rules.turnsPerDay) % Rules.voteForImpPeriod == 0: for galaxyID in obj.galaxies: galaxy = tran.db[galaxyID] if not galaxy.timeEnabled: # skip this galaxy continue message = { "sender": "GNC", "senderID": galaxyID, "forum": "NEWS", "data": (galaxyID, MSG_GNC_VOTING_COMING, galaxyID, turn, None), "topic": "EVENT", } self.cmd(galaxy).sendMsg(tran, galaxy, message) if turn % Rules.voteForImpPeriod == 0: # voting # process each galaxy for galaxyID in obj.galaxies: log.debug("Voting for galaxy", galaxyID) galaxy = tran.db[galaxyID] if not galaxy.timeEnabled: # skip this galaxy continue # compute votes activePlayerCount = 0 piratePlayer = False selfName = None sum = 0 votes = {} votesID = {} voters = {} for playerID in obj.players: player = tran.db[playerID] if galaxyID not in player.galaxies: log.debug("Skipping player", playerID, " - not in this galaxy") continue if player.type == T_PIRPLAYER: log.debug("Skipping player", playerID, " - he/she is a pirate") piratePlayer = True activePlayerCount += 1 continue if player.type != T_PLAYER: log.debug("Skipping player", playerID, " - it's not a regular player") # skip non-regular players continue selfName = player.name # add to sum log.debug(playerID, "votes for", player.voteFor, "with votes", player.stats.slots) activePlayerCount += 1 sum += player.stats.slots if player.voteFor == OID_NONE: voteFor = None else: tmpPlayer = tran.db.get(player.voteFor, None) if not tmpPlayer or tmpPlayer.type != T_PLAYER: # reset vote player.voteFor = OID_NONE voteFor = None else: voteFor = tmpPlayer.name # count votes votes[voteFor] = votes.get(voteFor, 0) + player.stats.slots votesID[player.voteFor] = votesID.get(player.voteFor, 0) + player.stats.slots if voteFor in voters: voters[voteFor].append(player.name) else: voters[voteFor] = [player.name] # check winner nominated = votesID.keys() nominated.sort(lambda a, b: cmp(votesID[b], votesID[a])) winnerID = OID_NONE # remove OID_NONE from the list if OID_NONE in nominated: nominated.remove(OID_NONE) # check winner if nominated and float(votesID[nominated[0]]) / sum >= Rules.ratioNeededForImp: # we have the imperator! imperator = tran.db[nominated[0]] # 2 imperator, 3+ winner imperator.imperator = max(2, imperator.imperator + 1) if galaxy.imperator != OID_NONE and galaxy.imperator != imperator.oid: tran.db[galaxy.imperator].imperator = 0 galaxy.imperator = imperator.oid # send message message = { "sender": "GNC", "senderID": galaxyID, "forum": "NEWS", "data": (galaxyID, MSG_GNC_VOTING_IMPERATOR, galaxyID, turn, (imperator.name, (votes,voters))), "topic": "EVENT", } self.cmd(galaxy).sendMsg(tran, galaxy, message) elif len(nominated) >= 1: # we have the leader! leader = tran.db[nominated[0]] leader.imperator = 1 if galaxy.imperator != OID_NONE and galaxy.imperator != leader.oid: tran.db[galaxy.imperator].imperator = 0 galaxy.imperator = leader.oid # send message message = { "sender": "GNC", "senderID": galaxyID, "forum": "NEWS", "data": (galaxyID, MSG_GNC_VOTING_LEADER, galaxyID, turn, (leader.name, (votes,voters))), "topic": "EVENT", } self.cmd(galaxy).sendMsg(tran, galaxy, message) else: # nobody wins galaxy.imperator = OID_NONE message = { "sender": "GNC", "senderID": galaxyID, "forum": "NEWS", "data": (galaxyID, MSG_GNC_VOTING_NOWINNER, galaxyID, turn, ((votes,voters),)), "topic": "EVENT", } self.cmd(galaxy).sendMsg(tran, galaxy, message) # check one player win conditions, but only in normal mode (not development) if activePlayerCount <= 1 and tran.gameMngr.config.server.mode == "normal": log.message("AUTO RESTARTING GALAXY", galaxyID) if activePlayerCount == 0: self.restartGalaxy2(tran, obj, galaxyID, ["The galaxy was ended with no active players."]) elif piratePlayer: #if the pirate is still alive, then he must be the winner. self.restartGalaxy2(tran, obj, galaxyID, ["The galaxy was automatically ended with the Pirate as winner!"]) elif selfName: #if there is only one player, selfName must be themselves if it isn't null self.restartGalaxy2(tran, obj, galaxyID, ["The galaxy was automatically ended with commander %s as the only remaining player." % selfName]) # collect mailboxes used = [self.cmd(obj).getMailboxName(tran, obj)] for galaxyID in obj.galaxies: tmpObj = tran.db[galaxyID] used.append(self.cmd(tmpObj).getMailboxName(tran, tmpObj)) for playerID in obj.players: tmpObj = tran.db[playerID] used.append(self.cmd(tmpObj).getMailboxName(tran, tmpObj)) # trash unused mailboxes tran.gameMngr.msgMngr.trashUnusedMailboxes(used) return obj.galaxies
def saveDB(): if db: log.message('OSClient', 'Saving database') db.save()
def _save(): # shut down game try: if game: log.message('Shutting down game...') game.shutdown() if msgMngr: log.message('Shutting down message manager...') msgMngr.shutdown() if clientMngr: log.message('Shutting down client manager...') clientMngr.shutdown() if issueMngr: log.message('Shutting down issue manager...') issueMngr.shutdown() if bookingMngr: log.message('Shutting down booking manager...') bookingMngr.shutdown() except: log.exception("Shutdown of the server failed") config.save() log.message('Shutted down') log.message("Cleaning up...")
optRestore = arg elif opt == "--config": optConfig = os.path.abspath(arg) elif opt == "--workingdir": optWorkingDir = arg # change workding directory (if required) if optWorkingDir: os.chdir(optWorkingDir) # legacy logger from ige import log log.setMessageLog('var/logs/messages.log') log.setErrorLog('var/logs/errors.log') log.message("Working directory", os.getcwd()) # read configuration from ige.Config import Config log.message("Configuration file", optConfig) config = Config(optConfig) # record my pid pidFd = os.open("var/server.pid", os.O_CREAT | os.O_EXCL | os.O_WRONLY) os.write(pidFd, str(os.getpid())) # TODO: check if server.pid points to the running process game = None msgMngr = None clientMngr = None issueMngr = None
def updateDatabaseUnsafe(clearDB=0, force=0): """Update database by fetching data from the server.""" global lastUpdate, nonexistingObj, db # get real turn result = cmdProxy.getIntroInfo(OID_UNIVERSE) if not db: db = IClientDB.IClientDB(result.cid, result.turn) if clearDB: db.clear() db.turn = result.turn # if db.turn <= lastUpdate and not force: return log.message('IClient', 'Updating...') lastUpdate = db.turn nonexistingObj.clear() # start updating... messageIgnore(SMESSAGE_NEWTURN) messageIgnore(SMESSAGE_NEWMESSAGE) callbackObj.onUpdateStarting() current = 0 max = 1 # compute total objects to be fetched max += 6 # clear map, get messages, ... current += 1 callbackObj.onUpdateProgress(current, max, _("Deleting obsolete data...")) # delete selected objects # reset combatCounters for objID in db.keys(): obj = db[objID] if hasattr(obj, "combatCounter"): obj.combatCounter = 0 if not hasattr(obj, 'type'): del db[objID] elif obj.type in (T_FLEET, T_ASTEROID): del db[objID] elif hasattr(obj, 'owner') and obj.owner == db.playerID \ and objID != db.playerID: # delete player's objects del db[objID] else: if hasattr(obj, "scanPwr"): obj.scanPwr = 0 if hasattr(obj, "scannerPwr"): obj.scannerPwr = 0 # update player current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading player data...")) db[db.playerID] = get(db.playerID) player = db[db.playerID] # update from scanner's map current += 1 callbackObj.onUpdateProgress(current, max, _("Updating scanner...")) map = cmdProxy.getScannerMap(db.playerID) for objID in map: db[objID] = map[objID] # update player's planets and fleets current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading planets and fleets data...")) for obj in cmdProxy.multiGetInfo(1, player.planets[:] + player.fleets[:]): db[obj.oid] = obj #~ # compute system's positions #~ current += 1 #~ callbackObj.onUpdateProgress(current, max, _("Updating astronomical coordinates...")) #~ systems = {} #~ for objID in db.keys(): #~ obj = db[objID] #~ if obj.type == T_SYSTEM or obj.type == T_PLANET: #~ if obj.type == T_SYSTEM: #~ galaxy = get(obj.compOf) #~ system = obj #~ else: #~ if obj.compOf in systems: #~ system = systems[obj.compOf] #~ else: #~ system = get(obj.compOf, canBePublic = 0) #~ systems[obj.compOf] = system #~ if hasattr(system, "compOf"): #~ galaxy = get(system.compOf) #~ else: #~ continue #~ angle = system.sAngle / 1000.0 + (db.turn / Rules.rotationMod) * system.dAngle / 1000.0 #~ obj.x = galaxy.x + system.dist * math.cos(angle) / 1000.0 #~ obj.y = galaxy.y + system.dist * math.sin(angle) / 1000.0 #~ del systems # TODO: try to load allies's info # get messages from server current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading messages...")) getMessages() # clean maps on server current += 1 callbackObj.onUpdateProgress(current, max, _("Clearing data on the server...")) try: cmdProxy.setResolution(db.playerID, gdata.scrnSize[0], gdata.scrnSize[1]) except: log.debug('Server does not yet support resolution tracking') # TODO not needed - delete cmdProxy.clearScannerMap(db.playerID) # finished log.message('IClient', 'Update finished.') callbackObj.onUpdateFinished() messageEnable(SMESSAGE_NEWTURN) messageEnable(SMESSAGE_NEWMESSAGE)
def init(configDir): global Tech, techs ## check, if anything has been changed def chsumDir(chsum, dirname, names): names.sort() for filename in names: if os.path.splitext(filename)[1] in ('.xml', '.py'): log.debug('Checking file', filename) fh = open(os.path.join(dirname, filename), 'rb') chsum.update(fh.read()) fh.close() # compute checksum moduleFile = sys.modules['ige.ospace.Rules'].__file__ forceLoad = 0 # regular module moduleDirectory = os.path.dirname(moduleFile) chsum = hashlib.sha1() os.walk(moduleDirectory, chsumDir, chsum) # read old checksum try: fh = open(os.path.join(configDir, 'checksum'), 'rb') oldChsum = fh.read() fh.close() except IOError: oldChsum = '' # compare if forceLoad or chsum.hexdigest() == oldChsum: # load old definitions log.message('Loading stored specifications from', configDir) techs = pickle.load(open(os.path.join(configDir, 'techs.spf'), 'rb')) Tech = pickle.load(open(os.path.join(configDir, 'Tech.spf'), 'rb')) log.message("There is %d technologies" % len(techs)) # clean up 'type' in lists for key in attrs.keys(): if type(attrs[key]) == list and len(attrs[key]) == 1: log.debug("Cleaning up " + key) attrs[key] = [] else: # create new ones ## load technologies definitions def processDir(arg, dirname, names): log.message('Loading XML files from', dirname) names.sort() for filename in names: if os.path.splitext(filename)[1] == '.xml': log.message('Parsing XML file', filename) xml.sax.parse(os.path.join(dirname, filename), TechTreeContentHandler()) # collect xml files os.walk(moduleDirectory, processDir, None) # clean up 'type' in lists for key in attrs.keys(): if type(attrs[key]) == list and len(attrs[key]) == 1: log.debug("Cleaning up " + key) attrs[key] = [] elif type(attrs[key]) == dict and len(attrs[key]) == 1: log.debug("Cleaning up " + key) attrs[key] = {} # link tech tree using researchRequires fields # construct researchEnables fields log.message('Converting symbolic fields...') for techID in techs.keys(): tech = techs[techID] # convert symbolic names to numbers techIDs = [] for techSymName in tech.researchRequires: symName, improvement = techSymName.split('-') techIDs.append((getattr(Tech, symName), int(improvement))) tech.researchRequires = techIDs techIDs = {1: [], 2: [], 3: [], 4: [], 5: [], 6: []} for techSymName in tech.researchEnables: improvement, symName = techSymName.split('-') techIDs[int(improvement)].append(getattr(Tech, symName)) tech.researchEnables = techIDs techIDs = [] for techSymName in tech.researchDisables: techIDs.append(getattr(Tech, techSymName)) tech.researchDisables = techIDs techIDs = [] if tech.unpackStruct: tech.unpackStruct = getattr(Tech, tech.unpackStruct) else: tech.unpackStruct = 0 # strat. resources # this has to be here to prevent import deadlock in Rules from ige.ospace.Rules import stratResAmountBig from ige.ospace.Rules import stratResAmountSmall stratRes = [] for sr in tech.researchReqSRes: stratRes.append(getattr(Const, sr)) tech.researchReqSRes = stratRes # build requirements with quantities stratRes = {} for resource in tech.buildSRes: resource_id = getattr(Const, resource) # prescription contains constants for big and small amounts # possibly within expression resource_amount = eval(tech.buildSRes[resource]) stratRes[resource_id] = resource_amount tech.buildSRes = stratRes # evaluate researchMod if tech.researchMod == "expr": tech.researchMod = 1.0 else: tech.researchMod = eval(tech.researchMod) # link log.message('Linking tech tree...') for techID in techs.keys(): tech = techs[techID] for tmpTechID, improvement in tech.researchRequires: if techID not in techs[tmpTechID].researchEnables[improvement]: techs[tmpTechID].researchEnables[improvement].append( techID) for improvement in tech.researchEnables.keys(): for tmpTechID in tech.researchEnables[improvement]: if (techID, improvement ) not in techs[tmpTechID].researchRequires: techs[tmpTechID].researchRequires.append( (techID, improvement)) changed = 1 while changed: changed = 0 log.debug("Tech disable iteration") for techID in techs: tech = techs[techID] for tech2ID in tech.researchDisables: tech2 = techs[tech2ID] if techID not in tech2.researchDisables and techID != tech2ID: tech2.researchDisables.append(techID) changed = 1 log.debug("Adding", tech2ID, "DISABLES", techID, ", NOW", tech2.researchDisables) for tech3ID in tech2.researchDisables: tech3 = techs[tech3ID] if tech3ID not in tech.researchDisables and tech3ID != techID: tech.researchDisables.append(tech3ID) changed = 1 log.debug("Adding", techID, "DISABLES", tech3ID, "NOW", tech.researchDisables) # save new specification log.message('Saving specification...') pickle.dump(techs, open(os.path.join(configDir, 'techs.spf'), 'wb'), 1) pickle.dump(Tech, open(os.path.join(configDir, 'Tech.spf'), 'wb'), 1) fh = open(os.path.join(configDir, 'checksum'), 'w') fh.write(chsum.hexdigest()) fh.close() log.message("There is %d technologies" % len(techs))
def runAIClient(options): import time import traceback import sys import os # tweak PYTHONPATH basepath = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(basepath, "client/osci")) for item in ("libsrvr", "server/lib"): path = os.path.join(basepath, item) if os.path.exists(path): sys.path.insert(0, path) break from config import Config import osci, random, time import ige.version from ige import log import os, os.path import re # log initialization log.message("Starting Outer Space Client", ige.version.versionString) log.debug("sys.path =", sys.path) log.debug("os.name =", os.name) log.debug("sys.platform =", sys.platform) log.debug("os.getcwd() =", os.getcwd()) log.debug("sys.frozen =", getattr(sys, "frozen", None)) # create required directories if not os.path.exists(options.configDir): os.makedirs(options.configDir) # client import ai_client as client from igeclient.IClient import IClientException if options.ai: try: ai = __import__("AIs." + options.ai) ai = sys.modules["AIs." + options.ai] except: # This prints the type, value, and stack trace of the # current exception being handled. traceback.print_exc() raise else: raise Exception, 'You have to provide AI.' import ige.ospace.Const as Const import gdata # reload is here for multiprocessing support (as the process is used more # than once reload(client) gdata.config = Config(os.path.join(options.configDir, 'ais_dummy')) client.initialize(options.server, options) import gettext tran = gettext.NullTranslations() tran.install(unicode=1) if options.login: login = options.login else: raise Exception, 'You have to provide login.' if options.password: password = options.password else: raise Exception, 'You have to provide password.' # first get list of sessions, then iterate over them # this is to prevent exceptions flooding logs # TODO: make session optional argument for main_ai_pool if client.login(options.game, login, password): activePositions = client.cmdProxy.getActivePositions() client.logout() if options.test: return True else: return False for playerID, galaxyName, playerType in activePositions: if options.galaxies and galaxyName not in options.galaxies: continue client.login(options.game, login, password) client.cmdProxy.selectPlayer(playerID) client.updateDatabase() try: ai.run(client) except Exception as e: # This prints the type, value, and stack trace of the # current exception being handled. traceback.print_exc() raise e client.logout()
def updateDatabaseUnsafe(clearDB=0, force=0): """Update database by fetching data from the server.""" global lastUpdate, nonexistingObj, db # get real turn result = cmdProxy.getIntroInfo(Const.OID_UNIVERSE) if not db: dbLocation = os.path.join(options.configDir, 'player_data') db = IClientDB.IClientDB(result.cid, result.turn, dbLocation, cmdProxy.gameID) if clearDB: db.clear() db.turn = result.turn # if db.turn <= lastUpdate and not force: return log.message('IClient', 'Updating...') lastUpdate = db.turn nonexistingObj.clear() # start updating... messageIgnore(Const.SMESSAGE_NEWTURN) messageIgnore(Const.SMESSAGE_NEWMESSAGE) callbackObj.onUpdateStarting() current = 0 max = 1 # compute total objects to be fetched max += 6 # clear map, get messages, ... current += 1 callbackObj.onUpdateProgress(current, max, _("Deleting obsolete data...")) # delete selected objects # reset combatCounters for objID in db.keys(): obj = db[objID] if hasattr(obj, "combatCounter"): obj.combatCounter = 0 if not hasattr(obj, 'type'): del db[objID] elif obj.type in (Const.T_FLEET, Const.T_ASTEROID): del db[objID] elif hasattr(obj, 'owner') and obj.owner == db.playerID \ and objID != db.playerID: # delete player's objects del db[objID] else: if hasattr(obj, "scanPwr"): obj.scanPwr = 0 if hasattr(obj, "scannerPwr"): obj.scannerPwr = 0 # update player current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading player data...")) db[db.playerID] = get(db.playerID) player = db[db.playerID] # update from scanner's map current += 1 callbackObj.onUpdateProgress(current, max, _("Updating scanner...")) map = cmdProxy.getScannerMap(db.playerID) for objID in map: db[objID] = map[objID] # update player's planets and fleets current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading planets and fleets data...")) for obj in cmdProxy.multiGetInfo(1, player.planets[:] + player.fleets[:]): db[obj.oid] = obj # TODO: try to load allies's info # get messages from server current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading messages...")) getMessages() log.message('IClient', 'Update finished.') callbackObj.onUpdateFinished() messageEnable(Const.SMESSAGE_NEWTURN) messageEnable(Const.SMESSAGE_NEWMESSAGE)
def checkForUpdate(): global totalSize, downloadedSize, progressDlg, currentFilename # check platform, only 'nt' is supported for now if os.name != 'nt': log.message("Unsupported platform '%s' -- will not update" % os.name) return if "oslauncher" in sys.modules: log.message( "Application launched from Outer Space Launcher -- will not update" ) return if not hasattr(sys, "frozen"): log.message("Application not frozen using py2exe -- will not update") return # remove old update directory try: shutil.rmtree('_update') except: pass # update mode if gdata.config.client.updatemode != None: updateMode = gdata.config.client.updatemode else: updateMode = 'normal' gdata.config.client.updatemode = updateMode # quit if update is disabled if updateMode == 'never': return # force update on every start. TODO remove - just for Alfa/Beta testing updateMode = 'always' # check for config if gdata.config.client.updateurl == None: gdata.config.client.updateurl = 'http://www.ospace.net/files/osclient/latest/' url = gdata.config.client.updateurl # check for last update if gdata.config.client.lastupdate != None: lastUpdate = gdata.config.client.lastupdate else: lastUpdate = 'NEVER' now = time.strftime('%Y-%m-%d') log.debug('UPDATER', 'Checking last update. Last update:', lastUpdate) if lastUpdate == now and updateMode != 'always': return # init dialog progressDlg = dialog.ProgressDlg(gdata.app) progressDlg.display('Updating client', 0, 1) progressDlg.setProgress('Checking for updates...', 0, 1) # read global checksum log.debug('UPDATER', 'Downloading %schecksum.global' % url) # create urlopener proxies = {} if gdata.config.proxy.http != None: proxies['http'] = gdata.config.proxy.http log.debug('UPDATER', 'Using proxies', proxies) urlopener = urllib.FancyURLopener(proxies) try: fh = urlopener.open(url + 'checksum.global') latestChsum = fh.read() fh.close() latestChsum = latestChsum.strip() except IOError: # cannot update log.warning('UPDATER', 'Cannot download file.') progressDlg.hide() return log.debug('UPDATER', 'Downloading checksum.global') try: fh = open('checksum.global', 'r') myChsum = fh.read() fh.close() myChsum = myChsum.strip() except IOError: myChsum = None log.debug('UPDATER', 'Global chsums:', latestChsum, myChsum) if latestChsum == myChsum: updateConfig() progressDlg.hide() return # load files chsums progressDlg.setProgress('Selecting files to update...', 0, 1) log.debug('UPDATER', 'Downloading %schecksum.files' % url) try: fh = urlopener.open(url + 'checksum.files') latestData = fh.read() fh.close() except IOError: log.warning('UPDATER', 'Cannot download file.') progressDlg.hide() return log.debug('UPDATER', 'Downloading checksum.files') try: fh = open('checksum.files', 'r') myData = fh.read() fh.close() except IOError: myData = '' # parse latestChsums = {} recipe = [] retrieve = [] totalSize = 0 for line in latestData.split('\n'): if not line: continue chsum, file, size = line.strip().split(' ') size = int(size) latestChsums[file] = (chsum, size) for line in myData.split('\n'): if not line: continue chsum, file, size = line.strip().split(' ') size = int(size) if latestChsums.has_key(file): # file remains, check, if update shall be performed if latestChsums[file][0] != chsum or not os.path.exists(file): retrieve.append((file, latestChsums[file][1])) totalSize += latestChsums[file][1] recipe.append('C%s' % file) del latestChsums[file] else: # remove old file recipe.append('D%s' % file) # new files for file in latestChsums.keys(): retrieve.append((file, latestChsums[file][1])) totalSize += latestChsums[file][1] recipe.append('C%s' % file) # log #@log.debug('UPDATER', 'Retrieve', retrieve) #@log.debug('UPDATER', 'Total length', totalSize) #@log.debug('UPDATER', 'Recipe', recipe) # retrieve file by file downloadedSize = 0 for filename, size in retrieve: currentFilename = os.path.basename(filename) fileUrl = '%s%s' % (url, filename) log.debug('UPDATER', 'Downloading', fileUrl) progressDlg.setProgress('Downloading file %s...' % currentFilename, downloadedSize, totalSize) targetFile = os.path.join('_update', filename) try: os.makedirs(os.path.dirname(targetFile)) except OSError: pass try: urlopener.retrieve(fileUrl, targetFile, retrieveCallback) except IOError: log.warning('UPDATER', 'Cannot download file.') progressDlg.hide() return downloadedSize += size # finish progressDlg.setProgress('Finishing upgrade...') updateConfig() # save latest checksums fh = open('checksum.global', 'w') fh.write(latestChsum) fh.close() fh = open('checksum.files', 'w') fh.write(latestData) fh.close() # save update header = ['_update', '.', 'osc.exe', str(len(recipe))] header.extend(recipe) fh = open('.update', 'w') fh.write(string.join(header, '\n')) fh.close() # copy update program (if possible) try: shutil.copy2('_update/update.exe', '.') os.remove('_update/update.exe') except IOError: pass # delete data files # decide if this is needed #log.warning('UPDATER', 'Deleting data files...') #for filename in glob.glob('var/[0-9]*.data'): # os.remove(filename) #for filename in glob.glob('var/[0-9]*.timestamp'): # os.remove(filename) # execute update program # TODO does not work os.spawnv(os.P_NOWAIT, 'update.exe', ()) os.startfile('update.exe') progressDlg.hide() log.warning('UPDATER', 'Exitting...') sys.exit(1)
def cleanup(): # shut down game try: if game: log.message('Shutting down game...') game.shutdown() if msgMngr: log.message('Shutting down message manager...') msgMngr.shutdown() if clientMngr: log.message('Shutting down client manager...') clientMngr.shutdown() if issueMngr: log.message('Shutting down issue manager...') issueMngr.shutdown() except: log.exception("Shutdown of the server failed") log.message('Shutted down') log.message("Cleaning up...") # delete my pid os.close(pidFd) os.remove("var/server.pid")
def runAIClient(options): import time import traceback import sys import os # tweak PYTHONPATH basepath = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(basepath, "client/osci")) for item in ("libsrvr", "server/lib"): path = os.path.join(basepath, item) if os.path.exists(path): sys.path.insert(0, path) break from config import Config import osci, random, time import ige.version from ige import log import os, os.path import re # log initialization log.message("Starting Outer Space Client", ige.version.versionString) log.debug("sys.path =", sys.path) log.debug("os.name =", os.name) log.debug("sys.platform =", sys.platform) log.debug("os.getcwd() =", os.getcwd()) log.debug("sys.frozen =", getattr(sys, "frozen", None)) # create required directories if not os.path.exists(options.configDir): os.makedirs(options.configDir) # client import ai_client as client from igeclient.IClient import IClientException if options.ai: try: ai = __import__("AIs." + options.ai) ai = sys.modules["AIs." + options.ai] except: # This prints the type, value, and stack trace of the # current exception being handled. traceback.print_exc() raise else: raise Exception, 'You have to provide AI.' import ige.ospace.Const as Const import gdata # reload is here for multiprocessing support (as the process is used more # than once reload(client) gdata.config = Config(os.path.join(options.configDir, 'ais_dummy')) client.initialize(options.server, options) import gettext tran = gettext.NullTranslations() tran.install(unicode = 1) if options.login: login = options.login else: raise Exception, 'You have to provide login.' if options.password: password = options.password else: raise Exception, 'You have to provide password.' # first get list of sessions, then iterate over them # this is to prevent exceptions flooding logs # TODO: make session optional argument for main_ai_pool if client.login(options.game, login, password): activePositions = client.cmdProxy.getActivePositions() client.logout() if options.test: return True else: return False for playerID, galaxyName, playerType in activePositions: if options.galaxies and galaxyName not in options.galaxies: continue client.login(options.game, login, password) client.cmdProxy.selectPlayer(playerID) client.updateDatabase() try: ai.run(client) except Exception as e: # This prints the type, value, and stack trace of the # current exception being handled. traceback.print_exc() raise e client.logout()
def runAIClient(options): import time import sys import os # tweak PYTHONPATH basepath = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.join(basepath, "client/osci")) for item in ("libsrvr", "server/lib"): path = os.path.join(basepath, item) if os.path.exists(path): sys.path.insert(0, path) break from config import Config import osci, random, time import ige.version from ige import log import os, os.path import re # log initialization log.message("Starting Outer Space Client", ige.version.versionString) log.debug("sys.path =", sys.path) log.debug("os.name =", os.name) log.debug("sys.platform =", sys.platform) log.debug("os.getcwd() =", os.getcwd()) log.debug("sys.frozen =", getattr(sys, "frozen", None)) # create required directories if not os.path.exists(options.configDir): os.makedirs(options.configDir) # client import ai_client as client import ai_handler from igeclient.IClient import IClientException if options.ai: ai = __import__("AIs." + options.ai) ai = sys.modules["AIs." + options.ai] else: raise Exception, 'You have to provide AI.' import ige.ospace.Const as Const import gdata # reload is here for multiprocessing support (as the process is used more # than once reload(client) gdata.config = Config(os.path.join(options.configDir, 'ais_dummy')) client.initialize(options.server, ai_handler, options) import gettext tran = gettext.NullTranslations() tran.install(unicode = 1) if options.login: login = options.login else: raise Exception, 'You have to provide login.' if options.password: password = options.password else: raise Exception, 'You have to provide password.' client.login(options.game, login, password) # event loop client.updateDatabase() ai.run(client) client.logout() log.debug("Shut down")
def initTechnologies(path): """Init technologies from XML files in the path""" # holder for all technologies techs = {} # holder for tech IDs Tech = IDataHolder() # compute checksum file = sys.modules[__name__].__file__ forceLoad = 0 if os.path.exists(file): # regular module chsum = sha.new() os.path.walk(path, chsumDir, chsum) else: # packed, cannot access xml specifications path = os.path.join('res', 'rules/standard') forceLoad = 1 # read old checksum try: fh = open(os.path.join(path, 'checksum'), 'rb') oldChsum = fh.read() fh.close() except IOError: oldChsum = '' # compare if forceLoad or chsum.hexdigest() == oldChsum: # load old definitions log.message('Loading stored specifications from', path) techs = pickle.load(open(os.path.join(path, 'techs.spf'), 'rb')) Tech = pickle.load(open(os.path.join(path, 'Tech.spf'), 'rb')) log.message("There is %d technologies" % len(techs)) # clean up 'type' in lists for key in attrs.keys(): if type(attrs[key]) == types.ListType and len(attrs[key]) == 1: log.debug("Cleaning up", key) attrs[key] = [] return techs, Tech # create new ones ## load technologies definitions def processDir(arg, dirname, names): if dirname.find(".svn") >= 0: log.message("Skipping directory", dirname) return log.message('Loading XML files from', dirname) names.sort() for filename in names: if os.path.splitext(filename)[1] == '.xml': log.message('Parsing XML file', filename) contentHandler = TechTreeContentHandler() contentHandler.setGlobals(techs, Tech) xml.sax.parse(os.path.join(dirname, filename), contentHandler) # collect xml files os.path.walk(path, processDir, None) # clean up 'type' in lists for key in attrs.keys(): if type(attrs[key]) == types.ListType and len(attrs[key]) == 1: log.debug("Cleaning up", key) attrs[key] = [] # link tech tree using researchRequires fields # construct researchEnables fields log.message('Converting symbolic fields...') for techID in techs.keys(): tech = techs[techID] # convert symbolic names to numbers techIDs = [] for techSymName in tech.researchRequires: #@log.debug('Converting REQ', techSymName) symName, improvement = techSymName.split('-') techIDs.append((getattr(Tech, symName), int(improvement))) tech.researchRequires = techIDs techIDs = {1: [], 2:[], 3:[], 4:[], 5:[], 6:[]} for techSymName in tech.researchEnables: #@log.debug('Converting EN', techSymName) improvement, symName = techSymName.split('-') techIDs[int(improvement)].append(getattr(Tech, symName)) tech.researchEnables = techIDs techIDs = [] for techSymName in tech.researchDisables: techIDs.append(getattr(Tech, techSymName)) tech.researchDisables = techIDs techIDs = [] if tech.unpackStruct: tech.unpackStruct = getattr(Tech, tech.unpackStruct) else: tech.unpackStruct = 0 # strat. resources stratRes = [] for sr in tech.researchReqSRes: stratRes.append(getattr(Const, sr)) tech.researchReqSRes = stratRes stratRes = [] for sr in tech.buildSRes: stratRes.append(getattr(Const, sr)) tech.buildSRes = stratRes # evaluate researchMod if tech.researchMod == "expr": tech.researchMod = 1.0 else: tech.researchMod = eval(tech.researchMod) #~ # convert weapons #~ techIDs = [] #~ for weaponName in tech.weapons: #~ techIDs.append(getattr(Tech, weaponName)) #~ tech.weapons = techIDs # link log.message('Linking tech tree...') for techID in techs.keys(): tech = techs[techID] #@log.debug(techID, 'Req', tech.researchRequires) #@log.debug(techID, 'En', tech.researchEnables) for tmpTechID, improvement in tech.researchRequires: if techID not in techs[tmpTechID].researchEnables[improvement]: #@log.debug('Adding', tmpTechID, improvement, 'ENABLES', techID) techs[tmpTechID].researchEnables[improvement].append(techID) for improvement in tech.researchEnables.keys(): for tmpTechID in tech.researchEnables[improvement]: if (techID, improvement) not in techs[tmpTechID].researchRequires: #@log.debug('Adding', tmpTechID, 'REQUIRES', techID, improvement) techs[tmpTechID].researchRequires.append((techID, improvement)) changed = 1 while changed: changed = 0 log.debug("Tech disable iteration") for techID in techs: tech = techs[techID] for tech2ID in tech.researchDisables: tech2 = techs[tech2ID] if techID not in tech2.researchDisables and techID != tech2ID: tech2.researchDisables.append(techID) changed = 1 log.debug("Adding", tech2ID, "DISABLES", techID, ", NOW", tech2.researchDisables) for tech3ID in tech2.researchDisables: tech3 = techs[tech3ID] if tech3ID not in tech.researchDisables and tech3ID != techID: tech.researchDisables.append(tech3ID) changed = 1 log.debug("Adding", techID, "DISABLES", tech3ID, "NOW", tech.researchDisables) # just for debug #for techID in techs.keys(): # tech = techs[techID] # log.debug('Link:', techID, tech.isStarting, tech.researchRequires, tech.researchEnables) # save new specification log.message('Saving specification...') pickle.dump(techs, open(os.path.join(path, 'techs.spf'), 'wb'), 1) pickle.dump(Tech, open(os.path.join(path, 'Tech.spf'), 'wb'), 1) fh = open(os.path.join(path, 'checksum'), 'wb') fh.write(chsum.hexdigest()) fh.close() log.message("There is %d technologies" % len(techs)) return techs, Tech
def _generateKeys(size): global publicKey, privateKey # no keys, let's generate them log.message("Generating RSA keys of size {0}, please wait...".format(size)) publicKey, privateKey = rsa.newkeys(size)
def logout(): if cmdProxy and cmdProxy.logged: cmdProxy.logout() if db: log.message('OSClient', 'Saving database') db.save()
def backup(self, backupPath): """ Creates bzip2 archive of ais_list file and ai_data directory """ log.debug('Creating backup {0}-ais.osbackup'.format(backupPath)) tar = tarfile.open('{0}-ais.osbackup'.format(backupPath), 'w:bz2') tar.add(os.path.join(self.configDir, self.listname)) tar.add(os.path.join(self.configDir, 'ai_data', self.gameName)) tar.close() def restore(self, backupPath): """ Extracts data of the ai players, as well as the ais_list file. """ os.remove(os.path.join(self.configDir, self.listname)) shutil.rmtree(os.path.join(self.configDir, 'ai_data', self.gameName)) log.message('Restoring AI backup {0}'.format(backupPath)) tar = tarfile.open(backupPath, 'r:bz2') tar.extractall() tar.close() self.records = [] # parsing the file try: self.records = json.load(open(os.path.join(self.configDir, self.listname), "r"), object_hook=aiRecordDecoder) except Exception, e: listfile = open(os.path.join(self.configDir, self.listname), "a") listfile.close() log.message('AI backup restored')
def updateDatabaseUnsafe(clearDB = 0, force = 0): """Update database by fetching data from the server.""" global lastUpdate, nonexistingObj, db # get real turn result = cmdProxy.getIntroInfo(OID_UNIVERSE) if not db: db = IClientDB.IClientDB(result.cid, result.turn, options.configDir) if clearDB: db.clear() db.turn = result.turn # if db.turn <= lastUpdate and not force: return log.message('IClient', 'Updating...') lastUpdate = db.turn nonexistingObj.clear() # start updating... messageIgnore(SMESSAGE_NEWTURN) messageIgnore(SMESSAGE_NEWMESSAGE) callbackObj.onUpdateStarting() current = 0 max = 1 # compute total objects to be fetched max += 6 # clear map, get messages, ... current += 1 callbackObj.onUpdateProgress(current, max, _("Deleting obsolete data...")) # delete selected objects # reset combatCounters for objID in db.keys(): obj = db[objID] if hasattr(obj, "combatCounter"): obj.combatCounter = 0 if not hasattr(obj, 'type'): del db[objID] elif obj.type in (T_FLEET, T_ASTEROID): del db[objID] elif hasattr(obj, 'owner') and obj.owner == db.playerID \ and objID != db.playerID: # delete player's objects del db[objID] else: if hasattr(obj, "scanPwr"): obj.scanPwr = 0 if hasattr(obj, "scannerPwr"): obj.scannerPwr = 0 # update player current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading player data...")) db[db.playerID] = get(db.playerID) player = db[db.playerID] # update from scanner's map current += 1 callbackObj.onUpdateProgress(current, max, _("Updating scanner...")) map = cmdProxy.getScannerMap(db.playerID) for objID in map: db[objID] = map[objID] # update player's planets and fleets current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading planets and fleets data...")) for obj in cmdProxy.multiGetInfo(1, player.planets[:] + player.fleets[:]): db[obj.oid] = obj #~ # compute system's positions #~ current += 1 #~ callbackObj.onUpdateProgress(current, max, _("Updating astronomical coordinates...")) #~ systems = {} #~ for objID in db.keys(): #~ obj = db[objID] #~ if obj.type == T_SYSTEM or obj.type == T_PLANET: #~ if obj.type == T_SYSTEM: #~ galaxy = get(obj.compOf) #~ system = obj #~ else: #~ if obj.compOf in systems: #~ system = systems[obj.compOf] #~ else: #~ system = get(obj.compOf, canBePublic = 0) #~ systems[obj.compOf] = system #~ if hasattr(system, "compOf"): #~ galaxy = get(system.compOf) #~ else: #~ continue #~ angle = system.sAngle / 1000.0 + (db.turn / Rules.rotationMod) * system.dAngle / 1000.0 #~ obj.x = galaxy.x + system.dist * math.cos(angle) / 1000.0 #~ obj.y = galaxy.y + system.dist * math.sin(angle) / 1000.0 #~ del systems # TODO: try to load allies's info # get messages from server current += 1 callbackObj.onUpdateProgress(current, max, _("Skipping messages...")) # getMessages() # clean maps on server current += 1 callbackObj.onUpdateProgress(current, max, _("Clearing data on the server...")) try: cmdProxy.setResolution(db.playerID,gdata.scrnSize[0],gdata.scrnSize[1]) except: log.debug('Server does not yet support resolution tracking') # TODO not needed - delete cmdProxy.clearScannerMap(db.playerID) # finished log.message('IClient', 'Update finished.') callbackObj.onUpdateFinished() messageEnable(SMESSAGE_NEWTURN) messageEnable(SMESSAGE_NEWMESSAGE)
def runClient(options): # log initialization log.message("Starting Outer Space Client", ige.version.versionString) log.debug("sys.path =", sys.path) log.debug("os.name =", os.name) log.debug("sys.platform =", sys.platform) log.debug("os.getcwd() =", os.getcwd()) log.debug("sys.frozen =", getattr(sys, "frozen", None)) # create required directories if not os.path.exists(options.configDir): os.makedirs(options.configDir) log.debug("options.configDir =", options.configDir) running = 1 first = True #while running: if not first: reload(osci) # parse configuration if first: import osci.gdata as gdata else: reload(gdata) gdata.config = Config( os.path.join(options.configDir, options.configFilename)) gdata.config.game.server = options.server setDefaults(gdata, options) language = gdata.config.client.language import gettext log.debug('OSCI', 'Installing translation for:', language) if language == 'en': log.debug('OSCI', 'English is native - installing null translations') tran = gettext.NullTranslations() else: try: tran = gettext.translation('OSPACE', resources.get('translations'), languages=[language]) except IOError: log.warning('OSCI', 'Cannot find catalog for', language) log.message('OSCI', 'Installing null translations') tran = gettext.NullTranslations() tran.install(unicode=1) #initialize pygame and prepare screen if (gdata.config.defaults.sound == "yes") or (gdata.config.defaults.music == "yes"): pygame.mixer.pre_init(44100, -16, 2, 4096) os.environ['SDL_VIDEO_ALLOW_SCREENSAVER'] = '1' os.environ['SDL_DEBUG'] = '1' pygame.init() flags = pygame.SWSURFACE DEFAULT_SCRN_SIZE = (800, 600) gdata.scrnSize = DEFAULT_SCRN_SIZE if gdata.config.display.resolution == "FULLSCREEN": gdata.scrnSize = (0, 0) flags |= pygame.FULLSCREEN elif gdata.config.display.resolution is not None: width, height = gdata.config.display.resolution.split('x') gdata.scrnSize = (int(width), int(height)) if gdata.config.display.depth == None: # guess best depth bestdepth = pygame.display.mode_ok(gdata.scrnSize, flags) else: bestdepth = int(gdata.config.display.depth) # initialize screen try: screen = pygame.display.set_mode(gdata.scrnSize, flags, bestdepth) # gdata.scrnSize is used everywhere to setup windows gdata.scrnSize = screen.get_size() except pygame.error: # for example if fullscreen is selected with resolution bigger than display # TODO: as of now, fullscreen has automatic resolution gdata.scrnSize = DEFAULT_SCRN_SIZE screen = pygame.display.set_mode(gdata.scrnSize, flags, bestdepth) gdata.screen = screen log.debug('OSCI', 'Driver:', pygame.display.get_driver()) log.debug('OSCI', 'Using depth:', bestdepth) log.debug('OSCI', 'Display info:', pygame.display.Info()) pygame.mouse.set_visible(1) pygame.display.set_caption(_('Outer Space %s') % ige.version.versionString) # set icon pygame.display.set_icon( pygame.image.load(resources.get('icon48.png')).convert_alpha()) # UI stuff if first: import pygameui as ui else: reload(ui) setSkinTheme(gdata, ui) app = ui.Application(update, theme=ui.SkinableTheme) app.background = defineBackground() app.draw(gdata.screen) app.windowSurfaceFlags = pygame.SWSURFACE | pygame.SRCALPHA gdata.app = app pygame.event.clear() # resources import osci.res osci.res.initialize() # load resources import osci.dialog dlg = osci.dialog.ProgressDlg(gdata.app) osci.res.loadResources(dlg) dlg.hide() osci.res.prepareUIIcons(ui.SkinableTheme.themeIcons) while running: if first: import osci.client, osci.handler from igeclient.IClient import IClientException else: reload(osci.client) reload(osci.handler) osci.client.initialize(gdata.config.game.server, osci.handler, options) # create initial dialogs if first: import osci.dialog else: reload(osci.dialog) gdata.savePassword = gdata.config.game.lastpasswordcrypted != None if options.login and options.password: gdata.config.game.lastlogin = options.login gdata.config.game.lastpassword = options.password gdata.config.game.lastpasswordcrypted = binascii.b2a_base64( options.password).strip() gdata.config.game.autologin = '******' gdata.savePassword = '******' loginDlg = osci.dialog.LoginDlg(gdata.app) updateDlg = osci.dialog.UpdateDlg(gdata.app) # event loop update() lastSave = time.clock() # set counter to -1 to trigger Update dialog (see "if" below) counter = -1 needsRefresh = False session = 1 first = False while running and session: try: counter += 1 if counter == 0: # display initial dialog in the very first cycle updateDlg.display(caller=loginDlg, options=options) # process as many events as possible before updating evt = pygame.event.wait() evts = pygame.event.get() evts.insert(0, evt) forceKeepAlive = False saveDB = False for evt in evts: if evt.type == pygame.QUIT: running = 0 break if evt.type == ( ui.USEREVENT) and evt.action == "localExit": session = False break if evt.type == pygame.ACTIVEEVENT: if evt.gain == 1 and evt.state == 6: # pygame desktop window focus event needsRefresh = True if evt.type == pygame.KEYUP and evt.key == pygame.K_F12: if not pygame.key.get_mods() & pygame.KMOD_CTRL: running = 0 break if evt.type == pygame.KEYUP and evt.key == pygame.K_F9: forceKeepAlive = True evt = gdata.app.processEvent(evt) if gdata.app.needsUpdate() or needsRefresh: needsRefresh = False update() # keep alive connection osci.client.keepAlive(forceKeepAlive) # save DB every 4 hours in case of a computer crash # using "counter" to limit calls to time.clock() to approximately every 10-15 minutes if counter > 5000: # set this to zero so we don't display Update dialog counter = 0 if time.clock() - lastSave > 14400: saveDB = True if saveDB: osci.client.saveDB() lastSave = time.clock() except IClientException, e: osci.client.reinitialize() gdata.app.setStatus(e.args[0]) loginDlg.display(message=e.args[0]) except Exception, e: log.warning('OSCI', 'Exception in event loop') if not isinstance(e, SystemExit) and not isinstance( e, KeyboardInterrupt): log.debug("Processing exception") # handle exception import traceback, StringIO fh = StringIO.StringIO() exctype, value, tb = sys.exc_info() funcs = [entry[2] for entry in traceback.extract_tb(tb)] faultID = "%06d-%03d" % ( hash("/".join(funcs)) % 1000000, traceback.extract_tb(tb)[-1][1] % 1000, ) del tb # high level info print >> fh, "Exception ID:", faultID print >> fh print >> fh, "%s: %s" % (exctype, value) print >> fh print >> fh, "--- EXCEPTION DATA ---" # dump exception traceback.print_exc(file=fh) excDlg = osci.dialog.ExceptionDlg(gdata.app) excDlg.display(faultID, fh.getvalue()) del excDlg # reference to the dialog holds app's intance fh.close() del fh else: break
def processFINALPhase(self, tran, obj, data): if obj.timeEnabled: #try/except so that entire final process doesn't break on error in sub-phase try: self.cmd(obj).processRSRCHPhase(tran, obj, data) except: log.warning('Cannot execute FINAL/RSRCH on %d' % (obj.oid)) try: self.cmd(obj).processDIPLPhase(tran, obj, data) except: log.warning('Cannot execute FINAL/DIPL on %d' % (obj.oid)) # efficiency obj.prodEff = 1.0 obj.sciEff = 1.0 if obj.imperator == 1: log.debug(obj.oid, "Leader bonus") obj.prodEff += Rules.galLeaderBonus obj.sciEff += Rules.galLeaderBonus elif obj.imperator >= 2: log.debug(obj.oid, "Imperator bonus") obj.prodEff += Rules.galImperatorBonus obj.sciEff += Rules.galImperatorBonus #@log.debug("Fleet upgrade pool", obj.oid, obj.fleetUpgradePool, obj.fleetUpgradeInProgress) # compute some stats # TODO remove, RAW SCI PTS represented now obj.stats.prodSci = obj.effSciPoints obj.stats.planets = len(obj.planets) # fleet support #@log.debug("Fleet support", obj.oid, obj.stats.fleetSupportProd, obj.stats.prodProd) if obj.stats.fleetSupportProd > 0 and obj.stats.prodProd > 0: # TODO 0.1 shall be dependend on the race / government type obj.prodEff += min(0.1 - float(obj.stats.fleetSupportProd + obj.fleetUpgradePool * Rules.operProdRatio) / obj.stats.prodProd, 0.0) # delete non active player if obj.lastLogin + Rules.playerTimeout < time.time(): log.message("Resigning inactive player", obj.name, obj.oid) # TODO send a message? self.cmd(obj).resign(tran, obj) # delete nonactive newbie player if obj.lastLogin + Rules.novicePlayerTimeout < time.time() \ and len(obj.planets) < 4: log.message("Resigning inactive novice player", obj.name, obj.oid) # TODO send a message? self.cmd(obj).resign(tran, obj) # acquire government power if obj.planets: planet = tran.db[obj.planets[0]] for slot in planet.slots: tech = Rules.techs[slot[STRUCT_IDX_TECHID]] if tech.govPwr > 0 and slot[STRUCT_IDX_STATUS] & STRUCT_STATUS_ON: eff = Utils.getTechEff(tran, slot[STRUCT_IDX_TECHID], obj.oid) obj.govPwr = max(int(tech.govPwr * eff * (slot[STRUCT_IDX_OPSTATUS] / 100.0)), obj.govPwr) # compute government controll range if not hasattr(obj,"tmpPopDistr"): #when player is force-resigned, tmpPopDistr is unset. This is easiest fix. obj.tmpPopDistr = {} ranges = obj.tmpPopDistr.keys() ranges.sort() sum = 0 range = 1 for range in ranges: sum += obj.tmpPopDistr[range] if sum > obj.govPwr: break obj.govPwrCtrlRange = max(1, range) if sum < obj.govPwr and sum > 0: #@log.debug(obj.oid, "GovPwr compensation", obj.govPwrCtrlRange, obj.govPwr, sum) obj.govPwrCtrlRange = int(obj.govPwrCtrlRange * obj.govPwr / float(sum)) #@log.debug(obj.oid, "GovPwr control range", obj.govPwrCtrlRange) # compute prodBonus and sciBonus sum = 0 for range in ranges: sum += obj.tmpPopDistr[range] if sum < obj.govPwr and sum > 0: ratio = float(obj.govPwr - sum) / obj.govPwr #@log.debug(obj.oid, "SMALL EMPIRE BONUS", ratio, "govPwr", obj.govPwr, "sum", sum) # TODO let user to define how much to invest into prod and to sci obj.prodEff += ratio / 2 obj.sciEff += ratio / 2 del obj.tmpPopDistr # delete temporary attribute # increase prod eff from pacts # CPs from allies sum = 0 for partnerID in obj.diplomacyRels: if self.cmd(obj).isPactActive(tran, obj, partnerID, PACT_MINOR_CP_COOP): partner = tran.db[partnerID] pactSpec = Rules.pactDescrs[PACT_MINOR_CP_COOP] sum += min( partner.stats.prodProd * pactSpec.effectivity, obj.stats.prodProd * pactSpec.effectivity, ) if self.cmd(obj).isPactActive(tran, obj, partnerID, PACT_MAJOR_CP_COOP): partner = tran.db[partnerID] pactSpec = Rules.pactDescrs[PACT_MAJOR_CP_COOP] sum += min( partner.stats.prodProd * pactSpec.effectivity, obj.stats.prodProd * pactSpec.effectivity, ) # apply production increase pool obj.prodIncreasePool += sum if obj.stats.prodProd > 0: ratio = (Rules.unusedProdMod * obj.prodIncreasePool) / obj.stats.prodProd real = min(ratio, math.sqrt(ratio)) #@log.debug(obj.oid, "Increase production by", ratio, "real", real) obj.prodEff += real # clean up prodEff if prodEff < 0 (prevent abuse) if obj.prodEff < 0: obj.prodEff = 0.0 # clean up ship redirections systems = {} for planetID in obj.planets: systems[tran.db[planetID].compOf] = None for systemID in obj.shipRedirections.keys(): if systemID not in systems: del obj.shipRedirections[systemID] # delete allied bouys obj.alliedBuoys = {} # find all allies for partnerID in obj.diplomacyRels.keys(): dipl = obj.diplomacyRels[partnerID] getAllyBuoys = False getScannerBuoys = False if dipl.relation >= REL_ALLY_LO: getAllyBuoys = True if self.isPactActive(tran, obj, partnerID, PACT_SHARE_SCANNER): getScannerBuoys = True if (getAllyBuoys or getScannerBuoys): partner = tran.db[partnerID] if hasattr(partner, "buoys"): for systemID in partner.buoys.keys(): toAllyBuoy = BUOY_NONE if getAllyBuoys and partner.buoys[systemID][1] == BUOY_TO_ALLY: toAllyBuoy = (partner.buoys[systemID][0], BUOY_FROM_ALLY, partner.name) elif getScannerBuoys and partner.buoys[systemID][1] == BUOY_TO_SCANNERSHARE: toAllyBuoy = (partner.buoys[systemID][0], BUOY_FROM_ALLY, partner.name) if toAllyBuoy != BUOY_NONE: if systemID in obj.alliedBuoys: obj.alliedBuoys[systemID].append(toAllyBuoy) else: obj.alliedBuoys[systemID] = [toAllyBuoy] return None
def updateDatabaseUnsafe(clearDB = 0, force = 0): """Update database by fetching data from the server.""" global lastUpdate, nonexistingObj, db # get real turn result = cmdProxy.getIntroInfo(Const.OID_UNIVERSE) if not db: dbLocation = os.path.join(options.configDir, 'player_data') db = IClientDB.IClientDB(result.cid, result.turn, dbLocation, cmdProxy.gameID) if clearDB: db.clear() db.turn = result.turn # if db.turn <= lastUpdate and not force: return log.message('IClient', 'Updating...') lastUpdate = db.turn nonexistingObj.clear() # start updating... messageIgnore(Const.SMESSAGE_NEWTURN) messageIgnore(Const.SMESSAGE_NEWMESSAGE) callbackObj.onUpdateStarting() current = 0 max = 1 # compute total objects to be fetched max += 6 # clear map, get messages, ... current += 1 callbackObj.onUpdateProgress(current, max, _("Deleting obsolete data...")) # delete selected objects # reset combatCounters for objID in db.keys(): obj = db[objID] if hasattr(obj, "combatCounter"): obj.combatCounter = 0 if not hasattr(obj, 'type'): del db[objID] elif obj.type in (Const.T_FLEET, Const.T_ASTEROID): del db[objID] elif hasattr(obj, 'owner') and obj.owner == db.playerID \ and objID != db.playerID: # delete player's objects del db[objID] else: if hasattr(obj, "scanPwr"): obj.scanPwr = 0 if hasattr(obj, "scannerPwr"): obj.scannerPwr = 0 # update player current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading player data...")) db[db.playerID] = get(db.playerID) player = db[db.playerID] # update from scanner's map current += 1 callbackObj.onUpdateProgress(current, max, _("Updating scanner...")) map = cmdProxy.getScannerMap(db.playerID) for objID in map: db[objID] = map[objID] # update player's planets and fleets current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading planets and fleets data...")) for obj in cmdProxy.multiGetInfo(1, player.planets[:] + player.fleets[:]): db[obj.oid] = obj # TODO: try to load allies's info # get messages from server current += 1 callbackObj.onUpdateProgress(current, max, _("Downloading messages...")) getMessages() log.message('IClient', 'Update finished.') callbackObj.onUpdateFinished() messageEnable(Const.SMESSAGE_NEWTURN) messageEnable(Const.SMESSAGE_NEWMESSAGE)
def runServer(options): import os import shutil import sys import time import passlib # checking it early in the process # setup system path baseDir = os.path.abspath(os.path.dirname(__file__)) sys.path.insert(0, os.path.join(baseDir, "lib")) sys.path.insert(0, os.path.join(baseDir, "..", "client-ai")) sys.path.insert(0, os.path.join(baseDir, "data")) import os, atexit #configure gc #import gc #gc.set_debug(gc.DEBUG_STATS | gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | # gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS) # legacy logger from ige import log log.setMessageLog(os.path.join(options.configDir,'logs/messages.log')) log.setErrorLog(os.path.join(options.configDir,'logs/errors.log')) import ige.version log.message("Outer Space %s" % ige.version.versionString) #~ # standard logger #~ import logging, logging.handlers #~ log = logging.getLogger() #~ log.setLevel(logging.DEBUG) #~ # file handler #~ h = logging.handlers.RotatingFileHandler(os.path.join(options.configDir,'log/server.log'), 'a', 16 * 1024 * 1024, 5) #~ h.setLevel(logging.INFO) #~ h.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(name)s %(message)s')) #~ log.addHandler(h) #~ # stdout handler (TODO: disable in productin server) #~ h = logging.StreamHandler(sys.stdout) #~ h.setLevel(logging.DEBUG) #~ h.setFormatter(logging.Formatter('%(created)d %(levelname)-5s %(name)-8s %(message)s')) #~ log.addHandler(h) # record my pid pidFd = os.open(os.path.join(options.configDir,"server.pid"), os.O_CREAT | os.O_EXCL | os.O_WRONLY) os.write(pidFd, str(os.getpid())) # TODO: check if server.pid points to the running process game = None msgMngr = None clientMngr = None issueMngr = None bookingMngr = None # define and register exit function def _save(): # shut down game try: if game: log.message('Shutting down game...') game.shutdown() if msgMngr: log.message('Shutting down message manager...') msgMngr.shutdown() if clientMngr: log.message('Shutting down client manager...') clientMngr.shutdown() if issueMngr: log.message('Shutting down issue manager...') issueMngr.shutdown() if bookingMngr: log.message('Shutting down booking manager...') bookingMngr.shutdown() except: log.exception("Shutdown of the server failed") config.save() log.message('Shutted down') log.message("Cleaning up...") def _cleanup(pidFd): _save() # delete my pid os.close(pidFd) os.remove(os.path.join(options.configDir,"server.pid")) cleanup = _cleanup atexit.register(cleanup, pidFd) #~fh = open(pidFilename, 'w') #~print >> fh, os.getpid() #~fh.close() # startup game log.debug('Importing IGE modules...') # set runtime mode ige.setRuntimeMode(options.mode) import ige.RPCServer as server import ige from ige.ClientMngr import ClientMngr from ige.MsgMngr import MsgMngr from ige.IssueMngr import IssueMngr from ige.ospace.GameMngr import GameMngr from ige.BookingMngr import BookingMngr # read configuration from ige.Config import Config log.message("Reading configuration from", os.path.join(options.configDir, options.configFilename)) config = Config(os.path.join(options.configDir, options.configFilename)) gameName = 'Alpha' # open database from ige.SQLiteDatabase import Database, DatabaseString if not config.vip.password: config.vip.password = '' log.debug("Creating databases...") gameDB = Database(os.path.join(options.configDir,"db_data"), "game_%s" % gameName, cache = 15000) clientDB = DatabaseString(os.path.join(options.configDir,"db_data"), "accounts", cache = 100) msgDB = DatabaseString(os.path.join(options.configDir,"db_data"), "messages", cache = 1000) bookingDB = DatabaseString(os.path.join(options.configDir,"db_data"), "bookings", cache = 100) if options.restore: gameDB.restore("%s-game_%s.osbackup" % (options.restore, gameName)) clientDB.restore("%s-accounts.osbackup" % options.restore) # TODO: remove afer fix of the message database # the following code imports to the message database only valid entries # and forces mailbox scan incl = [1] incl.extend(gameDB[1].galaxies) incl.extend(gameDB[1].players) def include(k, l = incl): for i in l: if k.startswith("%s-%d-" % (gameName, i)) or (k == "%s-%d" % (gameName, i)): return True return False msgDB.restore("%s-messages.osbackup" % options.restore, include = include) bookingDB.restore("%s-bookings.osbackup" % options.restore, include = include) # initialize game log.message('Initializing game \'%s\'...' % gameName) log.debug("Initializing issue manager") issueMngr = IssueMngr() log.debug("Initializing client manager") clientMngr = ClientMngr(clientDB, config.server.authmethod, options.configDir) log.debug("Initializing message manager") msgMngr = MsgMngr(msgDB) log.debug("Initializing game manager") game = GameMngr(gameName, config, clientMngr, msgMngr, gameDB, options.configDir) log.debug("Initializing booking manager") bookingMngr = BookingMngr(clientMngr, game, bookingDB) # either forced reset, or uninitialized server if options.reset or not gameDB.keys(): # reset game log.message('Resetting game \'%s\'...' % gameName) game.reset() # remote web directory should be populated for the first time # with contents of server/website # but then, no overwrite should happen, as we want customization # to be painless if not os.path.exists(os.path.join(options.configDir, 'website')): log.debug("Populating website directory") actual_dir = os.path.dirname(os.path.realpath(__file__)) shutil.copytree(os.path.join(actual_dir, 'website'), os.path.join(options.configDir, 'website')) # normal operations game.init() if options.upgrade: game.upgrade() msgMngr.upgrade() bookingMngr.upgrade() game.start() server.init(clientMngr, bookingMngr) server.register(game) server.xmlrpcPublish('clientmngr', clientMngr) server.xmlrpcPublish('issuemngr', issueMngr) log.message('Initialized. Starting server...') try: import psyco psyco.full() log.message("Using psyco with full acceleration") except ImportError: log.message("NOT using psyco") server.start(options.configDir)