mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00

* Option RangeWithSpecialMax * amendment to typing in web options * compare string with number * lots of work on zillion * fix zillion fill logic * fix a few more issues in zillion fill logic * can make zillion patch and use it * put multi items in zillion rom * work on ZillionClient * logging and auth in client * work on sending and receiving items * implement item_handling flag * fix locations ids to NuktiServer package * use rewrite of zri * cache logic rule data for performance * use new id maps * fix some problems with the big recent merge * ZillionClient: use new context manager for Memory class * fix ItemClassification for Zillion items and some debug statements for asserts, documentation on running scripts for manual testing type correction in CommonContext * fix some issues in client, start on docs, put rescue and item ram addresses in slot data * use new location name system fix item locations getting out of sync in progression balancing * zillion client can read slot name from game * zillion: new item names * remove extra unneeded import * newer options (room gen and starting cards) * update comment in zillion patch * zillion non static regions * change some logging, update some comments * allow ZillionClient to exit in certain situations * todo note to fix options doc strings * don't force auto forfeit * rework validation of floppy requirement and item counts and fix race condition in generate_output * reorganize Zillion component structure with System class * documentation updates for Zillion * attempt inno_setup.iss * remove todo comment for something done * update comment * rework item count zillion options and some small cleanups * fix location check count * data package version 1 * Zillion can pass unit tests without rom * fix freeze if closing ZillionClient while it's waiting for server login * specify commit hash for zilliandomizer package * some changes to options validation * Zillion doors saved on multiworld server * add missing function in inno_setup and name of vanilla continues in options * rework zillion sync task and context * Apply documentation suggestions from SoldierofOrder Co-authored-by: SoldierofOrder <107806872+SoldierofOrder@users.noreply.github.com> * update zillion package * workaround for asyncio udp bug There is a bug in Python in Windows https://github.com/python/cpython/issues/91227 that makes it so if I look for RetroArch before it's ready, it breaks the asyncio udp transport system. As a workaround, we don't look for RetroArch until the user asks for it with /sms * a few of the smaller suggestions from review * logic only looks at my locations instead of all the multiworld locations * some adjustments from pull request discussion and some unit tests * patch webhost changes from pull request discussion * zillion logic tests * better vblr test * test interaction of character rescue items with logic * move unit tests to new worlds folder * comment improvements * fix minor logic issue and add memory read timeout * capitalization in option display names Opa-Opa is a proper noun * redirect zz stdout to debug * fix option validation bug making unbeatable seeds * remove line that does nothing * attach logic cache to world Co-authored-by: SoldierofOrder <107806872+SoldierofOrder@users.noreply.github.com> Co-authored-by: Doug Hoskisson <doughoskisson@novuslabs.com>
98 lines
4.2 KiB
Python
98 lines
4.2 KiB
Python
import json
|
|
import zipfile
|
|
from io import BytesIO
|
|
|
|
from flask import send_file, Response, render_template
|
|
from pony.orm import select
|
|
|
|
from worlds.Files import AutoPatchRegister
|
|
from . import app, cache
|
|
from .models import Slot, Room, Seed
|
|
|
|
|
|
@app.route("/dl_patch/<suuid:room_id>/<int:patch_id>")
|
|
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)
|
|
if "patch_file_ending" in manifest:
|
|
patch_file_ending = manifest["patch_file_ending"]
|
|
else:
|
|
patch_file_ending = AutoPatchRegister.patch_types[patch.game].patch_file_ending
|
|
fname = f"P{patch.player_id}_{patch.player_name}_{app.jinja_env.filters['suuid'](room_id)}" \
|
|
f"{patch_file_ending}"
|
|
new_file.seek(0)
|
|
return send_file(new_file, as_attachment=True, download_name=fname)
|
|
else:
|
|
return "Old Patch file, no longer compatible."
|
|
|
|
|
|
@app.route("/dl_spoiler/<suuid:seed_id>")
|
|
def download_spoiler(seed_id):
|
|
return Response(Seed.get(id=seed_id).spoiler, mimetype="text/plain")
|
|
|
|
|
|
@app.route("/slot_file/<suuid:room_id>/<int:player_id>")
|
|
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, download_name=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 == "Zillion":
|
|
fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_SP.apzl"
|
|
elif slot_data.game == "Super Mario 64":
|
|
fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}_SP.apsm64ex"
|
|
elif slot_data.game == "Dark Souls III":
|
|
fname = f"AP_{app.jinja_env.filters['suuid'](room_id)}.json"
|
|
else:
|
|
return "Game download not supported."
|
|
return send_file(io.BytesIO(slot_data.data), as_attachment=True, download_name=fname)
|
|
|
|
|
|
@app.route("/templates")
|
|
@cache.cached()
|
|
def list_yaml_templates():
|
|
files = []
|
|
from worlds.AutoWorld import AutoWorldRegister
|
|
for world_name, world in AutoWorldRegister.world_types.items():
|
|
if not world.hidden:
|
|
files.append(world_name)
|
|
return render_template("templates.html", files=files)
|