diff --git a/WebHostLib/__init__.py b/WebHostLib/__init__.py
index 9c713419..934cc249 100644
--- a/WebHostLib/__init__.py
+++ b/WebHostLib/__init__.py
@@ -80,10 +80,8 @@ def register():
"""Import submodules, triggering their registering on flask routing.
Note: initializes worlds subsystem."""
# has automatic patch integration
- import worlds.AutoWorld
import worlds.Files
- app.jinja_env.filters['supports_apdeltapatch'] = lambda game_name: \
- game_name in worlds.Files.AutoPatchRegister.patch_types
+ app.jinja_env.filters['is_applayercontainer'] = worlds.Files.is_ap_player_container
from WebHostLib.customserver import run_server_process
# to trigger app routing picking up on it
diff --git a/WebHostLib/templates/hostGame.html b/WebHostLib/templates/hostGame.html
index 38406351..d7d0a963 100644
--- a/WebHostLib/templates/hostGame.html
+++ b/WebHostLib/templates/hostGame.html
@@ -17,9 +17,7 @@
This page allows you to host a game which was not generated by the website. For example, if you have
generated a game on your own computer, you may upload the zip file created by the generator to
host the game here. This will also provide a tracker, and the ability for your players to download
- their patch files if the game is core-verified. For Custom Games, you can find the patch files in
- the output .zip file you are uploading here. You need to manually distribute those patch files to
- your players.
+ their patch files.
In addition to the zip file created by the generator, you may upload a multidata file here as well.
diff --git a/WebHostLib/templates/macros.html b/WebHostLib/templates/macros.html
index b95b8820..0416658d 100644
--- a/WebHostLib/templates/macros.html
+++ b/WebHostLib/templates/macros.html
@@ -29,27 +29,15 @@
{% if patch.game == "Minecraft" %}
Download APMC File...
- {% elif patch.game == "Factorio" %}
-
- Download Factorio Mod...
- {% elif patch.game == "Kingdom Hearts 2" %}
-
- Download Kingdom Hearts 2 Mod...
- {% elif patch.game == "Ocarina of Time" %}
-
- Download APZ5 File...
{% elif patch.game == "VVVVVV" and room.seed.slots|length == 1 %}
Download APV6 File...
{% elif patch.game == "Super Mario 64" and room.seed.slots|length == 1 %}
Download APSM64EX File...
- {% elif patch.game | supports_apdeltapatch %}
+ {% elif patch.game | is_applayercontainer(patch.data, patch.player_id) %}
Download Patch File...
- {% elif patch.game == "Final Fantasy Mystic Quest" %}
-
- Download APMQ File...
{% else %}
No file to download for this game.
{% endif %}
diff --git a/worlds/Files.py b/worlds/Files.py
index e451d08c..447219bd 100644
--- a/worlds/Files.py
+++ b/worlds/Files.py
@@ -6,6 +6,7 @@ import zipfile
from enum import IntEnum
import os
import threading
+from io import BytesIO
from typing import ClassVar, Dict, List, Literal, Tuple, Any, Optional, Union, BinaryIO, overload, Sequence
@@ -70,6 +71,18 @@ class AutoPatchExtensionRegister(abc.ABCMeta):
container_version: int = 6
+def is_ap_player_container(game: str, data: bytes, player: int):
+ if not zipfile.is_zipfile(BytesIO(data)):
+ return False
+ with zipfile.ZipFile(BytesIO(data), mode='r') as zf:
+ if "archipelago.json" in zf.namelist():
+ manifest = json.loads(zf.read("archipelago.json"))
+ if "game" in manifest and "player" in manifest:
+ if game == manifest["game"] and player == manifest["player"]:
+ return True
+ return False
+
+
class InvalidDataError(Exception):
"""
Since games can override `read_contents` in APContainer,