def presetWebService(self): # web service to get the content of the preset file if self.vars.preset == None: raiseHttp(400, "Missing parameter preset") preset = self.vars.preset if IS_ALPHANUMERIC()(preset)[1] is not None: raiseHttp(400, "Preset name must be alphanumeric") if IS_LENGTH(maxsize=32, minsize=1)(preset)[1] is not None: raiseHttp(400, "Preset name must be between 1 and 32 characters") print("presetWebService: preset={}".format(preset)) fullPath = '{}/{}.json'.format(getPresetDir(preset), preset) # check that the presets file exists if os.path.isfile(fullPath): # load it try: params = PresetLoader.factory(fullPath).params except Exception as e: raiseHttp(400, "Can't load the preset") params = json.dumps(params) return params else: raiseHttp(400, "Preset not found")
def trackerWebService(self): # unified web service for item/area trackers ws = WS.factory(self) ws.validate() ret = ws.action() if ret is None: # return something raiseHttp(200, "OK", True) else: return ret
def randoParamsWebService(self): # get a json string of the randomizer parameters for a given seed. # seed is the id in randomizer table, not actual seed number. if self.vars.seed == None: raiseHttp(400, "Missing parameter seed", True) seed = getInt(self.request, 'seed', False) if seed < 0 or seed > sys.maxsize: raiseHttp(400, "Wrong value for seed", True) with DB() as db: (seed, params) = db.getRandomizerSeedParams(seed) return json.dumps({"seed": seed, "params": params})
def downloadPlandoWebService(self): if self.vars.plando is None: raiseHttp(400, "Missing parameter plando") plandoName = self.vars.plando if IS_LENGTH(maxsize=32, minsize=1)(plandoName)[1] is not None: raiseHttp(400, "Plando name must be between 1 and 32 characters") if IS_MATCH('^[a-zA-Z0-9 -_]*$')(plandoName)[1] is not None: raiseHttp(400, "Plando name can only contain [a-zA-Z0-9 -_]") ipsFileName = os.path.join(ipsBasePath, "{}.ips".format(plandoName)) if not os.path.isfile(ipsFileName): raiseHttp(400, "Plando ips not found on server") with open(ipsFileName, 'rb') as ipsFile: ipsData = ipsFile.read() with DB() as db: maxSize = db.getPlandoIpsMaxSize(plandoName) db.increaseDownloadCount(plandoName) data = { "ips": base64.b64encode(ipsData).decode(), "fileName": "{}.sfc".format(plandoName), "maxSize": maxSize } return json.dumps(data)
def getSpcFile(self): songName = self.vars.songName if IS_NOT_EMPTY()(songName)[1] is not None: raiseHttp(400, "Song is empty") if IS_MATCH('[a-zA-Z0-9_\.() ,\-/]*', strict=True)(songName)[1] is not None: raiseHttp(400, "Invalid char in song name") if IS_LENGTH(64)(songName)[1] is not None: raiseHttp(400, "Song must be max 64 chars") print("getSpcFile songName: {}".format(songName)) musics = self.loadMusics() if songName not in musics: raiseHttp(400, "No preview for this song") if 'spc_path' not in musics[songName] or musics[songName][ 'spc_path'] == "": raiseHttp(400, "No preview for this song") songFile = musics[songName]['spc_path'] with open(os.path.join('music', songFile), 'rb') as spcFile: spcFileData = spcFile.read() return json.dumps({'spc': base64.b64encode(spcFileData).decode()})
def skillPresetActionWebService(self): print("skillPresetActionWebService call") if self.session.presets is None: self.session.presets = {} # for create/update, not load (ok, msg) = self.validatePresetsParams(self.vars.action) if not ok: raiseHttp(400, json.dumps(msg)) else: self.session.presets['currentTab'] = self.vars.currenttab if self.vars.action == 'Create': preset = self.vars.presetCreate else: preset = self.vars.preset # check if the presets file already exists password = self.vars['password'] password = password.encode('utf-8') passwordSHA256 = hashlib.sha256(password).hexdigest() fullPath = '{}/{}.json'.format(getPresetDir(preset), preset) if os.path.isfile(fullPath): # load it end = False try: oldParams = PresetLoader.factory(fullPath).params except Exception as e: msg = "UC:Error loading the preset {}: {}".format(preset, e) end = True if end == True: raiseHttp(400, json.dumps(msg)) # check if password match if 'password' in oldParams and passwordSHA256 == oldParams[ 'password']: # update the presets file paramsDict = self.genJsonFromParams(self.vars) paramsDict['password'] = passwordSHA256 try: PresetLoader.factory(paramsDict).dump(fullPath) with DB() as db: db.addPresetAction(preset, 'update') self.updatePresetsSession() msg = "Preset {} updated".format(preset) return json.dumps(msg) except Exception as e: msg = "Error writing the preset {}: {}".format(preset, e) raiseHttp(400, json.dumps(msg)) else: msg = "Password mismatch with existing presets file {}".format( preset) raiseHttp(400, json.dumps(msg)) else: # prevent a malicious user from creating presets in a loop if not self.maxPresetsReach(): # write the presets file paramsDict = self.genJsonFromParams(self.vars) paramsDict['password'] = passwordSHA256 try: PresetLoader.factory(paramsDict).dump(fullPath) with DB() as db: db.addPresetAction(preset, 'create') self.updatePresetsSession() # add new preset in cache (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) comPresets.append(preset) comPresets.sort(key=lambda v: v.upper()) msg = "Preset {} created".format(preset) return json.dumps(msg) except Exception as e: msg = "Error writing the preset {}: {}".format(preset, e) raiseHttp(400, json.dumps(msg)) redirect(URL(r=request, f='presets')) else: msg = "Sorry, maximum number of presets reached, can't add more" raiseHttp(400, json.dumps(msg))
def customWebService(self): print("customWebService") # check validity of all parameters switchs = [ 'itemsounds', 'spinjumprestart', 'rando_speed', 'elevators_speed', 'fast_doors', 'AimAnyButton', 'max_ammo_display', 'supermetroid_msu1', 'Infinite_Space_Jump', 'refill_before_save', 'customSpriteEnable', 'customItemsEnable', 'noSpinAttack', 'customShipEnable', 'remove_itemsounds', 'remove_elevators_speed', 'remove_fast_doors', 'remove_Infinite_Space_Jump', 'remove_rando_speed', 'remove_spinjumprestart', 'gamepadMapping', 'widescreen', 'hell', 'lava_acid_physics' ] others = [ 'colorsRandomization', 'suitsPalettes', 'beamsPalettes', 'tilesPalettes', 'enemiesPalettes', 'bossesPalettes', 'minDegree', 'maxDegree', 'invert', 'hellrun_rate', 'etanks' ] validateWebServiceParams(self.request, switchs, [], [], others, isJson=True) if self.vars.customSpriteEnable == 'on': if self.vars.customSprite == 'random': for sprite in self.vars.customSpriteMultiSelect.split(','): if sprite not in customSprites: raiseHttp(400, "Wrong value for customSpriteMultiSelect", True) elif self.vars.customSprite not in customSprites: raiseHttp(400, "Wrong value for customSprite", True) if self.vars.customShipEnable == 'on': if self.vars.customShip == 'random': for ship in self.vars.customShipMultiSelect.split(','): if ship not in customShips: raiseHttp(400, "Wrong value for customShipMultiSelect", True) elif self.vars.customShip not in customShips: raiseHttp(400, "Wrong value for customShip", True) if self.vars.music not in [ "Don't touch", "Disable", "Randomize", "Customize", "Restore" ]: raiseHttp(400, "Wrong value for music", True) if self.session.customizer == None: self.session.customizer = {} # update session self.session.customizer[ 'colorsRandomization'] = self.vars.colorsRandomization self.session.customizer['suitsPalettes'] = self.vars.suitsPalettes self.session.customizer['beamsPalettes'] = self.vars.beamsPalettes self.session.customizer['tilesPalettes'] = self.vars.tilesPalettes self.session.customizer['enemiesPalettes'] = self.vars.enemiesPalettes self.session.customizer['bossesPalettes'] = self.vars.bossesPalettes self.session.customizer['minDegree'] = self.vars.minDegree self.session.customizer['maxDegree'] = self.vars.maxDegree self.session.customizer['invert'] = self.vars.invert self.session.customizer['globalShift'] = self.vars.globalShift self.session.customizer[ 'customSpriteEnable'] = self.vars.customSpriteEnable self.session.customizer['customSprite'] = self.vars.customSprite if self.vars.customSprite == 'random': self.session.customizer[ 'customSpriteMultiSelect'] = self.vars.customSpriteMultiSelect.split( ',') self.session.customizer[ 'customItemsEnable'] = self.vars.customItemsEnable self.session.customizer['noSpinAttack'] = self.vars.noSpinAttack self.session.customizer[ 'customShipEnable'] = self.vars.customShipEnable self.session.customizer['customShip'] = self.vars.customShip if self.vars.customShip == 'random': self.session.customizer[ 'customShipMultiSelect'] = self.vars.customShipMultiSelect.split( ',') self.session.customizer['gamepadMapping'] = self.vars.gamepadMapping if self.session.customizer['gamepadMapping'] == "on": self.session.customizer['preset'] = self.vars.preset self.session.customizer['itemsounds'] = self.vars.itemsounds self.session.customizer['spinjumprestart'] = self.vars.spinjumprestart self.session.customizer['rando_speed'] = self.vars.rando_speed self.session.customizer['elevators_speed'] = self.vars.elevators_speed self.session.customizer['fast_doors'] = self.vars.fast_doors self.session.customizer[ 'Infinite_Space_Jump'] = self.vars.Infinite_Space_Jump self.session.customizer[ 'refill_before_save'] = self.vars.refill_before_save self.session.customizer['widescreen'] = self.vars.widescreen self.session.customizer['AimAnyButton'] = self.vars.AimAnyButton self.session.customizer[ 'max_ammo_display'] = self.vars.max_ammo_display self.session.customizer[ 'supermetroid_msu1'] = self.vars.supermetroid_msu1 self.session.customizer[ 'remove_itemsounds'] = self.vars.remove_itemsounds self.session.customizer[ 'remove_elevators_speed'] = self.vars.remove_elevators_speed self.session.customizer[ 'remove_fast_doors'] = self.vars.remove_fast_doors self.session.customizer[ 'remove_spinjumprestart'] = self.vars.remove_spinjumprestart self.session.customizer[ 'remove_Infinite_Space_Jump'] = self.vars.remove_Infinite_Space_Jump self.session.customizer[ 'remove_rando_speed'] = self.vars.remove_rando_speed self.session.customizer[ 'lava_acid_physics'] = self.vars.lava_acid_physics self.session.customizer['hell'] = self.vars.hell self.session.customizer['hellrun_rate'] = self.vars.hellrun_rate self.session.customizer['etanks'] = self.vars.etanks self.session.customizer['music'] = self.vars.music if self.vars.music == 'Customize': musics = self.loadMusics() for song, songId in musics["_list"]: self.session.customizer[songId] = self.vars[songId] # when beam doors patch is detected, don't randomize blue door palette no_blue_door_palette = self.vars.no_blue_door_palette # call the randomizer (fd, jsonFileName) = tempfile.mkstemp() params = [ getPythonExec(), os.path.expanduser("~/RandomMetroidSolver/randomizer.py"), '--output', jsonFileName, '--patchOnly' ] if self.vars.itemsounds == 'on': params += ['-c', 'itemsounds.ips'] if self.vars.elevators_speed == 'on': params += ['-c', 'elevators_speed.ips'] if self.vars.fast_doors == 'on': params += ['-c', 'fast_doors.ips'] if self.vars.spinjumprestart == 'on': params += ['-c', 'spinjumprestart.ips'] if self.vars.rando_speed == 'on': params += ['-c', 'rando_speed.ips'] if self.vars.AimAnyButton == 'on': params += ['-c', 'AimAnyButton.ips'] if self.vars.max_ammo_display == 'on': params += ['-c', 'max_ammo_display.ips'] if self.vars.supermetroid_msu1 == 'on': params += ['-c', 'supermetroid_msu1.ips'] if self.vars.Infinite_Space_Jump == 'on': params += ['-c', 'Infinite_Space_Jump'] if self.vars.refill_before_save == 'on': params += ['-c', 'refill_before_save.ips'] if self.vars.widescreen == 'on': params += ['-c', 'widescreen.ips'] if self.vars.remove_itemsounds == 'on': params += ['-c', 'remove_itemsounds.ips'] if self.vars.remove_elevators_speed == 'on': params += ['-c', 'remove_elevators_speed.ips'] if self.vars.remove_fast_doors == 'on': params += ['-c', 'remove_fast_doors.ips'] if self.vars.remove_rando_speed == 'on': params += ['-c', 'remove_rando_speed.ips'] if self.vars.remove_spinjumprestart == 'on': params += ['-c', 'remove_spinjumprestart.ips'] if self.vars.remove_Infinite_Space_Jump == 'on': params += ['-c', 'remove_Infinite_Space_Jump.ips'] if self.vars.music == 'Disable': params += ['-c', 'No_Music'] if self.vars.music == 'Randomize': params += ['-c', 'random_music.ips'] if self.vars.music == 'Restore': params += ['-c', 'vanilla_music.ips'] if self.vars.lava_acid_physics == 'on': params += ['-c', 'lava_acid_physics.ips'] if self.vars.hell == 'on': params += ['-c', 'hell.ips'] if self.vars.hellrun_rate != 'off': params += ['--hellrun', self.vars.hellrun_rate] if self.vars.etanks != 'off': params += ['--etanks', self.vars.etanks] if self.vars.colorsRandomization == 'on': params.append('--palette') if self.vars.suitsPalettes == 'off': params.append('--no_shift_suit_palettes') if self.vars.beamsPalettes == 'off': params.append('--no_shift_beam_palettes') if self.vars.tilesPalettes == 'off': params.append('--no_shift_tileset_palette') if self.vars.enemiesPalettes == 'off': params.append('--no_shift_enemy_palettes') if self.vars.bossesPalettes == 'off': params.append('--no_shift_boss_palettes') if self.vars.globalShift == 'off': params.append('--no_global_shift') params.append('--individual_suit_shift') params.append('--individual_tileset_shift') params.append('--no_match_ship_and_power') params += [ '--min_degree', self.vars.minDegree, '--max_degree', self.vars.maxDegree ] if self.vars.invert == 'on': params.append('--invert') if no_blue_door_palette == 'on': params.append('--no_blue_door_palette') if self.vars.customSpriteEnable == 'on': if self.vars.customSprite == 'random': sprite = random.choice( self.session.customizer['customSpriteMultiSelect']) else: sprite = self.vars.customSprite params += ['--sprite', "{}.ips".format(sprite)] with DB() as db: db.addSprite(sprite) if self.vars.customItemsEnable == 'on': params.append('--customItemNames') if self.vars.noSpinAttack == 'on': params.append('--no_spin_attack') if self.vars.customShipEnable == 'on': if self.vars.customShip == 'random': ship = random.choice( self.session.customizer['customShipMultiSelect']) else: ship = self.vars.customShip params += ['--ship', "{}.ips".format(ship)] with DB() as db: db.addShip(ship) if customShips[ship].get("hideSamus", False): params += ['-c', 'custom_ship.ips'] if customShips[ship].get("showSamusAtTakeoff", False): params += ['-c', 'Ship_Takeoff_Disable_Hide_Samus'] if self.vars.seedKey != None: with DB() as db: seedIpsInfo = db.getSeedIpsInfo(self.vars.seedKey) print("seedIpsInfo: {}".format(seedIpsInfo)) if seedIpsInfo == None or len(seedIpsInfo) == 0: raiseHttp(400, json.dumps("Can't get seed info")) (uploadStatus, fileName) = seedIpsInfo[0] if uploadStatus not in ['local', 'pending', 'uploaded']: raiseHttp(400, json.dumps("Seed is not available")) ipsFileName = os.path.join(localIpsDir, self.vars.seedKey, fileName.replace('sfc', 'ips')) params += ['--seedIps', ipsFileName] if self.vars.music == "Customize": musics = self.loadMusics() customMusic = { 'params': { "varia": self.vars.varia == "true", "area": self.vars.area == "true", "boss": self.vars.boss == "true" }, 'mapping': {} } for song, songId in musics["_list"]: newSong = self.vars[songId] if newSong not in musics: raiseHttp(400, "unknown song for {}".format(song)) if newSong != song: customMusic['mapping'][song] = newSong (fd2, jsonMusicFileName) = tempfile.mkstemp() with open(jsonMusicFileName, 'w') as musicFile: json.dump(customMusic, musicFile) params += ['--music', jsonMusicFileName] if self.vars.gamepadMapping == "on": preset = self.vars.preset fullPath = '{}/{}.json'.format(getPresetDir(preset), preset) controlMapping = PresetLoader.factory( fullPath).params['Controller'] (custom, controlParam) = getCustomMapping(controlMapping) if custom == True: print("apply custom gamepad mapping from preset: {}".format( self.vars.preset)) params += ['--controls', controlParam] if "Moonwalk" in controlMapping and controlMapping[ "Moonwalk"] == True: params.append('--moonwalk') print("before calling: {}".format(params)) start = datetime.now() ret = subprocess.call(params) end = datetime.now() duration = (end - start).total_seconds() print("ret: {}, duration: {}s".format(ret, duration)) if self.vars.music == "Customize": os.close(fd2) os.remove(jsonMusicFileName) if ret == 0: with open(jsonFileName) as jsonFile: data = json.load(jsonFile) os.close(fd) os.remove(jsonFileName) return json.dumps(data) else: # extract error from json try: with open(jsonFileName) as jsonFile: msg = json.load(jsonFile)['errorMsg'] except: msg = "customizerWebService: something wrong happened" os.close(fd) os.remove(jsonFileName) raiseHttp(400, json.dumps(msg))
def randoPresetWebService(self): # web service to get the content of the rando preset file if self.vars.randoPreset == None: raiseHttp(400, "Missing parameter rando preset") preset = self.vars.randoPreset if IS_ALPHANUMERIC()(preset)[1] is not None: raiseHttp(400, "Preset name must be alphanumeric") if IS_LENGTH(maxsize=32, minsize=1)(preset)[1] is not None: raiseHttp(400, "Preset name must be between 1 and 32 characters") if self.vars.origin not in ["extStats", "randomizer"]: raiseHttp(400, "Unknown origin") print("randoPresetWebService: preset={}".format(preset)) fullPath = 'rando_presets/{}.json'.format(preset) # check that the preset file exists if os.path.isfile(fullPath): # load it try: # can be called from randomizer and extended stats pages updateSession = self.vars.origin == "randomizer" params = self.loadRandoPreset(fullPath) # first load default preset to set all parameters to default values, # thus preventing parameters from previous loaded preset to stay when loading a new one, # (like comfort patches from the free preset). if updateSession and preset != 'default': defaultParams = self.loadRandoPreset('rando_presets/default.json') # don't reset skill preset defaultParams.pop('preset', None) defaultParams.update(params) params = defaultParams if updateSession: self.updateRandoSession(params) return json.dumps(params) except Exception as e: raiseHttp(400, "Can't load the rando preset: {}".format(e)) else: raiseHttp(400, "Rando preset not found")
def plandoRateWebService(self): if self.vars.plando == None: raiseHttp(400, "Missing parameter plando") plando = self.vars.plando if self.vars.rate == None: raiseHttp(400, "Missing parameter rate") rate = self.vars.rate if IS_LENGTH(maxsize=32, minsize=1)(plando)[1] is not None: raiseHttp(400, "Plando name must be between 1 and 32 characters") if IS_MATCH('^[a-zA-Z0-9 -_]*$')(plando)[1] is not None: raiseHttp(400, "Plando name can only contain [a-zA-Z0-9 -_]") if IS_INT_IN_RANGE(1, 6)(rate)[1] is not None: raiseHttp(400, "Rate name must be between 1 and 5") rate = int(rate) ip = self.request.client with DB() as db: db.addRating(plando, rate, ip) newRate = db.getPlandoRate(plando) if newRate == None: raiseHttp(400, "Can't get new rate") newCount = newRate[0][0] newRate = float(newRate[0][1]) data = { "msg": "", "purePlandoName": re.sub('[\W_]+', '', plando), "rate": newRate, "count": newCount } return json.dumps(data)
def updatePlandoWebService(self): for param in ["author", "plandoName", "longDesc", "preset", "plandoKey"]: if self.vars[param] == None: raiseHttp(400, "Missing parameter {}".format(param)) for param in ["author", "plandoName", "preset"]: if IS_LENGTH(maxsize=32, minsize=1)(self.vars[param])[1] is not None: raiseHttp(400, "{} must be between 1 and 32 characters".format(param)) for param in ["plandoKey"]: if IS_LENGTH(maxsize=8, minsize=1)(self.vars[param])[1] is not None: raiseHttp(400, "{} must be between 1 and 8 characters".format(param)) for param in ["longDesc"]: if IS_LENGTH(maxsize=2048, minsize=1)(self.vars[param])[1] is not None: raiseHttp(400, "{} must be between 1 and 2048 characters".format(param)) plandoName = self.vars.plandoName if IS_MATCH('^[a-zA-Z0-9 -_]*$')(plandoName)[1] is not None: raiseHttp(400, "Plando name can only contain [a-zA-Z0-9 -_]") author = self.vars.author longDesc = self.removeHtmlTags(self.vars.longDesc) preset = self.vars.preset plandoKey = self.vars.plandoKey # check update key with DB() as db: valid = db.isValidPlandoKey(plandoName, plandoKey) if valid is None or len(valid) == 0: raiseHttp(400, "Plando key mismatch") if self.vars.romData is not None: print("updatePlandoWebService: update ips") maxSize = self.handleIps(plandoName, self.vars.romData) db.updatePlandoAll((author, longDesc, preset, maxSize, plandoName)) else: db.updatePlandoMeta((author, longDesc, preset, plandoName)) return json.dumps("Plando {} updated succesfully.".format(plandoName))
def deletePlandoWebService(self): for param in ["plandoName", "plandoKey"]: if self.vars[param] == None: raiseHttp(400, "Missing parameter {}".format(param)) plandoName = self.vars.plandoName plandoKey = self.vars.plandoKey if IS_LENGTH(maxsize=32, minsize=1)(plandoName)[1] is not None: raiseHttp(400, "Plando name must be between 1 and 32 characters") if IS_MATCH('^[a-zA-Z0-9 -_]*$')(plandoName)[1] is not None: raiseHttp(400, "Plando name can only contain [a-zA-Z0-9 -_]") if IS_LENGTH(maxsize=8, minsize=1)(plandoKey)[1] is not None: raiseHttp(400, "Plando key must be between 1 and 8 characters") if IS_MATCH('^[a-zA-Z0-9]*$')(plandoKey)[1] is not None: raiseHttp(400, "Plando key can only contain [a-zA-Z0-9]") with DB() as db: valid = db.isValidPlandoKey(plandoName, plandoKey) if valid is None or len(valid) == 0: raiseHttp(400, "Plando key mismatch") db.deletePlandoRating(plandoName) db.deletePlando(plandoName) return json.dumps("Plando {} deleted".format(plandoName))
def uploadPlandoWebService(self): with DB() as db: count = db.getPlandoCount() plandoLimit = 2048 if count is None or count[0][0] >= plandoLimit: raiseHttp(400, "Maximum number of plandos reach: {}".format(plandoLimit)) for param in ["author", "plandoName", "longDesc", "preset", "romData"]: if self.vars[param] == None: raiseHttp(400, "Missing parameter {}".format(param)) for param in ["author", "plandoName", "preset"]: if IS_LENGTH(maxsize=32, minsize=1)(self.vars[param])[1] is not None: raiseHttp(400, "{} must be between 1 and 32 characters".format(param)) for param in ["longDesc"]: if IS_LENGTH(maxsize=2048, minsize=1)(self.vars[param])[1] is not None: raiseHttp(400, "{} must be between 1 and 2048 characters".format(param)) plandoName = self.vars.plandoName if IS_MATCH('^[a-zA-Z0-9 -_]*$')(plandoName)[1] is not None: raiseHttp(400, "Plando name can only contain [a-zA-Z0-9 -_]") # check if plando doesn't already exist with DB() as db: check = db.checkPlando(plandoName) if check is not None and len(check) > 0 and check[0][0] == plandoName: raiseHttp(400, "Can't create plando, a plando with the same name already exists") author = self.vars.author longDesc = self.removeHtmlTags(self.vars.longDesc) preset = self.vars.preset maxSize = self.handleIps(plandoName, self.vars.romData) updateKey = self.generateUpdateKey() with DB() as db: db.insertPlando((plandoName, author, longDesc, preset, updateKey, maxSize)) if webhookAvailable: self.plandoWebhook(plandoName, author, preset, longDesc) return json.dumps(updateKey)
def run(self): self.initExtStatsSession() if self.vars.action == 'Load': (ok, msg) = self.validateExtStatsParams() if not ok: self.session.flash = msg redirect(URL(r=self.request, f='extStats')) self.updateExtStatsSession() skillPreset = self.vars.preset randoPreset = self.vars.randoPreset # load rando preset to get majors split fullPath = 'rando_presets/{}.json'.format(randoPreset) if not os.path.isfile(fullPath): raiseHttp(400, "Unknown rando preset: {}".format(e)) try: with open(fullPath) as jsonFile: randoPresetContent = json.load(jsonFile) except Exception as e: raiseHttp(400, "Can't load the rando preset: {}".format(e)) majorsSplit = randoPresetContent["majorsSplit"] # load skill preset fullPath = '{}/{}.json'.format(getPresetDir(skillPreset), skillPreset) try: skillPresetContent = PresetLoader.factory(fullPath).params completePreset(skillPresetContent) except Exception as e: raiseHttp(400, "Error loading the skill preset: {}".format(e)) with DB() as db: (itemsStats, techniquesStats, difficulties, solverStatsRaw) = db.getExtStat(skillPreset, randoPreset) solverStats = {} if "avgLocs" in solverStatsRaw: solverStats["avgLocs"] = transformStats( solverStatsRaw["avgLocs"]) solverStats["avgLocs"].insert( 0, ['Available locations', 'Percentage']) if "open14" in solverStatsRaw: open14 = transformStats(solverStatsRaw["open14"]) open24 = transformStats(solverStatsRaw["open24"]) open34 = transformStats(solverStatsRaw["open34"]) open44 = transformStats(solverStatsRaw["open44"]) solverStats["open"] = zipStats( [open14, open24, open34, open44]) solverStats["open"].insert(0, [ 'Collected items', '1/4 locations available', '2/4 locations available', '3/4 locations available', '4/4 locations available' ]) # check that all items are present in the stats: nbItems = 19 nbLocs = 109 if itemsStats and len(itemsStats) != nbItems: for i, item in enumerate([ 'Bomb', 'Charge', 'Grapple', 'Gravity', 'HiJump', 'Ice', 'Missile', 'Morph', 'Plasma', 'PowerBomb', 'ScrewAttack', 'SpaceJump', 'Spazer', 'SpeedBooster', 'SpringBall', 'Super', 'Varia', 'Wave', 'XRayScope' ]): if itemsStats[i][1] != item: itemsStats.insert(i, [itemsStats[0][0], item] + [0] * nbLocs) else: itemsStats = None techniquesStats = None difficulties = None solverStats = None skillPresetContent = None majorsSplit = None (randoPresets, tourRandoPresets) = loadRandoPresetsList(self.cache, filter=True) (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) return dict(stdPresets=stdPresets, tourPresets=tourPresets, randoPresets=randoPresets, tourRandoPresets=tourRandoPresets, itemsStats=itemsStats, techniquesStats=techniquesStats, categories=Knows.categories, knowsDesc=Knows.desc, skillPresetContent=skillPresetContent, locations=locations, majorsSplit=majorsSplit, difficulties=difficulties, solverStats=solverStats)