def run(self): # init session if self.session.plando is None: self.session.plando = { "state": {}, "preset": "regular", "seed": None, "startLocation": "Landing Site", # rando params "rando": {}, # set to False in plando.html "firstTime": True } # load presets list (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) # access points vanillaAPs = [] for (src, dest) in vanillaTransitions: vanillaAPs += [transition2isolver(src), transition2isolver(dest)] vanillaBossesAPs = [] for (src, dest) in vanillaBossesTransitions: vanillaBossesAPs += [ transition2isolver(src), transition2isolver(dest) ] escapeAPs = [] for (src, dest) in vanillaEscapeTransitions: escapeAPs += [transition2isolver(src), transition2isolver(dest)] # generate list of addresses to read in the ROM addresses = getAddressesToRead(plando=True) startAPs = GraphUtils.getStartAccessPointNamesCategory() startAPs = [ OPTGROUP(_label="Standard", *startAPs["regular"]), OPTGROUP(_label="Custom", *startAPs["custom"]), OPTGROUP(_label="Custom (Area rando only)", *startAPs["area"]) ] return dict(stdPresets=stdPresets, tourPresets=tourPresets, comPresets=comPresets, vanillaAPs=vanillaAPs, vanillaBossesAPs=vanillaBossesAPs, escapeAPs=escapeAPs, curSession=self.session.plando, addresses=addresses, startAPs=startAPs, version=displayedVersion)
def run(self): # init session if self.session.tracker is None: self.session.tracker = { "state": {}, "preset": "regular", "seed": None, "startLocation": "Landing Site", # set to False in tracker.html "firstTime": True } # load presets list (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) # access points vanillaAPs = [] for (src, dest) in vanillaTransitions: vanillaAPs += [transition2isolver(src), transition2isolver(dest)] vanillaBossesAPs = [] for (src, dest) in vanillaBossesTransitions: vanillaBossesAPs += [ transition2isolver(src), transition2isolver(dest) ] escapeAPs = [] for (src, dest) in vanillaEscapeTransitions: escapeAPs += [transition2isolver(src), transition2isolver(dest)] # generate list of addresses to read in the ROM addresses = getAddressesToRead() startAPs = GraphUtils.getStartAccessPointNamesCategory() startAPs = [ OPTGROUP(_label="Standard", *startAPs["regular"]), OPTGROUP(_label="Custom", *startAPs["custom"]), OPTGROUP(_label="Custom (Area rando only)", *startAPs["area"]) ] # get ap -> grapharea for auto tracker apsGraphArea = { locName4isolver(ap.Name): ap.GraphArea for ap in accessPoints } return dict(stdPresets=stdPresets, tourPresets=tourPresets, comPresets=comPresets, vanillaAPs=vanillaAPs, vanillaBossesAPs=vanillaBossesAPs, escapeAPs=escapeAPs, curSession=self.session.tracker, addresses=addresses, startAPs=startAPs, areaAccessPoints=InteractiveSolver.areaAccessPoints, bossAccessPoints=InteractiveSolver.bossAccessPoints, escapeAccessPoints=InteractiveSolver.escapeAccessPoints, nothingScreens=InteractiveSolver.nothingScreens, doorsScreen=InteractiveSolver.doorsScreen, bossBitMasks=InteractiveSolver.bossBitMasks, apsGraphArea=apsGraphArea)
def skillPresetListWebService(self): # load presets list (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) return json.dumps(stdPresets + tourPresets + comPresets)
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 run(self): self.initPresetsSession() # use web2py builtin cache to avoid recomputing the hardrooms requirements hardRooms = self.cache.ram('hardRooms', lambda: dict(), time_expire=None) if len(hardRooms) == 0: self.computeHardRooms(hardRooms) hellRuns = self.cache.ram('hellRuns', lambda: dict(), time_expire=None) if len(hellRuns) == 0: self.computeHellruns(hellRuns) if self.vars.action is not None: (ok, msg) = self.validatePresetsParams(self.vars.action) if not ok: self.session.flash = msg redirect(URL(r=self.request, f='presets')) else: self.session.presets['currentTab'] = self.vars.currenttab preset = self.vars.preset # in web2py.js, in disableElement, remove 'working...' to have action with correct value if self.vars.action == 'Load': # check that the presets file exists fullPath = '{}/{}.json'.format(getPresetDir(preset), preset) if os.path.isfile(fullPath): # load it try: params = PresetLoader.factory(fullPath).params self.updatePresetsSession() self.session.presets["presetDict"] = None except Exception as e: self.session.flash = "L:Error loading the preset {}: {}".format( preset, e) else: self.session.flash = "Presets file not found: {}".format( fullPath) redirect(URL(r=self.request, f='presets')) # load conf from session if available error = False try: params = self.loadPreset() except Exception as e: self.session.presets['preset'] = 'regular' self.session.flash = "S:Error loading the preset: {}".format(e) error = True if error == True: redirect(URL(r=request, f='presets')) # load presets list (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) # add missing knows/settings completePreset(params) # compute score for skill bar skillBarData = self.getSkillLevelBarData( self.session.presets['preset']) # send values to view return dict(desc=Knows.desc, difficulties=diff2text, categories=Knows.categories, settings=params['Settings'], knows=params['Knows'], easy=easy, medium=medium, hard=hard, harder=harder, hardcore=hardcore, mania=mania, controller=params['Controller'], stdPresets=stdPresets, tourPresets=tourPresets, comPresets=comPresets, skillBarData=skillBarData, hardRooms=hardRooms, hellRuns=hellRuns)
def maxPresetsReach(self): # to prevent a spammer to create presets in a loop and fill the fs maxPresets = 4096 (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) return len(comPresets) >= maxPresets
def run(self): # init session self.initSolverSession() if self.vars.action == 'Solve': (ok, msg) = self.validateSolverParams() if not ok: self.session.flash = msg redirect(URL(r=self.request, f='solver')) self.updateSolverSession() preset = self.vars.preset # new uploaded rom ? error = False if self.vars.romJson != '': try: (base, jsonRomFileName) = generateJsonROM(self.vars.romJson) self.session.solver['romFile'] = base if base not in self.session.solver['romFiles']: self.session.solver['romFiles'].append(base) except Exception as e: print( "Error loading the ROM file, exception: {}".format(e)) self.session.flash = "Error loading the json ROM file" error = True elif self.vars['romFile'] is not None and len( self.vars['romFile']) != 0: self.session.solver['romFile'] = os.path.splitext( self.vars['romFile'])[0] jsonRomFileName = 'roms/' + self.session.solver[ 'romFile'] + '.json' else: self.session.flash = "No rom file selected for upload" error = True if not error: # check that the json file exists if not os.path.isfile(jsonRomFileName): self.session.flash = "Missing json ROM file on the server" else: try: (ok, result) = self.computeDifficulty( jsonRomFileName, preset) if not ok: self.session.flash = result redirect(URL(r=self.request, f='solver')) self.session.solver['result'] = result except Exception as e: print( "Error loading the ROM file, exception: {}".format( e)) self.session.flash = "Error loading the ROM file" redirect(URL(r=self.request, f='solver')) # display result result = self.prepareResult() ROMs = self.getROMsList() # last solved ROM lastRomFile = self.getLastSolvedROM() # load presets list (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) # generate list of addresses to read in the ROM addresses = getAddressesToRead() # send values to view return dict(desc=Knows.desc, stdPresets=stdPresets, tourPresets=tourPresets, comPresets=comPresets, roms=ROMs, lastRomFile=lastRomFile, difficulties=diff2text, categories=Knows.categories, result=result, addresses=addresses, easy=easy, medium=medium, hard=hard, harder=harder, hardcore=hardcore, mania=mania)
def run(self): self.initCustomSprites() self.initCustomizerSession() musics = self.loadMusics() (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) url = self.request.env.request_uri.split('/') msg = "" seedInfo = None seedParams = None defaultParams = None if len(url) > 0 and url[-1] != 'customizer': # a seed unique key was passed as parameter key = url[-1] # decode url key = urllib.parse.unquote(key) # sanity check if IS_MATCH('^[0-9a-z-]*$')(key)[1] is not None: msg = "Seed key can only contain [0-9a-z-]" elif IS_LENGTH(maxsize=36, minsize=36)(key)[1] is not None: msg = "Seed key must be 36 chars long" else: with DB() as db: seedInfo = db.getSeedInfo(key) if seedInfo is None or len(seedInfo) == 0: msg = "Seed {} not found".format(key) seedInfo = None else: # get a dict with seed info and another one with seed parameters info = {} seedParams = {} infoKeys = [ 'time', 'filename', 'preset', 'runtime', 'complexity', 'upload_status', 'seed', 'raceMode' ] for (k, value) in seedInfo: if k in infoKeys: info[k] = value else: seedParams[k] = updateParameterDisplay(value) seedInfo = info seedInfo['key'] = key # if new parameters have been added since the seed creation, add them with value "n/a" defaultParams = getRandomizerDefaultParameters() for k in defaultParams: if k not in infoKeys and k not in seedParams: seedParams[k] = "n/a" # check that the seed ips is available if seedInfo["upload_status"] not in [ 'pending', 'uploaded', 'local' ]: msg = "Seed {} not available".format(key) seedInfo = None seedParams = None # accessing the url tell us to store the ips for more than 7 days elif seedInfo["upload_status"] == 'local': with DB() as db: db.updateSeedUploadStatus(key, 'pending') return dict(customSprites=customSprites, customShips=customShips, musics=musics, comPresets=comPresets, seedInfo=seedInfo, seedParams=seedParams, msg=msg, defaultParams=defaultParams)
def run(self): self.initRandomizerSession() (stdPresets, tourPresets, comPresets) = loadPresetsList(self.cache) randoPresetsDesc = { "all_random": "all the parameters set to random", "Chozo_Speedrun": "speedrun progression speed with Chozo split", "default": "VARIA randomizer default settings", "doors_long": "be prepared to hunt for beams and ammo to open doors", "doors_short": "uses Chozo/speedrun settings for a quicker door color rando", "free": "easiest possible settings", "hardway2hell": "harder highway2hell", "haste": "inspired by DASH randomizer with Nerfed Charge / Progressive Suits", "highway2hell": "favors suitless seeds", "hud": "Full rando with remaining major upgrades in the area shown in the HUD", "hud_hard": "Low resources and VARIA HUD enabled to help you track of actual items count", "hud_start": "Non-vanilla start with Major or Chozo split", "minimizer":"Typical 'boss rush' settings with random start and nerfed charge", "minimizer_hardcore":"Have fun 'rushing' bosses with no equipment on a tiny map", "minimizer_maximizer":"No longer a boss rush", "quite_random": "randomizes a few significant settings to have various seeds", "scavenger_hard":"Pretty hostile Scavenger mode", "scavenger_random":"Randomize everything within Scavenger mode", "scavenger_speedrun":"Quickest Scavenger settings", "scavenger_vanilla_but_not":"Items are vanilla, but area and bosses are not", "stupid_hard": "hardest possible settings", "surprise": "quite_random with Area/Boss/Doors/Start settings randomized", "vanilla": "closest possible to vanilla Super Metroid", "way_of_chozo": "chozo split with boss randomization", "where_am_i": "Area mode with random start location and early morph", "where_is_morph": "Area mode with late Morph", "Multi_Category_Randomizer_Week_1": "Multi-Category Randomizer Tournament week 1", "Multi_Category_Randomizer_Week_2": "Multi-Category Randomizer Tournament week 2", "Multi_Category_Randomizer_Week_3": "Multi-Category Randomizer Tournament week 3", "Multi_Category_Randomizer_Week_4": "Multi-Category Randomizer Tournament week 4", "Multi_Category_Randomizer_Week_5": "Multi-Category Randomizer Tournament week 5", "Multi_Category_Randomizer_Week_6": "Multi-Category Randomizer Tournament week 6", "Multi_Category_Randomizer_Week_7": "Multi-Category Randomizer Tournament week 7", "Season_Races": "rando league races (Majors/Minors split)", "SGLive2022_Race_1": "SGLive 2022 Super Metroid randomizer tournament race 1", "SGLive2022_Race_2": "SGLive 2022 Super Metroid randomizer tournament race 2", "SGLive2022_Race_3": "SGLive 2022 Super Metroid randomizer tournament race 3", "SMRAT2021": "Super Metroid Randomizer Accessible Tournament 2021", "VARIA_Weekly": "Casual logic community races" } randoPresetsCategories = { "Standard": ["", "default", "Chozo_Speedrun", "free", "haste", "vanilla"], "Hud": ["hud", "hud_hard", "hud_start"], "Scavenger": ["scavenger_hard", "scavenger_random", "scavenger_speedrun", "scavenger_vanilla_but_not"], "Area": ["way_of_chozo", "where_am_i", "where_is_morph"], "Doors": ["doors_long", "doors_short"], "Minimizer": ["minimizer", "minimizer_hardcore", "minimizer_maximizer"], "Hard": ["hardway2hell", "highway2hell", "stupid_hard"], "Random": ["all_random", "quite_random", "surprise"], "Tournament": ["Season_Races", "SMRAT2021", "VARIA_Weekly", "SGLive2022_Race_1", "SGLive2022_Race_2", "SGLive2022_Race_3", "Multi_Category_Randomizer_Week_1", "Multi_Category_Randomizer_Week_2", "Multi_Category_Randomizer_Week_3", "Multi_Category_Randomizer_Week_4", "Multi_Category_Randomizer_Week_5", "Multi_Category_Randomizer_Week_6", "Multi_Category_Randomizer_Week_7"] } startAPs = GraphUtils.getStartAccessPointNamesCategory() startAPs = [OPTGROUP(_label="Standard", *startAPs["regular"]), OPTGROUP(_label="Custom", *startAPs["custom"]), OPTGROUP(_label="Custom (Area rando only)", *startAPs["area"])] # get multi currentMultiValues = self.getCurrentMultiValues() defaultMultiValues = getDefaultMultiValues() # objectives self exclusions objectivesExclusions = Objectives.getExclusions() objectivesTypes = Objectives.getObjectivesTypes() objectivesSort = Objectives.getObjectivesSort() objectivesCategories = Objectives.getObjectivesCategories() # check if we have a guid in the url url = self.request.env.request_uri.split('/') if len(url) > 0 and url[-1] != 'randomizer': # a seed unique key was passed as parameter key = url[-1] # decode url key = urllib.parse.unquote(key) # sanity check if IS_MATCH('^[0-9a-z-]*$')(key)[1] is None and IS_LENGTH(maxsize=36, minsize=36)(key)[1] is None: with DB() as db: seedInfo = db.getSeedInfo(key) if seedInfo is not None and len(seedInfo) > 0: defaultParams = getRandomizerDefaultParameters() defaultParams.update(seedInfo) seedInfo = defaultParams # check that the seed ips is available if seedInfo["upload_status"] in ['pending', 'uploaded', 'local']: # load parameters in session for key, value in seedInfo.items(): if key in ["complexity", "randoPreset", "raceMode"]: continue elif key in defaultMultiValues: keyMulti = key + 'MultiSelect' if keyMulti in seedInfo: if key == 'objective' and value == 'nothing': self.session.randomizer[key] = "" else: self.session.randomizer[key] = seedInfo[key] valueMulti = seedInfo[keyMulti] if type(valueMulti) == str: valueMulti = valueMulti.split(',') self.session.randomizer[keyMulti] = valueMulti currentMultiValues[key] = valueMulti elif key in self.session.randomizer and 'MultiSelect' not in key: self.session.randomizer[key] = value return dict(stdPresets=stdPresets, tourPresets=tourPresets, comPresets=comPresets, randoPresetsDesc=randoPresetsDesc, randoPresetsCategories=randoPresetsCategories, startAPs=startAPs, currentMultiValues=currentMultiValues, defaultMultiValues=defaultMultiValues, maxsize=sys.maxsize, displayNames=displayNames, objectivesExclusions=objectivesExclusions, objectivesTypes=objectivesTypes, objectivesSort=objectivesSort, objectivesCategories=objectivesCategories)
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)