def download_slot_file(room_id, player_id: int): room = Room.get(id=room_id) slot_data: Slot = select(patch for patch in room.seed.slots if patch.player_id == player_id).first() if not slot_data: return "Slot Data not found" else: import io if slot_data.game == "Minecraft": from worlds.minecraft import mc_update_output fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_P{slot_data.player_id}_{slot_data.player_name}.apmc" data = mc_update_output(slot_data.data, server=app.config['PATCH_TARGET'], port=room.last_port) return send_file(io.BytesIO(data), as_attachment=True, attachment_filename=fname) elif slot_data.game == "Factorio": with zipfile.ZipFile(io.BytesIO(slot_data.data)) as zf: for name in zf.namelist(): if name.endswith("info.json"): fname = name.rsplit("/", 1)[0] + ".zip" elif slot_data.game == "Ocarina of Time": fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_P{slot_data.player_id}_{slot_data.player_name}.apz5" elif slot_data.game == "VVVVVV": fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_SP.apv6" elif slot_data.game == "Super Mario 64": fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_SP.apsm64ex" else: return "Game download not supported." return send_file(io.BytesIO(slot_data.data), as_attachment=True, attachment_filename=fname)
def download_patch(room_id, patch_id): patch = Patch.get(id=patch_id) if not patch: return "Patch not found" else: import io room = Room.get(id=room_id) last_port = room.last_port patch_data = update_patch_data( patch.data, server=f"{app.config['PATCH_TARGET']}:{last_port}") patch_data = io.BytesIO(patch_data) fname = f"P{patch.player_id}_{patch.player_name}_{app.jinja_env.filters['suuid'](room_id)}.apbp" return send_file(patch_data, as_attachment=True, attachment_filename=fname)
def download_patch(room_id, patch_id): patch = Slot.get(id=patch_id) if not patch: return "Patch not found" else: room = Room.get(id=room_id) last_port = room.last_port filelike = BytesIO(patch.data) greater_than_version_3 = zipfile.is_zipfile(filelike) if greater_than_version_3: # Python's zipfile module cannot overwrite/delete files in a zip, so we recreate the whole thing in ram new_file = BytesIO() with zipfile.ZipFile(filelike, "a") as zf: with zf.open("archipelago.json", "r") as f: manifest = json.load(f) manifest[ "server"] = f"{app.config['PATCH_TARGET']}:{last_port}" if last_port else None with zipfile.ZipFile(new_file, "w") as new_zip: for file in zf.infolist(): if file.filename == "archipelago.json": new_zip.writestr("archipelago.json", json.dumps(manifest)) else: new_zip.writestr(file.filename, zf.read(file), file.compress_type, 9) fname = f"P{patch.player_id}_{patch.player_name}_{app.jinja_env.filters['suuid'](room_id)}" \ f"{AutoPatchRegister.patch_types[patch.game].patch_file_ending}" new_file.seek(0) return send_file(new_file, as_attachment=True, attachment_filename=fname) else: patch_data = update_patch_data( patch.data, server=f"{app.config['PATCH_TARGET']}:{last_port}") patch_data = BytesIO(patch_data) fname = f"P{patch.player_id}_{patch.player_name}_{app.jinja_env.filters['suuid'](room_id)}." \ f"{preferred_endings[patch.game]}" return send_file(patch_data, as_attachment=True, attachment_filename=fname)
def download_patch(room_id, patch_id): patch = Patch.get(id=patch_id) if not patch: return "Patch not found" else: import io room = Room.get(id=room_id) last_port = room.last_port pname = room.seed.multidata["names"][0][patch.player - 1] patch_data = update_patch_data(patch.data, server="berserkermulti.world:" + str(last_port)) patch_data = io.BytesIO(patch_data) fname = f"P{patch.player}_{pname}_{app.jinja_env.filters['suuid'](room_id)}.bmbp" return send_file(patch_data, as_attachment=True, attachment_filename=fname)
def getTracker(tracker: UUID): room = Room.get(tracker=tracker) if not room: abort(404) locations, names, use_door_tracker, seed_checks_in_area, player_location_to_area = get_static_room_data( room) inventory = { teamnumber: { playernumber: collections.Counter() for playernumber in range(1, len(team) + 1) } for teamnumber, team in enumerate(names) } checks_done = { teamnumber: { playernumber: {loc_name: 0 for loc_name in default_locations} for playernumber in range(1, len(team) + 1) } for teamnumber, team in enumerate(names) } precollected_items = room.seed.multidata.get("precollected_items", None) hints = {team: set() for team in range(len(names))} if "hints" in room.multisave: for key, hintdata in room.multisave["hints"]: for hint in hintdata: hints[key[0]].add(Hint(*hint)) for (team, player), locations_checked in room.multisave.get( "location_checks", {}): if precollected_items: precollected = precollected_items[player - 1] for item_id in precollected: attribute_item(inventory, team, player, item_id) for location in locations_checked: if (location, player ) not in locations or location not in player_location_to_area[ player]: continue item, recipient = locations[location, player] attribute_item(inventory, team, recipient, item) checks_done[team][player][player_location_to_area[player] [location]] += 1 checks_done[team][player]["Total"] += 1 for (team, player), game_state in room.multisave.get("client_game_state", []): if game_state: inventory[team][player][106] = 1 # Triforce activity_timers = {} now = datetime.datetime.utcnow() for (team, player), timestamp in room.multisave.get("client_activity_timers", []): activity_timers[ team, player] = now - datetime.datetime.utcfromtimestamp(timestamp) player_names = {} for team, names in enumerate(names): for player, name in enumerate(names, 1): player_names[(team, player)] = name long_player_names = player_names.copy() for (team, player), alias in room.multisave.get("name_aliases", []): player_names[(team, player)] = alias long_player_names[( team, player)] = f"{alias} ({long_player_names[(team, player)]})" video = {} for (team, player), data in room.multisave.get("video", []): video[(team, player)] = data return render_template("tracker.html", inventory=inventory, get_item_name_from_id=get_item_name_from_id, lookup_id_to_name=Items.lookup_id_to_name, player_names=player_names, tracking_names=tracking_names, tracking_ids=tracking_ids, room=room, icons=icons, multi_items=multi_items, checks_done=checks_done, ordered_areas=ordered_areas, checks_in_area=seed_checks_in_area, activity_timers=activity_timers, key_locations=key_locations, small_key_ids=small_key_ids, big_key_ids=big_key_ids, video=video, big_key_locations=key_locations if use_door_tracker else big_key_locations, hints=hints, long_player_names=long_player_names)
def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int): # Team and player must be positive and greater than zero if tracked_team < 0 or tracked_player < 1: abort(404) room = Room.get(tracker=tracker) if not room: abort(404) # Collect seed information and pare it down to a single player locations, names, use_door_tracker, seed_checks_in_area, player_location_to_area, player_big_key_locations, player_small_key_locations, precollected_items = get_static_room_data( room) player_name = names[tracked_team][tracked_player - 1] seed_checks_in_area = seed_checks_in_area[tracked_player] location_to_area = player_location_to_area[tracked_player] inventory = collections.Counter() checks_done = {loc_name: 0 for loc_name in default_locations} # Add starting items to inventory starting_items = precollected_items[tracked_player - 1] if starting_items: for item_id in starting_items: attribute_item_solo(inventory, item_id) if room.multisave: multisave = restricted_loads(room.multisave) else: multisave = {} # Add items to player inventory for (ms_team, ms_player), locations_checked in multisave.get("location_checks", {}): # logging.info(f"{ms_team}, {ms_player}, {locations_checked}") # Skip teams and players not matching the request if ms_team == tracked_team: # If the player does not have the item, do nothing for location in locations_checked: if (location, ms_player) not in locations: continue item, recipient = locations[location, ms_player] if recipient == tracked_player: # a check done for the tracked player attribute_item_solo(inventory, item) if ms_player == tracked_player: # a check done by the tracked player checks_done[location_to_area[location]] += 1 checks_done["Total"] += 1 # Note the presence of the triforce item for (ms_team, ms_player), game_state in multisave.get("client_game_state", []): # Skip teams and players not matching the request if ms_team != tracked_team or ms_player != tracked_player: continue if game_state: inventory[106] = 1 # Triforce acquired_items = [] for itm in inventory: acquired_items.append(get_item_name_from_id(itm)) # Progressive items need special handling for icons and class progressive_items = { "Progressive Sword": 94, "Progressive Glove": 97, "Progressive Bow": 100, "Progressive Mail": 96, "Progressive Shield": 95, } # Determine which icon to use for the sword sword_url = icons["Fighter Sword"] sword_acquired = False sword_names = [ 'Fighter Sword', 'Master Sword', 'Tempered Sword', 'Golden Sword' ] if "Progressive Sword" in acquired_items: sword_url = icons[sword_names[ min(inventory[progressive_items["Progressive Sword"]], 4) - 1]] sword_acquired = True else: for sword in reversed(sword_names): if sword in acquired_items: sword_url = icons[sword] sword_acquired = True break gloves_url = icons["Power Glove"] gloves_acquired = False glove_names = ["Power Glove", "Titan Mitts"] if "Progressive Glove" in acquired_items: gloves_url = icons[glove_names[ min(inventory[progressive_items["Progressive Glove"]], 2) - 1]] gloves_acquired = True else: for glove in reversed(glove_names): if glove in acquired_items: gloves_url = icons[glove] gloves_acquired = True break bow_url = icons["Bow"] bow_acquired = False bow_names = ["Bow", "Silver Bow"] if "Progressive Bow" in acquired_items: bow_url = icons[bow_names[ min(inventory[progressive_items["Progressive Bow"]], 2) - 1]] bow_acquired = True else: for bow in reversed(bow_names): if bow in acquired_items: bow_url = icons[bow] bow_acquired = True break mail_url = icons["Green Mail"] mail_names = ["Blue Mail", "Red Mail"] if "Progressive Mail" in acquired_items: mail_url = icons[mail_names[ min(inventory[progressive_items["Progressive Mail"]], 2) - 1]] else: for mail in reversed(mail_names): if mail in acquired_items: mail_url = icons[mail] break shield_url = icons["Blue Shield"] shield_acquired = False shield_names = ["Blue Shield", "Red Shield", "Mirror Shield"] if "Progressive Shield" in acquired_items: shield_url = icons[shield_names[ min(inventory[progressive_items["Progressive Shield"]], 3) - 1]] shield_acquired = True else: for shield in reversed(shield_names): if shield in acquired_items: shield_url = icons[shield] shield_acquired = True break # The single player tracker doesn't care about overworld, underworld, and total checks. Maybe it should? sp_areas = ordered_areas[2:15] return render_template( "playerTracker.html", inventory=inventory, get_item_name_from_id=get_item_name_from_id, player_name=player_name, room=room, icons=icons, checks_done=checks_done, checks_in_area=seed_checks_in_area, acquired_items=acquired_items, sword_url=sword_url, sword_acquired=sword_acquired, gloves_url=gloves_url, gloves_acquired=gloves_acquired, bow_url=bow_url, bow_acquired=bow_acquired, small_key_ids=small_key_ids, big_key_ids=big_key_ids, sp_areas=sp_areas, key_locations=player_small_key_locations[tracked_player], big_key_locations=player_big_key_locations[tracked_player], mail_url=mail_url, shield_url=shield_url, shield_acquired=shield_acquired)