diff --git a/.run/Archipelago Unittests.run.xml b/.run/Archipelago Unittests.run.xml
new file mode 100644
index 0000000000..24fea0f73f
--- /dev/null
+++ b/.run/Archipelago Unittests.run.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CommonClient.py b/CommonClient.py
index c4d80f3416..736cf4922f 100644
--- a/CommonClient.py
+++ b/CommonClient.py
@@ -460,7 +460,7 @@ class CommonContext:
else:
self.update_game(cached_game)
if needed_updates:
- await self.send_msgs([{"cmd": "GetDataPackage", "games": list(needed_updates)}])
+ await self.send_msgs([{"cmd": "GetDataPackage", "games": [game_name]} for game_name in needed_updates])
def update_game(self, game_package: dict):
for item_name, item_id in game_package["item_name_to_id"].items():
@@ -477,6 +477,7 @@ class CommonContext:
current_cache = Utils.persistent_load().get("datapackage", {}).get("games", {})
current_cache.update(data_package["games"])
Utils.persistent_store("datapackage", "games", current_cache)
+ logger.info(f"Got new ID/Name DataPackage for {', '.join(data_package['games'])}")
for game, game_data in data_package["games"].items():
Utils.store_data_package_for_checksum(game, game_data)
@@ -727,7 +728,6 @@ async def process_server_cmd(ctx: CommonContext, args: dict):
await ctx.server_auth(args['password'])
elif cmd == 'DataPackage':
- logger.info("Got new ID/Name DataPackage")
ctx.consume_network_data_package(args['data'])
elif cmd == 'ConnectionRefused':
diff --git a/Main.py b/Main.py
index 8dac8f7d20..e49d8e781d 100644
--- a/Main.py
+++ b/Main.py
@@ -114,7 +114,9 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
for _ in range(count):
world.push_precollected(world.create_item(item_name, player))
- for item_name, count in world.start_inventory_from_pool.setdefault(player, StartInventoryPool({})).value.items():
+ for item_name, count in getattr(world.worlds[player].options,
+ "start_inventory_from_pool",
+ StartInventoryPool({})).value.items():
for _ in range(count):
world.push_precollected(world.create_item(item_name, player))
# remove from_pool items also from early items handling, as starting is plenty early.
@@ -167,10 +169,14 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
# remove starting inventory from pool items.
# Because some worlds don't actually create items during create_items this has to be as late as possible.
- if any(world.start_inventory_from_pool[player].value for player in world.player_ids):
+ if any(getattr(world.worlds[player].options, "start_inventory_from_pool", None) for player in world.player_ids):
new_items: List[Item] = []
depletion_pool: Dict[int, Dict[str, int]] = {
- player: world.start_inventory_from_pool[player].value.copy() for player in world.player_ids}
+ player: getattr(world.worlds[player].options,
+ "start_inventory_from_pool",
+ StartInventoryPool({})).value.copy()
+ for player in world.player_ids
+ }
for player, items in depletion_pool.items():
player_world: AutoWorld.World = world.worlds[player]
for count in items.values():
diff --git a/ModuleUpdate.py b/ModuleUpdate.py
index c33e894e8b..c3dc8c8a87 100644
--- a/ModuleUpdate.py
+++ b/ModuleUpdate.py
@@ -4,14 +4,29 @@ import subprocess
import multiprocessing
import warnings
-local_dir = os.path.dirname(__file__)
-requirements_files = {os.path.join(local_dir, 'requirements.txt')}
if sys.version_info < (3, 8, 6):
raise RuntimeError("Incompatible Python Version. 3.8.7+ is supported.")
# don't run update if environment is frozen/compiled or if not the parent process (skip in subprocess)
-update_ran = getattr(sys, "frozen", False) or multiprocessing.parent_process()
+_skip_update = bool(getattr(sys, "frozen", False) or multiprocessing.parent_process())
+update_ran = _skip_update
+
+
+class RequirementsSet(set):
+ def add(self, e):
+ global update_ran
+ update_ran &= _skip_update
+ super().add(e)
+
+ def update(self, *s):
+ global update_ran
+ update_ran &= _skip_update
+ super().update(*s)
+
+
+local_dir = os.path.dirname(__file__)
+requirements_files = RequirementsSet((os.path.join(local_dir, 'requirements.txt'),))
if not update_ran:
for entry in os.scandir(os.path.join(local_dir, "worlds")):
diff --git a/MultiServer.py b/MultiServer.py
index 9d2e9b564e..15ed22d715 100644
--- a/MultiServer.py
+++ b/MultiServer.py
@@ -2210,25 +2210,24 @@ def parse_args() -> argparse.Namespace:
async def auto_shutdown(ctx, to_cancel=None):
await asyncio.sleep(ctx.auto_shutdown)
+
+ def inactivity_shutdown():
+ ctx.server.ws_server.close()
+ ctx.exit_event.set()
+ if to_cancel:
+ for task in to_cancel:
+ task.cancel()
+ logging.info("Shutting down due to inactivity.")
+
while not ctx.exit_event.is_set():
if not ctx.client_activity_timers.values():
- ctx.server.ws_server.close()
- ctx.exit_event.set()
- if to_cancel:
- for task in to_cancel:
- task.cancel()
- logging.info("Shutting down due to inactivity.")
+ inactivity_shutdown()
else:
newest_activity = max(ctx.client_activity_timers.values())
delta = datetime.datetime.now(datetime.timezone.utc) - newest_activity
seconds = ctx.auto_shutdown - delta.total_seconds()
if seconds < 0:
- ctx.server.ws_server.close()
- ctx.exit_event.set()
- if to_cancel:
- for task in to_cancel:
- task.cancel()
- logging.info("Shutting down due to inactivity.")
+ inactivity_shutdown()
else:
await asyncio.sleep(seconds)
diff --git a/README.md b/README.md
index a1e03293d5..ce2130ce8e 100644
--- a/README.md
+++ b/README.md
@@ -58,6 +58,7 @@ Currently, the following games are supported:
* Heretic
* Landstalker: The Treasures of King Nole
* Final Fantasy Mystic Quest
+* TUNIC
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled
diff --git a/WebHostLib/api/generate.py b/WebHostLib/api/generate.py
index 61e9164e26..5a66d1e693 100644
--- a/WebHostLib/api/generate.py
+++ b/WebHostLib/api/generate.py
@@ -20,8 +20,8 @@ def generate_api():
race = False
meta_options_source = {}
if 'file' in request.files:
- file = request.files['file']
- options = get_yaml_data(file)
+ files = request.files.getlist('file')
+ options = get_yaml_data(files)
if isinstance(options, Markup):
return {"text": options.striptags()}, 400
if isinstance(options, str):
diff --git a/WebHostLib/templates/generate.html b/WebHostLib/templates/generate.html
index 33f8dbc09e..53d98dfae6 100644
--- a/WebHostLib/templates/generate.html
+++ b/WebHostLib/templates/generate.html
@@ -69,8 +69,8 @@
|
@@ -185,12 +185,12 @@ Warning: playthrough can take a significant amount of time for larger multiworld
+
+
+
-
-
-
diff --git a/WebHostLib/templates/islandFooter.html b/WebHostLib/templates/islandFooter.html
index 7b89c4a9e0..08cf227990 100644
--- a/WebHostLib/templates/islandFooter.html
+++ b/WebHostLib/templates/islandFooter.html
@@ -1,6 +1,6 @@
{% block footer %}
|