from objects import glob from common.ripple import userUtils from os.path import dirname, basename, isfile import glob as _glob import importlib import json from secret.achievements import common def load_achievements(): """Load all the achievements from handler list into glob.achievementClasses, and sets glob.ACHIEVEMENTS_VERSION to the highest version number in our achievement list. """ modules = _glob.glob("secret/achievements/handlers/*.py") modules = [basename(f)[:-3] for f in modules if isfile(f) and not f.endswith("__init__.py")] # ^ cat face for module in modules: module = importlib.import_module("secret.achievements.handlers." + module) module.load() if module.ORDER in glob.achievementClasses: print("\n!!! FOUND OVERLAPPING ACHIEVEMENT ORDER FOR {}!!!".format(module.ORDER)) print("Unable to load {} due to {} already loaded in slot {}\n".format(module.__name__, glob.achievementClasses[module.ORDER].__name__, module.ORDER)) continue glob.achievementClasses[module.ORDER] = module glob.ACHIEVEMENTS_VERSION = max(glob.ACHIEVEMENTS_VERSION, module.VERSION) print("Loaded {} achievement classes!".format(len(glob.achievementClasses)), end=" ") def unlock_achievements_update(userID, version): """Scans the user for past achievements they should have unlocked Arguments: userID {int} -- User id of a player version {int} -- Last achivement version the player had Returns: Array -- List of achievements """ achievements = [] # Scan all past achivement versions from the user's achivement version to the latest index = 1 for handler in glob.achievementClasses.values(): if handler.VERSION > version: achievements += [x + index for x in handler.update(userID)] index += handler.LENGTH # Update achivement version for user userUtils.updateAchievementsVersion(userID) return achievements def unlock_achievements(score, beatmap, user_data): """Return array of achievements the current play recived Arguments: score {Score} -- Score data recived from replay beatmap {Beatmap} -- Played beatmap user_data {dict} -- Info about the current player Returns: Array -- List of achievements for the current play """ achievements = [] userID = userUtils.getID(score.playerName) user_cache = common.get_usercache(userID) # Get current gamemode and change value std to osu gamemode_index = score.gameMode # Check if user should run achivement recheck if user_cache["version"] < glob.ACHIEVEMENTS_VERSION: achievements += unlock_achievements_update(userID, user_cache["version"]) # Check if gameplay should get new achivement index = 1 for handler in glob.achievementClasses.values(): achievements += [x + index for x in handler.handle(gamemode_index, score, beatmap, user_data)] index += handler.LENGTH # Add pending achievements that were added though redis or mysql achievements += [-x for x in user_cache["achievements"] if x < 0] # Negative achievements id's means its pending # Remove pending achievements from redis object since we added it to the post achievements user_cache["achievements"] = [x for x in user_cache["achievements"] if x > 0] # Remove duplicated achievements (incase of unlock_achievements_update adding stuff) achievements = list(set(achievements)) # Remove already achived achievements from list achievements = [x for x in achievements if x not in user_cache["achievements"]] user_cache["achievements"] += achievements glob.redis.set("lets:user_achievement_cache:{}".format(userID), json.dumps(user_cache), 1800) for achievement in achievements: userUtils.unlockAchievement(userID, achievement) return achievements def achievements_response(achievements): achievement_objects = [] index = 1 for handler in glob.achievementClasses.values(): achievement_objects += [handler.ACHIEVEMENTS[x - index] for x in achievements if len(handler.ACHIEVEMENTS) > x - index and x - index >= 0] index += handler.LENGTH achievements_packed = [] for achievement_object in achievement_objects: achievements_packed.append("+".join([achievement_object["icon"], achievement_object["name"], achievement_object["description"]])) return "/".join(achievements_packed)